3

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

原则上,我可以直接将原始 (float64) 与重构 (float64(float32(original)) 进行比较,并了解最大误差等信息。

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

我最好先将所有值(64位)映射到[-1,1]上(作为极值的一部分,可以保留在64位中)以利用接近零的更大密度的浮点数?

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

4

3 回答 3

7

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

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

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

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

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

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

如果 double 的值可以精确地表示为 float,则转换没有错误。

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

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

于 2012-06-13T17:06:23.847 回答
5

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

缩放只能通过两种方式产生影响:第一,它将值从单精度值的非正规区间 (-2 -126 , 2 -126 ) 移开。(例如,如果你乘以[2 -249 , 2 -126 )中的 2 123个值,则映射到非正规区间之外的 [2 -126 , 2 -3)。)二,它会改变其中值位于每个“binade”中(从 2 的一个幂到下一个的间隔)。例如,您的最大值是 20,其中相对误差可能是 1/2 ULP / 20,其中该 binade 的 ULP 是 16*2 -23 = 2 -19,因此相对误差可能是 1/2 * 2 - 19/ 20,约 4.77e-8。假设您按 32/20 缩放,因此 20 以下的值将变为 32 以下的值。然后,当您转换为浮点数时,相对误差最多为 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 的转换并测量了错误?

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

于 2012-06-14T05:34:12.840 回答
2

float32 的指数要小得多(或在负指数的情况下更大),但假设你所有的数字都小于你只需要担心精度损失。float32 只适用于大约 7 或 8 位有效十进制数字

于 2012-06-13T01:56:02.747 回答