为浮点比较选择Epsilon值

我的团队正在使用财务软件,它将货币价值暴露为C#浮点数的两倍。 有时,我们需要比较这些值,看它们是否等于零,或者是否属于特定限制。 当我注意到这个逻辑中的意外行为时,我很快就了解了浮点双精度中固有的舍入误差(例如1.1 + 2.2 = 3.3000000000000003)。 到目前为止,我主要使用C#小数来表示货币值。

我的团队决定使用epsilon值方法解决这个问题。 基本上,当你比较两个数字时,如果这两个数字之间的差异小于epsilon,它们被认为是相等的。 我们以下面文章中描述的类似方式实现了这种方法: https : //www.codeproject.com/Articles/383871/Demystify-Csharp-floating-point-equality-and-relat

我们的挑战是为epsilon确定合适的价值。 我们的货币值最多可以包含小数点右侧的3位数(比例= 3)。 这意味着我们可以使用的最大epsilon是0.0001(任何更大的东西都会被忽略)。 由于epsilon值应该很小,我们决定将它再移出一个小数点到.00001(只是为了安全,你可以说)。 C#双精度具有至少15位的精度,所以我相信如果小数点左边的数字小于或等于10位数(15 – 5 = 10,其中5是数字,则epsilon的值应该有效)数字epsilon位于小数点右侧)。 使用10位数字,我们可以将数值表示为数十亿,最高可达9,999,999,999.999。 我们可能有数亿的数字,但我们不希望达到数十亿,所以这个限制就足够了。

我选择这个epsilon值的理由是正确的吗? 我找到了很多讨论这种方法的资源,但是我找不到很多资源来提供选择epsilon的指导。

你的推理似乎很合理,但正如你已经发现的那样,这是一个复杂的问题。 您可能想要阅读每个计算机科学家应该知道的关于浮点运算的内容 。 使用64位双精度数,您至少具有15位精度。 但是,您还需要validation输入,因为浮点数可以包含Nan,+ / – Infinity,负零和比15位十进制数字大得多的“范围”。 如果有人给你的图书馆提供像1.2E102这样的值,你应该处理它还是认为它超出范围? 同上,价值非常小。 垃圾输入,垃圾输出,但如果您编码检测到垃圾的“气味”并且至少记录它可能会很好。

您可能还需要考虑提供用于设置精度的属性以及不同forms的舍入。 这在很大程度上取决于您正在使用的规格。 您可能还想确定这些值是否可以代表美元以外的货币(1美元目前> 112日元)。

选择你的epsilon的长度和短缺数字低于你的需要(所以十进制右边的四位数)是合理的,并给你一个数字用于一致的舍入。 否则$ 10.0129和$ 10.0121将是相等的,但他们的金额将是20.025美元,而不是20.024美元……会计师喜欢“脚”的东西。