【问题标题】:A C++ large integer precision question during multiplication乘法过程中的一个 C++ 大整数精度问题
【发布时间】:2021-01-03 22:14:00
【问题描述】:

如果我运行以下程序:

#include <iostream>

int main()
{
   using namespace std;

   uint64_t f12 = 18446744073709551568;
   uint64_t f3 = 2;
   uint64_t f123 = f12 * f3;

   cout << f12 << endl;
   cout << f3 << endl;
   cout << f123 << endl;

   return 0;

}

我得到输出:

18446744073709551568
2
18446744073709551520

我不明白为什么 2 次 f12 会导致值更小(正好是 48)。如果由于达到 uint64 值的大小而导致值翻转,那会不会有很大的不同(除非这是一个极端的巧合)?

【问题讨论】:

  • uint64_t f12=-48;,它看起来就不那么令人惊讶了。或打印-f12-f123
  • 你加倍的值等于 2^64 - 48(使用 ^ 表示幂)在数学上将它加倍产生 2^65 - 96。这大于 uint64_t 的范围,所以减去 2^64,得到 2^64 - 96。与原始值的差为 48。

标签: c++ integer precision multiplication


【解决方案1】:

您可以将其归结为“极端巧合”。 18446744073709551568 二进制是

FFFFFFFFFFFFFFD0

我们在学习二进制数学时都发现,乘以 2 相当于左移,变为:

FFFFFFFFFFFFFFA0

注意D0

11010000

二进制,高位设置,所以低8位左移变为

10100000

A0(高位左移)。

现在,通过以十进制计算 FFFFFFFFFFFFFFA0 是什么,您将得到问题的答案(您已经有点线索了,因为 A0 小于 D0 小于 30 十六进制,这碰巧是,纯属偶然,48)。

【讨论】:

  • 山姆,我现在明白了。毕竟,这并不是巧合,因为我在玩梅森素数,而 2^61-1 最终成为“种子”值,这使我在 2^64 翻转限制的 8 倍以内。
【解决方案2】:

将整数值乘以 2 可以看作是位的左移。当您将您的号码18446744073709551568 转换为二进制时,这是...

1111111111111111111111111111111111111111111111111111111111010000

如果将这些位左移一位,则结果是...

1111111111111111111111111111111111111111111111111111111110100000

在最低有效字节中,即在右端,11010000(十进制208)被10100000(十进制160)替换,这正是你的48少。所有较高的有效字节保持不变。所以总体结果也少了48

【讨论】:

    【解决方案3】:

    转移是一条红鲱鱼。

    C++ 中的 64 位无符号数学是数学模 2 的 64 次幂。如果 2*a 比 a 小 48,则 a 是 2 的 64 次幂减去 48。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-18
      • 1970-01-01
      相关资源
      最近更新 更多