如何确定一个数字,例如1.577,是否可以用float或double格式精确表示?
这意味着它是真正的1.577而不是1.566999999999994324等。
编辑: 我正在寻找一个工具,我可以在其中输入一个数字,它将显示它的双重/浮动表示。所以它不仅仅是与c#相关的问题。
答案 0 :(得分:17)
您可以使用online decimal to floating-point converter。例如,输入1.577,您会得到两个不准确的指示:
1)选中“不精确”框
2)它以双精度浮点转换为1.5769999999999999573674358543939888477325439453125。
对比1.25这样的数字,打印为1.25,并且不检查“不精确”框。
(该转换器还可以检查单精度数字。)
答案 1 :(得分:4)
您已经有了如何明确检查确切表示的答案。此外,能够在没有正式测试的情况下消除许多数字,并在视线上检查短小数部分是可行和有用的。
假设您的数字的十进制表示在N个小数位后终止。例如,对于1.577,N为3。取小数点后的部分,并以整数577查看它。如果数字可以精确表示为二进制分数,则该部分必须是5 ^ N的整数倍。 577不是125的整数倍,因此1.577不能完全表示。
如果你有一个合理的数量,其十进制表示只有几个有效数字,那么如果它通过了这个测试,它就是完全可以表示的。例如,我知道没有计算机化测试,1.625是完全可以表示的。
答案 2 :(得分:1)
嗯,IEEE-754双精度具有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
跟踪尾随的小数零(详见下文),因此1m
和1.0m
具有不同的二进制表示形式。因此,decimal x = (decimal)(double)1.00m ;
之类的往返会导致x
具有与1m
相同的二进制表示形式,而不是1.00m
;
由于小数的内部表示是well documented in the .Net CLR documentation and specs。它的后备存储可以通过方法Decimal.GetBits()
随时使用,由4个32位字组成,具体如下:
十进制数的二进制表示由1位符号组成, 一个96位整数,和一个用于分割的缩放因子 整数,并指定它的小数部分。 缩放因子隐含地为数字10,提升为指数 范围从0到28。
bits
是一个四元素长的32位有符号整数数组。
位[0],位1和位[2]包含低位,中位数和 高位32位的96位整数。
bits [3]包含比例因子和符号,由[the]组成 以下部分:
- 0到15位,低位字未使用,必须为零。
- 第16位至第23位必须包含0到28之间的指数,表示除以10的幂以除以整数。
- 第24至30位未使用,且必须为零。
- 第31位包含符号; 0表示正面,1表示负面。
数值可能有几种可能的二进制表示形式;全部是 同等有效和数字上等同。注意位表示 区分负零和正零。这些值被处理 在所有操作中都是平等的。
所以你可能会变得聪明,并且有点笨拙地加快速度。踢球者decimal
跟踪尾随零,因此1m
和1.00m
的二进制表示不同 - 1m
表示为 +1,缩放为10 0功能 的; 1.00m
表示为+100,缩放为10 2 。这使事情变得复杂。