menghasilkan bilangan bulat dengan menggeser sedikit. Seberapa jauh saya bisa pergi?
Sampai representasi integer membungkus (default di kebanyakan shell).
Bilangan bulat 64 bit biasanya membungkus di 2**63 - 1
.
Itu 0x7fffffffffffffff
atau9223372036854775807
di bulan Desember.
Angka '+1' menjadi negatif.
Itu sama dengan 1<<63
, jadi:
$ echo "$((1<<62)) $((1<<63)) and $((1<<64))"
4611686018427387904 -9223372036854775808 and 1
Setelah itu prosesnya berulang lagi.
$((1<<80000)) $((1<<1022)) $((1<<1023)) $((1<<1024)) $((1<<1025)) $((1<<1026))
Hasilnya tergantung pada mod 64
nilai pergeseran [a] .
[a] Dari: Manual Pengembang Perangkat Lunak Arsitektur Intel® 64 dan IA-32: Volume 2 Hitungannya disamarkan menjadi 5 bit (atau 6 bit jika dalam mode 64-bit dan REX.W digunakan). Kisaran hitungan dibatasi hingga 0 hingga 31 (atau 63 jika mode 64-bit dan REX.W digunakan). .
Juga: ingat bahwa $((1<<0))
adalah1
$ 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
Jadi, itu semua tergantung pada seberapa dekat angka ke kelipatan 64.
Menguji batas:
Cara kuat untuk menguji yang merupakan bilangan bulat positif (dan negatif) maksimum adalah dengan menguji setiap bit pada gilirannya. Itu kurang dari 64 langkah untuk sebagian besar komputer, itu tidak akan terlalu lambat.
pesta
Pertama kita membutuhkan bilangan bulat terbesar dari bentuk 2^n
(set 1 bit diikuti oleh nol). Kita dapat melakukannya dengan menggeser ke kiri sampai shift berikutnya membuat angka negatif, juga disebut "membungkus":
a=1; while ((a>0)); do ((b=a,a<<=1)) ; done
Di mana b
hasilnya: nilai sebelum shift terakhir yang gagal dalam loop.
Maka kita perlu mencoba setiap bit untuk mencari tahu mana yang mempengaruhi tanda e
:
c=$b;d=$b;
while ((c>>=1)); do
((e=d+c))
(( e>0 )) && ((d=e))
done;
intmax=$d
Integer maksimum ( intmax
) dihasilkan dari nilai terakhir dari d
.
Di sisi negatif (kurang dari 0
) kami mengulangi semua tes tetapi menguji kapan bit bisa dibuat 0 tanpa melilit.
Seluruh pengujian dengan pencetakan semua langkah adalah ini (untuk 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
Diterjemahkan ke hampir semua 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"
Menjalankan hal di atas untuk banyak shell,
semua (kecuali bash 2.04 dan mksh) menerima nilai hingga ( 2**63 -1
) di komputer ini.
Sangat menarik untuk melaporkan bahwa shell att :
$ attsh --version
version sh (AT&T Research) 93u+ 2012-08-01
mencetak kesalahan pada nilai $((2^63))
, bukan ksh sekalipun.