如何解决一些舍入错误?

时间:2010-06-23 01:28:51

标签: math floating-point double floating-accuracy epsilon

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

特别是比较存在问题。 255.99999998足够接近256,因此它应该等于它。比较双打时我该怎么办?使用某种epsilon值?


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

4 个答案:

答案 0 :(得分:3)

这听起来像打印数字的问题,而不是如何存储。 double有大约15个有效数字,所以它可以从256精确到255.99999998。

答案 1 :(得分:1)

您可以选择格式字符串,以便您可以根据需要显示尽可能多的数字。

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

答案 2 :(得分:1)

你可以使用epsilon方法,但是epsilon通常可以解决浮点运算有损的问题。

您可以考虑完全避免使用二进制浮点并使用一个好的Rational类。

如果您使用Rational类型进行无损算术,则上面的计算可能注定为256。

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

这是一个example。 这是another


编辑...

要理解您的问题,请考虑当十进制值0.01转换为二进制表示时,它不能精确地存储在有限的内存中。该值的十六进制表示为0.028F5C28F5C,其中“28F5C”无限重复。因此,即使在进行任何计算之前,只要以二进制格式存储0.01,就会失去准确性。

Rational和Decimal类用于克服此问题,尽管性能成本较高。 Rational类型通过存储分子和分母来表示您的值来避免此问题。十进制类型使用二进制编码的十进制format,它可以在除法中有损,但可以精确地存储公共十进制值。

为了您的目的,我仍然建议使用Rational类型。

答案 3 :(得分:0)

您必须自己决定两个值相等的阈值。这相当于使用所谓的定点数(与浮点相对)。然后,您必须手动执行舍入。

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

例如

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);
}

或更精心设计以适应舍入约定(更接近,更低,更高,更奇,甚至)的东西。最高8位固定保持整数部分,24位低位保持小数部分。绝对精度为2 ^ { - 24}。

请注意,添加和减去这些数字自然会在256处回绕。对于乘法,你应该小心。