大家好,
今天碰到了一个问题,如下的代码: float f1 = 935.5f;
float f2 = 909.9f;
Console.WriteLine(f1-f2);输出结果是:25.59998希望高手讲讲是什么原因,还有,如果我就是想简单得到:25.6 ,该怎么处理才能保证得到正确结果,并且比较通用,不仅仅是做1位的四舍五入?非常感谢。
今天碰到了一个问题,如下的代码: float f1 = 935.5f;
float f2 = 909.9f;
Console.WriteLine(f1-f2);输出结果是:25.59998希望高手讲讲是什么原因,还有,如果我就是想简单得到:25.6 ,该怎么处理才能保证得到正确结果,并且比较通用,不仅仅是做1位的四舍五入?非常感谢。
就会存在
value = significant digits × baseexponent 的问题
也就会存在一定的偏差。
因为二进制数值可以准确表示整数(可以使用整数转换为二进制方法验证下),所以可以将小数乘以10或100等变成整数,然后做运算,最后再通过除以10或100等获得结果
double d1 = 935.5;
double d2 = 909.9;
Console.WriteLine(d1 - d2); //25.6
decimal f2 = 909.9m;
decimal f = f1 - f2; //f=25.6
float f1 = 935.5f;
float f2 = 909.9f;
Console.WriteLine((f1 - f2).ToString("0.0")); //25.6
float f2 = 909.9f;
Console.WriteLine((f1 - f2).ToString("0.0")); //25.6
使用double
总结来说,
就是一句话,float精度不够,运算会出问题,建议用 double,decimal
可是问题是 float 连这么简单个问题都处理不了,存在还有啥意义呀。
并且前面大家指教的一些方法: *10,再 /10 或者用 ToString("0.0") 这些之类的,都不通用呀,还得做小数位数的判断。比起这个问题的简单,常见程度来,我们解决它的方法是多么地费力。如果说是计算机的问题,我试了C++的同样程序,同样的数值,同样的float 型,为啥就好好的25.6结果就出来了呢?希望能继续得到大家的帮助
static void Main(string[] args)
{
float f1 = 935.5f;
float f2 = 909.9f;
float f3 = f1 - f2;
Console.WriteLine(f3);
Console.ReadKey();
}//输出
25.59998
//调试看到f3
25.5999756int main()
{
float f1 = 935.5f;
float f2 = 909.9f;
float f3 = f1-f2;
cout<<f3;
cin.get();
return 0;
}//输出
25.6
//调试看到f3
25.599976结论:
和语言无关。
估计cout的<<方法有优化。
大家给出的方法为什么不能用,Math.Round() 就是一个很通用的阿你说的C++程序能够出来,因为cout的时候会根据输出会根据你输入的精度做一个判断
如果两个的精度不一致你再看看,
cout << fixed << setprecision(4) c++也有这种方式来控制精度的。
但是,这个位数怎么来的呢?我前面例子是1位就够了,但是我并不知道每次那个float型倒底值会是几位,
下次如果是 1998.255-1909.268 ,这次我要指定精度就为3了。也就是说每次都要加一个额外的判断来判断需要精确的位数。这就是我说的不通用,费力的原因。你提到的:“你说的C++程序能够出来,因为cout的时候会根据输出会根据你输入的精度做一个判断
如果两个的精度不一致你再看看,”
这个麻烦详细讲一下可以吗?我前面的示例中没有指定cout的精度呀,但输出是正确的,我也如前面朋友所讲的调试时看了一下,确实也是不精确的,确实是cout自己进行了优化,既然cout都能优化,为啥不直接在计算结果中就优化成正确的值呢。。更加感觉郁闷了,那这个float型真是废柴呀
float f1 = 935.59f;
float f2 = 909.9f;
然后你看看
再用
double f1 = 935.59;
double f2 = 909.9;
和
double f1 = 935.5;
double f2 = 909.9;三个结果你对比看看就知道了。 因为在转换二进制的时候,很有可能最后一位会有一个1,这样导致编译输出时系统无法知道你是否需要截断尾部,必须要你自己手动来指定,没人敢确定你就是只需要输入的精度。
“如果能确定两个操作数的小数位数,那么就可以确定结果需要精确到的位数,
但现在的问题是,两个操作数本身存储就没有精确的位数可言,因此,编译器无法判断得到结果位数的精度,而必须自己手动指定。”我不是很清楚你说的很有可能最后一位会有一个1怎么就会影响对位数的判断了。但是我们显然看到,C++中的cout 跟 Python 中的 print 是完全可以正确的打印出准确结果来的,说明编译器是有方法判断用户所需要精度的!并且现在的问题是,这并不是一个非正常结果,不是1/3之类,或者是要溢出的运算,这只是非常普通的一类,绝对能得到准确结果的运算。而我们非常尴尬的得到了一个错误的结果