【问题标题】:Arithmetic on a struct representing a large integer表示大整数的结构的算术
【发布时间】:2015-06-19 02:13:20
【问题描述】:

我编写了 Murmur3 哈希的实现,并将 128 位密钥定义为 hash128_t

typedef struct
{
    uint64_t p1;
    uint64_t p2;
} hash128_t;

我正在尝试使用这些键编写自己的哈希图,但我不确定如何使用结构或这么大的数字进行算术运算。我需要专门针对模运算的帮助,但非常感谢有关如何将这两个内存块视为一个整数的帮助。

我的模数公式是

Dividend - ((Dividend/Divisor) * Divisor)

【问题讨论】:

  • 关于128位数字的不同表示可以看stackoverflow.com/questions/1188939/…
  • 如果您使用 gcc __uint128_t 可用于 64 位架构
  • @user1929959:大部分答案都与 C++ 相关,而不是 C,尽管据我所知,GMP 主要是带有 C++ 接口的 C。
  • 一方面,您可以使用大量预先编写的多精度库。但另一方面,自己编写是一项很棒的练习。我不记得上次做的所有细节,但在大多数方面,它可能就像你在学校学的算术一样。
  • 逐位数字,是的,尽管不一定以 10 为基数。另一个流行的选择是 16。(我,我使用基数 2147483648。)它不一定是不必要的低效。当你做长除法时,你同时得到商和余数;你不必乘法和减法。另请参阅右侧的链接,例如 stackoverflow.com/questions/6952424/algorithm 。或者,如果您关心效率,那肯定会使平衡偏向于使用其他人的,大概是优化的库。

标签: c math largenumber integer-arithmetic


【解决方案1】:

您可以做的最简单的事情是简单地丢弃一半散列并在另一半上做模(简单地使用%)。

下一个最简单的方法是使用现有的 bignum 库。

如果你想使用整个哈希,你需要在这里做一个长除法。有很多方法可以实际做到这一点;这是一个(完全未经测试)方法:

uint64_t big_modulo(hash128_t hash, uint64_t divisor) {
    uint64_t accum = hash.p1 % divisor;
    uint64_t shift_buf = hash.p2;

    for (int i = 0; i < 64; i++) {
      accum = accum << 1 | (shift_buf >> 63);
      shift_buf = shift_buf << 1;
      if (accum & (~1LU << 63)) accum = accum % divisor;
    }

    return accum % divisor;
}

请注意,如果除数大于2^63 - 1,这将中断。解决这个问题留给读者作为练习,如果您可以将除数限制为 32 位空间,则可以进行各种优化。

【讨论】:

  • 感谢您的精彩开始!这实际上是我一直在寻找的,我完全不知道该往哪个方向走。
猜你喜欢
  • 1970-01-01
  • 2010-09-07
  • 1970-01-01
  • 2014-02-13
  • 1970-01-01
  • 1970-01-01
  • 2015-01-19
  • 1970-01-01
相关资源
最近更新 更多