2010-06-23 45 views
2

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

特别是有比较的问题。 255.99999998足够接近256,所以它应该等于它。比较双打时我应该怎么做?使用某种类型的epsilon值?


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

+0

使用epsilon是比较浮点值的唯一合法方法。 abs(a - b)<= eps – Andrey 2010-06-23 01:37:38

+0

将两个浮点数与==进行比较是完全合法的,因此几乎没有任何编译器抱怨它。然而,最小的四舍五入误差会导致这两个值在数学说他们应该是不相等的,这就是为什么如果你重视你的理智不建议。 – cHao 2010-06-23 02:08:52

+0

如果您确实只需要将原始值准确恢复,您是不是可以直接存储它,或者是关于原始计算过程的一些信息以及数字? – 2010-06-24 18:52:13

回答

1

您可以使用epsilon方法,但是epsilon通常是解决浮点算法有损的事实的一种巧妙方法。

你可能会考虑完全避免二进制浮点,并使用一个很好的Rational类。

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

理性类型可以通过比率或成分类的名称去了,是相当简单写

这里有一个example。 这里的another


编辑....

要了解你的问题考虑,当十进制值0.01转换为二进制表示它不能准确地存储在内存有限。该值的十六进制表示是0.028F5C28F5C,其中“28F5C”无限重复。所以即使在进行任何计算之前,只要将二进制格式存储为0.01就可以避免精确性。

理性和小数类用于克服这个问题,虽然性能成本。通过存储分子和分母来表示您的价值,Rational类型可避免此问题。十进制类型使用二进制编码的十进制format,这可能是划分中的有损分量,但可以精确地存储常见的十进制值。

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

3

这听起来像打印号码的问题,而不是如何存储。 A double约有15位有效数字,因此它可以从256中精确地分辨出255.99999998。

1

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

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

+0

使用R格式说明符而不是默认的G使它显示正确的值。 – 2010-06-23 03:09:00

0

您必须在两个值相等的阈值上自行决定。这相当于使用所谓的定点数(而不是浮点)。然后,您必须手动执行取整。

我会用一些未签名的类型与已知的大小(例如,UINT32 UINT64或者,如果他们提供,我不知道.NET)去把它作为一个固定点数量型模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处包装。对于乘法,您应该小心。