2015-09-27 2 views
3

У меня довольно приличное понимание 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)

ответ

0

Пользователя «термометр» связан с другим вопросом, который я подозреваю, имеет наилучший возможный ответ имеющийся на этот вопрос ... хотя был некоторый нечеткий-Несс на деталях и документация. (К сожалению, комментарий удален.)

Связанный вопрос: Formatting doubles for output in C#.

И, как сообщается, если вы не используете спецификатор G или R, выход всегда будет уменьшен до 15 знаков после запятой перед пользовательским форматированием. Лучшим документом, с кем можно было связаться, в этом вопросе был this MSDN page. Детали и формулировки не так кристально чисты, как хотелось бы, но, как я сказал, это лучшее, что я найду.

+0

Два комментария, которые не очень понятны из ссылок. 1) Математика выполняется в базе 2, поэтому происходит переход от десятичной к двоичной и обратно к десятичной, что влияет на округление результатов. 2) Математика может выполняться с использованием оборудования с плавающей запятой внутри микропроцессора ПК или путем моделирования в компиляторе C#. Поэтому иногда вы получаете другой ответ в зависимости от того, используете ли вы исполняемый файл в папке отладки или используете исполняемый файл в папке выпуска. – jdweng

+0

@jdweng Не была бы эта последняя часть, которую вы упомянули, быть деталью реализации JIT? В любом случае, если бы вы могли ссылаться на какую-либо спецификацию или другую документацию, о которой я бы хотел ее прочитать. :) – AnorZaken

+0

Если моя собственная память служит мне правильной, спецификация позволяет выполнять промежуточные вычисления с более высокой точностью. Другими словами, до тех пор, пока значение все еще находится в регистре cpu, оно может иметь более высокую точность. (Если вы вернетесь в память, дополнительная точность будет потеряна ofc.) Это не всегда желательно, поэтому вы можете использовать синтаксис cast для усечения дополнительной точности путем литья в один и тот же тип. Другими словами, этот код: 'float x =/* некоторый расчет * /; bool isIdentical = x == (float) x; 'может не всегда возвращать true, как можно было бы ожидать ... _ (если я правильно помню спецификацию) _. – AnorZaken