关于浮点表示,已经向SO发布了几个问题.例如,十进制数0.1没有精确的二进制表示,因此使用==运算符将其与另一个浮点数进行比较是危险的.我理解浮点表示的原理.
我不明白的是,从数学的角度来看,为什么小数点右边的数字比左边的数字更"特殊"?
例如,数字61.0具有精确的二进制表示,因为任何数字的整数部分始终是精确的.但数字6.10并不准确.我所做的只是将十进制移动到一个地方,然后我突然从Exactopia转到了Inexactville.在数学上,两个数字之间应该没有内在差异 - 它们只是数字.
相比之下,如果我将小数位移到另一个方向以产生数字610,我仍然在Exactopia中.我可以继续向那个方向前进(6100,610000000,610000000000000),它们仍然是精确,准确,准确的.但是一旦小数越过某个阈值,数字就不再精确了.
这是怎么回事?
编辑:为了澄清,我想远离关于行业标准表示的讨论,例如IEEE,并坚持我认为是数学上"纯粹"的方式.在基数10中,位置值为:
... 1000 100 10 1 1/10 1/100 ...
Run Code Online (Sandbox Code Playgroud)
在二进制文件中,它们将是:
... 8 4 2 1 1/2 1/4 1/8 ...
Run Code Online (Sandbox Code Playgroud)
对这些数字也没有任何限制.位置无限增加到左侧和右侧.
我有一些十进制数据,我将其推入SharePoint列表中进行查看.我想根据我对具体计算的了解来限制结果数据中显示的有效数字的数量.有时候它会是3,所以12345会变成12300而0.012345会变成0.0123.偶尔它会是4或5.有没有方便的方法来处理这个?
我想将一个数字缩短为非0的第一个有效数字.后面的数字应该是四舍五入的.
例子:
0.001 -> 0.001
0.00367 -> 0.004
0.00337 -> 0.003
0.000000564 -> 0.0000006
0.00000432907543029 -> 0.000004
Run Code Online (Sandbox Code Playgroud)
目前我有以下程序:
if (value < (decimal) 0.01)
{
value = Math.Round(value, 4);
}
Run Code Online (Sandbox Code Playgroud)
注意:
从上面的示例中可以看出,舍入到4个小数位可能不够,值可能会有很大差异.
是否有任何代码(或内置函数)允许以工程符号输出浮点数?
例如,1.5e-4将显示为,150µ并且5e-3将显示为5m.
截断float值为0.6000002且值为0.6000 的C++ 变量并将其存储回变量的最简单方法是什么?
我们现有的应用程序从文件中读取一些浮点数.这些数字是由其他一些应用程序写的(我们称之为应用程序B).此文件的格式很久以前就已修复(我们无法更改).在此文件中,所有浮点数都以二进制表示形式保存为浮点数(文件中为4个字节).
在我们的程序中,一旦我们读取数据,我们就将浮点数转换为双精度数并使用双精度数进行所有计算,因为计算非常广泛,我们关注舍入误差的传播.
我们注意到,当我们通过十进制转换浮点数时(参见下面的代码),我们得到的结果比直接转换时更精确.注意:应用程序B也在内部使用双精度数,只将它们作为浮点数写入文件中.假设应用程序B将数字0.012写入文件为float.如果我们在读取到十进制后转换它然后加倍我们得到0.012,如果我们直接转换它,我们得到0.0120000001043081.
这可以在不读取文件的情况下重现 - 只需一个作业:
float readFromFile = 0.012f;
Console.WriteLine("Read from file: " + readFromFile);
//prints 0.012
double forUse = readFromFile;
Console.WriteLine("Converted to double directly: " + forUse);
//prints 0.0120000001043081
double forUse1 = (double)Convert.ToDecimal(readFromFile);
Console.WriteLine("Converted to double via decimal: " + forUse1);
//prints 0.012
Run Code Online (Sandbox Code Playgroud)
通过十进制从float转换为double总是有益的,如果不是,在什么条件下它是有益的?
编辑:应用程序B可以通过两种方式获取它保存的值:
据我所知,有些数字不能用二进制精确表示,这就是为什么浮点运算有时会给我们带来意想不到的结果; 像4.35*100 = 434.99999999999994.与十进制中的1/3相似的东西.
这是有道理的,但这引发了另一个问题.似乎在二进制中4.35和435都可以精确表示.那就是它停止对我有意义的时候.为什么4.35*100的评估结果为434.99999999999994?435和4.35在双重类型动态中具有精确表示:
double number1 = 4.35;
double number2 = 435;
double number3 = 100;
System.out.println(number1); // 4.35
System.out.println(number2); // 435.0
System.out.println(number3); // 100.0
// So far so good. Everything ok.
System.out.println(number1 * number3); // 434.99999999999994 !!!
// But 4.35 * 100 evaluates to 434.99999999999994
Run Code Online (Sandbox Code Playgroud)
为什么?
编辑:此问题被标记为重复,但事实并非如此.正如您在接受的答案中所看到的,我的困惑在于实际值与印刷值之间的差异.
我需要舍入双打的有效数字。示例 Round(1.2E-20, 0) 应该变成 1.0E-20
我不能使用返回 0 的 Math.Round(1.2E-20, 0),因为 Math.Round() 不会将浮点数中的有效数字四舍五入,而是将其四舍五入为十进制数字,即 E 为 0 的双精度数。
当然,我可以这样做:
double d = 1.29E-20;
d *= 1E+20;
d = Math.Round(d, 1);
d /= 1E+20;
Run Code Online (Sandbox Code Playgroud)
这实际上有效。但这不会:
d = 1.29E-10;
d *= 1E+10;
d = Math.Round(d, 1);
d /= 1E+10;
Run Code Online (Sandbox Code Playgroud)
在这种情况下,d 是 0.00000000013000000000000002。问题是 double 在内部存储 2 的分数,它不能完全匹配 10 的分数。在第一种情况下,C# 似乎只处理 * 和 / 的指数,但在第二种情况下,它会生成实际的 * 或/ 操作,然后导致问题。
当然,我需要一个总能给出正确结果的公式,不仅仅是有时。
这意味着我不应该在四舍五入后使用任何双重运算,因为双重算术无法准确处理小数。
上述计算的另一个问题是没有返回 double 指数的 double 函数。当然可以使用 Math 库来计算它,但可能很难保证它始终与 double 内部代码的结果完全相同。
无奈之下,我考虑将双精度数转换为字符串,找到有效数字,进行四舍五入并将四舍五入的数字转换回字符串,然后最终将其转换为双精度数。丑吧?在所有情况下也可能无法正常工作:-(
是否有任何图书馆或任何建议如何正确舍入双精度数的有效数字?
PS:在声明这是一个重复的问题之前,请确保您了解SIGNIFICANT数字和小数位之间的区别
将小数字加倍到两位小数的最佳方法是什么?
例如,我想转换
3.45345323423423E+28
Run Code Online (Sandbox Code Playgroud)
至
3.45
Run Code Online (Sandbox Code Playgroud)