Отрицательный ноль в C

Привет, я изучаю цель C, и я делал классический пример калькулятора.

проблема в том, что я получаю отрицательный ноль, когда я умножаю ноль на любое отрицательное число, и я помещаю результат в (двойной) тип!

чтобы увидеть, что происходит, я играл с отладчиком, и вот что я получил:

(gdb) печать -2 * 0
$1 = 0

(gdb) печать (двойной) -2 * 0
2 $ = -0

в второй случай, когда я бросил его на двойной тип, он превращается в отрицательный ноль! Как я могу исправить это в своем приложении? Мне нужно работать с двойниками. Как я могу исправить результат, чтобы получить ноль, когда результат должен быть равен нулю?

спасибо заранее.

4 ответов


Я сделал простой тест:

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;

http://en.wikipedia.org/wiki/Signed_zero

число 0 обычно кодируется как +0, но может быть представлено либо +0, либо -0

Это не должно влиять на вычисления или вывод пользовательского интерфейса.


здесь есть недоразумение о приоритете оператора:

(double) -2 * 0

анализируется как

((double)(-(2))) * 0

что по существу то же самое, что (-2.0) * 0.0.

в C стандартные информационное приложение J перечислены как поведение 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

как я могу исправить это в моем приложении?

код действительно не сломан, поэтому ничего не нужно "исправлять". @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.