Деление на ноль: неопределенное поведение или реализация, определенная в C и/или C++?

Относительно деления на ноль в стандартах сказано:

C99 6.5.5p5 - Результатом оператора / является частное от деления первого операнда на второй; результатом оператора % является остаток. В обеих операциях, если значение второго операнда равно нулю, поведение не определено.

C++03 5.6.4. Двоичный оператор / дает частное, а бинарный оператор % дает остаток от деления первого выражения на второе. Если второй операнд / или % равен нулю, поведение не определено.

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

C99 7.12p4 - Макрос INFINITY расширяется до константного выражения типа float, представляющего положительную или беззнаковую бесконечность, если доступно;

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

Мне любопытно, каков консенсус (если таковой имеется) по этому вопросу для каждого из двух языков. Изменится ли ответ, если мы будем говорить о целочисленном делении int i = 1 / 0 по сравнению с делением с плавающей запятой float i = 1.0 / 0.0?

Примечание (1) Стандарт C++03 говорит о библиотеке <cmath>, которая включает макрос INFINITY.


person SiegeX    schedule 09.06.2010    source источник
comment
Вот еще один известный анекдот: Если x * 0 = y, то как найти x?   -  person psihodelia    schedule 09.06.2010
comment
@paxdiablo: как ты отменил y/(xy) ? Вы должны получить 1/x, но не x   -  person psihodelia    schedule 09.06.2010
comment
@psihodelia - я бы сказал, что x * 0 = y, найти x было бы математическим эквивалентом риторического вопроса. х есть что угодно или ничего, и поэтому он не имеет ответа, но и не требует ответа.   -  person pxl    schedule 09.06.2010
comment
@paxdiablo: Если вы разделите на x, вы также должны принять x != 0.   -  person u0b34a0f6ae    schedule 09.06.2010
comment
Я не думаю, что неразумно делать вывод, что если ваша реализация определяет макрос INFINITY, деление на ноль определяется как таковое: это действительно неразумно, поскольку C99 7.12p4 не упоминает деление. В любом случае, назначение INFINITY не является несовместимым с UB.   -  person Yves Daoust    schedule 21.10.2016
comment
Я проголосовал против, потому что никак не вижу второй цитаты, подразумевающей, что БЕСКОНЕЧНОСТЬ есть результат деления на ноль, поэтому вопрос, на мой взгляд, некорректен.   -  person Antonio    schedule 04.10.2017
comment
Связанный поведение деления с плавающей запятой на ноль   -  person Antonio    schedule 04.10.2017
comment
@Antonio должным образом отмечено и записано как таковое. Хорошего дня, сэр!   -  person SiegeX    schedule 04.10.2017
comment
Я добавил новый ответ на вопрос, на который ссылается @Antonio, и в нем гораздо больше деталей.   -  person Shafik Yaghmour    schedule 21.11.2018


Ответы (8)


Я не вижу никакого противоречия. Деление на ноль не определено, точка. Нигде в цитируемом тексте нет упоминания о "... если INFINITY не определено".

Обратите внимание, что нигде в математике не определено, что 1 / 0 = бесконечность. Можно можно интерпретировать это таким образом, но это скорее личная интерпретация в стиле "кратчайшего пути", чем достоверный факт.

person Péter Török    schedule 09.06.2010
comment
Согласованный. 1 / 0; и подобные выражения никоим образом не включают макрос INFINITY (если только реализация случайно не решит использовать его для устранения неопределенного поведения). - person Matthew Flaschen; 09.06.2010
comment
@Matthew: относительно вашего комментария в скобках: мои выводы показывают, что это действительно способ, которым многие (большинство?) Реализации решают эту проблему. Не сказать, что это определяет поведение, определяемое реализацией, но это действительно добавляет путаницы. - person SiegeX; 09.06.2010
comment
Не с GCC и друзьями. Я прогнал #include <math.h> int div_0_i = 1 / 0; float div_0_f = 1.0f / 0.0f; float my_inf = INFINITY; через GNU cpp и получил int div_0_i = 1 / 0; float div_0_f = 1.0f / 0.0f; float my_inf = (__builtin_inff()); Так что я не вижу связи. - person Matthew Flaschen; 09.06.2010
comment
@Matthew: Очевидно, gcc недостаточно умен, чтобы заменить ноль div во время препроцессора, но скомпилируйте и запустите этот код, и вы поймете, что я имею в виду. --› #include <math.h> float f = 1.0f / 0.0f; if(f == INFINITY) puts("f == INFINITY"); - person SiegeX; 09.06.2010
comment
@SiegeX, обратите внимание, что, как указал @Kenny в своем ответе, это вполне может быть просто использовано как сигнал переполнения, то есть недопустимое значение, а не результат вычисления как таковой. - person Péter Török; 10.06.2010
comment
@PéterTörök, так в математике какой ответ на 1/0? - person Pacerier; 22.09.2013
comment
Ничего себе... Какое отношение математика имеет к определению языка? Что происходит с das computar, когда das program sez int x = 1 / 0;? Компьютер выбирает возвышения? Или (как почти на каждой платформе, о которой я слышал) мы сильно падаем и горим? Ответ на what is 1 / 0? может быть неопределенным, но аномальное завершение программы и исключение не являются неопределенными. Действительно ли стандарт до сих пор такой свободный? - person ; 15.04.2014
comment
Мало того, что стандарты ужасающе расплывчаты, так еще и интерпретация стала более расплывчатой ​​за последние несколько лет. Раньше считалось, что в тех случаях, когда платформа естественным образом демонстрировала определенное поведение в случаях, не предусмотренных стандартом, компиляторы позволяли программистам использовать его. Философия гиперсовременного компилятора, однако, предполагает, что при наличии программы, которая потребует таких функций для удовлетворения требований при определенных входных данных, компилятору лучше создать исполняемый файл меньшего размера, который будет подчиняться стандарту C во всех случаях, указанных в нем. . - person supercat; 10.06.2015
comment
... чем более крупный исполняемый файл, который удовлетворит требованиям даже в случаях, не предусмотренных стандартом C. - person supercat; 10.06.2015
comment
@Pacerier в математике все зависит от того, что вы называете делением и что вы называете нулем. - person floribon; 19.09.2015

