下面的探讨主要针对Python3,在Python2中不一定适用。

查看Python的浮点数如何在内存中存储

Python的浮点数实现原理:
CPython实现有一个PyFloatObject的结构体,用来构造Python的浮点数类型:

typedef struct {
PyObject_HEAD # 这个对象包含:引用计数+对象类型,占8+8=16字节
double ob_fval; # 这个是存储浮点数的地方,Python的浮点数就是C的double,即双精度浮点
} PyFloatObject;

所以Python的浮点数类型占24字节:
引用计数+对象类型+双精度浮点数 = 8+8+8 = 24字节
不过Python3的整数长度无限,所以占字节数不定

用Python代码验证浮点数:

代码:

from ctypes import string_at
from sys import getsizeof
from binascii import hexlify
a=134.375
buffer=hexlify(string_at(id(a),getsizeof(a)))
print(buffer)
buffer_float=buffer[len(buffer)-16:]
print(buffer_float)
tmp=[buffer_float[i:i+2] for i in range(0,len(buffer_float),2)]
tmp=[bin(int(tmp[i].decode(),16))[2:].rjust(8,'0') for i in range(len(tmp)-1,-1,-1)]
print(' '.join(tmp))
print('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~')
b = ''.join(tmp)
S=b[0]
print('符号位',S)
E=b[1:12]
print('指数位',E)
M=b[12:]
print('尾数位',M)

探讨一下

十进制数 134.375 如何转换为二进制浮点数,并存储在内存中的:

134.375 等于二进制的 10000110.011,转换为IEEE754的浮点数格式:1.0000110011x2^7,其中首位1隐藏,尾数位=0000110011,符号位=0,指数位=(7+1023)的二进制=10000000110

134.375转换二进制小数的方法详见:浮点数在内存中是怎么存储的?

十进制小数部分最后一位不是5时,小数部分与2相乘不会得到1.0,就无法准确转换为二进制,比如134.372,小数0.372如果允许60个二进制位,将转换为:
010111110011101101100100010110100001110010101,100000010000000

整数部分134二进制为:10000110,首位1隐藏,变成0000110(7位),双精度52位尾数-7位整数部分=45位供小数存储。

因为小数0.372无法准确转换为二进制,第46进行“向偶数舍入”(见 整数转浮点数精度溢出的原因和处理方式),变成:
010111110011101101100100010110100001110010110
010111110011101101100100010110100001110010101,100000010000000 (原60位小数)

用代码验证

import struct
# 134.372 整数部分隐藏首位1 二进制=0000110
# 小数部分向偶数舍入后 二进制=010111110011101101100100010110100001110010110
# 指数二进制=10000000110
# 符号位=0
# S E M = 0,10000000110,0000110(整数)010111110011101101100100010110100001110010110(小数)
# 134.372 64位浮点数实际如下
a = '0100000001100000110010111110011101101100100010110100001110010110'
i = 0
h = ''
while i<64:h += f'{int(a[i:i+8],2):x}'i+=8
# 134.372 的浮点数十六进制
print(h)  # 4060cbe76c8b4396
# 复原
print(struct.unpack('!d', bytes.fromhex(h)))  # 输出结果是 (134.372,)

十进制数转换浮点数步骤(双精度)

1、整数部分转二进制:可以精确转换,假如数值为134.375

2、小数部分转二进制:可能无法精确转换,当小数最后一位是5时,一定能准确转换,转换后为10000110.011

3、写成规范化形式:1.0000110011x2^7

4、隐藏首位1:变成0000110011,这是尾数部分

5、计算符号位:正数0,负数1

6、计算指数位:双精度浮点数偏移=2^(指数位11-1)-1=1023,指数7+偏移1023=1030=10000000110(二进制)

7、最终内存中的样子:得到符号(S=1位)+指数(E=11位)+尾数(M=52位)的64比特二进制=0,10000000110,0000110011000000000000000000000000000000000000000000

浮点数(双精度)转换十进制数步骤

1、提取尾数位:补全首位的到,1.0000110011000000000000000000000000000000000000000000

2、指数移位操作:指数位10000000110=1030,1030-偏移1023=7,对尾数右移位7(负指数向左移位)=10000110.011000000000000000000000000000000000000000000

3、转换二进制整数+小数部分:1x2^7+0x2^6...0x2^0.0x(2^-1)+1x(2^-2)+1x(2^-3)...=134.375

Python的struct.pack()与struct.unpack()

python的struct主要用来处理C结构数据。主要有如下两个方法:

struct.pack(fmt, v1, v2, …)
struct.unpack(fmt, string)

参考:Python中struct.pack()和struct.unpack()用法详细说明

下面用struct来验证python的浮点数是不是C的double:

可以看到,上面截图的两段代码显示的134.375浮点数的S、E、M是完全一样的。

浮点数的IEEE754标准

