2016-12-13 7 views
0

Я нашел несколько вопросов о проверке операций перед выполнением перед выполнением при переопределении/недопущении. Кажется, что есть способы сделать это довольно легко. Итак, почему нет возможности автоматически проверять каждую математическую операцию перед исполнением или почему нет исключения для buffer over/underflow арифметических операций? Или сформулированы по-разному: в каком сценарии было бы полезно позволить операциям переполнять незаметно?Почему проверка переполнения по умолчанию

Возможно, это вопрос времени выполнения? Или является основным источником переполнения, возникающим во время не-математических операций?

+1

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

+1

В C операции, которые приводят к переполнению/недогрузке, во многих случаях имеют неопределенное поведение. Что, между прочим, означает, что компилятор не обязан проверять операции. Проверка каждой операции - особенно во время выполнения - приведет к поражению производительности. И разработчик обычно имеет больше информации (например, понимание общего алгоритма), поэтому лучше всего решать, какие операции являются критическими. Теоретически по крайней мере ..... слишком многие разработчики вообще не думают о таких вещах. – Peter

ответ

3

На самом деле, для C есть варианты проверки, смотрите здесь: http://danluu.com/integer-overflow/

Как для Java, добавив целочисленное переполнение проверки откроет банку с червями. Поскольку java не предлагает неподписанные типы, математика без знака часто выполняется в простых int или long-типах - очевидно, что VM не будет волшебно знать о неподписанном характере предполагаемой операции, то есть вам нужно либо добавить неподписанные типы, либо программисту уделять большое внимание включению и выключению чеков. Пример для unsigned math с подписанными типами можно найти в Arrays.binarySearch. На стороне примечание, Java точно определяет, что результат в случае переполнения, поэтому полагаться на поведение переполнения является законным использованием определенного поведения.

Как кратко проанализировано в ссылке C выше, эти проверки могут оказать серьезное влияние на производительность на практике из-за сочетания грубой реализации и/или вмешательства в другие оптимизации кода.

Кроме того, в то время как большинство ЦП могут обнаружить переполнение (как правило, с помощью флагов C и V), они делают это одновременно для подписанных/неподписанных (общие ЦП ISA не делают различий между подписанными/неподписанными операциями в случае добавления /). Его программа реагирует на эти флаги, что означает вставку дополнительных инструкций в код. Опять же, это означает, что программист/компилятор должен знать, должна ли операция быть подписана или без знака, чтобы сделать правильный выбор.

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

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

Мне нужно много думать о тех случаях, когда я действительно ощущал необходимость проверки переполнения. Обычно вам гораздо больше нравится проверять диапазон значений в определенных точках (например, аргументы функции). Но это произвольные проверки для диапазона specfic значений функций, которые компилятор даже не знает (ну, на некоторых языках он будет, потому что он явно выражен, но ни Java, ни C не попадают в эту категорию).

Так что проверка переполнения не является универсальной. Это не означает, что нет никаких потенциальных ошибок, которые он мог бы предотвратить, но по сравнению с другими переполнениями типов ошибок переполнение не является обычной проблемой. Я не могу вспомнить, когда я в последний раз видел ошибку, вызванную переполнением целых чисел. Например, одни ошибки чаще встречаются. С другой стороны, существуют некоторые микрооптимизации, которые явно полагаются на переполнение (например, старый вопрос), см. Принятый ответ: Performance: float to int cast and clipping result to range).

В ситуации, описанной выше, принуждение C/Java проверять и реагировать на переполнение целых чисел сделает их хуже языков. Они будут медленнее, и/или программист просто деактивирует эту функцию, потому что она мешает больше, чем полезно. Это не означает, что проверка переполнения в качестве языковой функции обычно была бы плохой; но для того, чтобы действительно получить что-то из этого, окружающая среда также должна соответствовать (например, как упомянуто выше, Java будет нуждаться в неподписанных типах).

TL; DR Это может быть полезно, но для этого требуется гораздо более глубокая поддержка языка, чем просто переключатель, который будет полезен.

1

Язык Java просто не имеет этой функции, встроенной в качестве ключевого слова или механизма для непосредственного применения для операторов +, - и *. Например, у C# есть ключевые слова checked и unchecked. Тем не менее, эти проверки могут быть дорогостоящими и трудно реализовать, когда в языке нет встроенной поддержки. Что касается Java 1.8, то методы API addExact, subtractExact и multiplyExact были добавлены в API для предоставления этой функции, как указано в комментариях к @Tom.

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

В целом, ваш дизайн приложения должен либо явно указать разумное использования арифметики чрезмерной и недостаточные или лучше не нужно использовать их на всех, потому что это может привести к путанице, неинтуитивному поведению или критическим ошибкам. В первом случае вы не проверяете, во втором случае проверка будет бесполезной. Автоматическая проверка будет превосходной и только экономичной.

Надуманный пример желаемого переполнения, может быть счетчиком. Скажите, что у вас короткий знак без знака и подсчитайте его. После 65536 он возвращается к нулю из-за переполнения, что может быть удобно.

+1

* «Java просто не имеет встроенной функции». * Java предоставляет API: [add] (https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html # addExact-int-int-), [multiply] (https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#multiplyExact-int-int-) и [вычесть] (https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#subtractExact-int-int-). – Tom

+0

@Tom Спасибо за ваше замечание. Я имел в виду, что язык Java не определяет ключевое слово или механизм, например, например. C#, так что вы можете использовать '+', '-' и' * 'как обычно. Стоит отметить, что API был добавлен не до Java 1.8. Отредактировано, кредиты для вас. – thatguy

1

Я могу предложить два возможных факторов, почему бесконтрольно арифметика по умолчанию:

  • Чувство фамильярности: Арифметика в C и C++, флажок по умолчанию, и люди, которые привыкли к этим языкам не будет ожидайте, что программа бросит, но тихо продолжать. Это заблуждение, поскольку как C, так и C++ имеют неопределенное поведение в значении integer overflow/underflow. Но тем не менее он создал определенное ожидание во многих умах людей, и новые языки в одной семье склонны уклоняться от очевидного нарушения установленных конвенций.
  • Benchmark performance: Обнаружение переполнения/underflow обычно требует выполнения большего количества инструкций, чем вам нужно, если вы решили проигнорировать его. Представьте себе, как выглядел бы новый язык, если бы человек, не знакомый с ним, написал математический тест (как это часто бывает) и «доказал», что язык значительно медленнее C и C++ даже для простейших математических операций. Это могло бы повредить восприятию человеком характеристик языка, и это может помешать его принятию.
Смежные вопросы