В документации MSDN упоминается, что тип double
включает отрицательный нуль. Однако и -1.0 / double.PositiveInfinity
, и -double.Epsilon / 2
возвращают обычный 0 (и равны ему). Как я могу получить -0?
Как получить результат -0 в вычислениях с плавающей запятой и отличить его от +0 в С#?
Ответы (5)
Вот практический пример различия между ними без изучения битов. Ссылки 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
Or
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
.