Как получить результат -0 в вычислениях с плавающей запятой и отличить его от +0 в C#?
-
20-08-2019 - |
Вопрос
В документации MSDN упоминается, что double
тип включает отрицательный ноль.Однако оба -1.0 / double.PositiveInfinity
и -double.Epsilon / 2
похоже, возвращает нормальный 0 (и сравнивает его с ним).Как я могу получить -0?
Решение
Вот практический пример различения этих двух значений без изучения битов.Ссылки 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, получится -Бесконечность или Бесконечность, в зависимости от того, какой у вас ноль.
Другие советы
Отрицательный ноль связан с тем, как число хранится в двоичном виде, а не с каким-либо реальным достижимым результатом математического вычисления.
В хранилище с плавающей запятой верхний бит часто используется для обозначения знака. Это оставляет 31 бит для данных (в 32-битном значении с плавающей запятой), поэтому фактически есть два представления для нуля.
00000000 00000000 00000000 00000000
Или
00000000 00000000 00000000 00000001
Оба представляют ноль, но один со знаковым битом, установленным в отрицательное значение.
Естественно, это обычно происходит, когда вы увеличиваете максимально возможное положительное число, оно переполняется обратно до отрицательного нуля.
В .net, однако, я думаю, что по умолчанию тип выполняет проверки переполнения и выдает исключение, а не позволяет переполнить, поэтому единственный способ действительно заархивировать это значение - установить его напрямую. Кроме того, -0 всегда должен сравниваться равным +0.
Подробнее об этом можно узнать на Википедии . р>
Одним из способов является использование BitConverter.GetBytes. Если вы проверите байты, вы увидите, что бит знака для значения фактически установлен, что указывает на его отрицательное значение.
byte[] zeroBytes = BitConverter.GetBytes(zero);
byte[] negZeroBytes = BitConverter.GetBytes(negZero);
bool sameBytes = zeroBytes[7] == negZeroBytes[7];
Попробуй это. Если pz
положительный ноль, а nz
отрицательный ноль:
Double.PositiveInfinity/pz => Double.PositiveInfinity
Double.PositiveInfinity/nz => Double.NegativeInfinity
Я получил это из спецификации ECMA C # .
Вы можете получить отрицательный ноль, разделив любое положительное число на отрицательную бесконечность:
10.0/Double.NegativeInfinity
После проверки я вижу, что -1.0 / double.PositiveInfinity
возвращает -0. Действительно, 1.0 / (-1.0 / double.PositiveInfinity)
возвращает -infinity
.