在 32 位进程中类型转换后的值错误 [英] Wrong Value after type casting in 32 bit process

查看:21
本文介绍了在 32 位进程中类型转换后的值错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请参阅以下 C# 代码.

Please see the following code in C#.

        float a = 10.0f;
        float b = 0.1f;

        float c = a / b;
        int indirect = (int)(c);
        // Value of indirect is 100 always

        int direct = (int)(a / b);
        // Value of direct is 99 in 32 bit process (?)
        // Value of direct is 100 in 64 bit process

为什么我们在 32 位进程中得到 99?

Why do we get 99 in 32-bit processes?

我使用的是 VS2013.

I am using VS2013.

推荐答案

直接操作时,允许以更高的精度进行操作,并允许以更高的精度进行多次操作.

When you operate directly, it's permittable for operations to be performed at a higher precision, and for that higher precision to be continued for multiple operations.

来自 C# 5 规范的第 4.1.6 节:

From section 4.1.6 of the C# 5 specification:

浮点运算的执行精度可能高于运算的结果类型.例如,一些硬件架构支持比双精度型更大范围和精度的扩展"或长双精度"浮点类型,并使用这种精度更高的类型隐式执行所有浮点运算.只有在性能成本过高的情况下,才能使这种硬件架构执行精度较低的浮点运算,而不是要求实现同时牺牲性能和精度,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.

我希望在某些优化场景中,如果 JIT 决定它永远不需要将值作为 float.(我见过只添加日志会改变这里行为的情况......)

I'd expect that in some optimization scenarios, it would even be possible for the answer to be "wrong" with the extra local variable, if the JIT decides that it never really needs the value as a float. (I've seen cases where just adding logging changes the behaviour here...)

在这种情况下,我相信使用 64 位算术有效地执行除法,然后将 from double 直接转换为 int而不是先通过 float.

In this case, I believe that the division is effectively being performed using 64-bit arithmetic and then cast from double straight to int rather than going via float first.

以下是一些代码来演示这一点,使用 DoubleConverter 类可以让您找到浮点二进制点数的精确十进制表示:

Here's some code to demonstrate that, using a DoubleConverter class which allows you to find the exact decimal representation of a floating binary point number:

using System;

class Test
{
    static void Main()
    {
        float a = 10f;
        float b = 0.1f;
        float c = a / b;
        double d = (double) a / (double) b;
        float e = (float) d;
        Console.WriteLine(DoubleConverter.ToExactString(c));
        Console.WriteLine(DoubleConverter.ToExactString(d));
        Console.WriteLine(DoubleConverter.ToExactString(e));
        Console.WriteLine((int) c);
        Console.WriteLine((int) d);
        Console.WriteLine((int) e);
    }
}

输出:

100
99.999998509883909036943805404007434844970703125
100
100
99
100

请注意,该操作可能不仅仅以 64 位执行 - 它可能以更高的精度执行,例如80 位.

Note that the operation may not just be performed in 64-bits - it may be performed at even higher precision, e.g. 80 bits.

这只是浮点二进制小数点算术的乐趣之一 - 也是为什么您需要非常小心自己在做什么的一个例子.

This is just one of the joys of floating binary point arithmetic - and an example of why you need to be very careful about what you're doing.

请注意,0.1f 正好 0.100000001490116119384765625 - 所以大于 0.1.鉴于它大于 0.1,我希望 expect 10/b 小于 100 - 如果少一点"是可表示的,那么截断结果就会发生自然导致99.

Note that 0.1f is exactly 0.100000001490116119384765625 - so more than 0.1. Given that it's more than 0.1, I would expect 10/b to be a little less than 100 - if that "little less" is representable, then truncating the result is going to naturally lead to 99.

这篇关于在 32 位进程中类型转换后的值错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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