【问题标题】:Fixed-point modulo edge cases定点模边缘情况
【发布时间】:2012-12-25 15:41:54
【问题描述】:

我正在 C# 中基于 System.Int64 实现 Q31.32 fixed-point numeric type。现在我正在尝试正确地进行模运算 (%)。

我见过的所有定点算术实现都简单地根据整数模来定义 Qm.n 模,即两个 Qm.n 数字的模是它们底层整数表示的模。这在一般情况下有效,但在两种特定情况下失败:

  • x % y 如果x == Int64.MinValuey == -1 抛出OverflowException。 我可以使用 if 语句轻松处理此问题并返回 0 这种情况,虽然这是一种奇怪的行为(unchecked 在这里没有帮助)。

  • x % y 对于xy 的一些小值错误地返回0。为了 例如,如果xy 的整数表示为-41359 (十进制:~-0.000000096159 和~0,000000013737),模为0 (十进制:0)而它们的十进制值的模是(根据System.Decimal) ~-0.000000013737。这个误差大约是 60 倍 类型的最大精度 (2^-32),因此不能将其视为 舍入误差。

最后一个错误的原因是什么,我可以做些什么来获得更好的准确性?

【问题讨论】:

  • 你使用什么样的模除法?也许问题就在那里。要清楚(整数或定点/浮点除法?)如果您使用移位整数除法应该没有错误,在浮动除法器上,小数总是有一些错误
  • 不确定你是否理解这个问题。我正在实现基于 Int64 模的定点模。一般来说,这只是工作,除了在上述情况下。你可以在这里看到实现:github.com/asik/FixedMath.Net/blob/master/Fix64.cs
  • 我完全理解。我看到你使用长模数所以有两个选项 1st。长模数是错误的(不可能)或第二个。您的打印是四舍五入尝试打印 raw_values 以检查模数是否正常。在这种情况下,您需要编写自己的打印例程,该例程会更精确,或者重新配置旧的打印例程以匹配精度。
  • 长模没有错,我从Fix64到十进制或双精度的转换操作也没有错。问题在于,以长模数形式实现 Q31.32 模数会导致特定值的不准确(虽然它对绝大多数值都非常有效),我不太明白为什么。

标签: c# math fixed-point


【解决方案1】:

我发现了问题。

-413 % 59 = 0 是正确的!!!

因为 -7 * 59 = -413

您假设的正确结果很可能取自 -413 的 2s 补码,这会导致混淆。

[编辑 1]

根据 Asik 的建议,我使用计算器,我对他的问题的最后评论是正确的。问题在于他的打印精度,而不是超过 2s 的补码或模数,请参见:

413 >> 32 = 0.00000009615905582904815673828125  
 59 >> 32 = 0.00000001373700797557830810546875

0.00000009615905582904815673828125 / 0.00000001373700797557830810546875 = 7
0.00000009615905582904815673828125 % 0.00000001373700797557830810546875 = 0

有关打印数字的更多信息,请参阅:https://stackoverflow.com/a/18401040/2521214

附:您究竟是如何获得模数应为 ~-0.000000013737 的结果?它可疑地等于 -59>>32 ...也许您的参考无法正确处理带符号的数字 (-413)

【讨论】:

  • 我的猜测是混淆的根源是 remaindermodulus 之间的区别。 C# 有一个 remainder 运算符,而不是模数运算符。其他一些语言使用% 作为模数运算符,或者有些人只是希望% 执行模数。
  • 我知道 -413 % 59 == 0。我也知道这些数字在我的数字类型中表示的定点值的模数,即 ~-0.000000096159 和 ~0,000000013737,不是 0。(如果您怀疑,请使用计算器)。误差远大于类型的精度,这表明根据其底层 Int64 表示的模来实现 Q31.32 是不正确的。我的问题是在这种情况下正确的实现是什么。
  • 我按照你写的做了(计算器显示了我原来怀疑的打印程序)并相应地编辑了答案。请参阅我的答案末尾的编辑
  • 我的打印例程只使用 Decimal 的。如果你使用十进制来计算,你会得到我提到的结果。我假设 Decimal 类是正确的:这可能是 Decimal 中的错误吗?
  • 是的,但小数是您数字的截断值!因此,如果您想对截断值取模,则不能使用未截断数字的整数取模,而是必须应用某种更正,但我认为这样做没有任何好处
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-17
  • 1970-01-01
  • 2016-09-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多