这是我的生成算法,它为数组生成随机双元素,其总和必须为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
但在接下来的测试中,它有时会通过所有这些测试,有时候不会。
亲爱的专家们,我知道那些四舍五入的麻烦并请求帮助。)
答案 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)
Single
和Double
)的情况下,舍入错误是常见的,例如让我们计算 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);