производя целое число, сдвигая немного. Как далеко я могу пойти?
Пока целочисленное представление не оборачивается (по умолчанию в большинстве оболочек).
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.