【问题标题】:Choosing an Epsilon Value for Floating Point Comparisons为浮点比较选择 Epsilon 值
【发布时间】:2018-03-21 01:10:06
【问题描述】:

我的团队正在使用将货币值作为 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 值应该很小,我们决定将其再移一位小数点到 0.00001(为了安全起见,您可以说)。 C# doubles 的精度为at least 15 digits,所以我相信如果小数点左侧的数字小于或等于 10 位(15 - 5 = 10,其中 5 是位数epsilon 位于小数点右侧)。使用 10 位数字,我们可以将值表示为数十亿,最高可达 9,999,999,999.999。我们可能有数亿的数字,但我们预计不会达到数十亿,所以这个限制应该足够了。

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

【问题讨论】:

  • 我认为使用普通的,甚至是 DP,IEEE754 对财务计算都不是一个好主意。感知的智慧是使用 C# 的 decimal 类型;你考虑过这个吗?
  • @IsaacWoods 我正在为现成的金融软件编写插件代码,因此我无法控制它使用的数据类型。我想过将双精度值转换为小数,但如果双精度已经包含舍入错误,它只会被复制到小数中。
  • 由于一些痛苦的经历,从一位经理告诉我“你永远不必阅读超过 200 张打孔卡。”,形式为“我们预计不会达到数十亿”的条款让我很紧张。你将如何执行限制?如果有一段时间的通货膨胀会发生什么?你得到一家大型银行作为客户?您的代码用于不同的货币?

标签: c# double epsilon


【解决方案1】:

您的推理似乎很合理,但正如您已经发现的那样,这是一个复杂的问题。您可能想阅读What Every Computer Scientist Should Know About Floating-Point Arithmetic。使用 64 位双精度,您确实有 15 位精度的最小值。但是,您还需要验证您的输入,因为浮点数可以包含 Nan、+/- Infinity、负零和比 15 位十进制数字大得多的“范围”。如果有人给你的库一个像 1.2E102 这样的值,你应该处理它还是认为它超出了范围?同样具有非常小的值。 Garbage In, Garbage out,但如果您的代码检测到垃圾的“气味”并至少记录下来,这可能会很好。

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

选择您的 epsilon 比您的需要低一个数字(因此小数点右侧的四个数字)的长短是合理的,并为您提供一个用于一致舍入的数字。否则 10.0129 美元和 10.0121 美元将相等,但它们的总和将是 20.025 美元而不是 20.024 美元......会计师喜欢“脚”的东西。

【讨论】:

    猜你喜欢
    • 2021-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多