我正在用 C 语言使用 float 执行一些计算。我专门处理我得到指数的最低可能单精度值的情况。
假设我的指数是 -126,我必须将它递减。在这种情况下,我不能再低了,所以我需要将尾数右移一次。我知道我应该得到计算的确切答案,然后然后四舍五入(到指定的任何地方)。
我正在考虑这样做(让 M
成为尾数):
M >>= 1;
//round mantissa
由于我将尾数向右移动并且浮点左侧隐含了 1,我是否需要在移动后修改 M,如:
M |= (1 << 23)
确保最高有效位为 1?
在丢失一些信息后四舍五入似乎很奇怪,但这是标准/公认的做法吗?或者我应该通过使用更多位然后然后四舍五入来计算完整结果吗?
最佳答案
对于 float ,有“法线”和“非法线”。
对于“法线”,尾数隐含 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 位 float ”和“64 位 double ”。
关于 float 计算 : When to Round?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30541294/