У меня довольно приличное понимание IEEE 754, поэтому это не один из тех, «почему добавление числа a и число b приводит к ...» - тип вопросов.Обозначение формата номера с фиксированной точкой округления удвоений?
Скорее я хочу спросить, правильно ли я понял спецификатор формата с фиксированной запятой, потому что он не ведет себя так, как я ожидал бы для некоторых двойных значений.
Например:
double d = 0x3FffffFFFFfffe * (1.0/0x3FffffFFFFffff);
Console.WriteLine(d.ToString("R"));
Console.WriteLine(d.ToString("G20"));
Console.WriteLine(d.ToString("F20"));
Оба "R"
и "G"
спецификатор печатает одно и то же - правильное значение: 0.99999999999999989
но "F"
спецификатор всегда округляет до 1.0
независимо от того, сколько знаков после запятой я сказать ему включают. Даже если я скажу ему, чтобы напечатать максимальное число из 99 десятичных знаков ("F99"
), он по-прежнему выводит только «1.», А затем 99 нулей.
Мое понимание сломано, и может ли кто-то указать меня на соответствующий раздел в спецификации, или это нарушение нарушено? (Для меня это не сделка, я просто хочу знать.)
Here Это то, на что я смотрел, но я ничего не вижу, объясняя это.
(Это .Net4.0)
Два комментария, которые не очень понятны из ссылок. 1) Математика выполняется в базе 2, поэтому происходит переход от десятичной к двоичной и обратно к десятичной, что влияет на округление результатов. 2) Математика может выполняться с использованием оборудования с плавающей запятой внутри микропроцессора ПК или путем моделирования в компиляторе C#. Поэтому иногда вы получаете другой ответ в зависимости от того, используете ли вы исполняемый файл в папке отладки или используете исполняемый файл в папке выпуска. – jdweng
@jdweng Не была бы эта последняя часть, которую вы упомянули, быть деталью реализации JIT? В любом случае, если бы вы могли ссылаться на какую-либо спецификацию или другую документацию, о которой я бы хотел ее прочитать. :) – AnorZaken
Если моя собственная память служит мне правильной, спецификация позволяет выполнять промежуточные вычисления с более высокой точностью. Другими словами, до тех пор, пока значение все еще находится в регистре cpu, оно может иметь более высокую точность. (Если вы вернетесь в память, дополнительная точность будет потеряна ofc.) Это не всегда желательно, поэтому вы можете использовать синтаксис cast для усечения дополнительной точности путем литья в один и тот же тип. Другими словами, этот код: 'float x =/* некоторый расчет * /; bool isIdentical = x == (float) x; 'может не всегда возвращать true, как можно было бы ожидать ... _ (если я правильно помню спецификацию) _. – AnorZaken