Найдите наибольшее число, с которым может справиться арифметика Bash?

добавить следующее в файл конфигурации ifcfg

DEFROUTE=нет

Маршрут по умолчанию для этого интерфейса не создается.

14
04.04.2021, 15:43
2 ответа

В арифметике Bash используются числа со знаком.

Таким образом, быстрый ответ будет:

((MAX=(1<<63)-1))

Но так как вы хотите, чтобы ваш скрипт не знал о разрядности системы, на которой он работает, то продолжим.

Грубая сила заключалась бы в том, чтобы продолжать добавлять 1 в цикле, пока не дойдете до точки, где она переполнится до отрицательного числа. Но на это могут уйти годы! :-)Более быстрый и элегантный способ сделать это — использовать -простой битовый сдвиг.

Найдем знаковый бит, т. е. найдем число, имеющее 1в старшем значащем бите и нули во всех остальных битах, сколько бы их ни было. Получив это число, мы просто вычтем из него 1и получим наибольшее число со знаком.

# MIN -- the smallest signed number 0x8000...00  (it equals MAX+1)
# MAX -- the largest signed number  0x7Fff...FF  <-- what we are looking for

MIN=1; until (( (MIN<<=1) < 0 )) ;do :;done
((MAX=MIN-1))

echo $MAX

Result:
9223372036854775807

Или вот один -вкладыш, без петли. Мы помещаем шестнадцатеричное представление числа в переменную, а затем маскируем бит знака через расширение переменной при передаче его во встроенную функцию printf:

printf -v MAX %x -1 && printf -v MAX %d 0x${MAX/f/7}

echo $MAX

Result:
9223372036854775807

На машине с разрядностью, отличной от моей, результатом будет другое число.

И просто для иллюстрации, в моем случае:

printf "MAX %X  %d\nMIN %X %d\n" $MAX $MAX $MIN $MIN
MAX 7FFFFFFFFFFFFFFF  9223372036854775807
MIN 8000000000000000 -9223372036854775808

Небольшое примечание о MIN. :Возможно, вы захотите ограничить себя использованием ((MIN=-MAX)), иначе время от времени у вас возникнут проблемы с некоторыми арифметическими операциями.

((MIN=-MAX)) ; printf "MIN %X %d\n" $MIN $MIN
MIN 8000000000000001 -9223372036854775807
16
28.04.2021, 22:54

I am sitting at a 64-bit machine, but how can I let my script determine that for itself?

Обратите внимание, что это отдельный вопрос от того, каковы самые большие числа в арифметике bash. Вы не можете использовать это, чтобы определить разрядность вашей машины, а разрядность вашей машины не определяет целочисленный размер Bash.

Числа Bash всегда 64 -бит, даже на 32 -битной машине.(Или, возможно, шире, на экзотической машине, где long longшире, чем требуемый ISO C минимум 64 -бит. Возможно даже, что они могут быть дополнением или знаком/величиной (, и в этом случае у вас будет
min = -max, вместо дополнения 2 -max - 1), если Bash переносим на реализации C, которые не используют дополнение 2. По словам комментаторов, Bash использует long longи unsigned long longвнутри. Об этом следует помнить при разработке методов тестирования времени -выполнения.)


Просто из любопытства я протестировал это на старой 32-битной -системе Debian с Bash 3.2.39. Метод LL3 показывает, что printf %x -1печатает 16 fс (, поэтому 8 байтов, 64 бита ).

И я проверил математику bash с увеличением INT64 _MAX перенос на INT64 _MIN

$ uname -a
Linux <non-updated kernel version hidden to protect the guilty> i686 GNU/Linux

$ echo $((9223372036854775807 + 1))
-9223372036854775808

Таким образом, исходный код Bash явно использует int64_tилиlong long(или, надеюсь, uint64_t, чтобы избежать неопределенного поведения C при переносе, если только они не собираются с gcc -fwrapvдля определения этого поведения ), а не типа, подобного long. ] это 32 -бита на 32 -битных машинах.

Добавление 64 -бит на 32 -битной машине просто заставляет компилятор использовать 2 инструкции, например add+adc(добавить -с -переносом ), на машинах, которые иметь флаг переноса или третью инструкцию на таких машинах, как MIPS, которые этого не делают. Таким образом, для языков совершенно нормально предоставлять 64 -битные типы, а для языков более высокого -уровня, которые имеют только один тип, использовать хороший широкий тип.

3
28.04.2021, 22:54

Теги

Похожие вопросы