виробляючи ціле число, переміщуючи трохи. Як далеко я можу зайти?
Поки ціле представлення не завершиться (за замовчуванням у більшості оболонок).
64-бітове ціле число зазвичай обертається на 2**63 - 1
.
Це 0x7fffffffffffffff
або 9223372036854775807
в грудні.
Це число "+1" стає негативним.
Це те саме, що 1<<63
, таким чином:
$ echo "$((1<<62)) $((1<<63)) and $((1<<64))"
4611686018427387904 -9223372036854775808 and 1
Після цього процес повторюється знову.
$((1<<80000)) $((1<<1022)) $((1<<1023)) $((1<<1024)) $((1<<1025)) $((1<<1026))
Результат залежить від mod 64
значення зсуву [a] .
[a] Від: Інструкція для розробників програмного забезпечення для архітектури Intel® 64 та IA-32: Том 2 Кількість маскується до 5 біт (або 6 біт, якщо використовується 64-бітний режим і використовується REX.W). Діапазон підрахунку обмежений від 0 до 31 (або 63, якщо використовується 64-бітний режим і REX.W). .
Також: пам’ятайте, що $((1<<0))
це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
Отже, все залежить від того, наскільки число наближене до кратного 64.
Тестування межі:
Надійний спосіб перевірити максимальне додатне (і негативне) ціле число - перевірити кожен біт по черзі. Це менше 64 кроків для більшості комп'ютерів у будь-якому разі, це не буде занадто повільно.
баш
Спочатку нам потрібно найбільше ціле число форми 2^n
(1 бітний набір з подальшим нулями). Ми можемо це зробити, перемістивши вліво, поки наступна зміна не зробить число негативним, яке також називається "обернути навколо":
a=1; while ((a>0)); do ((b=a,a<<=1)) ; done
Де b
результат: значення перед останньою зміною, яка не працює циклом.
Тоді нам потрібно спробувати кожен шматочок, щоб з’ясувати, які з них впливають на ознаку e
:
c=$b;d=$b;
while ((c>>=1)); do
((e=d+c))
(( e>0 )) && ((d=e))
done;
intmax=$d
Максимальне число ( intmax
) є результатом останнього значення d
.
З негативної сторони (менше, ніж 0
) ми повторюємо всі тести, але тестування, коли трохи можна зробити 0, не обертаючись.
Ціле випробування з друком усіх кроків - це таке (для 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"
ш
Перекладається майже на будь-яку оболонку:
#!/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"
Запускаючи вищезазначене для багатьох оболонок,
усі (крім bash 2.04 та mksh) прийняли значення на ( 2**63 -1
) на цьому комп'ютері.
Цікаво повідомити, що оболонка att :
$ attsh --version
version sh (AT&T Research) 93u+ 2012-08-01
надрукував помилку на значеннях $((2^63))
, не ksh, хоча.