tạo ra một số nguyên bằng cách dịch chuyển một chút. Tôi có thể đi bao xa?
Cho đến khi biểu diễn số nguyên bao bọc xung quanh (mặc định trong hầu hết các shell).
Một số nguyên 64 bit thường bao quanh tại 2**63 - 1
.
Đó là 0x7fffffffffffffff
hoặc 9223372036854775807
trong tháng mười hai.
Con số '+1' trở thành âm.
Điều đó cũng giống như 1<<63
, do đó:
$ echo "$((1<<62)) $((1<<63)) and $((1<<64))"
4611686018427387904 -9223372036854775808 and 1
Sau đó, quá trình lặp lại một lần nữa.
$((1<<80000)) $((1<<1022)) $((1<<1023)) $((1<<1024)) $((1<<1025)) $((1<<1026))
Kết quả phụ thuộc vào mod 64
giá trị dịch chuyển [a] .
[a] Từ: Hướng dẫn dành cho nhà phát triển phần mềm Intel® 64 và IA-32 Architectures: Tập 2 Đếm được che dấu thành 5 bit (hoặc 6 bit nếu ở chế độ 64 bit và REX.W được sử dụng). Phạm vi đếm được giới hạn từ 0 đến 31 (hoặc 63 nếu sử dụng chế độ 64 bit và REX.W). .
Ngoài ra: hãy nhớ rằng đó $((1<<0))
là1
$ for i in 80000 1022 1023 1024 1025 1026; do echo "$((i%64)) $((1<<i))"; done
0 1
62 4611686018427387904
63 -9223372036854775808
0 1
1 2
2 4
Vì vậy, tất cả phụ thuộc vào mức độ gần với số bội của 64.
Kiểm tra giới hạn:
Cách mạnh mẽ để kiểm tra số nguyên dương (và âm) tối đa là kiểm tra lần lượt từng bit một. Dù chưa đến 64 bước đối với hầu hết các máy tính, nó sẽ không quá chậm.
bash
Đầu tiên chúng ta cần số nguyên lớn nhất của biểu mẫu 2^n
(tập 1 bit theo sau là số không). Chúng ta có thể làm điều đó bằng cách dịch chuyển sang trái cho đến khi sự thay đổi tiếp theo làm cho số âm, còn được gọi là "bao quanh":
a=1; while ((a>0)); do ((b=a,a<<=1)) ; done
Trong trường hợp b
là kết quả: giá trị trước sự thay đổi cuối cùng thất bại vòng lặp.
Sau đó, chúng ta cần cố gắng từng chút một để tìm ra cái nào ảnh hưởng đến dấu hiệu của e
:
c=$b;d=$b;
while ((c>>=1)); do
((e=d+c))
(( e>0 )) && ((d=e))
done;
intmax=$d
Số nguyên tối đa ( intmax
) kết quả từ giá trị cuối cùng củad
.
Về mặt tiêu cực (ít hơn 0
), chúng tôi lặp lại tất cả các thử nghiệm nhưng kiểm tra khi một bit có thể được thực hiện 0 mà không bao quanh.
Toàn bộ bài kiểm tra với việc in tất cả các bước là thế này (đối với bash):
#!/bin/bash
sayit(){ printf '%020d 0x%016x\n' "$1"{,}; }
a=1; while ((a>0)) ; do((b=a,a<<=1)) ; sayit "$a"; done
c=$b;d=$b; while((c>>=1)); do((e=d+c));((e>0))&&((d=e)) ; sayit "$d"; done;
intmax=$d
a=-1; while ((a<0)) ; do((b=a,a<<=1)) ; sayit "$b"; done;
c=$b;d=$b; while ((c<-1)); do((c>>=1,e=d+c));((e<0))&&((d=e)); sayit "$d"; done
intmin=$d
printf '%20d max positive value 0x%016x\n' "$intmax" "$intmax"
printf '%20d min negative value 0x%016x\n' "$intmin" "$intmin"
sh
Được dịch sang hầu hết mọi shell:
#!/bin/sh
printing=false
sayit(){ "$printing" && printf '%020d 0x%016x\n' "$1" "$1"; }
a=1; while [ "$a" -gt 0 ];do b=$a;a=$((a<<1)); sayit "$a"; done
c=$b;d=$b; while c=$((c>>1)); [ "$c" -gt 0 ];do e=$((d+c)); [ "$e" -gt 0 ] && d=$e ; sayit "$d"; done;
intmax=$d
a=-1; while [ "$a" -lt 0 ];do b=$a;a=$((a<<1)); sayit "$b"; done;
c=$b;d=$b; while [ "$c" -lt -1 ];do c=$((c>>1));e=$((d+c));[ "$e" -lt 0 ] && d=$e ; sayit "$d"; done
intmin=$d
printf '%20d max positive value 0x%016x\n' "$intmax" "$intmax"
printf '%20d min negative value 0x%016x\n' "$intmin" "$intmin"
Chạy ở trên cho nhiều shell,
tất cả (ngoại trừ bash 2.04 và mksh) giá trị được chấp nhận lên đến (2**63 -1
) trong máy tính này.
Thật thú vị khi báo cáo rằng vỏ att :
$ attsh --version
version sh (AT&T Research) 93u+ 2012-08-01
in một lỗi trên các giá trị của $((2^63))
, mặc dù không phải ksh.