在返回浮点更改结果的方法中将结果转换为浮点数 [英] Casting a result to float in method returning float changes result

查看:34
本文介绍了在返回浮点更改结果的方法中将结果转换为浮点数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么此代码在 .NET 4 中打印 False?显式转换似乎导致了一些意外行为.

Why does this code print False in .NET 4? It seems some unexpected behavior is being caused by the explicit cast.

我想要一个超越浮点数不准确"或不要那样做"的答案.

I'd like an answer beyond "floating point is inaccurate" or "don't do that".

float a(float x, float y)
{
  return ( x * y );
}

float b(float x, float y)
{
  return (float)( x * y );
}

void Main()
{
  Console.WriteLine( a( 10f, 1f/10f ) == b( 10f, 1f/10f ) );
}

PS:此代码来自单元测试,而不是发布代码.代码是故意这样写的.我怀疑它最终会失败,但我想知道确切的时间和原因.答案证明了这种技术的有效性,因为它提供了超出浮点确定性通常理解的理解.这就是以这种方式编写代码的重点;刻意探索.

PS: This code came from a unit test, not release code. The code was written this way deliberately. I suspected it would fail eventually but I wanted to know exactly when and exactly why. The answer proves the validity of this technique because it provides an understanding that goes beyond the usual understanding of floating point determinism. And that was the point of writing this code this way; deliberate exploration.

PPS:单元测试在 .NET 3.5 中通过,但现在升级到 .NET 4 后失败.

PPS: The unit test was passing in .NET 3.5, but now fails after the upgrade to .NET 4.

推荐答案

David 的评论是正确的,但不够有力.不能保证在同一个程序中进行两次计算会产生相同的结果.

David's comment is correct but insufficiently strong. There is no guarantee that doing that calculation twice in the same program will produce the same results.

C# 规范在这一点上非常清楚:

The C# specification is extremely clear on this point:

浮点运算的执行精度可能高于运算的结果类型.例如,一些硬件架构支持比双精度型更大范围和精度的扩展"或长双精度"浮点类型,并使用这种精度更高的类型隐式执行所有浮点运算.只有在性能成本过高的情况下,才能使这种硬件架构执行精度较低的浮点运算,而不是要求实现同时牺牲性能和精度,C# 允许对所有浮点运算使用精度更高的类型.除了提供更精确的结果之外,这很少产生任何可衡量的影响.但是,在 x * y/z 形式的表达式中,乘法产生的结果在双精度范围之外,但随后的除法将临时结果带回双精度范围,事实是以更高范围的格式计算表达式可能会导致产生有限结果而不是无穷大.

Floating-point operations may be performed with higher precision than the result type of the operation. For example, some hardware architectures support an "extended" or "long double" floating-point type with greater range and precision than the double type, and implicitly perform all floating-point operations using this higher precision type. Only at excessive cost in performance can such hardware architectures be made to perform floating-point operations with less precision, and rather than require an implementation to forfeit both performance and precision, C# allows a higher precision type to be used for all floating-point operations. Other than delivering more precise results, this rarely has any measurable effects. However, in expressions of the form x * y / z, where the multiplication produces a result that is outside the double range, but the subsequent division brings the temporary result back into the double range, the fact that the expression is evaluated in a higher range format may cause a finite result to be produced instead of an infinity.

<小时>

C# 编译器、抖动和运行时都具有广泛的自由度,可以随时为您提供比规范要求更准确的结果——他们不需要选择始终如一地这样做,事实上他们没有这样做.


The C# compiler, the jitter and the runtime all have broad lattitude to give you more accurate results than are required by the specification, at any time, at a whim -- they are not required to choose to do so consistently and in fact they do not.

如果您不喜欢那样,请不要使用二进制浮点数;使用小数或任意精度的有理数.

If you don't like that then do not use binary floating point numbers; either use decimals or arbitrary precision rationals.

我不明白为什么在返回 float 的方法中强制转换为 float 会产生不同

I don't understand why casting to float in a method that returns float makes the difference it does

优秀的点.

您的示例程序演示了微小的变化如何产生巨大的影响.您注意到在运行时的某些版本中,显式转换为 float 与不这样做会产生不同的结果.当您显式转换为浮点数时,C# 编译器会提示运行时说如果您碰巧正在使用此优化,请将其从超高精度模式中移除".正如规范所指出的,这有潜在的性能成本.

Your sample program demonstrates how small changes can cause large effects. You note that in some version of the runtime, casting to float explicitly gives a different result than not doing so. When you explicitly cast to float, the C# compiler gives a hint to the runtime to say "take this thing out of extra high precision mode if you happen to be using this optimization". As the specification notes, this has a potential performance cost.

这样做恰好可以得到正确答案"只是一个快乐的意外;获得正确答案是因为在这种情况下失去精度恰好在正确的方向上失去了它.

That doing so happens to round to the "right answer" is merely a happy accident; the right answer is obtained because in this case losing precision happened to lose it in the correct direction.

.net 4 有何不同?

How is .net 4 different?

你问3.5和4.0运行时有什么区别;区别很明显,在 4.0 中,抖动选择在您的特定情况下达到更高的精度,而 3.5 抖动选择不这样做.这并不意味着这种情况在 3.5 中是不可能的;它在每个版本的运行时和每个版本的 C# 编译器中都是可能的.您碰巧遇到过这样的情况:在您的机器上,它们的细节不同.但是抖动总是被允许进行这种优化,而且总是随心所欲地这样做.

You ask what the difference is between 3.5 and 4.0 runtimes; the difference is clearly that in 4.0, the jitter chooses to go to higher precision in your particular case, and the 3.5 jitter chooses not to. That does not mean that this situation was impossible in 3.5; it has been possible in every version of the runtime and every version of the C# compiler. You've just happened to run across a case where, on your machine, they differ in their details. But the jitter has always been allowed to make this optimization, and always has done so at its whim.

在编译时计算常量浮点数时,C# 编译器也完全有权选择进行类似的优化.常量中两个看似相同的计算可能会产生不同的结果,具体取决于编译器运行时状态的详细信息.

The C# compiler is also completely within its rights to choose to make similar optimizations when computing constant floats at compile time. Two seemingly-identical calculations in constants may have different results depending upon details of the compiler's runtime state.

更一般地说,你对浮点数应该具有实数代数性质的期望是完全不符合现实的;他们没有那些代数性质.浮点运算甚至不是关联;它们当然不会像您期望的那样遵守乘法逆定律.浮点数只是实数运算的近似值;一种足够接近的近似值,例如模拟物理系统或计算汇总统计数据,或诸如此类的事情.

More generally, your expectation that floating point numbers should have the algebraic properties of real numbers is completely out of line with reality; they do not have those algebraic properties. Floating point operations are not even associative; they certainly do not obey the laws of multiplicative inverses as you seem to expect them to. Floating point numbers are only an approximation of real arithmetic; an approximation that is close enough for, say, simulating a physical system, or computing summary statistics, or some such thing.

这篇关于在返回浮点更改结果的方法中将结果转换为浮点数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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