Как преобразовать отрицательный ноль в положительный ноль в C?
Здравствуйте, я изучаю Цель C, и я делал классический пример калькулятора.
Проблема в том, что я получаю отрицательный ноль, когда я умножаю ноль на любое отрицательное число, и я помещаю результат в (двойной) тип!
Чтобы увидеть, что происходит, я поиграл с отладчиком, и вот что я получил:
(gdb) печать -2 * 0
$ 1 = 0
(GDB) печать (двойной) -2 * 0
$ 2 = -0
Во втором случае, когда я приводил его к двойному типу, он превращается в отрицательный ноль! Как я могу это исправить в моем приложении? Мне нужно работать с двойниками. Как я могу исправить результат, чтобы получить ноль, когда результат должен быть нулем?
Ответы
Ответ 1
Я сделал простой тест:
double d = (double) -2.0 * 0;
if (d < 0)
printf("d is less than zero\n");
if (d == 0)
printf("d is equal to zero\n");
if (d > 0)
printf("d is greater than zero\n");
printf("d is: %lf\n", d);
Он выводит:
d равно нулю d: -0.000000
Итак, чтобы исправить это, вы можете добавить простую if-check в ваше приложение:
if (d == 0) d = 0;
Ответ 2
http://en.wikipedia.org/wiki/Signed_zero
Число 0 обычно кодируется как +0, но может быть представлено либо +0, либо -0
Он не должен влиять на вычисления или вывод пользовательского интерфейса.
Ответ 3
Здесь есть недоразумение относительно приоритета оператора:
(double) -2 * 0
анализируется как
((double)(-(2))) * 0
который по существу совпадает с (-2.0) * 0.0
.
Информационное приложение C Standard Information указано как поведение Unspecifier. Независимо от того, могут ли определенные операторы генерировать отрицательные нули и равен ли отрицательный ноль нормальному нулю при хранении в объекте (6.2.6.2).
И наоборот, (double)(-2 * 0)
должен генерировать положительный нуль 0.0
на большинстве современных платформ, поскольку умножение выполняется с использованием целочисленной арифметики. Стандарт C имеет поддержку архитектур, которые отличают положительные и отрицательные целые числа нулей, но в настоящее время они исчезающе редки.
Если вы хотите, чтобы нули были положительными, это простое исправление должно работать:
if (d == 0) {
d = 0;
}
Вы можете сделать это понятным с помощью этого:
if (d == -0.0) {
d = +0.0;
}
Но тест будет успешным, если d
- положительный нуль.
Chux имеет более простое решение для совместимых с IEC 60559 сред:
d = d + 0.0; // turn -0.0 to +0.0
Ответ 4
Как я могу исправить это в своем приложении?
Код действительно не сломан, поэтому ничего не нужно "фиксировать". @kennytm
Как я могу исправить результат, чтобы получить нуль, когда результат должен быть равен нулю?
Чтобы легко избавиться от -
, когда результат -0.0
, добавьте 0.0
. Код, следующий стандартным правилам (IEC 60559 с плавающей запятой), приведет к снижению знака -
.
double nzero = -0.0;
printf("%f\n", nzero);
printf("%f\n", nzero + 0.0);
printf("%f\n", fabs(nzero)); // This has a side effect of changing all negative values
// pedantic code using <math.h>
if (signbit(nzero)) nzero = 0.0; // This has a side effect of changing all negative values
printf("%f\n", nzero);
Обычный вывод.
-0.000000
0.000000
0.000000
0.000000
Однако для общего double x
, который может иметь любое значение, трудно превзойти следующее. @Richard J. Ross III @chqrlie Подход x + 0.0
имеет преимущество в том, что, вероятно, не вводит ветвь, но ясно.
if (x == 0.0) x = 0.0;
Примечание: fmax(-0.0, 0.0)
может производить -0.0.
Ответ 5
В моем коде (на компиляторе C MPI intel) -0.0
и +0.0
не совпадают.
В качестве примера:
d = -0.0
if (d < 0.0)
do something...
и он делает это "что-то".
также добавляем -0.0 + 0.0 = -0.0...