【问题标题】:Algorithm for difference of products of large integers大整数乘积的差分算法
【发布时间】:2012-09-27 15:59:33
【问题描述】:

我正在寻找一种算法来解决 ab-cd 类型的差异,其中 a、b、c 和 d 是类型容量边缘的整数,即 ab 溢出或丢失数字取决于实际表示在机器上。我不能使用任意精度的数学;其中一个平台是 SQL 数据库。

我考虑将产品分解为 (a'+a'')b-(c'+c'')d 然后以某种方式向下迭代。但可能有一种更有效的方法,或者至少有一个聪明的想法来进行分解。不幸的是,在大多数情况下,a,b;光盘; a, c; b,d 互质,所以至少约简并不简单。

有什么想法吗?

【问题讨论】:

标签: php sql algorithm integer


【解决方案1】:

如果您的产品接近 Int32 的限制,您可以使用 Int64。

【讨论】:

    【解决方案2】:

    您可以使用BC Math Functions 在 32 位和 64 位系统上处理大量数字

    大数示例

    $a = "4543534543543534543543543543545";
    $b = "9354354546546756765756765767676";
    $c = "5654656565656556565654656565656";
    $d = "4556565656546546546546546356435" ;
    
    
    var_dump(calculate($a, $b, $c, $d));
    

    输出

    string '257010385579862137851193415136408786476450997824338960635377204776397393100227657735978132009487561885957134796870587800' (length=120)
    

    使用的功能

    function calculate($a, $b, $c, $d) 
    {
        return bcmul(bcmul(bcmul(bcsub($a, $c),bcsub($a, $d)),bcsub($b, $c)),bcsub($b, $d));
    }
    

    【讨论】:

      【解决方案3】:

      警告

      此方法只是部分功能。也有解决不了的情况。


      取自您的文字:

      我正在寻找一种算法来解决 ab-cd 类型的差异, 其中a、b、c、d是类型容量边缘的整数,

      据我了解,您希望计算 (a * b) - (c * d) 以避免数字溢出。你想用算法解决这个问题。

      首先我们需要认识到(a * b) - (c * d) 的结果可能不适合数据类型。我不会尝试解决这些情况。

      所以,我会寻找不同的方法来计算“ab-cd”。我发现是这样的:

      (a * b) - (c * d) = ((a - c) * b) - (c * (d - b))
      

      您可以重新排序变量以获得不同的产品,从而增加找到一个案例的机会,该案例允许您计算运算而不会出现可怕的数字溢出:

      ((a - d) * b) - (d * (c - b))
      ((b - c) * a) - (c * (d - a))
      ((a - c) * b) - (c * (d - b))
      ((b - d) * c) - (b * (c - a))
      ((a - d) * c) - (a * (c - b))
      ((b - c) * d) - (b * (d - a))
      ((a - c) * d) - (a * (d - b))
      

      还要注意,这仍然是产品的差异,这意味着您可以递归地应用它们,直到找到一个有效的产品。例如:

          Starting with:
              (a * b) - (c * d)
          =>
          Using the transformation:
              ((a - d) * b) - (d * (c - b))
          =>
          By substitution:
              (e * b) - (d * f)
          =>
          Rinse an repeat:
              ((e - f) * b) - (f * (d - b))
      

      当然,我们需要确保这样做不会导致数字溢出。值得庆幸的是,还可以使用以下方法测试特定产品是否会导致数字溢出(实际上不做产品):

              var max = MaxValue;
              var min = MinValue;
              if (a == 0 || b == 0)
              {
                  return false;
              }
              else
              {
                  var lim = a < 0 != b < 0 ? min : max;
                  if ((a < 0 == b < 0) == a < 0)
                  {
                      return lim / a > b;
                  }
                  else
                  {
                      return lim / a < b;
                  }
              }
      

      此外,还可以使用以下方法测试特定差异是否会导致数字溢出(实际上不做差异):

              var max = MaxValue;
              var min = MinValue;
              if (a < 0 == b < 0)
              {
                  return true;
              }
              else
              {
                  if (a < 0)
                  {
                      if (b > 0)
                      {
                          return min + b < a;
                      }
                      else
                      {
                          return min - b < a;
                      }
                  }
                  else
                  {
                      if (b > 0)
                      {
                          return max - b > a;
                      }
                      else
                      {
                          return max + b > a;
                      }
                  }
              }
      

      这样就可以从上面的八个表达式中选择一个表达式,这样您就可以在没有数字溢出的情况下进行计算。

      但是...有时这些都不起作用。似乎在某些情况下,甚至它们的组合都不起作用(即冲洗和重复不起作用)*。或许还有其他身份可以补图。

      *:我确实尝试使用一些启发式方法来探索组合,也尝试过随机探索,存在我没有选择好的启发式方法并且我没有随机的“运气”的风险。这就是为什么我不能确定。

      我想我已经取得了一些进展......但是关于最初的问题我最终失败了。可能我有更多时间时会回到这个问题......或者我可能只是玩电子游戏。

      【讨论】:

      • 很遗憾,这是错误的。尝试例如a = 7, b = 15, c = 3, d = 4; a*b - c*d = 105 - 12 = 93; (a - c*d)*(b - c*d) = (7 - 12)*(15 - 12) = (-5)*3 = -15; (a - c)*(a - d)*(b - c)*(b - d) = 4*3*12*11 = 1584.
      • -1,x = (a - c) * (a - d) * (b - c) * (b - d) 是错误的。采取a = 1, b = 2, c = 3, d = 4。原始公式给出-10,而您的公式给出12。我不知道你用的是什么,但这不是分配性。
      • 谢谢。我会修复它。我正在设置一个环境来测试这个,实际上我发现它错了。
      • 是的,这与我正在考虑的算法有关。在分析了一些表达式后,我发现通常 a > b > c > d(对于绝对值)并且 a-d ~ a。可能像 a-nd ~ d 这样的术语可能会有所帮助。我会看看我能找到什么。
      • @RichardTheKiwi 拼写错误,已修复。
      【解决方案4】:

      我所知道的解决此类问题的标准方法是像人类对超过一位数的数字所做的那样,这是我们用手指自然数数的极限。我们carry号码转发。

      例如,假设您的数字计算器中的数字限制是 256 (2^8)。为了得到 (243*244)-(242*245) 的差异,我们需要将数字分解为

      Label | Part 1 (shifted 2 right) | Part 2 (remainder)
      a       2                           43
      b       2                           44
      c       2                           42
      d       2                           45
      

      您需要一个数组来存储结果的各个数字,或者一个字符串。我认为数组更快,但字符串更方便和可见(用于调试)。

         (a*b)-(c*d)
      =>   a1*b1 shift4 + a1*b2 shift2 + a2*b1 shift2 + a2*b2
         - c1*d1 shift4 + c1*d2 shift2 + c2*d1 shift2 + c2*d2
      => 987654321 (right-aligned string positioning)
        +    4xxxx
        +     88xx
        +     86xx
        +     1892
        -    4xxxx
        -     90xx
        -     84xx
        -     1890
        ==========
                 2
      

      一个简单的实现会独立完成每个步骤,将每个数字推入到位并在必要时将其向前推进。可能有很多关于优化这些算法的文献,例如将其分解为每个 2 位数字的数组槽(因为您的 number-limit 256 寄存器可以轻松处理 2 个 2 位数字的加法)。

      【讨论】:

      • 在考虑了剩余类数学之后,我得出了一个非常相似的解决方案。刚刚完成测试,当我回到这里看到你的建议时。当然,重要的部分是在同一累加器步骤中具有 +4xxxx 和 -4xxxx,此时它尚未左移。看起来,它也可以用来比较分数,由于精度限制,分数减少到相同的浮点表示。
      【解决方案5】:

      在玩了一点之后,我发现了一个更简单的算法,遵循我最初的想法。它可能比组合乘法要慢一些,因为它需要真正的乘法和除法,而不仅仅是移位和加法,但到目前为止我还没有对抽象语言的性能进行基准测试。

      思路如下重写ab-cd = (a'+q*d)b-cd = a'b-(c-qb)d = a'b-c'd

      如果您将 ab-cd 排序为 a>b 和 c>d,则该算法似乎转换最快,即减少最大数字并最大化 q。

      q=(int)floor((a>c)? a/d : c/b);
      a -= q*d;
      c -= q*b;
      

      现在重新排序并重新开始。只要所有数字都小到可以安全乘法,任何数字都小于 2 甚至为负数,或者两边的任何数字都找到相同的值,您就可以完成。

      【讨论】:

        猜你喜欢
        • 2021-02-20
        • 2011-08-21
        • 1970-01-01
        • 2015-02-18
        • 1970-01-01
        • 1970-01-01
        • 2014-07-14
        • 2011-05-09
        • 1970-01-01
        相关资源
        最近更新 更多