如何将浮点表示与不连续函数相结合

本文关键字:连续函数 相结合 表示 | 更新日期: 2023-09-27 18:22:41

我读过很多关于浮动误差和浮动近似的东西
问题是:我从来没有读过现实世界问题的答案。今天,我遇到了一个现实世界中的问题。这真的很糟糕,我真的不知道如何逃离。

看看这个例子:

    [TestMethod]
    public void TestMethod1()
    {
        float t1 = 8460.32F;
        float t2 = 5990;
        var x = t1 - t2;
        var y = F(x);
        Assert.AreEqual(x, y);
    }
    float F(float x)
    {
        if (x <= 2470.32F) { return x; }
        else { return -x; }
    }

假设CCD_ 1是CCD_。但实际上,由于舍入误差,其值为2470.32031
大多数时候,这不是问题。函数是连续的,一切都很好,结果相差一点值
但在这里,我们有一个不连续的函数,误差真的非常大。测试正好在不连续的点上失败了。

如何处理函数不连续的舍入误差?

如何将浮点表示与不连续函数相结合

这里的关键问题是:

  • 在某些情况下,当输入值发生微小变化时,函数的输出值会发生较大(且显著)变化
  • 您向函数传递的输入值不正确

正如你所写的,"由于舍入误差,[x的值]为2470.32031"。假设你可以写任何你想要的代码——简单地描述要执行的函数,一个专家程序员团队将在几秒钟内提供完整的、无错误的源代码。你会告诉他们什么?

你提出的问题是,"我将向这个函数传递一个错误的值2470.32031。我想让它知道正确的值是其他值,并提供我没有传递的正确值的结果,而不是我传递的错误值。"

一般来说,这个问题是不可能解决的,因为不可能区分2470.32031何时传递给函数,而2470.32何时传递到函数,而247 0.32031是预期的。你不能指望电脑能读懂你的心思。当您传递不正确的输入时,就不能期望得到正确的输出。

这个告诉我们的是函数F内部不可能有解。因此,我们必须缩小视野,看看更大的问题。您必须检查传递给F的值是否可以改进(以更好的方式、更高的精度或补充信息计算),或者问题的性质是否是这样的,即当传递2470.32031时,2470.32始终是预期的,以便将这些知识纳入F中。

注意:这个答案与Eric的答案基本相同
它只是启发了测试的观点,因为测试是规范的一种形式。

这里的问题是testMethod1不测试F。
相反,它测试了小数8460.32到浮点的转换和浮点减法是不精确的
但这是测试的目的吗
你所能说的是,在某些糟糕的条件下(接近不连续性),输入上的小错误会导致输出上的大错误,所以测试可以表示这是一个预期的结果。

注意,函数F几乎是完美的,除了浮点值2470.32F本身
事实上,浮点近似值会将小数点四舍五入(精确到1/3200)
所以答案应该是:

Assert.AreEqual(F(2470.32F), -2470.32F); /* because 2470.32F exceed the decimal 2470.32 */

如果你想测试这种低级别的需求,你需要一个高(任意/无限)精度的库来执行测试。

如果你不能承受函数F的不精确性,那么Float就是一个不匹配。,您将不得不找到另一个具有更高、任意或无限精度的实现
由您来指定您的需求,testMethod1将比现在更好地明确此规范。

如果您需要8460.32数字准确无舍入误差,您可以查看.NET Decimal类型,它是显式创建的,用于表示基数为10的小数,无舍入误差。我无法理解他们是如何施展魔法的

现在,我意识到这对你来说可能不切实际,因为float可能来自某个地方,将其重构为Decimal类型可能太难了,但如果你需要它对依赖于该值的不连续函数有那么高的精度,你要么需要一个更精确的类型,要么需要一些数学技巧。也许有某种方法可以确保创建的浮点值具有舍入误差,从而始终小于实际数字?我不确定这样的事情是否存在,但它也应该解决你的问题。

您的应用程序中有三个数字,通过将它们表示为浮点数,您已经接受了每个数字的不精确性。

所以我认为你可以合理地宣称你的程序工作正常

(oneNumber +/- some imprecision ) - (another number +/- some imprecision) 
        is not quite bigger than another number +/- some imprecision

当在纸上以十进制表示时,它看起来是错误的,但这不是你所实现的。数据的来源是什么?8460.32究竟是怎么知道的?如果是8460.31999,会发生什么?8460.32001?原来的数值知道得这么精确吗?

最后,如果您想更准确地建模,请使用其他地方建议的不同数据类型。

我总是认为,在比较浮点值时,由于舍入问题,需要较小的误差幅度。在你的情况下,这很可能意味着在你的测试方法中选择不那么严格的值——例如,定义一个非常小的误差常数,并从x中减去这个值。

编辑以更好地解决结论性问题:假设函数在不连续性上输出的内容并不重要,所以只在它的两侧稍微测试一下。如果确实重要,那么你能做的最好的事情就是在这一点上允许函数的两个输出中的任何一个。