C# Float 表达式:将结果浮点数转换为 int 时的奇怪

C# Float expression: strange behavior when casting the result float to int(C# Float 表达式:将结果浮点数转换为 int 时的奇怪行为)
本文介绍了C# Float 表达式:将结果浮点数转换为 int 时的奇怪行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下简单的代码:

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

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

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.

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

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

我在java中也试过同样的代码,我正确得到了62和62.

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

谁能解释一下?

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

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

对于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.

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

至于虚拟机,我尝试了 Mono/Win7、Mono/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(实际上是表示为 double 时的值 61.99999809265137)并且您的问题只是关于为什么两个看似相同的计算会导致错误的值.

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) 的情况下,您将 double 值 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.

float f = 6.2f * 10 的情况下,您将取双精度值 61.99999809265137 并 四舍五入 到最近的 float,即 62.然后将 float 截断为整数,结果为 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

更新:如注释中所述,表达式 6.2f * 10 正式是 float 因为第二个参数隐式转换为 float 比隐式转换为 更好 到 .

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.

实际问题是编译器被允许(但不是必需)使用 比正式类型的精度更高(第 11.2.2 节).这就是您在不同系统上看到不同行为的原因:在表达式 (int)(6.2f * 10) 中,编译器可以选择保留值 6.2f * 10在转换为 int 之前以高精度中间形式.如果是,则结果为 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 (section 11.2.2). 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.

在第二个示例中,对 float 的显式赋值强制舍入在转换为整数之前进行.

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

这篇关于C# Float 表达式:将结果浮点数转换为 int 时的奇怪行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本站部分内容来源互联网,如果有图片或者内容侵犯您的权益请联系我们删除!

相关文档推荐

DispatcherQueue null when trying to update Ui property in ViewModel(尝试更新ViewModel中的Ui属性时DispatcherQueue为空)
Drawing over all windows on multiple monitors(在多个监视器上绘制所有窗口)
Programmatically show the desktop(以编程方式显示桌面)
c# Generic Setlt;Tgt; implementation to access objects by type(按类型访问对象的C#泛型集实现)
InvalidOperationException When using Context Injection in ASP.Net Core(在ASP.NET核心中使用上下文注入时发生InvalidOperationException)
LINQ many-to-many relationship, how to write a correct WHERE clause?(LINQ多对多关系,如何写一个正确的WHERE子句?)