Простой вопрос о «исключении с плавающей точкой» в C - PullRequest
1 голос
/ 01 августа 2011

У меня есть следующая программа на C:

#include <stdio.h>

int main()
{
double x=0;
double y=0/x;
if (y==1)
  printf("y=1\n");
else
  printf("y=%f\n",y);
if (y!=1)
  printf("y!=1\n");
else
  printf("y=%f\n",y);

return 0;
}

Вывод, который я получаю:

y=nan
y!=1

Но когда я меняю строку, double x = 0;для int x = 0;вывод становится

Floating point exception

Кто-нибудь может объяснить, почему?

Ответы [ 7 ]

2 голосов
/ 01 августа 2011

Вы вызываете деление 0/0 с целочисленной арифметикой (которая недопустима и создает исключение, которое вы видите).Независимо от типа y, первым оценивается 0/x.

Когда x объявлен как double, ноль также преобразуется в double, иОперация выполняется с использованием арифметики с плавающей точкой.

Когда x объявлен как int, вы делите один int 0 на другой, и результат недопустим.

1 голос
/ 01 августа 2011

Поскольку из-за IEEE 754 , NaN будет создаваться при выполнении недопустимой операции над числами с плавающей запятой (например, 0/0, ∞×0 или sqrt(−1)).

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

Представление NaN, указанное в стандарте, имеет неопределенные биты, которые можно использовать для кодирования типа ошибки; но для этой кодировки нет стандарта. В теории сигнализация NaNs может использоваться системой времени выполнения для расширения чисел с плавающей точкой с другими специальными значениями, не замедляя вычисления с обычные ценности. Такие расширения, похоже, не являются распространенными.

Кроме того, Википедия говорит это о целочисленном делении на ноль :

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

0 голосов
/ 01 августа 2011

Если вы разделите int на int, вы можете разделить на 0.

0/0 в двойных числах равно NaN.

int x=0;
double y=0/x; //0/0 as ints **after that** casted to double. You can use
double z=0.0/x; //or
double t=0/(double)x; // to avoid exception and get NaN
0 голосов
/ 01 августа 2011

С плавающей точкой по своей сути моделирует вещественные числа с ограниченной точностью.Существует только конечное число бит-паттернов, но бесконечное (непрерывное!) Количество реалов.Конечно, он делает все возможное, возвращая наиболее близкие представимые вещественные значения к точным вводимым данным.Ответы, которые слишком малы для непосредственного представления, вместо этого представлены нулем.Деление на ноль - ошибка в действительных числах.Однако в плавающей точке, поскольку из этих очень маленьких ответов может возникнуть ноль, может оказаться полезным считать x / 0.0 (для положительного x) «положительной бесконечностью» или «слишком большим, чтобы его можно было представить».Это больше не полезно для x = 0.0.

Лучшее, что мы могли бы сказать, это то, что деление нуля на ноль действительно "делит что-то маленькое, что нельзя отличить от нуля чем-то маленьким, которое не может бытьсказано отдельно от нуля ".Какой ответ на это?Ну, нет точного ответа для случая 0/0, и нет правильного способа трактовать его неточно.Это будет зависеть от относительных величин, поэтому процессор в основном пожимает плечами и говорит: «Я потерял всю точность - любой результат, который я дал вам, будет вводить в заблуждение», возвращая Not a Number.

Напротив, при выполнениицелочисленное деление на ноль, делитель действительно может означать только точно ноль.Невозможно придать ему непротиворечивое значение, поэтому, когда ваш код запрашивает ответ, он действительно делает что-то нелегитимное.

(Это целочисленное деление во втором случае, но не в первом из-заправила продвижения C. 0 могут быть приняты как целочисленный литерал, и так как обе стороны являются целыми числами, деление является целочисленным делением.В первом случае тот факт, что x является двойным, приводит к тому, что дивиденд увеличивается вдвоеЕсли вы замените 0 на 0.0, это будет деление с плавающей запятой, независимо от типа x.)

0 голосов
/ 01 августа 2011

В IEE754 есть специальный битовый шаблон, который указывает NaN как результат деления с плавающей запятой на ноль ошибок.

Однако при использовании целочисленной арифметики такого представления нет, поэтомусистема должна выдать исключение вместо возврата NaN.

0 голосов
/ 01 августа 2011

Целочисленное деление на 0 недопустимо и не обрабатывается.С другой стороны, значения с плавающей запятой обрабатываются в C с использованием NaN .Следующее, как когда-либо будет работать.

int x=0;
double y = 0.0 / x;
0 голосов
/ 01 августа 2011

Проверьте минимальное и максимальное значения целочисленного типа данных.Вы увидите, что неопределенный результат или результат nan не находятся в пределах его диапазона.

И прочитайте это то, что должен знать каждый компьютерщик о плавающей точке.

...