четверг, 6 февраля 2014 г.

Floating Point Exception

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

Для примера реализуем простую программу обрабатывающую SIGFPE :

Это демонстрационный пример и дабы не загромождать код, упустим некоторые проверки.
Начнем с вещей очевидных, что будет если передать вторым параметром 0 ?
bash -> ./sigfpe 1 0
SIGFPE catched!
Думаю всем понятно, почему все пошло именно по такому пути развития.

Теперь перейдем к чему-то более интересному и не всем известному.
Вот такой пример :
bash -> ./sigfpe -2147483648 -1
SIGFPE catched!
Почему произошло исключение? Давай-те взглянем, как представлено число -2147483648, данное число является минимальным отрицательным, которое можно представить в 32-х разрядном регистре.
-2147483648 -> 0x80000000 -> 1000 0000  0000 0000  0000 0000  0000 0000
Теперь о том, как происходит смена знака. Смена знака происходит инвертированием всех битов числа и добавления к получившемуся значению единицы. Это справедливо почти для всех чисел, кроме 0 и -2147483648

0x80000000       -> 1000 0000  0000 0000  0000 0000  0000 0000
NOT(0x80000000)  -> 0111 1111  1111 1111  1111 1111  1111 1111
ADD(1)           -> 1000 0000  0000 0000  0000 0000  0000 0000


0x00000000 -> 0000 0000  0000 0000  0000 0000  0000 0000
NOT (0)    -> FFFF FFFF  FFFF FFFF  FFFF FFFF  FFFF FFFF
ADD (1)    -> 0000 0000  0000 0000  0000 0000  0000 0000
Таким образом, число 2147483648 невозможно представить в 32-х разрядном регистре.

Интересный факт о функции abs(int) :
/* Return the absolute value of I.  */
int
abs (int i)
{
  return i < 0 ? -i : i;
}
Как уже была сказано, -INT_MIN = INT_MIN.