如何解决一些四舍五入错误?
-
29-09-2019 - |
题
我有一种处理.NET中某些地理坐标的方法,并且我有一个结构,该结构存储一个坐标对,以便如果将256传递给其中一个坐标,则将变为0。但是,在一个特定的实例中,计算大约255.9999998,因此存储在结构中。当它在tostring()中打印时,它变为256,不应该发生-256应该是0。我不介意它是否打印255.9999998,但是当调试器显示255.999999998时,它打印了256,这一事实是一个问题。将其存储和显示0会更好。
特别是比较存在问题。 255.99999998足够接近256,因此它应该等于它。比较双打时该怎么办?使用某种类型的Epsilon值?
编辑:具体来说,我的问题是我采用一个值,执行一些计算,然后对该数字执行相反的计算,我需要准确地恢复原始值。
解决方案
您可以使用Epsilon方法,但是Epsilon通常是一种软糖,可以解决浮点算术是有损的事实。
您可以考虑完全避免二进制浮点,并使用一个不错的理性课程。
如果您做无损算术,则上面的计算可能注定为256,因为您将获得理性类型。
理性类型可以按比例或分数类别的名称进行,并且编写非常简单
编辑....
要理解您的问题,请考虑,当小数值0.01转换为二进制表示时,它不能精确存储在有限内存中。该值的六边性表示为0.028F5C28F5C,其中“ 28F5C”无限重复。因此,即使在进行任何计算之前,您就可以通过以二进制格式存储0.01来放松精确性。
尽管有绩效成本,但使用理性和十进制类来克服这个问题。理性类型通过存储分子和分母来表示您的价值来避免此问题。小数类型使用二进制编码小数 格式, ,这可能会在分裂中有损失,但可以精确存储共同的小数值。
出于您的目的,我仍然建议一种理性类型。
其他提示
这听起来像是打印数字的问题,而不是如何存储数字。一种 double
有大约15个重要的数字,因此可以从256中告诉255.9999998,精确到备用。
您可以选择格式字符串,该字符串应该使您可以按照自己的方式显示数字中的大量数字。
比较双打平等的通常方法是减去它们,看看绝对值是否小于某些预定义的Epsilon,也许是0.000001。
您必须决定两个值相等的阈值。这相当于使用所谓的 固定点号 (而不是浮点)。然后,您必须手动执行舍入。
我会选择一些已知尺寸的未签名类型(例如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处包装。要乘法,您应该提防。