我在C#中遇到了浮点计算精度问题,这是最小的工作示例:
int num = 160;
float test = 1.3f;
float result = num * test;
int result_1 = (int)result;
int result_2 = (int)(num * test);
int result_3 = (int)(float)(num * test);
Console.WriteLine("{0} {1} {2} {3}", result, result_1, result_2, result_3);
上面的代码会输出“208 208 207 208”,有人可以解释result_2
的奇怪值208
吗?
(二进制不能精确地表示1.3会导致浮点精度问题,但我对细节感到好奇)
答案 0 :(得分:1)
num * test
可能会为您提供207.9999998...
之类的结果,当您将此float
值转换为int
时,您会获得207
,因为请转到int
1}}会将结果向下舍入为最接近的整数207
(类似于Math.Floor()
)。
如果您将num * test
指定给float result = num * test;
这样的浮动类型,则值207.9999998...
将四舍五入到最近的浮点数值为208
。
让我们总结一下:
float result = num * test;
为您提供208,因为您要将num * test
分配给浮动类型。
int result_1 = (int)result;
为您提供208因为您将result
的值转换为int - > (int)208
。
int result_2 = (int)(num * test);
给你207,因为你正在施放像207.9999998 ...到int - > (int)207.9999998...
。
int result_3 = (int)(float)(num * test);
给你208,因为你是第一次施放207.9999998 ...浮动,它给你208,然后你将208施放到int。
答案 1 :(得分:0)
您还可以查看C#
language specification:
可以以比操作的结果类型更高的精度执行浮点运算。例如,某些硬件体系结构支持“扩展”或“长双”浮点类型,其范围和精度比double类型更大,并使用此更高精度类型隐式执行所有浮点运算。只有在性能成本过高的情况下,才能使这种硬件架构以较低的精度执行浮点运算,而不是要求实现失去性能和精度,C#允许更高精度的类型用于所有浮点运算。除了提供更精确的结果外,这几乎没有任何可衡量的影响。但是,在x * y / z形式的表达式中,乘法产生的结果超出双范围,但随后的除法将临时结果带回双范围,表达式的计算结果更高范围格式可能会导致生成有限结果而不是无穷大。
所以基本上回答你的问题 - 不,它不应该。您可以使用不同的类型,例如decimal
或Binary floating points等。如果您对浮点概念和格式更感兴趣,可以阅读Jeffrey Sax's - Floating Point in .NET part 1: Concepts and Formats。