2^n - 1 不会溢出 long
2^n - 1 without overflowing a long
这是一个 C89 项目,其中 LONG_IS_64BIT
定义为(且仅当)long
是 64 位,即包含从 -2^63 开始的所有整数-1 到 2^63-1。否则(根据 C 标准)它包含从 -2^31-1 到 2^31-1 的所有整数。
我有一个数字 n
如果定义了 LONG_IS_64BIT
则它保证在 0 到 63(含)之间,否则为 0 到 31(含)。我想计算 2^n-1,它适合 long.
目前代码有 (1L<<n) - 1
,但在极有可能 long
正好是 32 位或 64 位的情况下,这是未定义的行为。 (在这部分程序中 n==63
几乎是不可能的,但在 32 位计算机上 n==31
肯定会发生。)这样做的正确方法是什么?
我想我可以只测试 n==31
和 n==63
,但这感觉很老套。
如果您知道 (1L<<n)-1
的数学值适合 long
,您可以通过计算值减一然后加一来确保不会溢出,而不是计算值加一,然后减一。
n == 0 ? 1 : ((1L<<n-1)-1<<1)+1
这很复杂,如果 n == 0
,需要特殊的外壳来避免左移负值,但至少它可以为您提供所需的值。
或者,您可以使用右移:
#ifdef LONG_IS_64BIT
0x7FFFFFFFFFFFFFFF>>(63-n)
#else
0x7FFFFFFF>>(31-n)
#endif
如果它可能比您预期的要大,您不能在此处使用 LONG_MAX
。
但实际上,@melpomene 对使用 unsigned long
的评论应该足够好。在编写标准时,它具有与 long
相同数量的值位的平台已经不常见了。如果您已经假设 long
正好有 32 位或正好有 64 位,您可能不应该担心更深奥的实现。
这是一个 C89 项目,其中 LONG_IS_64BIT
定义为(且仅当)long
是 64 位,即包含从 -2^63 开始的所有整数-1 到 2^63-1。否则(根据 C 标准)它包含从 -2^31-1 到 2^31-1 的所有整数。
我有一个数字 n
如果定义了 LONG_IS_64BIT
则它保证在 0 到 63(含)之间,否则为 0 到 31(含)。我想计算 2^n-1,它适合 long.
目前代码有 (1L<<n) - 1
,但在极有可能 long
正好是 32 位或 64 位的情况下,这是未定义的行为。 (在这部分程序中 n==63
几乎是不可能的,但在 32 位计算机上 n==31
肯定会发生。)这样做的正确方法是什么?
我想我可以只测试 n==31
和 n==63
,但这感觉很老套。
如果您知道 (1L<<n)-1
的数学值适合 long
,您可以通过计算值减一然后加一来确保不会溢出,而不是计算值加一,然后减一。
n == 0 ? 1 : ((1L<<n-1)-1<<1)+1
这很复杂,如果 n == 0
,需要特殊的外壳来避免左移负值,但至少它可以为您提供所需的值。
或者,您可以使用右移:
#ifdef LONG_IS_64BIT
0x7FFFFFFFFFFFFFFF>>(63-n)
#else
0x7FFFFFFF>>(31-n)
#endif
如果它可能比您预期的要大,您不能在此处使用 LONG_MAX
。
但实际上,@melpomene 对使用 unsigned long
的评论应该足够好。在编写标准时,它具有与 long
相同数量的值位的平台已经不常见了。如果您已经假设 long
正好有 32 位或正好有 64 位,您可能不应该担心更深奥的实现。