Это был не чисто математический вопрос, а вопрос C/C++.

  • According to the IEEE 754 Standard, which all modern C compilers / FPU's use, we have
    • 3.0 / 0.0 = INF
    • 0,0 / 0,0 = NaN
    • -3,0 / 0,0 = -INF

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

INF может быть весьма полезен, чтобы избежать ветвления, когда INF является полезным результатом. Смотрите обсуждение здесь

http://people.eecs.berkeley.edu/~wkahan/ieee754status/IEEE754.PDF

person wcochran    schedule 20.07.2016

С чего бы это?

Математически это не имеет смысла, это не значит, что 1/x определяется как ∞ в математике вообще. Кроме того, вам потребуются как минимум еще два случая: -1/x и 0/x также не может равняться ∞.

См. деление на ноль в целом и раздел о компьютерная арифметика, в частности.

person unwind    schedule 09.06.2010
comment
Я бы сказал, что y = 1/x действительно равно ∞, поскольку x --› 0 - person SiegeX; 09.06.2010
comment
Это невероятно распространенная ошибка (я предполагаю, что люди, которые никогда не посещали формальный курс математического анализа, с большей вероятностью совершат ее). SiegeX, C/C++ не имеет концепции --> - person shoosh; 09.06.2010
comment
@shoosh: ты хочешь сказать, что lim [x --> +0] f(y) != ∞ где f(y) = 1/x ? - person SiegeX; 09.06.2010
comment
@shoosh: конечно, да, разве вы не видели этот ТАК вопрос stackoverflow.com/questions/1642028/? =П - person SiegeX; 09.06.2010
comment
@SiegeX: я бы сказал, что деление на ноль не определено в математике. y = 1/x стремится к бесконечности, если x положительно и стремится к 0. Однако оно стремится к -бесконечности, если x отрицательно и стремится к 0. Какой из них ты выбираешь? Ответ - ни то, ни другое, поскольку деление определяется математически в терминах умножения, то есть d = p/q определяется как число, умноженное на q, дает p, и никакое число, умноженное на 0, не может дать ничего, кроме 0. - person JeremyP; 09.06.2010

Реализации, которые определяют __STDC_IEC_559__, должны соблюдать требования, указанные в Приложении F, что, в свою очередь, требует семантики с плавающей запятой, соответствующей IEC 60559. Стандарт не налагает требований на поведение деления с плавающей запятой на ноль в реализациях, которые не определяют __STDC_IEC_559__, но подходит для тех, кто его определяет. В случаях, когда IEC 60559 определяет поведение, а стандарт C — нет, стандарт C требует, чтобы компилятор, определяющий __STDC_IEC_559__, вел себя так, как описано в стандарте IEC.

Согласно определению IEC 60559 (или стандарта США IEEE-754) деление нуля на ноль дает NaN, деление числа с плавающей запятой на положительный нуль или литеральную константу нуля дает значение INF с тем же знаком, что и делимое, и деление числа с плавающей запятой отрицательным нулем дает INF с противоположным знаком.

person supercat    schedule 20.07.2016

У меня есть только черновик C99. В 7.12/4 сказано:

Макрос

    INFINITY

расширяется до постоянного выражения типа float, представляющего положительную или беззнаковую бесконечность, если доступно; else в положительную константу типа float, которая переполняется во время трансляции.

Обратите внимание, что INFINITY можно определить с точки зрения переполнения с плавающей запятой, а не обязательно деления на ноль.

person kennytm    schedule 09.06.2010

Для макроса INFINITY: существует явное кодирование для представления +/- бесконечности в стандарте IEEE754, если установлены все биты экспоненты и очищены все биты дроби (если бит дроби установлен, он представляет NaN)

С моим компилятором (int) INFINITY == -2147483648, поэтому выражение, оценивающее int i = 1/0, определенно даст неправильные результаты, если будет возвращено INFINITIY.

person king_nak    schedule 09.06.2010

