【问题标题】:Computation with Floating Point Numbers: When to Round?浮点数计算:何时舍入?
【发布时间】:2015-08-13 00:16:47
【问题描述】:
我在 C 中使用浮点数执行一些计算。我正在专门处理我得到指数的最低单精度值的情况。
假设我的指数是 -126,我必须减少它。在这种情况下,我不能再低了,所以我需要右移一次尾数。我知道我应该得到一个计算的确切答案,然后 然后 回合(到指定的任何地方)。
我正在考虑做(让M 成为尾数):
M >>= 1;
//round mantissa
-
由于我将尾数向右移动,并且浮点左侧隐含 1,因此在移动后是否需要修改 M,如下所示:
M |= (1 << 23)
确保我在最高有效位中有一个 1?
在丢失一些信息后四舍五入似乎很奇怪,但这是标准/公认的做法吗?或者我应该通过使用更多位和然后四舍五入来计算完整结果?
【问题讨论】:
-
"左边有一个隐含的 1" 不同意:当 M == -126 时没有隐含的 1。 Ref
-
标签:
c
floating-point
rounding
ieee-754
【解决方案1】:
对于浮点数,有“法线”和“反法线”。
对于“法线”,尾数隐含 1 位,值为 ( 1 + (mantissa >> mantissa_bits) ) << (exponent_value - exponent_bias)。
对于“反法线”,尾数没有隐含的 1 位,指数始终是它的最小值(或者比法线的最小值小 1),并且值为 (mantissa >> mantissa_bits) << (0 - exponent_bias) 或 mantissa >> (exponent_bias + mantissa_bits)。
对于反法线,当您向右移动时,指数保持不变,而尾数移动。最低有效位将丢失,但用于对尾数进行舍入(根据舍入模式)。例如。 (假设四舍五入)1011001b >> 5 = 10.11001b = 11b 和 1001001b >> 5 = 10.01001b = 10b。
请注意,反法线很烦人,并且会采取影响性能的特殊情况处理;所以大多数现代 CPU 都有一个特殊的“反法线为零”模式(不符合 IEEE 标准),它只是用 +/- 0 替换任何反法线。
如果您在软件中执行此操作,则使用较大的浮点格式(精度更高)进行所有计算并忽略反法线(这会降低微小数字的精度)以最终得到相同的结果可能会更快精确度降低了很多头痛。如有必要,您可以在“较大且无反常态”和“较小且无反常态”格式之间进行转换。具体来说;我很想使用没有反规范的 64 位尾数和 32 位指数,并使用例程在这种内部格式之间转换为“32 位浮点数”和“64 位双精度数”。