铸造float时奇怪的行为在C#中为int [英] Strange behavior when casting a float to int in C#

查看:233
本文介绍了铸造float时奇怪的行为在C#中为int的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下简单的code:

I have the following simple code :

int speed1 = (int)(6.2f * 10);
float tmp = 6.2f * 10;
int speed2 = (int)tmp;

速度1和速度2应具有相同的价值,但事实上,我有:

speed1 and speed2 should have the same value, but in fact, I have :

speed1 = 61
speed2 = 62

我知道,我也许应该使用,而不是铸造Math.Round,但我想明白为什么值是不同的。

I know I should probably use Math.Round instead of casting, but I'd like to understand why the values are different.

我看着生成的字节code,但除了商店和负载,运codeS是相同的。

I looked at the generated bytecode, but except a store and a load, the opcodes are the same.

我也试过在Java中的code和我正常获取62和62。

I also tried the same code in java, and I correctly obtain 62 and 62.

有人能解释一下吗?

编辑:
在现实code,它不是直接6.2f * 10,但一个函数调用*一个​​常数。我有以下字节code:

Edit : In the real code, it's not directly 6.2f * 10 but a function call * a constant. I have the following bytecode :

速度1:

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

速度2:

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

we can see that operands are floats and that the only difference is the stloc/ldloc

对于虚拟机,我试着用单声道/ Win7的,单声道/ MacOS和.NET / Windows的,具有相同的结果。

As for the virtual machine, I tried with Mono/Win7, Mono/MacOS, and .NET/Windows, with the same results

推荐答案

首先,我假设你知道 6.2f * 10 不正是62,由于浮点舍入(它实际上是价值61.99999809265137时前pressed为双击),并且您的问题只是为什么两个看似相同的计算产生错误值。

First of all, I assume that you know that 6.2f * 10 is not exactly 62 due to floating point rounding (it's actually the value 61.99999809265137 when expressed as a double) and that your question is only about why two seemingly identical computations result in the wrong value.

答案是,在的情况下(INT)(6.2f * 10),你正在服用的双击 IT价值61.99999809265137和截断为整数,这将产生61。

The answer is that in the case of (int)(6.2f * 10), you are taking the double value 61.99999809265137 and truncating it to an integer, which yields 61.

浮动f的情况下= 6.2f * 10 ,你正在服用的双重价值61.99999809265137和四舍五入的到最近的浮动,这是62然后截断浮动为整数,结果为62。

In the case of float f = 6.2f * 10, you are taking the double value 61.99999809265137 and rounding to the nearest float, which is 62. You then truncate that float to an integer, and the result is 62.

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

Exercise: Explain the results of the following sequence of operations.

double d = 6.2f * 10;
int tmp2 = (int)d;
// evaluate tmp2

更新:由于在评论中指出,前pression 6.2f * 10 是一个正式的浮动由于第二个参数有一个隐式转换为浮动是的比隐式转换更好双击

Update: As noted in the comments, the expression 6.2f * 10 is formally a float since the second parameter has an implicit conversion to float which is better than the implicit conversion to double.

的实际问题是,允许编译器(但不要求)使用中间是更高的precision比正式类型。这就是为什么你看到在不同的系统不同的行为:在EX pression (INT)(6.2f * 10),编译器保持值的选项 6.2f * 10 在转换为 INT 前高precision中间形式。如果确实如此,那么结果是61,如果没有,则结果为62

The actual issue is that the compiler is permitted (but not required) to use an intermediate which is higher precision than the formal type. That's why you see different behavior on different systems: In the expression (int)(6.2f * 10), the compiler has the option of keeping the value 6.2f * 10 in a high precision intermediate form before converting to int. If it does, then the result is 61. If it does not, then the result is 62.

在第二个例子中,明确分配给<​​code>浮动迫使四舍五入发生在转换前为整数。

In the second example, the explicit assignment to float forces the rounding to take place before the conversion to integer.

这篇关于铸造float时奇怪的行为在C#中为int的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