Как получить -0 результат в вычислениях с плавающей запятой и отличить его от +0 в C #? - PullRequest
6 голосов
/ 25 июня 2009

В документации MSDN упоминается, что тип double включает отрицательный ноль. Однако, как -1.0 / double.PositiveInfinity, так и -double.Epsilon / 2 возвращают нормальный 0 (и сравнивают равные ему). Как я могу получить -0?

Ответы [ 5 ]

16 голосов
/ 25 июня 2009

Вот практический пример разграничения между ними без изучения битов. Ссылки MSDN здесь и здесь помогли мне создать этот пример.

static void Main(string[] args)
{
    float a = 5 / float.NegativeInfinity;
    float b = 5 / float.PositiveInfinity;
    float c = 1 / a;
    float d = 1 / b;
    Console.WriteLine(a);
    Console.WriteLine(b);
    Console.WriteLine(c);
    Console.WriteLine(d);
}

Выход:

0
0
-Infinity
Infinity

Обратите внимание, что -0 и 0 оба выглядят одинаково для сравнения, вывода и т. Д. Но если вы разделите 1 на них, вы получите -Infinity или Infinity, в зависимости от того, какой у вас ноль.

3 голосов
/ 25 июня 2009

Отрицательный ноль связан с тем, как число хранится в двоичном виде, а не с каким-либо реальным достижимым результатом математического вычисления.

В памяти с плавающей запятой, самый верхний бит часто используется для обозначения знака. Это оставляет 31 бит для данных (в 32-битном значении с плавающей запятой), поэтому фактически есть два представления для нуля.

00000000 00000000 00000000 00000000
Или
00000000 00000000 00000000 00000001

Оба представляют ноль, но один со знаком бит установлен в отрицательное значение.

Естественно, это обычно происходит, когда вы увеличиваете максимально возможное положительное число, оно переполняется обратно до отрицательного нуля.

В .net, однако, я думаю, что по умолчанию тип выполняет проверки переполнения и генерирует исключение, а не позволяет вам переполниться, поэтому единственный способ действительно архивировать это значение - установить его напрямую. Кроме того, -0 всегда должен сравниваться равным + 0.

Есть больше об этом на Wikipeida

2 голосов
/ 25 июня 2009

Попробуй это. Если pz - положительный ноль, а nz - отрицательный ноль:

Double.PositiveInfinity/pz => Double.PositiveInfinity
Double.PositiveInfinity/nz => Double.NegativeInfinity

Я получил это из спецификации ECMA C # .

Вы можете получить отрицательный ноль, разделив любое положительное число на отрицательную бесконечность:

10.0/Double.NegativeInfinity
2 голосов
/ 25 июня 2009

Одним из способов является использование BitConverter.GetBytes. Если вы проверите байты, вы увидите, что бит знака для значения фактически установлен, что указывает на его отрицательное значение.

byte[] zeroBytes = BitConverter.GetBytes(zero);
byte[] negZeroBytes = BitConverter.GetBytes(negZero);

bool sameBytes = zeroBytes[7] == negZeroBytes[7];
0 голосов
/ 25 июня 2009

После проверки я вижу, что -1.0 / double.PositiveInfinity возвращает и возвращает -0. Действительно, 1.0 / (-1.0 / double.PositiveInfinity) возвращает -infinity.

...