下面的探讨主要针对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. 【Android 逆向】函数拦截实例 ( ② 插桩操作 | 保存实际函数入口 6 字节数据 | 在插桩的函数入口写入跳转指令 | 构造拼接桩函数 )
  2. ShellCode的编写入门
  3. Python基础入门:反射
  4. unity3d的执行顺序
  5. Cloud for Customer的前端如何判断自己是运行在PC浏览器还是移动设备里
  6. Intent跳转传list集合
  7. struts中多个模块时,使用多个struts-config.xml文件之间时如何切换的!
  8. python作业:高级FTP程序
  9. 数据结构链表之栈——解决括号匹配问题和逆波兰表达式求值问题——6
  10. java 布尔逻辑运算符_Java运算符
  11. 糖豆人显示此服务器正在进行游戏,糖豆人服务器频繁崩溃,west滚石教技巧,蓝哥踢球做内鬼...
  12. 微信公众平台 获取用户列表
  13. 如何学好python基础_零基础如何学好Python开发?
  14. php 解析返回的xml,php解析cas返回的xml解决思路
  15. Sicily 1029. Rabbit 解题报告
  16. Redis 安装,主从配置及Sentinel配置自动Failover
  17. 抛出 java.lang.ClassCastException: android.widget.RelativeLayout$LayoutParams cannot be cast to andr异常
  18. 苹果服务器cpu型号怎么看,iphone6s plus怎么查cpu型号 iphone6s plus查询cpu型号方法
  19. vlan的tagged、untagged
  20. Android 简单的白天与夜晚模式切换

热门文章

  1. 顶级 JavaScript 技巧
  2. I——懒癌患者大四狗
  3. 区块链并不是什么都可解决的完美方案
  4. MySQL的month()函数方法对应得Oracle方法
  5. Harbor对接OIDC
  6. 利用python从GitHub获取https代理,采集网站的数据的速度翻倍
  7. 【数据增强】镜像mirror(图片+标签)
  8. hadoop的操作命令(第3课)
  9. JAVA错误: 找不到或无法加载主类
  10. 二维空间点到直线垂足计算公式推导及Java实现——学习笔记