Суть в том, что C99 (согласно вашим цитатам) ничего не говорит о INFINITY в контексте «определяемой реализацией». Во-вторых, то, что вы процитировали, не показывает противоречивого значения «неопределенного поведения».


[Цитируя страницу Undefined Behavior в Википедии] «В C и C++ также используется поведение, определяемое реализацией, когда стандарт языка не определяет поведение, но реализация должна выбирать поведение и должна документировать и соблюдать правила, которые он выбрал».

Точнее, стандарт означает «определенный реализацией» (я думаю, только), когда он использует эти слова по отношению к сделанному заявлению, поскольку «определенный реализацией» является особым атрибутом стандарта. В цитате C99 7.12p4 не упоминается «определенная реализацией».

[Из C99 std (поздний проект)] «неопределенное поведение: поведение при использовании непереносимой или ошибочной программной конструкции или ошибочных данных, для которых настоящий международный стандарт не предъявляет требований»

Обратите внимание, что для неопределенного поведения не существует «требований»!

[C99 ..] «поведение, определяемое реализацией: неуказанное поведение, при котором каждая реализация документирует, как сделан выбор»

[C99..] «неопределенное поведение: использование неопределенного значения или другое поведение, когда настоящий международный стандарт предоставляет две или более возможностей и не налагает дополнительных требований, которые выбираются в любом случае»

Документация является требованием для поведения, определяемого реализацией.

person Jose_X    schedule 26.09.2014
comment
Если реализация определяет __STDC_IEC_559__, она должна реализовать семантику деления на ноль, соответствующую этому стандарту, даже если стандарт C не иначе налагает какие-либо требования к поведению. - person supercat; 20.07.2016

person    schedule
comment
этот ответ не связан с программированием. - person Pete Kirkham; 09.06.2010
comment
... это совершенно правильный ответ на вопрос. - person Peter Alexander; 09.06.2010
comment
Это неверно, это верно только в том случае, если x ограничен положительными значениями. - person interjay; 09.06.2010
comment
@interjay: ты прав, я должен был поставить |lim 1/x| но смысл все равно не в этом :) - person František Žiačik; 09.06.2010
comment
@Pete Alexander, вопрос заключается в делении на ноль: неопределенное поведение или реализация, определенная в C и / или C ++?, а не в том, согласуется ли поведение в стандартах с математической концепцией. Стандарт использует HUGE_VAL для таких ограничений, что является той же битовой структурой, что и бесконечность в реализациях IEE745. - person Pete Kirkham; 09.06.2010
comment
@Pete Kirkham: Ну, был установлен стандарт, который отвечает на вопрос, и другой стандарт, который не противоречил первому, и противоречие было принято только из-за неправильного математического предположения, поэтому, на мой взгляд, отказ от этого предположения делает ответ ясный. - person František Žiačik; 09.06.2010
comment
В большинстве реализаций с плавающей запятой нет представления точного нуля. По крайней мере, в IEE fp есть как +0,0, так и -0,0, которые представляют диапазон либо размера от точного нуля до половины наименьшего представимого значения - все биты равны нулю или все нули с установленным битом знака. Не думайте, что 0.0 в C означает точный нуль в математике или что математика предписывает его поведение. Попробуйте добавить один к INT_MAX и посмотрите, дает ли интерпретация символов, как если бы математика работала, правильное поведение. - person Pete Kirkham; 09.06.2010
comment
Дело в том, что вы должны отвечать на вопросы, основанные на стандартах, со ссылкой на стандарты, а не со ссылкой на то, как все должно работать, если символы в коде интерпретируются в другой среде. Не более правильно сказать, что 1.0/0.0 не определено в математике, поэтому оно не определено в C99, чем сказать, что мусор вывозится по четвергам на моей улице, поэтому в Java мусор вывозится только по четвергам. - person Pete Kirkham; 09.06.2010
comment
Да, я, наверное, должен был сказать то, что вы говорите, - что автору вопроса не следует несоответствие математики стандартам, но опять же, автор сделал это и на основании этого подумал, что стандарты противоречивы, что не соответствует действительности. Кроме того, существует множество ситуаций, когда применима математика (в том числе и эта). - person František Žiačik; 09.06.2010
comment
@ František Žiačik, я думаю, что исправление может быть таким же простым, как изменение на (обратите внимание на знак плюс), x -> 0+. Абсолютное значение несуществующей величины не имеет особого смысла. Скорее, вы хотите использовать дефинитивную нотацию, которая дает определенное значение (где +бесконечность была определена). - person Jose_X; 26.09.2014
comment
@Pete Kirkham Дело в том, что вы должны отвечать на вопросы, основанные на стандартах, со ссылкой на стандарты, а не со ссылкой на то, как все должно работать, если символы в коде интерпретируются в другой среде. Вот о чем я думал; однако стандарт говорит, что результатом оператора / является частное от деления первого операнда на второй. Таким образом, C99, при отсутствии списка исключений или разъяснений/переопределений, вызывает обычные значения в математике как правильное поведение C99. - person Jose_X; 26.09.2014
comment
На проективном пространстве и на сфере Римана 1/0 и предел хорошо определены. - person jinawee; 19.09.2018