有效位计算方法1

一个十进制位需要多少二进制位来表示:

大约需要3.322个二进制位来表示一个十进制位,所以:

单精度浮点数24(23尾数位+1隐藏位)位二进制可以表示大约:24/3.322≈7.225 位的十进制。

可见单精度浮点数的准确有效位是7(有效位表示非零整数部分+小数部分的数字位数,如1.23有效位是3,0.1234有效位是4)。

双精度浮点数的有效位同理计算可得:53/3.322≈15.95,有效位是15,总的来说:

1、单精度浮点数是4字节32位,符号位+指数位+尾数位=1位+8位+23位,有效位7~8位

2、双精度浮点数是8字节64位,符号位+指数位+尾数位=1位+11位+52位,有效位15~16位

参考:浮点数的有效数字位数、浮点数(单精度、双精度数)的有效位、深入理解浮点数有效位

有效位计算方法2

1、单精度浮点数有效数24位全是1时:10^7 < 2^24-1=16777215 < 10^8

所以单精度浮点数能准确表示小数点后第7位,第8位部分准确。16777215是能够转化为单精度浮点数表示的整数的最大精度,超过这个数会进行“舍入”导致丢失精度。

2、双精度浮点数有效数53位全是1时:10^15 < 2^53-1=9007199254740991 < 10^16

所以双精度浮点数能准确表示小数点后第15位,第16位部分准确。9007199254740991是能够转化为双精度浮点数表示的整数的最大精度,超过这个数会进行“舍入”导丢失精度。

参考:理解浮点数的二进制表示、整数转浮点数精度溢出的原因和处理方式、浮点数标准详解参考

Python的sys.float_info详解

sys.float_info输出内容:

In [202]: sys.float_info
Out[202]: sys.float_info(max=1.7976931348623157e+308, max_exp=1024, max_10_exp=308, min=2.2250738585072014e-308, min_exp=-1021, min_10_exp=-307, dig=15, mant_dig=53, epsilon=2.220446049250313e-16, radix=2, rounds=1)

1、max表示的就是最大规约数(即远离0的很大的数,加个负号成为最小规约数);

2、radix表示的是在电脑中储存的基数,二进制显然是2;

3、max_exp表示的是使得radix**(e-1)为可表示的有限浮点数最大指数,由于移码后的规约数的指数范围为-1022~1023,即最大为1023,所以最大的e自然就是1024;

4、max_10_exp表示的是让10**e为一个可表示的浮点数最大的指数,从结果1.7976931348623157e+308,得出max_10_exp自然就是308;

5、min表示最小的正规约数(即靠近0的很小的数,加个负号为靠近0的负的很大的数);

6、min_exp表示的是使得radix**(e-1)为可表示的有限浮点数最小指数,移码后的最小指数为-1022(尽管指数为0时,设定偏移量为1022,移码后的指数依然为-1022),因此最小的e为-1021;

7、min_10_exp表示的是让10**e为一个可表示的规约浮点数最小的指数,从结果2.2250738585072014e-308,得出这时最小的e为-307(要注意不是-308,因为10**(-308)比最小正规约数2.2250738585072014e-308还小,这是不符合要求的,所以应该是-307);

8、dig表示可以保证被精确的转为浮点数的整数的数字个数,保证被精确的转为浮点数的整数应该小于等于9007199254740991,该数有16位数字,但是大于该数的16位数字的整数是无法被精确的转为浮点数的,所以能确保精确的有效位是15;

9、mant_dig就是mantissa digits,即尾数位数,因为尾数的首位1被隐藏,所以真正的尾数位数共有52+1=53位;

10、epsilon表示最小的大于1的浮点数和1之间的差值;

11、rounds表示的是当一个整数转成浮点数,对无法精确表示的整数的近似模式,这里为1表示的是取距离原值最近的浮点数表示;

参考:浮点数的各种最值推算以及对python sys.float_info的解释、整数转浮点数精度溢出的原因和处理方式、python文档

Python浮点数举例

首先,双精度浮点数的全部53有效位可表示的最大十进制数是(53位全是1的情况):

2**53-1=9007199254740991

看一个更长的小数:

In [220]: 0.123456789123456789

Out[220]: 0.12345678912345678

为什么得到的浮点数是0.12345678912345678?它的小数位有17个,难道有效位变成了17?

其实有效位是16,因为0.12345678912345678中的1234567891234567才是精确的,最后的8是舍入后的值。那为什么是16个有效位?

因为上文说了双精度浮点数有效位15位是精确的,第16位部分精确,而1234567891234567<9007199254740991,1234567891234567这个值并没有完全填满53位尾数,当然是可以的。

舍入的那个值举例:

In [264]: 0.123456789123456749

Out[264]: 0.12345678912345674

In [265]: 0.123456789123456759

Out[265]: 0.12345678912345676

