Numpy `.astype`四舍五入

fjnneemd  于 2023-10-19  发布在  其他
关注(0)|答案(1)|浏览(89)

类似于Numpy astype rounding to wrong value,但这似乎是相反的问题,实际上是我想要的(截断)。在我的真实的例子中,我正在做各种计算,其中一些值可以非常非常接近下一个整数,然后转换为整数。我 * 希望 * 数字被截断,我希望它等价于floor操作。最后我把结果作为索引。但是,当我执行.astype(np.int32)时,它似乎是四舍五入。这是怎么回事

In [2]: import numpy as np

...

In [49]: np.array([4319.9997], dtype=np.float32).astype(np.int32)
Out[49]: array([4319], dtype=int32)

In [50]: np.array([4319.9998], dtype=np.float32).astype(np.int32)
Out[50]: array([4320], dtype=int32)

我理解32位浮点精度和64位浮点精度,但我不理解astype在这里做什么的内部操作。

vdgimpew

vdgimpew1#

重复评论中所说的话。32位版本的“4319.9997”实际上更接近于“4319.9995”。当numpy/Python/C试图将“4319.9998”从64位浮点数转换为32位浮点数时,只有两个选项是“4319.9995”或“4320.0”,而“4320.0”更接近,因此它会向上舍入。我不能说这是怎么回事,但它使一些意义给我。

原始答案

我不能说我完全理解我要回答的问题,但有些是有道理的。我认为这可以归结为Python(或C或其他东西)如何将字符串字面量转换为32位浮点数。
二进制打印函数来自:
https://stackoverflow.com/a/16444778/433202

import struct
def binary(num):
    return ''.join('{:0>8b}'.format(c) for c in struct.pack('!f', num))

并使用它将数字打印为32位IEEE浮点数:

In [62]: binary(4319.9997)
Out[62]: '01000101100001101111111111111111'

In [63]: binary(4319.9998)
Out[63]: '01000101100001110000000000000000'

因此,0表示符号,10001011表示指数部分,00001101111..表示小数有效位部分。
所以当我输入的字符串字面量被转换成双精度数时,它达到了某个阈值,小数部分被加了一个1,这将所有的位都滚到了有效数的整数部分。
对我来说,这整件事的最大误解/误解是,当我被告知将浮点数转换为int将“截断”数字的小数部分时,我假设它是在以10为基数进行的,但它(C?)实际上是在基数2中进行的。这是显而易见的道理,但我从来没有想过,直到这个问题。
我仍然不明白的部分是,为什么从我输入的浮点字符串字面量“4319.9998”转换到下一个数字(+1)。为什么不接受精度问题并将其保持为与“4319.9997”相同的值?我做了一个64位(双精度)版本的二进制函数,当我打印出这两个版本的数字时:

In [91]: binary64(4319.9997)
Out[91]: '0100000010110000110111111111111111101100010101101101010111010000'

In [92]: binary64(4319.9998)
Out[92]: '0100000010110000110111111111111111110010111001001000111010001010'

如果你对64位浮点表示的位数进行计数并将其分开,两个值在正负号的“整数”部分之后都有很多1(在将.移位到指数位之后),所以我不确定为什么一个会被舍入而另一个不会。

相关问题