Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/298.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么(int)(float.Parse(";0.04";,System.Globalization.CultureInfo.InvariantCulture)*100)等于3_C#_.net - Fatal编程技术网

C# 为什么(int)(float.Parse(";0.04";,System.Globalization.CultureInfo.InvariantCulture)*100)等于3

C# 为什么(int)(float.Parse(";0.04";,System.Globalization.CultureInfo.InvariantCulture)*100)等于3,c#,.net,C#,.net,我的老板今天报告了我的一个bug,因为每当他想要指定一个低于5%的值时,我的配置就会减少。我知道我可以在将数字转换为int之前对其进行四舍五入以解决问题,但我不明白为什么会出现这个问题 我有一个值为“0.04”的app.config文件和一个带有float属性的配置部分。读取节时,检索到的浮点值为0.04,这很好。我想把这个值放在一个windows窗体跟踪栏中,它接受一个整数值,所以我将我的值乘以100,并将其转换为int。出于某种原因,结果不是4,而是3。您可以这样测试它: Console.W

我的老板今天报告了我的一个bug,因为每当他想要指定一个低于5%的值时,我的配置就会减少。我知道我可以在将数字转换为int之前对其进行四舍五入以解决问题,但我不明白为什么会出现这个问题

我有一个值为“0.04”的app.config文件和一个带有float属性的配置部分。读取节时,检索到的浮点值为0.04,这很好。我想把这个值放在一个windows窗体跟踪栏中,它接受一个整数值,所以我将我的值乘以100,并将其转换为int。出于某种原因,结果不是4,而是3。您可以这样测试它:

Console.WriteLine((int)(float.Parse("0.04", System.Globalization.CultureInfo.InvariantCulture) * 100)); // 3

发生了什么?

之所以发生这种情况,是因为浮点值实际上更像是0.039999999;因此,您正在将3.9999999999这样的值转换为int,这将产生3

您可以通过四舍五入解决此问题:

Console.WriteLine((int)Math.Round(float.Parse("0.04", System.Globalization.CultureInfo.InvariantCulture) * 100));

实际上不是4而是399999和很多其他数字。这样做:

(int)(float.Parse("0.04") * 100.0 + 0.5)

“强制转换为浮点”类似于一个楼层操作符,因为它不完全是4,所以它被截断为3。

这是因为0.04不能精确表示为
浮点-
,也不能表示它乘以100的结果。结果稍微小于4,因此转换为int将截断它

基本上,如果您想使用十进制准确表示的数字,应该使用
decimal
类型,而不是
float
double
。有关更多信息,请参阅我在和上的文章


编辑:事实上,这里发生了一些更有趣的事情。。。特别是,如果先将结果指定给局部变量,则会更改结果:

using System;
using System.Globalization;

class Test
{
    static void Main()
    {
        // Assign first, then multiply and assign back, then print
        float f = Foo();
        f *= 100;
        Console.WriteLine((int) f); // Prints 4

        // Assign once, then multiply within the expression...
        f = Foo();
        Console.WriteLine((int) (f * 100)); // Prints 4

        Console.WriteLine((int) (Foo() * 100)); // Prints 3
    }

    // No need to do parsing here. We just need to get the results from a method
    static float Foo()
    {
        return 0.04f;
    }
}
我不确定这里到底发生了什么,但0.04f的确切值是:

0.039999999105930328369140625
。。。因此,它不打印4是有意义的,这是可能的

如果用
double
算法而不是
float
执行100的乘法,我可以强制结果为3:

f = Foo();
Console.WriteLine((int) ((double)f * 100)); // Prints 3

。。。但我不清楚为什么在原始版本中会出现这种情况,因为
float.Parse
返回
float
,而不是
double
。猜测一下,结果保留在寄存器中,随后的乘法使用
double
算法执行(根据规范这是有效的),但这肯定是一个惊人的差异。

作为浮点0.04*100很可能表示为3.99999999999,而强制转换为int只会截断它,所以,这就是为什么你看到3要加上这个,如果你需要精度,并且你知道它只有2位小数,请使用十进制类型。阅读“每个计算机科学家都应该知道的关于浮点运算的知识”。是的,乔恩,我们知道,你的…;)“事实上,这里发生了更有趣的事情……仍在调查……”嗯?我看这里没什么特别的
f*100
在我的系统上是
4-8940697E-08
,显示为
4
,因为默认的
ToString()
转换忽略了最低有效位。而且舍入误差不会被抵消,因为一些中间结果保持为double/extended。中间结果可以保持比静态类型更高的精度。AFAIK分配给局部变量可能会改变,也可能不会改变。另一方面,显式强制转换为
float
(即使类型已经是
float
)将保证值降级为
float
可以表示的值。@CodeInChaos:Yes。。。我相信结果将取决于CLR版本和CPU体系结构。@CodeInChaos分配给局部变量确实会改变这一点,因为它会导致编译器发出一条指令,将值截断到精确的
浮点