Jon*_*nyK 10 python floating-point precision numpy
当对float16 Numpy数字执行数学运算时,结果也是float16类型数.我的问题是如何计算结果?假设我乘以/添加两个float16数字,python是否在float32中生成结果然后将结果截断/舍入为float16?或者计算是否在"16位多路复用器/加法器硬件"中执行?
另一个问题 - 是否有float8类型?我找不到这个......如果没有,那么为什么?谢谢你们!
Mar*_*son 11
对于第一个问题:float16
典型处理器(至少在GPU之外)没有硬件支持.NumPy完全按照你的建议:将float16
操作数转换为float32
,对float32
值执行标量操作,然后将float32
结果舍入到float16
.可以证明结果仍然是正确的舍入:精度float32
足够大(相对于float16
),双舍入在这里不是问题,至少对于四个基本算术运算和平方根.
在当前的NumPy源代码中,这就是float16
标量运算的四种基本算术运算的定义.
#define half_ctype_add(a, b, outp) *(outp) = \
npy_float_to_half(npy_half_to_float(a) + npy_half_to_float(b))
#define half_ctype_subtract(a, b, outp) *(outp) = \
npy_float_to_half(npy_half_to_float(a) - npy_half_to_float(b))
#define half_ctype_multiply(a, b, outp) *(outp) = \
npy_float_to_half(npy_half_to_float(a) * npy_half_to_float(b))
#define half_ctype_divide(a, b, outp) *(outp) = \
npy_float_to_half(npy_half_to_float(a) / npy_half_to_float(b))
Run Code Online (Sandbox Code Playgroud)
上面的代码取自NumPy源代码中的scalarmath.c.src.您还可以查看loops.c.src以获取数组ufuncs的相应代码.支持npy_half_to_float
和npy_float_to_half
函数在halffloat.c中定义,以及该float16
类型的各种其他支持函数.
对于第二个问题:不,float8
NumPy中没有类型.float16
是一种标准化类型(在IEEE 754标准中描述),在某些情况下(特别是GPU)已广泛使用.没有IEEE 754 float8
类型,并且似乎没有明显的"标准" float8
类型的候选者.我还猜测float8
NumPy的支持需求并不多.
jet*_*eon 11
这个答案建立在问题的float8
方面。接受的答案很好地涵盖了其余部分。float8
除了缺乏标准之外,没有被广泛接受的类型的主要原因之一是它实际上不是很有用。
在标准表示法中,float[n]
数据类型使用n
内存中的位存储。这意味着最多只能2^n
表示唯一值。在 IEEE 754 中,一些可能的值(例如nan
)不是偶数。这意味着所有浮点表示(即使你去float256
)在它们能够表示的一组有理数中都有间隙,如果你试图在这个间隙中获得一个数字的表示,它们会四舍五入到最接近的值。通常越高n
,这些差距越小。
如果您使用该struct
包来获取某些float32
数字的二进制表示,您可以看到实际操作中的差距。一开始遇到这个问题有点令人吃惊,但仅在整数空间中就有 32 的差距:
import struct
billion_as_float32 = struct.pack('f', 1000000000 + i)
for i in range(32):
billion_as_float32 == struct.pack('f', 1000000001 + i) // True
Run Code Online (Sandbox Code Playgroud)
通常,浮点数最擅长仅跟踪最重要的位,因此如果您的数字具有相同的比例,那么重要的差异将被保留。浮点标准通常仅在它们在基数和指数之间分配可用位的方式上有所不同。例如,IEEE 754float32
使用 24 位作为基数,使用 8 位作为指数。
float8
根据上述逻辑,一个float8
值只能取 256 个不同的值,无论您在基数和指数之间拆分位是多么聪明。除非您热衷于将数字四舍五入为聚集在零附近的 256 个任意数字之一,否则仅跟踪int8
.
例如,如果您想以粗略的精度跟踪一个非常小的范围,您可以将您想要的范围划分为 256 个点,然后存储您的数字最接近 256 个点中的哪一个。如果您想变得真正花哨,您可以根据对您最重要的内容,将值的非线性分布集中在中心或边缘。
其他任何人(甚至以后的您自己)需要这种精确方案的可能性非常小,而且大多数情况下,您为使用float16
或float32
代替而支付的额外字节或 3 字节太小而无法产生有意义的差异。因此......几乎没有人费心去写一个float8
实现。