2

为什么这个代码 http://ideone.com/YRcICG

void Main()
{   
    double a = 0.00004;
    Int32 castToInt = (Int32)(1.0/a);
    Int32 convertToInt = Convert.ToInt32(1.0/a);

    Console.WriteLine("{0} {1:F9} {2:F9}", castToInt == convertToInt, castToInt, convertToInt);

    Console.WriteLine((((int)(1.0/(1.0/25000))) == 24999));
}

结果是

假 24999,000000000 25000,000000000

在 CLR/C# 实现的上下文中

4

4 回答 4

5

诀窍在于双精度的表示方式,因此 (1.0/a) 将以下列方式表示:

(1.0/a) = 24999.99999999999636202119290828704833984375。

当你使用 cast 时,你只会得到这个数字的第一部分,而 convert 方法以不同的方式工作,这里是 Convert 方法的代码:

public static int ToInt32(double value)
{
    if (value >= 0.0)
    {
        if (value < 2147483647.5)
        {
            int num = (int)value;
            double num2 = value - (double)num;
            if (num2 > 0.5 || (num2 == 0.5 && (num & 1) != 0))
            {
                num++;
            }
            return num;
        }
    }
    else
    {
        if (value >= -2147483648.5)
        {
            int num3 = (int)value;
            double num4 = value - (double)num3;
            if (num4 < -0.5 || (num4 == -0.5 && (num3 & 1) != 0))
            {
                num3--;
            }
            return num3;
        }
    }
    throw new OverflowException(Environment.GetResourceString("Overflow_Int32"));
}

正如您所看到的,有一个 if 语句检查强制转换值和原始双精度之间的差异,在您的示例中它是:

int num = (int)value;
double num2 = value - (double)num;

24999.99999999999636202119290828704833984375 - 24999 > 0.5

,因此你得到增量。

于 2013-09-26T12:23:35.003 回答
3

在您的计算中,答案1.0/0.00004是转换为一个比 2500 略小的值,因为浮点数不能精确地表示所有可能的值。鉴于,

为什么这两个整数有不同的值?

将 double 转换为 int 会截断 value,因此小数点后的所有内容都将被丢弃。

Convert.ToInt32在双舍入到最接近的整数

为什么浮点数不精确?

请参阅另一个答案中链接的优秀文章:What Every Computer Scientist Should Know About Floating-Point Arithmetic

我怎样才能准确地表示值?

您可以使用十进制类型而不是双精度类型。这样做有利有弊,请参阅十进制与双精度!- 我应该使用哪一个以及何时使用?

于 2013-09-26T12:34:43.620 回答
1

投树干浮动号

(Int32)41.548 == 41

转换数字(功能?)

转换.ToInt32(41.548) == 42

于 2013-09-26T12:15:36.667 回答
0

Floating point math is not exact. Simple values like 0.2 cannot be precisely represented using binary floating point numbers, and the limited precision of floating point numbers means that slight changes in the order of operations can change the result. A must read:

What Every Computer Scientist Should Know About Floating-Point Arithmetic

The IEEE standard divides exceptions into 5 classes: overflow, underflow, division by zero, invalid operation and inexact. There is a separate status flag for each class of exception. The meaning of the first three exceptions is self-evident. Invalid operation covers the situations listed in TABLE D-3, and any comparison that involves a NaN.

于 2013-09-26T12:07:28.703 回答