C# double 表示中浪费的指数位
Wasted exponent bit in C# double representation
我最近一直在研究 .NET 中的浮点双精度数。在阅读 Jon Skeet 的文章 Binary floating points and .NET 时,我有一个问题。
我们先从文中46.428292315077
的例子说起。
表示为 64 位双精度数,这相当于以下位:
Sign Exponent Mantissa
0 10000000100 0111001101101101001001001000010101110011000100100011
1位表示符号,11位表示指数,52位表示mantissa。请注意双精度 1023 的偏差(我假设这是为了允许负指数 - 稍后会详细介绍)。
我的困惑在于表示指数的 11 位,以及它们对大数的使用(或缺少),特别是 double.MaxValue
(1.7976931348623157E+308
)。
对于指数,文章中引用了一些有助于确定数字值的特殊值。全零代表0;所有的都代表 NaN 和 positive/negative 无穷大。有 11 位可供使用:指数的第一位是偏差,因此我们可以忽略它。这给了我们 10 位来控制指数的实际大小。
double.MaxValue
上的指数是308,可以用9位来表示(100110100
,或者有偏差:10100110100
)。最小的小数值是double.Epsilon
(4.94065645841247E-324
),它的指数仍然可以用9位来表示(101000100
,或者有偏差:00101000100
)。
您可能会注意到偏置后的第一位似乎总是被浪费了。我对负指数的假设是否正确?如果是这样,为什么浪费了偏差后的第二位?无论如何,我们可以表示的 actual 最大数字(同时尊重特殊值和偏差后可能的符号位)似乎是 111111111
(或 511
以 10 为基数)。
如果bias之后的位真的被浪费了,为什么不能表示指数大于324的数呢?我对此有什么误解?
double 中没有浪费的位。
让我们来解决你的困惑。我们如何将 double 从位转换为数学值?假设 double 不是零、无穷大、负无穷大、NaN 或非正规数,因为它们都有特殊规则。
您混淆的症结在于混淆了十进制数量和二进制数量。对于这个答案,我将把所有二进制数量放在 this formatting
中,将十进制数量放在常规格式中。
我们取尾数的 52 位,然后将它们放在 之后 1.
所以在您的示例中,那将是
1.0111001101101101001001001000010101110011000100100011
那是一个二进制数。所以 1 + 0/2 + 1/4 + 1/8 + 1/16 + 0/32 ...
然后我们取指数的 11 位,将其视为 11 位无符号整数,并从该值中减去 1023。所以在你的例子中我们有 10000000100
这是无符号整数 1028。减去 1023,我们得到 5.
现在我们将"decimal place"(哈哈)移动5位:
101110.01101101101001001001000010101110011000100100011
请注意,这相当于乘以 25。 不是乘以105!
现在,如果符号位为 0
,我们将整个值乘以 1,如果符号位为 1
,则乘以 -1。所以最后的答案是
101110.01101101101001001001000010101110011000100100011
让我们看一个负指数的例子。
假设指数是 01111111100
。这是 1020 作为无符号整数。减去 1023。我们得到 -3,所以我们向左移动三位,得到:
0.0010111001101101101001001001000010101110011000100100011
让我们看一个大指数的例子。如果指数是 11111111100
怎么办?
解决这个问题。那是十进制的 2044。减去 1023。那就是 1021。所以这个数字将是 1.0111001101101101001001001000010101110011000100100011
乘以 21021 得到的极大数字。
所以那个 double 的值 正好等于
32603055608669827528875188998863283395233949199438288081243712122350844851941321466156747022359800582932574058697506453751658312301708309704448596122037141141297743099124156580613023692715652869864010740666615694378079258090383719888417882332809291228958035810952632190230935024250237637887765563383983636480
大约是 3.26030556 x 10307.
现在清楚了吗?
如果您对这个主题感兴趣,请阅读以下内容:
将 double 解码为多个部分的代码:
https://ericlippert.com/2015/11/30/the-dedoublifier-part-one/
一个简单的任意精度有理数:
https://ericlippert.com/2015/12/03/the-dedoublifier-part-two/
将双精度数转换为有理数的代码:
https://ericlippert.com/2015/12/07/the-dedoublifier-part-three/
浮点数的表示:
https://blogs.msdn.microsoft.com/ericlippert/2005/01/10/floating-point-arithmetic-part-one/
本福德定律如何用于最小化表示错误:
https://blogs.msdn.microsoft.com/ericlippert/2005/01/13/floating-point-and-benfords-law-part-two/
我们使用什么算法将浮点数显示为小数?
当您尝试比较不同精度级别的相等浮点数时会发生什么?
标准算术的哪些属性不能用浮点数表示?
如何表示无穷大和除以零?
https://blogs.msdn.microsoft.com/ericlippert/2009/10/15/as-timeless-as-infinity/
我最近一直在研究 .NET 中的浮点双精度数。在阅读 Jon Skeet 的文章 Binary floating points and .NET 时,我有一个问题。
我们先从文中46.428292315077
的例子说起。
表示为 64 位双精度数,这相当于以下位:
Sign Exponent Mantissa
0 10000000100 0111001101101101001001001000010101110011000100100011
1位表示符号,11位表示指数,52位表示mantissa。请注意双精度 1023 的偏差(我假设这是为了允许负指数 - 稍后会详细介绍)。
我的困惑在于表示指数的 11 位,以及它们对大数的使用(或缺少),特别是 double.MaxValue
(1.7976931348623157E+308
)。
对于指数,文章中引用了一些有助于确定数字值的特殊值。全零代表0;所有的都代表 NaN 和 positive/negative 无穷大。有 11 位可供使用:指数的第一位是偏差,因此我们可以忽略它。这给了我们 10 位来控制指数的实际大小。
double.MaxValue
上的指数是308,可以用9位来表示(100110100
,或者有偏差:10100110100
)。最小的小数值是double.Epsilon
(4.94065645841247E-324
),它的指数仍然可以用9位来表示(101000100
,或者有偏差:00101000100
)。
您可能会注意到偏置后的第一位似乎总是被浪费了。我对负指数的假设是否正确?如果是这样,为什么浪费了偏差后的第二位?无论如何,我们可以表示的 actual 最大数字(同时尊重特殊值和偏差后可能的符号位)似乎是 111111111
(或 511
以 10 为基数)。
如果bias之后的位真的被浪费了,为什么不能表示指数大于324的数呢?我对此有什么误解?
double 中没有浪费的位。
让我们来解决你的困惑。我们如何将 double 从位转换为数学值?假设 double 不是零、无穷大、负无穷大、NaN 或非正规数,因为它们都有特殊规则。
您混淆的症结在于混淆了十进制数量和二进制数量。对于这个答案,我将把所有二进制数量放在 this formatting
中,将十进制数量放在常规格式中。
我们取尾数的 52 位,然后将它们放在 之后 1.
所以在您的示例中,那将是
1.0111001101101101001001001000010101110011000100100011
那是一个二进制数。所以 1 + 0/2 + 1/4 + 1/8 + 1/16 + 0/32 ...
然后我们取指数的 11 位,将其视为 11 位无符号整数,并从该值中减去 1023。所以在你的例子中我们有 10000000100
这是无符号整数 1028。减去 1023,我们得到 5.
现在我们将"decimal place"(哈哈)移动5位:
101110.01101101101001001001000010101110011000100100011
请注意,这相当于乘以 25。 不是乘以105!
现在,如果符号位为 0
,我们将整个值乘以 1,如果符号位为 1
,则乘以 -1。所以最后的答案是
101110.01101101101001001001000010101110011000100100011
让我们看一个负指数的例子。
假设指数是 01111111100
。这是 1020 作为无符号整数。减去 1023。我们得到 -3,所以我们向左移动三位,得到:
0.0010111001101101101001001001000010101110011000100100011
让我们看一个大指数的例子。如果指数是 11111111100
怎么办?
解决这个问题。那是十进制的 2044。减去 1023。那就是 1021。所以这个数字将是 1.0111001101101101001001001000010101110011000100100011
乘以 21021 得到的极大数字。
所以那个 double 的值 正好等于
32603055608669827528875188998863283395233949199438288081243712122350844851941321466156747022359800582932574058697506453751658312301708309704448596122037141141297743099124156580613023692715652869864010740666615694378079258090383719888417882332809291228958035810952632190230935024250237637887765563383983636480
大约是 3.26030556 x 10307.
现在清楚了吗?
如果您对这个主题感兴趣,请阅读以下内容:
将 double 解码为多个部分的代码:
https://ericlippert.com/2015/11/30/the-dedoublifier-part-one/
一个简单的任意精度有理数:
https://ericlippert.com/2015/12/03/the-dedoublifier-part-two/
将双精度数转换为有理数的代码:
https://ericlippert.com/2015/12/07/the-dedoublifier-part-three/
浮点数的表示:
https://blogs.msdn.microsoft.com/ericlippert/2005/01/10/floating-point-arithmetic-part-one/
本福德定律如何用于最小化表示错误:
https://blogs.msdn.microsoft.com/ericlippert/2005/01/13/floating-point-and-benfords-law-part-two/
我们使用什么算法将浮点数显示为小数?
当您尝试比较不同精度级别的相等浮点数时会发生什么?
标准算术的哪些属性不能用浮点数表示?
如何表示无穷大和除以零?
https://blogs.msdn.microsoft.com/ericlippert/2009/10/15/as-timeless-as-infinity/