Python的numpy float16数据类型操作,和float8?

fsi0uk1n  于 11个月前  发布在  Python
关注(0)|答案(2)|浏览(177)

当对float 16 Numpy数字执行数学运算时,结果也是float 16类型的数字。我的问题是结果是如何计算的?假设我将两个float 16数字相乘/相加,python是否生成float 32的结果,然后将结果截断/舍入为float 16?或者计算一直在“16位多路复用器/加法器硬件”中执行?
另一个问题-有float 8类型吗?我找不到这个......如果没有,那是为什么?请-你们所有人!

eoigrqb6

eoigrqb61#

关于第一个问题:在典型的处理器上没有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))

字符串
上面的代码取自NumPy源代码中的scalarmath.c.src。您也可以查看loops.c.src以获取数组ufuncs的相应代码。支持npy_half_to_floatnpy_float_to_half的函数在halffloat.c中定义,沿着各种其他float16类型的支持函数。
关于第二个问题:不,NumPy中没有float8类型。float16是标准化类型(在IEEE 754标准中描述),在某些环境中已经广泛使用(特别是GPU)。没有IEEE 754 float8类型,而且似乎没有一个明显的“标准”候选人,float8类型。我还猜测NumPy中对float8支持的需求并不多。

vohkndzv

vohkndzv2#

这个答案建立在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

字符串
通常,浮点数最好只跟踪最高有效位,这样,如果您的数字具有相同的小数位数,则保留重要的差异。浮点数标准通常仅在基数和指数之间分配可用位的方式上有所不同。例如,IEEE 754 float32使用24位作为基数,使用8位作为指数。

返回float8

根据上面的逻辑,float8值只能有256个不同的值,无论你在基和指数之间分割位有多聪明。除非你热衷于将数字舍入为256个聚集在零附近的任意数字之一,否则只跟踪int8中的256个可能性可能更有效。
例如,如果你想以粗略的精度跟踪一个非常小的范围,你可以将你想要的范围划分为256个点,然后存储256个点中你的数字最接近的一个。如果你想得到真正的幻想,你可以有一个非线性分布的值,要么聚集在中心,要么聚集在边缘,这取决于什么对你最重要。
其他人(甚至是你自己)需要这个方案的可能性非常小,而且大多数时候,你为使用float16float32而付出的额外字节或3的代价太小了,以至于没有意义。因此,几乎没有人费心去写一个float8实现。

相关问题