我有以下简单的代码:
int speed1 = (int)(6.2f * 10);
float tmp = 6.2f * 10;
int speed2 = (int)tmp;
speed1
和speed2
应该有相同的值,但实际上,我有:
speed1 = 61
speed2 = 62
我知道我可能应该使用Math.Round而不是强制转换,但我想知道为什么值是不同的。
我查看了生成的字节码,但除了存储和加载之外,操作码都是相同的。
我还在java中尝试了相同的代码,我正确地获得了62和62。
有人能解释一下吗?
编辑:在实际代码中,它不是直接的6.2f * 10,而是一个函数调用*一个常量。我有以下字节码:
对于speed1
:
IL_01b3: ldloc.s V_8
IL_01b5: callvirt instance float32 myPackage.MyClass::getSpeed()
IL_01ba: ldc.r4 10.
IL_01bf: mul
IL_01c0: conv.i4
IL_01c1: stloc.s V_9
对于speed2
:
IL_01c3: ldloc.s V_8
IL_01c5: callvirt instance float32 myPackage.MyClass::getSpeed()
IL_01ca: ldc.r4 10.
IL_01cf: mul
IL_01d0: stloc.s V_10
IL_01d2: ldloc.s V_10
IL_01d4: conv.i4
IL_01d5: stloc.s V_11
我们可以看到,操作数是浮点数,唯一的区别是stloc/ldloc
。
至于虚拟机,我尝试了Mono/Win7,Mono/MacOS和.NET/Windows,结果相同。
发布于 2012-01-18 22:18:59
首先,我假设您知道由于浮点数四舍五入(当表示为double
时,它实际上是值61.99999809265137 ),6.2f * 10
不是恰好是62,并且您的问题只是关于为什么两个看似相同的计算会导致错误的值。
答案是,在使用(int)(6.2f * 10)
的情况下,您将获取double
值61.99999809265137并将其截断为一个整数,结果为61。
对于float f = 6.2f * 10
,您将采用双精度值61.99999809265137并四舍五入到最接近的float
,即62。然后将该float
截断为整数,结果为62。
练习:解释以下操作序列的结果。
double d = 6.2f * 10;
int tmp2 = (int)d;
// evaluate tmp2
更新:正如注释中所指出的,表达式6.2f * 10
在形式上是一个float
,因为第二个参数隐式转换为float
,它比隐式转换为double
的转换为better。
实际的问题是编译器被允许(但不是必需的)使用中间件higher precision than the formal type (section 11.2.2)。这就是为什么您会在不同的系统上看到不同的行为:在expression (int)(6.2f * 10)
中,编译器可以选择在转换为int
之前将值6.2f * 10
保留为高精度的中间形式。如果是,则结果为61。如果不是,则结果为62。
在第二个示例中,对float
的显式赋值强制在转换为整数之前进行舍入。
发布于 2012-01-18 22:26:34
描述
浮点数很少精确。6.2f
有点像6.1999998...
。如果你把它转换成一个整型,它会截断它,这个* 10结果是61。
查看Jon Skeets DoubleConverter
类。有了这个类,你就可以真正将浮点数的值可视化为字符串。Double
和float
都是浮点数,decimal不是(它是定点数字)。
示例
DoubleConverter.ToExactString((6.2f * 10))
// output 61.9999980926513671875
更多信息
发布于 2012-01-18 22:29:34
看看IL:
IL_0000: ldc.i4.s 3D // speed1 = 61
IL_0002: stloc.0
IL_0003: ldc.r4 00 00 78 42 // tmp = 62.0f
IL_0008: stloc.1
IL_0009: ldloc.1
IL_000A: conv.i4
IL_000B: stloc.2
编译器将编译时常量表达式减少为它们的常量值,我认为当它将常量转换为int
时,它会在某些时候进行错误的近似。在speed2
的情况下,这种转换不是由编译器进行的,而是由CLR进行的,它们似乎应用了不同的规则……
https://stackoverflow.com/questions/8911440
复制相似问题