每次双倍带来不同的价值观

时间:2018-05-21 11:38:47

标签: c# algorithm double rounding

这是我的生成算法,它为数组生成随机双元素,其总和必须为1

    public static double [] GenerateWithSumOfElementsIsOne(int elements)
    {
        double sum = 1;
        double [] arr = new double [elements];

        for (int i = 0; i < elements - 1; i++)
        {
            arr[i] = RandomHelper.GetRandomNumber(0, sum);
            sum -= arr[i];
        }

        arr[elements - 1] = sum;

        return arr;
    }

方法助手

    public static double GetRandomNumber(double minimum, double maximum)
    {
        Random random = new Random();
        return random.NextDouble() * (maximum - minimum) + minimum;
    }

我的测试用例是:

    [Test]
    [TestCase(7)]
    [TestCase(5)]
    [TestCase(4)]
    [TestCase(8)]
    [TestCase(10)]
    [TestCase(50)]
    public void GenerateWithSumOfElementsIsOne(int num)
    {
        Assert.AreEqual(1, RandomArray.GenerateWithSumOfElementsIsOne(num).Sum());   
    }

事情是 - 当我测试它时,每次返回不同的值,如下所示: Expected: 1 But was: 0.99999999999999967d
Expected: 1 But was: 0.99999999999999989d

但在接下来的测试中,它有时会通过所有这些测试,有时候不会。

亲爱的专家们,我知道那些四舍五入的麻烦并请求帮助。)

2 个答案:

答案 0 :(得分:1)

https://en.wikipedia.org/wiki/Floating-point_arithmetic

  

在计算中,浮点运算是使用公式算术   将实数表示为近似值以支持a   范围和精度之间的权衡。出于这个原因,浮点数   计算经常在包含非常小和的系统中找到   非常大的实数,需要快速的处理时间。一个号码   通常,大致表示固定数量   有效数字(有效数字)并使用指数缩放   一些固定基地;缩放的基础通常是两个,十个或   16。

简而言之,这就是花车所做的事情,它们并不能保持每一个价值并做出近似。如果您想要更精确,请尝试使用Decimal,或者使用epsilon添加容差(由于浮点运算中的舍入而导致的相对误差的上限)

var ratio = a / b;
var diff = Math.Abs(ratio - 1);
return diff <= epsilon;

答案 1 :(得分:1)

在浮点类型(例如SingleDouble)的情况下,

舍入错误是常见的,例如让我们计算 easy sum

  // 0.1 + 0.1 + ... + 0.1 = ? (100 times). Is it 0.1 * 100 == 10? No!
  Console.WriteLine((Enumerable.Range(1, 100).Sum(i => 0.1)).ToString("R"));

结果:

  9.99999999999998

为什么在将 floatinfg指向值与==!=添加容差进行比较时:

// We have at least 8 correct digits
// i.e. the asbolute value of the (round up) error is less than tolerance
Assert.IsTrue(Math.Abs(RandomArray.GenerateWithSumOfElementsIsOne(num).Sum() - 1.0) < 1e-8);