Как преобразовать отрицательный ноль в положительный ноль в 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...