可以明显看到最后一位4或6是舍入值,因为它变大还是变小是不精确的,这取决于浮点数的舍入规则,见 整数转浮点数精度溢出的原因和处理方式

Python中的浮点数探秘相关推荐

  1. python中的浮点数用法_如何利用Python在运算后得到浮点数值的方法详解

    在python中进行两个整数相除的时候,在默认情况下都是只能够得到整数的值,而在需要进行对除所得的结果进行精确地求值时,想在运算后即得到浮点值,那么如何进行处理呢? 1.修改被除数的值为带小数点的形式 ...

  2. 如何在python中获取浮点数的十六进制值?

    浮点数的十六进制值 (Hexadecimal value of a float number) To get the hexadecimal value of a float number we us ...

  3. python减法精确度不准是什么问题,聊聊Python中的浮点数运算不准确问题

    大家好,老 Amy 来了.之前就意识到一个问题,但是最近又有朋友提出来了,所以就想着干脆记录下来,分享给大家叭~ 啥问题呢?请看题: 也就是说,需要大家计算1.1-1的值,很多朋友会说:"e ...

  4. python中的浮点数类型

    一. 浮点数类型有一个特点需要注意: 在计算机中所有的数字都是采用二进制表示的 具体来说,在python中采用53位二进制来表示一个浮点数的小数部分 那么0.1在计算机中表示的二进制是一串0101这样 ...

  5. Python中关于浮点数运算的不确定尾数的解释

    一.浮点数类型 与数学中实数概念一致,带有小数点及小数的数字.浮点数取值范围和小数精度都存在限制,但常规计算可忽略. 取值范围数量级约-10308到10308,精度数量级10-16. 二.浮点数运算的 ...

  6. python中浮点数的表示方法_很好地在python中表示浮点数

    我想将浮点数表示为四舍五入到一定位数的字符串,并且从不使用指数格式. 本质上,我想显示任何浮点数并确保它看起来不错. 这个问题有几个部分: 我需要能够指定 有效位数. 有效位数 需要是可变的,不能是 ...

  7. Python 中的浮点数

    先看一个违反直觉的例子: >>> s = 0. >>> for i in range(10): s += .1 >>> s 0.999999999 ...

  8. Python中浮点数精度处理

    from: Python中浮点数精度处理 Python中,浮点数运算,经常会碰到如下情况: 出现上面的情况,主要还是因浮点数在计算机中实际是以二进制保存的,有些数不精确. 比如说: 0.1是十进制,转 ...

  9. python运算结果是浮点数_Python中的浮点数原理与运算分析 python中浮点数等于整数?为什么?...

    python的浮点数运算是不是精度有问题阿 python中浮点数的处理女生啊,平时要好好护肤,保持身材,多看书,多旅行,有自己的想法,去做自己喜欢的事,培养自信,不要把精力全部用在一个男人身上,成天胡 ...

最新文章

  1. TQ210裸机编程(4)——按键(中断法)
  2. 学习笔记Hadoop(一)—— Hadoop介绍(1)——认识大数据
  3. [羊城杯 2020]Power
  4. php编译优化,浅析使用Turck-mmcache编译来加速、优化PHP代码
  5. 【小技巧】自定义asp.net mvc的WebFormViewEngine修改默认的目录结构
  6. xdcms_3.0.1 | 代码审计
  7. 数字图像处理实践(一)
  8. 关于XP系统远程桌面的一点点记录
  9. Zlib文件压缩和解压
  10. NC:恢复菌群多样性或能降低耐药性
  11. 魔兽争霸php文件怎么打开,魔兽争霸之PHP设计模式
  12. 2018艾耕科技笔试题
  13. 苹果微信换行怎么打_微信两根毛表情怎么打出来?左右小辫子符号苹果安卓手机教程介绍...
  14. 通过OTA的方式在局域网分发iOS应用
  15. Java实现伪造邮件发信人
  16. 51单片机内存动态分配
  17. Not FoundThe requested URL was not found on the server. If you entered the URL manually please chec
  18. 软件测试职业发展方向有哪些
  19. 小六六平时的开发小技巧二(Nacos在服务配置中心的妙用)
  20. python数据分析、挖掘与可视化 慕课答案_知到APPPython数据分析与数据可视化2021慕课答案...

热门文章

  1. 通达信版弘历软件指标_弘历软件指标源码汇总。
  2. 微信新版也搞事情,一个小工具搞定
  3. linux安装ppt教程视频教程下载,Linux教程ch2Linux安装及入门.ppt
  4. crmeb多商户 商户后台目录结构
  5. ADO技巧精华10则(转)
  6. StringUtil(字符串工具类)
  7. 如何去掉网页复制到word后的黑(或灰)背景色
  8. [转载] Gedit快捷键
  9. Mysql数据库基础入门教程
  10. 【读书笔记】Android开发艺术探索