【问题标题】:How big can a 64 bit unsigned integer be?64 位无符号整数可以有多大?
【发布时间】:2017-09-27 07:57:16
【问题描述】:

我很清楚How big can a 64bit signed integer be? 感谢这个问题及其直截了当的答案。

那么,据此,我可以说unsigned int 可以是 2^64 - 1,而不是 2^63 - 1?

2^63 - 1:    0111111111111111111111111111111111111111111111111111111111111111

2^64 - 1:    1111111111111111111111111111111111111111111111111111111111111111

当且仅当我正确理解它时,我如何才能检测到无符号溢出?二进制补码表示中的有符号整数溢出将侵入最高位位置,返回负数。但是这个未签名的案例呢?

【问题讨论】:

  • 那就是2^64 - 1
  • 它与检测带符号数溢出没有本质区别。你会得到一个小整数,而不是一个负数。
  • 无符号整数不会溢出;他们环绕
  • 查看这里的讨论:stackoverflow.com/questions/3944505/… 最好的方法可能是使用 CPU 的溢出标志(但这些标志并未以标准方式公开,因此您需要使用 gcc 编译器宏或类似的东西)。
  • "64 位无符号整数可以有多大?"它可以是 64 位... 对于任何二进制(以 2 为基数)数字,数字数字 n 的值是 val * 2^n,其中 val 是二进制的 1 或 0。请注意,lsb 为 n=0。因此,只有 msb 设置为 1 的数字将是 2^63,而设置为“全一”的 64 位数字将是 2^64 - 1。在你被允许参加任何编程课程之前,这是他们在(体面的)学校教的完全基本的东西。

标签: c


【解决方案1】:

有符号整数只能达到2^63-1 (9,223,372,036,854,775,807),因为最高有效位是为符号保留的。如果该位为1,则该数字为负数,可以低至-2^63 (-9,223,372,036,854,775,808)。

在有符号的 64 位整数上,2^64-1 实际上是数字 -1

但是,如果您使用无符号整数,则该值从 0 开始,2^64-1 (18,446,744,073,709,551,615) 成为它的最大值,但无符号整数不能表示负值。

【讨论】:

  • 非常感谢您的简单示例!
  • 我想你忘了从2**64((2**64) - 1) == 18446744073709551615 中减去一个。
  • 这是一个非常好的答案,但我只想注意一个小的技术问题,可以用 uint64 表示数量的数字方面,并在单独的 @ 中表示它的正/负质量987654331@。但是,除非您已经实现了几个带有运算符重载的数字类,否则使用起来相当麻烦。
【解决方案2】:

通过查看值很难或不可能检测到。
问题是最大值加上即使只有 1 仍然/再次是有效值;即 0.

这就是为什么大多数程序员尽可能避免,如果它实际上是一个错误的值。对于某些应用程序,环绕是逻辑的一部分并且很好。

如果你计算例如c=a+b;(a、b、c 是 64 位无符号整数,而 a、b 令人担忧地接近最大值,或者可能是)并想知道结果是否受到影响,
然后检查是否((max - b) < a)max 是适当的编译器提供的符号。

不要自己计算最大值为 2^64-1,这将是特定于实现和特定于平台的。最重要的是,它将包含两次环绕(2^64 超出最大值,可能为 0;并且通过 0 减去 1...)。即使^ 被理解为“to the power of”的适当版本,这也适用。

【讨论】:

  • 64 位无符号整数的最大值是特定于实现还是特定于平台?
  • @chux 不是具体的最终最大值,而是计算2^64-1。我相信这是允许编译器做的,使用可以存储值的中间数据类型和/或(硬件特定的)寄存器,或者通过静态代码分析之类的东西来检测最终值是否适合64位无符号以及该值是什么以及(具体实现)将其用作常量。无论我在哪里看,编译器提供的符号定义都是不同的。但你的问题是有效的,我承认我想到了一些不同的东西,这在这里不适用。
  • 我可以想象一个实现的边缘情况,它在 2^64-1 处具有陷阱表示并使用 2^64-2 作为最大值。但我在这里不用作论据。
  • 我喜欢想象力,但对于 unsigned 类型,value bits 的组合不能成为陷阱。 “该类型的对象应能够使用纯二进制表示表示从 0 到 2N - 1 的值”C11 §6.2.6.2 1
  • @chux 好的报价,谢谢。幸运的是我没有用它作为论据。
