首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >C#浮点表达式:将结果浮点转换为整型时的奇怪行为

C#浮点表达式:将结果浮点转换为整型时的奇怪行为
EN

Stack Overflow用户
提问于 2012-01-18 22:04:01
回答 7查看 19.4K关注 0票数 130

我有以下简单的代码:

代码语言:javascript
复制
int speed1 = (int)(6.2f * 10);
float tmp = 6.2f * 10;
int speed2 = (int)tmp;

speed1speed2应该有相同的值,但实际上,我有:

代码语言:javascript
复制
speed1 = 61
speed2 = 62

我知道我可能应该使用Math.Round而不是强制转换,但我想知道为什么值是不同的。

我查看了生成的字节码,但除了存储和加载之外,操作码都是相同的。

我还在java中尝试了相同的代码,我正确地获得了62和62。

有人能解释一下吗?

编辑:在实际代码中,它不是直接的6.2f * 10,而是一个函数调用*一个常量。我有以下字节码:

对于speed1

代码语言:javascript
复制
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

代码语言:javascript
复制
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,结果相同。

EN

回答 7

Stack Overflow用户

回答已采纳

发布于 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。

练习:解释以下操作序列的结果。

代码语言:javascript
复制
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的显式赋值强制在转换为整数之前进行舍入。

票数 170
EN

Stack Overflow用户

发布于 2012-01-18 22:26:34

描述

浮点数很少精确。6.2f有点像6.1999998...。如果你把它转换成一个整型,它会截断它,这个* 10结果是61。

查看Jon Skeets DoubleConverter类。有了这个类,你就可以真正将浮点数的值可视化为字符串。Doublefloat都是浮点数,decimal不是(它是定点数字)。

示例

代码语言:javascript
复制
DoubleConverter.ToExactString((6.2f * 10))
// output 61.9999980926513671875

更多信息

票数 11
EN

Stack Overflow用户

发布于 2012-01-18 22:29:34

看看IL:

代码语言:javascript
复制
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进行的,它们似乎应用了不同的规则……

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8911440

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档