【问题标题】:How to compute (2^32)/n using 32-bit integers如何使用 32 位整数计算 (2^32)/n
【发布时间】:2018-03-05 00:33:50
【问题描述】:

我有一个 32 位定时器,我想在 n 步后溢出。这意味着每个步骤应该是 (2^32)/n。但是,如果我尝试使用 32 位整数来计算这个数字,编译器会抱怨 (1

我可以通过执行 (~0)/n 之类的操作来非常接近我正在寻找的答案。但是,让我感到困扰的是,在这种情况下,当 n 是 2 的幂时,我不会得到正确的答案,这意味着在这些情况下,计时器溢出需要额外的一步。

有没有只使用 32 位整数计算 (2^32)/n 的简单表达式?

【问题讨论】:

  • 你想如何对结果进行四舍五入?如果您向 0 舍入,则计时器将在 n=3 的第 4 步溢出。
  • (2^32)/n = 2*((2^31)/n)
  • @ScottHunter - 不使用整数运算。例如。 (2^32)/3 = 1431655765 2*((2^31)/3) = 1431655764。
  • @user2357112 公平点。我想我想四舍五入,或者计算 (2^32+n-1)/n。
  • 这看起来像XY-problem:要尽可能均匀地分布步骤并且接近 2^32 到零,请查看 Bresenham's algorithm

标签: algorithm math 32-bit


【解决方案1】:

如果您希望计数器恰好在第 n 步溢出(如果可能),那么您需要计算 ceil(2<sup>32</sup> / n)。考虑两种可能的情况:

  1. n 不是 2 的幂。在这种情况下,n 不是2<sup>32</sup> 的因数,并且除法的上限正好比下限大一。此外,(使用截断整数除法,如在 C 或 Java 中)floor(2<sup>32</sup> / n) == floor((2<sup>32</sup> - 1) / n)。所以想要的步骤是(2<sup>32</sup> - 1)/n + 1

  2. n 是 2 的幂。在这种情况下,n 精确除以 2<sup>32</sup>,因此 (2<sup>32</sup> - 1) / n 将比 2<sup>32</sup> / n 小一。所以想要的步骤是(2<sup>32</sup> - 1)/n + 1。方便的是,这与第一种情况的值相同。

注意:正如@greybeard 在评论中指出的那样,如果n &gt; 2<sup>16</sup>,则无法保证存在适当的步长。对于较大的n,上述过程将计算最大步长,以保证在步n之前不会发生溢出。

【讨论】:

  • overflow on precisely the nth step 不会发生在所有n > 2^16.
【解决方案2】:

如果您使用 C 作为您的编程语言,您可以使用它的无符号算术。考虑以下几点:

地板(232 / n) = 地板((232 - n) / n + 1)

如果您的n 具有无符号类型(例如uint32_t),则数学表达式2<sup>32</sup> - n 可以简单地计算为-n

所以在 C 中:

uint32_t n = ...;
uint32_t d = (-n) / n + 1;

或者:

uint32_t d = (0 - n) / n + 1;

你应该好好记录它,因为这真的是晦涩难懂的代码。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-09-19
    • 2013-09-18
    • 2019-12-18
    • 1970-01-01
    • 1970-01-01
    • 2015-07-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多