为什么基于投类型划分的结果有什么不同? (跟进) [英] Why does a division result differ based on the cast type? (Followup)

查看:105
本文介绍了为什么基于投类型划分的结果有什么不同? (跟进)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一个后续到这个问题:的为什么一个除法结果差异而有所不同投式

This is a followup to this question: Why does a division result differ based on the cast type?

快速总结:

byte b1 = (byte)(64 / 0.8f); // b1 is 79
int b2 = (int)(64 / 0.8f); // b2 is 79
float fl = (64 / 0.8f); // fl is 80



现在的问题是:为什么结果不同,这取决于演员的类型?虽然工作了一个答案我遇到了一个问题,我无法解释。

The question is: Why are the results different depending on the cast type? While working out an answer I ran into an issue I wasn't able to explain.

var bytes = BitConverter.GetBytes(64 / 0.8f).Reverse(); // Reverse endianness
var bits = bytes.Select(b => Convert.ToString(b, 2).PadLeft(8, '0'));
Console.WriteLine(string.Join(" ", bits));

这输出如下:

01000010 10100000 00000000 00000000

将它分解在IEEE 754格式为:

Breaking it down in IEEE 754 format:

0 10000101 01000000000000000000000

标记:

0 => Positive



指数:

Exponent:

10000101 => 133 in base 10



尾数:

Mantissa:

01000000000000000000000 => 0*2^-1 + 1*2^-2 + 0*2^-3 ... = 1/4 = 0.25

十进制表示形式:

(1 + 0.25) * 2^(133 - 127) (Subtract single precision bias)

这正好导致80.那么,为什么铸造结果有所作为?

This results in exactly 80. So why does casting the result make a difference?

推荐答案

我在其他线程的答案是不完全正确的:<击>事实上,当在运行时计算,(字节)(64 / 0.8f) 80

My answer in the other thread is not entirely correct: Actually, when computed at runtime, (byte)(64 / 0.8f) is 80.

在铸造包含的结果浮动 64 / 0.8f ,到字节在运行时,其结果实际上是80。但是,这不是当演员作为转让的一部分进行的情况:

When casting a float containing the result of 64 / 0.8f, to byte at runtime, the result actually is 80. However, this is not the case when the cast is done as a part of the assignment:

float f1 = (64 / 0.8f);

byte b1 = (byte) f1;
byte b2 = (byte)(64 / 0.8f);

Console.WriteLine(b1); //80
Console.WriteLine(b2); //79



虽然B1包含了预期的结果,B2处于关闭状态。据拆卸,B2被分配如下:

While b1 contains the expected result, b2 is off. According to the disassembly, b2 is assigned as following:

mov         dword ptr [ebp-48h],4Fh 

因此,编译器似乎在运行时的结果计算出不同的结果。我不知道,但是,如果这是预期的行为或不

Thus, the compiler seems to calculate a different result from the result at runtime. I don't know, however, if this is the expected behavior or not.

修改:也许是帕斯卡Cuoq描述的效果:在编译时,C#编译器使用双击来计算表达式。这导致79,其被截断为79(作为双含有足够的精度引起的问题,在这里)XXX。结果,
使用浮法,然而,我们不实际碰到的一个问题,因为。浮点错误发生不是一个浮动的范围之内。

EDIT: Maybe it is the effect Pascal Cuoq described: During compile time, the C# compiler uses double to calculate the expression. This results in 79,xxx which is truncated to 79 (as a double contains enough precision to cause an issue, here).
Using float, however, we don't actually run into an issue, as the floating-point "error" happens not within the range of a float.

在运行时,这其中还打印79:

During runtime, this one also prints 79:

double d1 = (64 / 0.8f);
byte b3 = (byte) d1;
Console.WriteLine(b3); //79



EDIT2:由于帕斯卡Cuoq的要求,我跑了下面的代码:

As of request of Pascal Cuoq, I ran the following code:

int sixtyfour = Int32.Parse("64");
byte b4 = (byte)(sixtyfour / 0.8f);
Console.WriteLine(b4); //79



结果是79所以上面的语句,编译器和运行时计算出不同的结果,是不正确的。

Result is 79. So the above statement that the compiler and the runtime calculate a different result is not true.

EDIT3 :当改变以前的代码(学分帕斯卡Cuoq,再次),结果是80:

EDIT3: When changing the previous code to (credits to Pascal Cuoq, again), the result is 80:

byte b5 = (byte)(float)(sixtyfour / 0.8f);
Console.WriteLine(b5); //80



但是请注意,这个写作(79结果)时,情况并非如此:

Note, however, that this is not the case when writing (results in 79):

byte b6 = (byte)(float)(64 / 0.8f);
Console.WriteLine(b6); //79



因此,这里是什么似乎是发生了什么:(字节) (64 / 0.8f)不计算为浮动,但评价为双击(它转换为字节之前)。这导致舍入误差(当计算是使用浮完成其中不会发生)。浮显式铸造的铸件翻番之前(被标记为ReSharper的冗余,BTW)解决这个问题。然而,当(仅使用常量如果可能)计算是在编译时做的,显式类型转换为浮动似乎被忽略/优化掉。

So here is what seems to be happening: (byte)(64 / 0.8f) is not evaluated as a float, but evaluated as a double (before casting it to byte). This results in a rounding error (which does not occur when the calculation is done using float). An explicit cast to float before casting to double (which is marked as redundant by ReSharper, BTW) "solves" this issue. However, when the calculation is done during compile time (possible when using constants only), the explicit cast to float seems to be ignored / optimized away.

TLDR:浮点计算更加复杂比他们最初看起来

TLDR: Floating point calculations are even more complicated than they initially seem.

这篇关于为什么基于投类型划分的结果有什么不同? (跟进)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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