【解决方案3】:

您对有符号和无符号整数的最大大小的假设是正确的。有符号的实际值为 9223372036854775807,无符号的实际值为 18446744073709551615。

检测无符号加法的溢出相当简单 - 如果结果小于任一操作数,则存在溢出。

减法类似,如果结果大于第一个操作数则溢出。

乘法很难,我不知道一个简单的规则。

除非你除以零,否则溢出是不可能的。

【讨论】:

    【解决方案4】:

    可以是18446744073709551615

    18,446,744,073,709,551,615
    q5 q4  t   b   m   t   h
    

    【讨论】:

      【解决方案5】:

      64 位有多大?

      回答无符号64位整数有多大,我建议在汇编或任何支持64位数据类型的编程语言中做一个小比较测试。

      从 0 计数到可以存储在变量中的最大值。第一次使用 32 位宽的变量,第二次使用 64 位宽的变量。尝试估计结果。

      在 C# 中,32 位变量的代码可能如下所示(……请忽略一个问题):

      for (uint i = 0; i < uint.MaxValue; i++)
      {
          Process(i);
      }
      

      uint.MaxValue是将变量的所有位设置为1时得到的数字。它基本上等于2^32 - 1 = 4294967295。这大约是42亿。

      64位变量案例的测试代码类似:

      for (ulong i = 0; i < ulong.MaxValue; i++)
      {
          Process(i);
      }
      

      ulong.MaxValue 这次是 2^64 – 1 = 18446744073709551615(20 位数字)。

      大约 10 亿次 Process() 操作/秒,第一个程序将在以下时间完成其工作:

      2^32 / 1000000000 = 4.29 秒

      以相同的处理速度,第二个程序将在以下时间完成其工作:

      2^64 / 1000000000 / 3600 / 24 / 365 = 585 年!

      差别很大!!!谁有时间等待 585 年才能完成它的工作!

      有趣的是,每秒 10 亿次操作是相当激进的!对于每秒执行 100 万到几亿次操作的更现实的场景,执行一次的时间会爆炸到数千甚至数十万年!!!

      对于大多数人来说,上述练习是 64 位功率的有趣可视化。但这个练习也展示了计算机科学工程师使用算法所面临的现实。采用蛮力方法的糟糕实现的算法(例如搜索或计算问题)很可能会破坏您的软件。

      其他大数字

      作为回顾,请记住存储在 64 位寄存器/变量中的最大数字是 2^64 – 1 = 18446744073709551615(20 位数字)。与 1 googol 相比,这个数字似乎很大,例如 10^100(1 后跟 100 个零)!

      即使是大的googol也小于70! (70 阶乘,即 1 * 2 * ... * 70)。哇!这确实显示了乘法的力量!

      您知道吗:googol 完全在双精度数据类型(IEEE 754 浮点)的范围内——也是 64 位结构。 double 如何存储如此大的数字将在以后的文章中介绍。

      希望你玩得开心!

      【讨论】:

        【解决方案6】:

        64 位无符号整数可以有多大?

        要编码最大,最好使用UINT64_MAX。它总是在 64 位类型可用时定义。

        #include <stdint.h>
        #define MAX64BIT UINT64_MAX 
        or 
        #define MAX64BIT 0xFFFFFFFFFFFFFFFF
        or
        #define MAX64BIT 18446744073709551615u
        

        如何检测无符号溢出?

        使用 N 位 无符号 类型:uintN_t a,b;

        溢出检测:

        // addition
        uintN_t sum = a + b;
        bool overflow = sum < a;  // or sum < b
        
        // subtraction
        bool overflow = b > a;
        uintN_t diff = a - b;  //
        

        由于有符号数学的未定义行为 (UB),有符号 类型需要其他代码。 Example

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-11-05
          • 2012-02-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-11-10
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多