[英]Numpy's float32 and float comparisons
继续Python float和numpy float32之间的区别 :
import numpy as np
a = 58682.7578125
print(type(a), a)
float_32 = np.float32(a)
print(type(float_32), float_32)
print(float_32 == a)
打印:
<class 'float'> 58682.7578125
<class 'numpy.float32'> 58682.8
True
我完全明白,将浮点数比较为平等并不是一个好主意但仍然不应该是假的(我们讨论的是第一个十进制数字的差异,而不是0.000000001)? 它是系统依赖的吗? 这种行为是否记录在案?
编辑:嗯,它是第三个小数:
print(repr(float_32), repr(a))
# 58682.758 58682.7578125
但我可以信任repr
吗? 这些内部存储在最终结局中的方式如何?
EDIT2:人们坚持认为以更高的精度打印float_32会给我它的代表性。 但是正如我已根据nympy的文档评论过:
%格式化运算符要求将其参数转换为标准python类型
和:
print(repr(float(float_32)))
版画
58682.7578125
一个有趣的见解是@MarkDickinson给出这里 ,显然repr
应该是忠实的(然后他说,这是不是忠实的np.float32
)。
所以让我重申我的问题如下:
float_32
和a
的确切内部表示 ? 如果这些是相同的,那么问题就解决了,如果没有, float
和np.float32
之间进行比较时,向上/向下转换的确切规则是什么? 虽然@WillemVanOnsem 在评论中暗示它是另一回事,但我猜它会将float_32向上移动。 我的python版本:
win32上的Python 3.5.2(v3.5.2:4def2a2901a5,2016年6月25日,22:18:55)[MSC v.1900 64位(AMD64)]
数字比较相等,因为58682.7578125可以在32位和64位浮点中精确表示。 让我们仔细看看二进制表示:
32 bit: 01000111011001010011101011000010
sign : 0
exponent: 10001110
fraction: 11001010011101011000010
64 bit: 0100000011101100101001110101100001000000000000000000000000000000
sign : 0
exponent: 10000001110
fraction: 1100101001110101100001000000000000000000000000000000
它们具有相同的符号,相同的指数和相同的分数 - 64位表示中的额外位用零填充。
无论他们演出哪种方式,他们都会比较平等。 如果您尝试使用其他数字,例如58682.757812 4,您将看到二进制级别的表示不同; 32位失去更高的精度,他们不会比较相等。
(在二进制表示中也很容易看到float32可以向上传播到float64而不会丢失任何信息。这就是numpy在比较两者之前应该做的事情。)
import numpy as np
a = 58682.7578125
f32 = np.float32(a)
f64 = np.float64(a)
u32 = np.array(a, dtype=np.float32).view(dtype=np.uint32)
u64 = np.array(a, dtype=np.float64).view(dtype=np.uint64)
b32 = bin(u32)[2:]
b32 = '0' * (32-len(b32)) + b32 # add leading 0s
print('32 bit: ', b32)
print('sign : ', b32[0])
print('exponent: ', b32[1:9])
print('fraction: ', b32[9:])
print()
b64 = bin(u64)[2:]
b64 = '0' * (64-len(b64)) + b64 # add leading 0s
print('64 bit: ', b64)
print('sign : ', b64[0])
print('exponent: ', b64[1:12])
print('fraction: ', b64[12:])
小数58682.7578125是精确分数( 7511393/128
)。
分母是2( 2**7
)的幂,分子跨度为23位。 所以这个十进制值可以在float32(有24位有效位)和float64中完全表示。
因此,Victor T的答案是正确的:在内部表示中,它是相同的值。
对于相同的值,即使对于不同的类型,平等回答是真的这一事实是IMO的一件好事,你期望什么(2 == 2.0)
?
他们是平等的。 他们只是不打印相同,因为他们使用不同的打印逻辑。
如何在示例中获得float_32和a的确切内部表示?
那么,这取决于你所说的“确切的内部表征”。 如果你真的想要一个比特值,你可以得到一个比特值数组:
>>> b = numpy.float32(a)
>>> numpy.unpackbits(numpy.array([b]).view(numpy.uint8))
array([1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0,
1, 0, 1, 0, 0, 0, 1, 1, 1], dtype=uint8)
这与你的“精确内部表示”一样接近,但它并不是最有用的东西。 (此外,结果将依赖于字节顺序,因为它实际上基于原始内部表示。)
如果你想要一个C级浮点数,这就是NumPy在C级表示float32值的方式......好吧,那就是C.除非你想编写自己的C扩展模块,否则你不能直接使用C级值。 你能得到的最接近的是C浮子周围的某种包装,嘿! 你已经有一个! 但是你似乎并不满意,所以这不是你想要的。
如果你想要用人类可读的十进制表示的确切值,使用str.format
以额外的精度打印它,或者将它转换为常规的float,然后是decimal.Decimal
就可以了。
>>> b
58682.758
>>> decimal.Decimal(float(b))
Decimal('58682.7578125')
您选择的58682.7578125值恰好可以表示为浮点数,因此出现的十进制表示恰好是您放入的值,但通常情况并非如此。 您键入的确切十进制表示将被丢弃并且不可恢复。
在python的float和np.float32之间进行比较时,向上/向下转换的确切规则是什么?
float32无损地转换为float64。
58682.8
我的机器显示58682.758这条线。
我完全理解比较花车的平等并不是一个好主意
如果他们独立计算,那就不是一个好主意。 另一方面,如果您获得相同的数字并检查其转换,这是一个好主意。
它是系统依赖的吗? 这种行为是否记录在案?
它完全依赖于转换为文本。 根据评论,float32是必不可少的。 如果是这样,float32的保证精度是7位十进制数字,不像Python的内部浮点数是float64(至少在x86上)。 这就是为什么该值在打印中被截断的原因。 以十进制形式打印浮点值的推荐方法是在输出形式转换回相同的内部值时停止。 所以它将58682.7578125减少到58682.758:差异小于ULP。
打印为内部“float”或numpy float64的相同值将具有更多有效数字,因为它们的省略将导致另一个内部值:
>>> 58682.758 == 58682.7578125
False
>>> numpy.float32(58682.758) == numpy.float32(58682.7578125)
True
>>> print(repr(numpy.float32(58682.758).data[0:4]))
'\xc2:eG'
>>> print(repr(numpy.float32(58682.7578125).data[0:4]))
'\xc2:eG'
>>> numpy.float64(58682.758) == numpy.float64(58682.7578125)
False
>>> print(numpy.float64(58682.758).hex(), numpy.float64(58682.7578125).hex())
('0x1.ca7584189374cp+15', '0x1.ca75840000000p+15')
你很幸运这两个值在float32中与这个具体值相同(这是故意吗?)但它可能与其他值不同。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.