Jak*_*ski 4 math floating-point truncated
我正在开发一种编程语言,9月,它使用标记的变体类型作为其主要值类型.3位用于类型(整数,字符串,对象,异常等),61位用于实际值(实际整数,指向对象的指针等).
很快,是时候float在语言中添加一种类型了.我几乎有64位双倍的空间,所以我想在内部使用双精度进行计算.因为实际上,我3个比特短用于存储,我将不得不圆双打关闭每次计算之后-本质造成了61位的双用尾数或指数由3个比特短.
但!我知道浮点数充满了危险,做一些听起来对于真实数字纸张合理的事情可能会因FP数学而产生灾难性后果,所以我对那里的专家提出了一个开放式的问题:
这种方法是否可行?通过在每一步舍入,我是否会在长时间运行的计算中遇到严重的错误累积问题?是否有一些特定的方法可以进行舍入以避免这种情况?是否有任何特殊的价值观,我无法以这种方式对待(想象出低于正常)?
理想情况下,我希望我的花车表现得像原生的61位双精灵一样.
Pas*_*uoq 10
我建议借用双精度格式的指数字段中的位.这是本文中描述的方法(您将修改为从指数借用3位而不是1).使用这种方法,所有不使用非常大或非常小的中间结果的计算都与原始的双精度计算完全相同.即使是新格式的低于正常区域的计算也与IEEE标准化1 + 8 + 52 61位格式的情况完全相同.
相比之下,从有效数据中天真地借用任意数量的比特会引入许多双舍入问题,更常见的是从52位有效数字舍入为有效数字而只删除了几位.正如您在编辑问题时所建议的那样,从有效数字中借用一点将是最糟糕的,其中一半的操作在统计上产生双舍入结果,这与理想的"本机61位双"产生的结果不同.这意味着,而不是被精确到0.5ULP,基本操作将是精确到3/4 ULP,准确性的显着损失,这取决于许多脱轨的意想不到0.5ULP现有,精细设计的数值算法.
三是从一个只有11的指数借用的大量位,你也可以考虑在你的语言中使用单精度32位格式(从主机调用单精度操作).
最后,我在这里给出了Jakub发现的另一个解决方案:从有效数据中借用三个比特,并在转换为49-explicit-significand-bit中最接近的数字之前模拟中间双精度计算的舍入到奇数, 11指数位格式.如果选择了这种方式,可以注意到通过以下操作可以实现四舍五入到49位有效数字:
if ((repr & 7) == 4)
repr += (repr & 8) >> 1); /* midpoint case */
else
repr += 4;
repr &= ~(uint64_t)7; /* round to the nearest */
Run Code Online (Sandbox Code Playgroud)
尽管处理的整数具有与double所考虑的相同的表示,但即使数字从正常变为低于正常,从低于正常到正常,或从正常变为无穷,上述片段仍然有效.您当然希望在上面释放的三个位中设置一个标记.要从未装箱的表示中恢复标准双精度数字,只需清除标签即可repr &= ~(uint64_t)7;.