如果我将float64数组压缩到numpy中的float32,我应该担心什么?

时间:2012-06-13 01:42:20

标签: python numpy floating-point compression

这是一种特殊的有损压缩,很容易在numpy中实现。

我原则上可以直接比较原始(float64)和重构(float64(float32(原始))并知道最大错误之类的事情。

除了查看实际数据的最大误差外,是否有人知道这会产生什么类型的扭曲,例如:作为原始值的大小的函数?

首先将所有值(以64位为单位)映射到[-1,1]上(作为极值的一小部分,可以保留为64位),以利用更高的密度漂浮在零附近?

我正在添加一个我想到的具体案例。假设我有500k到1e6的值,范围从-20到20,大约是IID~Normal(mu = 0,sigma = 4),所以它们已经非常集中在零附近,“20”是〜5-sigma罕见。让我们说它们是科学测量,其中真正的精度比64位浮点数少很多,但很难确切地知道。我有大量单独的实例(可能是TB的价值),因此压缩具有很多实用价值,而float32是获得50%的快速方法(如果有的话,通过gzip等额外的无损压缩更好地工作)。所以“-20到20”消除了很多关于真正大值的担忧。

3 个答案:

答案 0 :(得分:7)

以下假设您使用标准IEEE-754浮点运算,这些运算在通常的舍入到最近模式中是常见的(有一些例外)。

如果double值在float值的正常范围内,那么当double被舍入为float时发生的唯一变化是有效位数(值的小数部分)从53位舍入为24位。这将导致最多1/2 ULP(精度最低的单位)的误差。浮子的ULP是2 -23 乘以2的最大幂,不大于浮子。例如,如果浮点数为7.25,那么2的最大幂不大于4,因此其ULP为4 * 2 -23 = 2 -21 ,约为4.77 E-7。因此,当区间[4,8]中的双精度转换为浮点时的误差最多为2 -22 ,约为2.38e-7。再举一个例子,如果一个浮点数约为0.03,那么2的最大幂不大于2 -6 ,所以ULP是2 -29 ,并且转换为double时的最大误差为2 -30

这些都是绝对错误。相对误差小于2 -24 ,即1/2 ULP除以该值可能的最小值(特定ULP的间隔中的最小值,因此两个边界的幂)它)。例如,对于[4,8]中的每个数字x,我们知道该数字至少为4且误差最多为2 -22 ,因此相对误差最多为2 -22 / 4 = 2 -24 。 (错误不能正好是2 -24 ,因为将2的精确幂从float转换为double时没有错误,所以只有当x大于4时才会出错,所以相对错误小于,不等于2 -24 。)当你对被转换的值有更多了解时,例如,它接近8比4,你可以更严格地约束错误。

如果数字超出浮点数的正常范围,则错误可能会更大。最大有限浮点值为2 128 -2 104 ,约3.40e38。当你将1/2 ULP(浮点数;双精度具有更精细的ULP)的双精度值转换为浮点数或更大值时,返回无穷大,当然,这是一个无限的绝对误差和无限的相对误差。 (一个大于最大有限浮点数的double,但是大于1/2 ULP的二次转换为最大有限浮点数并且具有前一段中讨论的相同错误。)

最小正正常浮点数为2 -126 ,约为1.18e-38。将此(包括)的1/2 ULP内的数字转换为它,但小于该数字的数字将转换为特殊的非规范化格式,其中ULP固定为2 -149 。绝对误差最多为1/2 ULP,2 -150 。相对误差将在很大程度上取决于转换的值。

以上讨论了正数。负数的误差是对称的。

如果double的值可以完全表示为float,则转换中没有错误。

将输入数字映射到新的间隔可以减少特定情况下的错误。作为一个人为的例子,假设你的所有数字都是区间[2 48 ,2 48 +2 24 )的整数。然后将它们转换为float将丢失区分值的所有信息;他们都将被转换为2 48 。但将它们映射到[0,2 24 )将保留所有信息;每个不同的输入都会转换为不同的结果。

哪种地图最适合您的用途取决于您的具体情况。

答案 1 :(得分:5)

简单的转换不太可能显着减少错误,因为您的分布以零为中心。

缩放只能通过两种方式起作用:一,它将值从单精度值的非正规区间移开,(-2 -126 ,2 -126 )。 (例如,如果乘以[2 -249 ,2 -126 )中的2 123 值,则映射到[ 2 -126 ,2 -3 ),这是在非正规区间之外。)二,它改变了每个“binade”中值的位置(两个幂的间隔)到下一个)。例如,你的最大值是20,其中相对误差可能是1/2 ULP / 20,其中该binade的ULP是16 * 2 -23 = 2 -19 ,因此相对误差可能是1/2 * 2 -19 / 20,约为4.77e-8。假设您按比例缩放32/20,因此20以下的值变为低于32的值。然后,当您转换为float时,相对误差最多为1/2 * 2 -19 / 32(或者在32岁以下,约2.98e-8。所以你可以稍微减少错误。

关于前者,如果你的数值接近正态分布,很少有(-2 -126 ,2 -126 ),仅仅是因为那个区间太小了(正常分布的万亿个样本几乎肯定在该区间内没有值。)你说这些是科学测量,所以也许它们是用一些仪器生成的。可能是机器没有足够精确地测量或计算以返回从2 -126 到20的值,所以如果你在非正常间隔中没有值,那么我不会感到惊讶。如果在单精度非正规范围内没有值,则缩放以避免该范围是没有用的。

关于后者,我们发现在您的范围结束时可以获得一些小改进。然而,在你的范围内的其他地方,一些值也被移动到一个binade的高端,但是一些值被移动到一个binade边界到一个新的binade的小端,导致它们的相对误差增加。不太可能有显着的净改善。

另一方面,我们不知道您的申请有什么重要意义。您的应用程序可以容忍多少错误?如果每个数字增加1%的随机噪音,最终结果的变化是否会变得不明显?如果少数数字变化为2 -200 ,结果是否完全不可接受?

您对生产这些数字的机器了解多少?它是否真正产生比单精度浮子更精确的数字?也许,尽管它产生64位浮点值,但实际值仅限于可在32位浮点中表示的总体。您是否执行了从double到float的转换并测量了错误?

仍然没有足够的信息来排除这些或其他可能性,但我最好的猜测是任何转变都没有什么好处。转换为float会引入太多错误,或者不会引入错误,并且首先转换数字不太可能改变它。

答案 2 :(得分:2)

float32的指数相当小(或者在负指数的情况下更大),但假设所有数字都小于那个,你只需要担心精度的损失。 float32仅适用于大约7或8个有效小数位