这两种情况的计算精度是否有差异:
1) x = y / 1000d;
2) x = y * 0.001d;
编辑:不应该添加C#标签。问题只是从“浮点”的角度提出的。我不想知道什么是更快的,我需要知道什么样的情况会给我‘更好的精确度’。
发布于 2014-01-18 12:04:55
不,它们不一样--至少在我的处理器上使用我的机器上的版本(只有标准的C# 4.5.1) --有足够的微妙之处,我不想宣称它会在所有机器上或所有语言上都这样做。毕竟,这可能是一个特定于语言的问题。
使用我的DoubleConverter类来显示double的确切值,经过几次尝试和错误之后,下面是一个C#程序,它至少在我的机器上显示了一个不同之处:
using System;
class Program
{
static void Main(string[] args)
{
double input = 9;
double x1 = input / 1000d;
double x2 = input * 0.001d;
Console.WriteLine(x1 == x2);
Console.WriteLine(DoubleConverter.ToExactString(x1));
Console.WriteLine(DoubleConverter.ToExactString(x2));
}
}输出:
False
0.00899999999999999931998839741709161899052560329437255859375
0.009000000000000001054711873393898713402450084686279296875我可以用Microsoft编译器在C中再现这一点--如果它是可怕的C风格,请原谅,但我认为它至少说明了其中的不同之处:
#include <stdio.h>
void main(int argc, char **argv) {
double input = 9;
double x1 = input / 1000;
double x2 = input * 0.001;
printf("%s\r\n", x1 == x2 ? "Same" : "Not same");
printf("%.18f\r\n", x1);
printf("%.18f\r\n", x2);
}输出:
Not same
0.008999999999999999
0.009000000000000001我还没有研究过具体的细节,但这对我来说是有意义的,因为除以1,000并乘以“最接近的double到0.001”并不是相同的逻辑操作.因为0.001不能准确地表示为double。离0.001最近的double实际上是:
0.001000000000000000020816681711721685132943093776702880859375..。所以这就是你最后被乘的原因。你早早就失去了信息,希望它能与你失去的信息相对应,除以1000。在某些情况下,情况似乎并非如此。
发布于 2014-01-26 22:14:37
你是在基数10编程,但浮点数是2,你可以在基数2中表示1,000,但在基2中不能表示0.001,所以你选择了错误的数字来问你的问题,在计算机x/1000 != x*0.001上,你可能会在大多数情况下得到幸运的四舍五入和更高的精度,但这不是一个数学标识。
也许这就是你的问题,也许你想知道为什么x/1000 != x*0.001。这个问题的答案是,因为这是一台二进制计算机,它使用的是基2而不是基10,当到基2的时候,有0.001的转换问题,你不能用IEEE浮点数精确地表示这个分数。
在基数10中,我们知道,如果分母中有一个因子为3的分数(在分子中没有一个来抵消它),我们最终会有一个无限重复的模式,基本上我们不能用有限的数字集合来精确地表示这个数字。
1/3 =0.33333。
同样的问题,当你试图在基数2.10= 2*5中表示1/10时,2是好的1/2,但5是真正的问题1/5。
1/10 (1/1000工作方式相同)。初等长除法:
0 000110011
----------
1010 | 1.000000
1010
------
1100
1010
----
10000
1010
----
1100
1010
----
10我们必须继续拉零,直到我们得到10000,10到16,一次,剩下的6,放下下一个零。10进入12,1次余数2。我们重复这个模式,所以你最终得到了这个001100110011,永远重复。浮点是一个固定的位数,所以我们不能表示无限模式。
如果你的问题和除以4一样,等于乘以1/4。这是一个不同的问题。答案是,它应该是相同的,消耗更多的循环和/或逻辑做一个除法,而不是乘,但最终计算出相同的答案。
发布于 2014-01-17 14:22:39
可能不会。无论如何,编译器(或JIT)可能会将第一种情况转换为第二种情况,因为乘法通常比除法更快。您必须通过编译代码(无论是否启用优化)来检查这一点,然后使用诸如IL反汇编程序或.NET反射器之类的工具检查生成的IL,并/或在运行时使用调试器检查本机代码。
https://stackoverflow.com/questions/21187911
复制相似问题