为什么这段C代码中使用的IEEE-754指数偏移值是126.94269504而不是127?

14

以下C语言函数来自fastapprox项目。

static inline float 
fasterlog2 (float x)
{
  union { float f; uint32_t i; } vx = { x };
  float y = vx.i;
  y *= 1.1920928955078125e-7f;
  return y - 126.94269504f;
}

这里有没有专家可以解释一下为什么上述代码中使用的指数偏置是126.94269504而不是127?这个偏置值更精确吗?


1
编译器警告来自 float y = vx.i;,提示 "可能会丢失数据"。 - Weather Vane
1
为什么不问一下写代码的人呢?这不是真正的编码问题,更像是一个算法问题,对吧? - Dan
1
@Dan - 是的,但是C开发者是能够阅读C代码的人,他们通常关心这种底层知识。根据我的搜索,已经有很多使用fastapprox实现的C项目,所以也许对C开发者来说,这个问题的答案也是有用的。还有一点要说的是,为什么只有问作者才能得到问题的答案呢?在这里,我可能会从不同的专家那里更快地得到回复。 - Astaroth
2个回答

9
在你提供的项目中,他们附带了一个Mathematica笔记本,其中解释了他们的算法,包括“神秘”的-126.94269值。
如果你需要一个查看器,可以从Mathematica网站免费获取。

编辑:因为我很慷慨,这里是相关部分的截图形式

简单来说,他们解释说这个值“更简单、更快、更不准确”。
他们并没有用-126.94269代替-127,而是用它代替以下计算结果(为简洁起见,数值已四舍五入):

-124.2255 - 1.498 * mx - (1.72588 / (0.35201 + mx))

2
我喜欢它们使用1.1920928955078125e-7和126.94269504这些数字,分别具有17位和11位的精度,然后在末尾加上“f”使它们成为浮点数! - Steve Summit
@SteveSummit 这是17个十进制数字;也许它们在IEEE754中可以被精确表示。 - M.M
@Mr_Llama,我明白了,非常感谢。原来是我匆忙浏览他们的网站,没有注意到有这样一个Mathematica笔记本。 - Astaroth
考虑到所有2^32个可能的“float”编码,并且丢弃其“log2”结果为“NAN”或“INF”的编码,可以清楚地发现,“126.94269504”值比“127.0”更好,与“0.0303”的平均绝对误差相比,仅有“0.0129”的误差。然而,这个值并不是减少平均误差的最佳选择 - 使用“126.940”可以进一步将误差降至“0.0128”。我猜测作者在优化该值时使用了不同于“平均误差”的指标。 - MooseBoys
3
啊,果然,作者添加了一个修正因子,以使输入接近2的幂时的结果更加准确,但代价是总体精度降低。 - MooseBoys
@MooseBoys 虽然我自己没有测试过他们是否这样做,但我要指出一个常见的度量标准是“最差误差”,而不是平均值。这样你就可以将你的函数规定为+/- X 的精度。 - kylefinn

-4

不,126.94269504并不是“更准确”的偏差值。这段代码做了一些非常奇怪的事情;我很惊讶它居然能工作。它将一个浮点数的位视为整数(在我的经验中,这通常会给你一个完全无用的值,但也许不是),然后将这个“垃圾”整数值转换回浮点数,然后进行一些数学运算。这是一种快速和近似的方法,在这种情况下,它是取以2为底的对数。它本来根本不应该起作用,但127和126.94269504之间的差异显然只是几个荒谬的调整因素之一,旨在从本应毫无意义的代码中挽救一些含义。(有点像“两个几乎错误的东西组合在一起就变成了几乎正确的”那种感觉。)

如果您想精确提取浮点数的尾数和指数(虽然这既不会像快速又不会像近似),通常的方法是使用frexpf函数。


4
如果你依赖于特定的编码(即IEEE754单精度浮点数格式),那么这并不是垃圾,它所进行的“一些数学运算”非常有意义。 - MooseBoys
3
浮点数的指数部分是对数形式,而尾数部分是线性的。该代码似乎只是应用了线性最佳拟合逼近,其中线性方程的y轴偏移与指数偏置相结合。 - njuffa
2
这是一种疯狂而又聪明的技术。就像我说的,我很惊讶它居然能够工作,但我尝试了一下,发现它确实可以。我甚至有点理解它的工作原理,但最终结果仍然让我感到有些不可思议,好像在同一个指针上调用了两次free函数,并且它大致为我排序了数据! - Steve Summit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接