Bash 中的按位移位和最大整数

22 bash arithmetic

这是一个探索性问题,这意味着我不完全确定这个问题是关于什么的,但我认为它是关于 Bash 中最大的整数。无论如何,我会明示地定义它。

$ echo $((1<<8))
256
Run Code Online (Sandbox Code Playgroud)

我通过移动一点来产生一个整数。我能走多远?

$ echo $((1<<80000))
1
Run Code Online (Sandbox Code Playgroud)

显然没有那么远。(1 是出乎意料的,我会回到它。)但是,

$ echo $((1<<1022))
4611686018427387904
Run Code Online (Sandbox Code Playgroud)

仍然是积极的。然而,不是这个:

$ echo $((1<<1023))
-9223372036854775808
Run Code Online (Sandbox Code Playgroud)

再往前走一步,

$ echo $((1<<1024))
1
Run Code Online (Sandbox Code Playgroud)

为什么是 1?为什么会出现以下情况?

$ echo $((1<<1025))
2
$ echo $((1<<1026))
4
Run Code Online (Sandbox Code Playgroud)

有人想分析这个系列吗?

更新

我的机器:

$ uname -a
Linux tomas-Latitude-E4200 4.4.0-47-generic #68-Ubuntu SMP Wed Oct 26 19:39:52 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
Run Code Online (Sandbox Code Playgroud)

Ste*_*itt 32

Bash使用intmax_t变量进行算术运算。在您的系统上,这些长度为 64 位,因此:

$ echo $((1<<62))
4611686018427387904
Run Code Online (Sandbox Code Playgroud)

这是

100000000000000000000000000000000000000000000000000000000000000
Run Code Online (Sandbox Code Playgroud)

二进制(1 后跟 62 个 0)。再转移一下:

$ echo $((1<<63))
-9223372036854775808
Run Code Online (Sandbox Code Playgroud)

这是

1000000000000000000000000000000000000000000000000000000000000000
Run Code Online (Sandbox Code Playgroud)

二进制(63 0),二进制补码算法。

要获得最大的可表示整数,您需要减去 1:

$ echo $(((1<<63)-1))
9223372036854775807
Run Code Online (Sandbox Code Playgroud)

这是

111111111111111111111111111111111111111111111111111111111111111
Run Code Online (Sandbox Code Playgroud)

以二进制形式。

正如ilkkachu回答中所指出的,在64 位x86 CPU(无论是使用RCL还是SHL)上,移位采用偏移模 64 ,这解释了您所看到的行为:

$ echo $((1<<64))
1
Run Code Online (Sandbox Code Playgroud)

相当于$((1<<0))。因此$((1<<1025))$((1<<1))$((1<<1026))$((1<<2))...

您将在stdint.h; 中找到类型定义和最大值。在您的系统上:

/* Largest integral types.  */
#if __WORDSIZE == 64
typedef long int                intmax_t;
typedef unsigned long int       uintmax_t;
#else
__extension__
typedef long long int           intmax_t;
__extension__
typedef unsigned long long int  uintmax_t;
#endif

/* Minimum for largest signed integral type.  */
# define INTMAX_MIN             (-__INT64_C(9223372036854775807)-1)
/* Maximum for largest signed integral type.  */
# define INTMAX_MAX             (__INT64_C(9223372036854775807))
Run Code Online (Sandbox Code Playgroud)


Sat*_*ura 5

来自2.05b的CHANGES文件bash

j. shell 现在以机器支持的最大整数大小 (intmax_t) 执行算术,而不是 long。

在 x86_64 机器上intmax_t对应于有符号的 64 位整数。因此,您会在-2^63和之间获得有意义的值2^63-1。在这个范围之外,你只会得到环绕。