2014-09-30 2 views
3

Shell Arithmetic говорит:Какова ширина целых чисел фиксированной ширины в bash?

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

Пример:

$ echo $((1 << 32)) 
4294967296 
$ echo $(((1 << 64) - 1)) 
0 

Какие целые пределы в арифметике оболочки в ударе?

@rici pointed out, что POSIX shell гарантии подписал длинный диапазон целых чисел (как определено ISO C):

-2**31+1 to +2**31-1 

@John Zwinck pointed out что bash source code indicates that intmax_t is used:

Все арифметические операции выполняются в intmax_t целых чисел с не проверяя переполнение

Предоставляет ли bash в своей документации, что он использует intmax_t или какой-либо другой тип C для целых чисел?

+0

Я не думаю, вычитанием 1 после того, как она переполнена поможет :-) Попробуйте эхо $ (((1 << 63) - 1)) (!) .. 9223372036854775807 –

+0

@MarkSetchell: точка в том, что '1 << 64' переполняется на моей машине. В этом случае результат не имеет значения. – jfs

+1

У меня были видения о том, что вы делаете бинарный поиск, чтобы найти сдвиг, который не переполнялся ... << 48, << 56, << 60, –

ответ

2

Bash не документирует точный размер целых чисел, и размер может варьироваться от платформы к платформе.

Однако он пытается выполнить Posix, который указывает, что арифметическое расширение использует подписанную длинную арифметику, которая должна быть не менее 32 бит, включая бит знака.

Posix не требует целочисленной арифметики, чтобы быть по модулю 2 к при любом значении k [но см Примечание 1], хотя bash на общих платформах будет делать это, и это особенно не гарантирует, что арифметические операторы будут вести себя точно как будто значения были подписаны долго. Posix даже позволяет моделировать целочисленную арифметику с плавающей запятой при условии, что значения с плавающей запятой имеют достаточную точность:

В качестве расширения оболочка может распознавать арифметические выражения за пределами перечисленных. Оболочка может использовать подписанный целочисленный тип с рангом, большим, чем ранг подписанного long. Оболочка может использовать реальный плавающий тип вместо подписанного долго, пока он не влияет на результаты в случаях, когда переполнение не происходит. (XSH § 2.6.4)

Это было бы разрешить использование IEEE-754 с плавающей точкой удваивается (53 бита точности) на платформе, где long был только 32 бит, например.В то время как bash этого не делает - как задокументировано, bash использует целочисленный тип данных фиксированной ширины - другие реализации оболочек могут, а переносимый код не должен делать допущений.


Примечание:

  1. Posix обычно сдвинут со стандартом ISO C, но есть целый ряд мест, где Posix добавляет дополнительное ограничение, некоторые из которых помечен как расширения (CX):

    POSIX.1-2008 действует частично как профиль стандарта ISO C, и он может выбрать для дальнейшего конструк ain поведения допускается варьироваться в соответствии со стандартом ISO C. Такие ограничения и другие совместимые различия не считаются конфликтами, даже если отсутствует метка CX. Маркировка предназначена только для информации.

    Одним из таких дополнительных ограничений является существование целых чисел точной ширины. Стандарт C требует типов int_{least,fast}{8,16,32,64}_t и их неподписанных аналогов. Он не требует типов точной ширины, таких как int32_t, если не используется какой-либо целочисленный тип. Тип точной ширины должен иметь точно количество битов, указанных в его имени (т. Е. Никаких битов заполнения) и должно иметь представление 2's-комплемента. Таким образом, INT32_MIN, если он определен, должен быть точно -2 (§ 7.20.2.1).

    Однако Posix делает требует точных ширины типов int{8,16,32}_t (а также без знака аналогов), а также int64_t, если такой тип обеспечивается реализацией. В частности, требуется int64_t, если «реализация поддерживает среду программирования _POSIX_V7_LP64_OFF64, и приложение строится в среде программирования _POSIX_V7_LP64_OFF64». (XBD, § 13, stdint.h) (Эти требования помечены как CX.)

    Несмотря на то, что int32_t должен существовать, и, следовательно, должен быть около 2 Типа дополнения доступны, до сих пор нет гарантии, что signed long является 2'-дополнение, и даже если это так, нет гарантии, что целочисленное переполнение обернется вокруг, а не, например, захват.

    самое непосредственное отношение к первоначальному вопросу, однако, является тот факт, что даже если signed long того же типа, как int64_t и даже если знаковое целое переполнение обтекает, оболочка не несет никаких обязательств на самом деле использовать signed long для расширения арифметической. Он может использовать любой тип данных «пока он не влияет на результаты в случаях, когда нет переполнения». (XSH, § 2.6.4)

+0

+1 для упоминания ** подписанный длинный ** предел для оболочки POSIX. [posix] (http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_04) явно отклоняется от стандарта ISO C для целочисленной арифметики (так же, как ** подписанный long ** ISO C). Это ISO C, который не требует модуля 2 ** k арифметики, а не posix. – jfs

+0

@ J.F.Sebastian: Posix был свободен требовать арифметику 2s-дополнения. Например, для этого требуется 8-битный байт, поэтому он вполне способен требовать то, что нет в стандарте C. Поэтому я согласен с тем, что Posix не требует 2s-дополнения. Но более важным моментом является следующее предложение: Posix не требует, чтобы оболочка даже выполняла поведение подписанных longs на этой платформе, потому что она (явно) позволяет использовать плавающую точку, где она имеет как минимум такую ​​же точность, как подписанный долго. – rici

+0

@JFSebastian: добавлено немного полужирного (без изменения текста), чтобы продемонстрировать, что эта слишком длинная запись включает ответ на вопрос «Предоставляет ли бах в своей документации ...» (т. Е. «Нет, есть нет гарантии. ») Я проверил свое чтение руководства grepping bashref.texi для нескольких ключевых слов, поэтому я готов выйти на конечность с определенным« Нет ». Конечно, это правда на сегодняшний день (v4.3.25); документация может измениться в любой момент. – rici

1

Bash использует intmax_t в своей реализации арифметикой C. Вы можете увидеть его здесь: http://www.opensource.apple.com/source/bash/bash-30/bash/expr.c

Это означает, что это будет «самый большой» целочисленный тип на вашей платформе. Имейте в виду, что на некоторых платформах есть «еще большие» целые числа, например. 128 бит на некоторых 64-битных платформах, но эти «экстраординарные» типы здесь не включены, поэтому в большинстве систем Bash использует 32 или 64-битную математику.

+0

[текущий источник] (http: //git.savannah.gnu .org/cgit/bash.git/tree/expr.C# n22) также подтверждает, что используется 'intmax_t'. Он упоминается где-то в документации? – jfs

+0

Я не нашел места, где он находится в документации (не исходный код). Вероятно, это как-то считалось частью реализации.Я не думаю, что это все, что важно, потому что это очень четко документировано в самом исходном коде; Полагаю, вы можете отправить патч для документации. –

Смежные вопросы