C# dotNet decimal类型是否易受二进制比较错误的攻击?

C# dotNet decimal类型是否易受二进制比较错误的攻击?,c#,.net,comparison,decimal,C#,.net,Comparison,Decimal,我每隔几个月就会发现一个错误: double x = 19.08; double y = 2.01; double result = 21.09; if (x + y == result) { MessageBox.Show("x equals y"); } else { MessageBox.Show("that sh

我每隔几个月就会发现一个错误:

        double x = 19.08;
        double y = 2.01;
        double result = 21.09;

        if (x + y == result)
        {
            MessageBox.Show("x equals y");
        }
        else
        {
            MessageBox.Show("that shouldn't happen!");  // <-- this code fires
        }
有些值(如19.08加2.01的结果)不能用双精度位表示

一种解决方案是使用常数:

        double x = 19.08;
        double y = 2.01;
        double result = 21.09;
        double EPSILON = 10E-10;

        if ( x + y - result < EPSILON )
        {
            MessageBox.Show("x equals y"); // <-- this code fires
        }
        else
        {
            MessageBox.Show("that shouldn't happen!");
        }
double x=19.08;
双y=2.01;
双结果=21.09;
双ε=10E-10;
if(x+y-结果<ε)
{

MessageBox.Show(“x等于y”);//只要保持在适当范围内的自然小数值内,十进制将是准确的。因此,如果您只是进行加法和减法,例如,不做任何会使所需数字范围扭曲的事情(将非常大的数字添加到非常小的数字中)你会得到很容易比较的结果。乘法可能也可以,但我怀疑它更容易得到不准确的结果

一旦你开始除法,问题就可能出现——特别是如果你开始用除2或5以外的素数除法

一句话:在某些情况下是安全的,但你确实需要对你将要执行的操作有一个很好的把握


请注意,在这里帮助您的并不是十进制的128位,而是将数字表示为浮点十进制值,而不是浮点二进制值。有关更多信息,请参阅我在.NET上的文章。

System.decimal只是一个具有不同基的浮点数,因此理论上,它仍然是一个漏洞请注意您指出的那种错误。我想您只是遇到了一个不进行舍入的情况。更多信息。

是的,.NET System.Double结构取决于您描述的问题

发件人:

两个显然相等的浮点数可能不相等,因为它们的最低有效位不同。例如,C#表达式,(double)1/3==(double)0.33333,不比较相等,因为左侧的除法运算具有最大精度,而右侧的常数仅对指定的数字精确。如果创建自定义算法来确定两个浮点数是否可以视为相等,则必须使用大于ε常数的值nt,以确定两个值相等的可接受绝对差值。(通常,该差值比ε大很多倍。)


这确实是一篇著名的论文。谢谢,但问题不仅仅发生在除法上。在转换十进制->二进制->十进制的过程中,一个小数点后两位的十进制可能会转换成一个大的(甚至是无限的?)二进制“十进制”如果数量大于128位,将被忽略的位数。如果将此“四舍五入”二进制转换回十进制,则会得到不同的结果。@Schlaviener:如果在双精度和十进制之间转换,肯定会有问题。不要这样做。坚持一种或另一种格式。我不想转换。关于你的artikel“十进制浮点”您提到十进制是基于“10”的。这是否意味着如果a+b真的是c,a+b=c总是返回true?这完全取决于您所说的“如果a+b真的是c”"。在某些情况下,结果会四舍五入,在某些情况下则不会。如果你能给出具体的例子,我们可以给出更明确的答案。@Schlaviener:a
Decimal
代表的数字与a
Decimal
代表的数字相匹配,这是从直观的精度角度来看的一个好处通过它的
ToString()
表示形式来实现。事实上,它是一种浮点格式,这意味着,就像
double
,它不能保证(a+b)+c和a+(b+c)是相同的(例如,如果a=1d/3d,b=10d,c=-10d,第一个表达式将有舍入误差,而第二个表达式将避免舍入误差。事实上,人们处理的大多数金额都是以10为基数的,小数类型可以准确地表示这些金额(在精度限制内)因此,十进制类型非常适合于现实世界中的使用,例如处理金额。
        double x = 19.08;
        double y = 2.01;
        double result = 21.09;
        double EPSILON = 10E-10;

        if ( x + y - result < EPSILON )
        {
            MessageBox.Show("x equals y"); // <-- this code fires
        }
        else
        {
            MessageBox.Show("that shouldn't happen!");
        }