Math 如何避免一些舍入错误?

Math 如何避免一些舍入错误?,math,floating-point,double,floating-accuracy,epsilon,Math,Floating Point,Double,Floating Accuracy,Epsilon,我有一个处理.NET中某些地理坐标的方法,我有一个存储坐标对的结构,如果其中一个坐标传入256,它将变为0。但是,在一个特定实例中,计算出大约255.9999998的值,并将其存储在结构中。在ToString()中打印时,它会变成256,这是不应该发生的-256应该是0。我不介意它是否打印255.999998,但当调试器显示255.9999998时它打印256是个问题。让它同时存储和显示0会更好 具体来说,在比较方面存在一个问题。255.9999998足够接近256,因此应等于它。比较双打时我应

我有一个处理.NET中某些地理坐标的方法,我有一个存储坐标对的结构,如果其中一个坐标传入256,它将变为0。但是,在一个特定实例中,计算出大约255.9999998的值,并将其存储在结构中。在ToString()中打印时,它会变成256,这是不应该发生的-256应该是0。我不介意它是否打印255.999998,但当调试器显示255.9999998时它打印256是个问题。让它同时存储和显示0会更好

具体来说,在比较方面存在一个问题。255.9999998足够接近256,因此应等于它。比较双打时我应该怎么做?使用某种ε值



编辑:具体来说,我的问题是,我取一个值,执行一些计算,然后对该数字执行相反的计算,我需要准确地返回原始值。

这听起来像是数字如何打印的问题,而不是如何存储的问题。一个
double
大约有15个有效数字,因此它可以准确地从256中分辨出255.9999998

您可以选择格式字符串,该格式字符串应允许您显示任意数量的数字


比较双精度是否相等的常用方法是将它们相减,看看绝对值是否小于某个预定义的ε,可能是0.000001。

您可以使用ε方法,但ε通常是一种回避浮点运算有损这一事实的软糖

您可以考虑完全避免二进制浮点,并使用一个好的Rational类。 如果你像使用Rational类型一样进行无损运算,那么上面的计算结果可能是256

Rational类型可以使用Ratio或Fraction类的名称,并且编写起来相当简单

这里有一个。 这是


编辑

为了理解你的问题,当十进制值0.01被转换成二进制表示时,它不能精确地存储在有限内存中。该值的十六进制表示为0.028F5C28F5C,其中“28F5C”无限重复。因此,即使在进行任何计算之前,只需将0.01存储为二进制格式,即可降低精度

Rational和Decimal类用于克服这个问题,尽管会带来性能代价。Rational类型通过存储一个分子和一个分母来表示您的值来避免这个问题。Decimal类型使用二进制编码的十进制,它在除法中可能有损,但可以准确地存储常见的十进制值


出于您的目的,我仍然建议使用理性类型。

您必须确定两个值相等的阈值。这相当于使用所谓的定点数字(与浮点相反)。然后,您必须手动执行汇总

我会使用一些已知大小的无符号类型(如uint32或uint64,如果它们可用,我不知道.NET),并将其视为固定点数类型mod 256

例如

typedef uint32固定;
内联固定到_固定(双d)
{

return(fixed)(fmod(d,256.)*(double)(1使用epsilon是唯一合法的比较浮点值的方法。abs(a-b)将两个浮点值与==进行比较是完全合法的,因此几乎没有编译器对此抱怨。然而,当数学认为两个值应该相等时,最微小的舍入误差可能会导致两个值不相等,这就是为什么如果你重视你的理智,就不建议这样做。如果你真的只需要准确地返回原始值,你就不能这样做吗使用R格式说明符(而不是默认的G)存储它,或者存储有关原始计算过程以及数字的一些信息,使其显示正确的值。
typedef uint32 fixed;

inline fixed to_fixed(double d)
{
    return (fixed)(fmod(d, 256.) * (double)(1 << 24))
}

inline double to_double(fixed f)
{
    return (double)f / (double)(1 << 24);
}