判断一个数字是否可以精确表示为 float/double 格式

Determine if a number can be precisely represented in float/double format

如何确定一个数字,例如 1.577,是否可以精确表示为 float 或 double 格式?

这意味着它是真实的 1.577 而不是 1.566999999999994324 等等

编辑: 我正在寻找一种工具,我可以在其中输入一个数字,它会显示它的 double/float 表示形式。所以这不仅仅是c#相关的问题。

您可以使用 online decimal to floating-point converter。例如,输入 1.577,您会得到两个不准确的指示:

1) "Inexact" 框被选中

2) 双精度浮点数转换为1.5769999999999999573674358543939888477325439453125

将其与 1.25 之类的数字进行对比,打印为 1.25,并且未选中 "Inexact" 框。

(该转换器也可以检查单精度数。)

嗯,IEEE-754 双精度有 53 位精度。那么唯一可以准确表示的数字是:

  • 有理数,
  • 具有终止二进制表示,
  • 表示为53位或更少

所以...要弄清楚给定的十进制值是否可以精确表示,以下内容就足够了:

public bool IsExactlyRepresentableAsIeee754Double( decimal value )
{
  // An IEEE 754 double has 53 bits of precision (52 bits of which are explicitly stored).
  const decimal ieee754MaxBits = 0x001FFFFFFFFFFFFF ;

  // move the decimal place right until the decimal's absolute value is integral
  decimal n = Math.Abs(value) ;
  while ( Decimal.Floor(n) != n )
  {
    n *= 10m;
  }

  bool isRepresentable = n <= ieee754MaxBits ;
  return isRepresentable ;
}

这里有一个警告,但是:decimal 跟踪尾随的小数零(详情见下文),因此 1m1.0m 有不同的二进制表示。因此,像 decimal x = (decimal)(double)1.00m ; 这样的往返将导致 x 具有与 1m 相同的二进制表示,而不是 1.00m;

因为小数的内部表示是well documented in the .Net CLR documentation and specs。它的后备存储很容易通过方法 Decimal.GetBits() 获得,由 4 个 32 位字组成,指定如下:

The binary representation of a Decimal number consists of a 1-bit sign, a 96-bit integer number, and a scaling factor used to divide the integer number and specify what portion of it is a decimal fraction. The scaling factor is implicitly the number 10, raised to an exponent ranging from 0 to 28.

bits is a four-element long array of 32-bit signed integers.

  • bits [0], bits 1, and bits [2] contain the low, middle, and high 32 bits of the 96-bit integer number.

  • bits [3] contains the scale factor and sign, and consists of [the] following parts:

    • Bits 0 to 15, the lower word, are unused and must be zero.
    • Bits 16 to 23 must contain an exponent between 0 and 28, which indicates the power of 10 to divide the integer number.
    • Bits 24 to 30 are unused and must be zero.
    • Bit 31 contains the sign; 0 meaning positive, and 1 meaning negative.

A numeric value might have several possible binary representations; all are equally valid and numerically equivalent. Note that the bit representation differentiates between negative and positive zero. These values are treated as being equal in all operations.

所以你可能会变得聪明一点,并通过一点点摆弄来加快速度。更重要的是 decimal 跟踪尾随零,因此 1m1.00m 的二进制表示不同 — 1m 表示为 +1 乘以 1001.00m 表示为 +100 乘以 102。这让事情有点复杂。

您已经有了关于如何明确检查精确表示的答案。另外,不用正式测试就可以剔除很多数字,并且可以在短时间内检查短小数,这既可行又有用。

假设您的数字的十进制表示形式在 N 位小数后终止。例如,N 为 3 表示 1.577。取小数点后的部分,并将其视为整数,577。如果该数字可以精确表示为二进制分数,则该部分必须是 5^N 的整数倍。 577 不是 125 的整数倍,所以 1.577 不能准确表示。

如果你有一个合理的数量级,其十进制表示中只有几个有效数字,那么如果它通过了这个测试,它就是可以精确表示的。例如,我知道没有计算机化测试 1.625 是完全可以表示的。