Сломано ли двойное умножение in.NET [дубликат]


этот вопрос уже есть ответ здесь:

если я выполняю следующее выражение В C#:

double i = 10*0.69;

i - это: 6.8999999999999995. Зачем?

Я понимаю, что числа, такие как 1/3, могут быть трудно представить в двоичном формате, поскольку он имеет бесконечное повторение десятичные знаки, но это не так для 0.69. И 0.69 можно легко представить в двоичном виде, одно двоичное число для 69 и другое для обозначения позиции десятичного знака.

как мне обойти это? Используйте decimal тип?

6   51   2009-09-14 14:30:56

6 ответов:

потому что вы неправильно поняли арифметику с плавающей запятой и как хранятся данные.

фактически, ваш код фактически не выполняет никакой арифметики во время выполнения в этом конкретном случае -компилятор сделает это, а затем сохранит константу в сгенерированном исполняемом файле. Однако это не могу хранить точное значение 6.9, потому что это значение не может быть точно представлено в формате с плавающей запятой, так же, как 1/3 не может быть точно сохранено в конечное десятичное представление.

посмотреть, если в этой статье поможет вам.

почему фреймворк не работает вокруг этого и не скрывает эту проблему от меня и не дает мне правильный ответ,0.69!!!

прекратите вести себя как менеджер Дилберта и примите, что компьютеры, хотя и классные и потрясающие, имеют ограничения. В вашем конкретном случае это не просто "скрывает" проблему, потому что вы специально сказали ей не делать этого. Язык (компьютер) предоставляет альтернативы формату, который вы не выбрали. Вы выбрали двойной, который имеет определенные преимущества перед десятичными, и некоторые недостатки. Теперь, зная ответ, вы расстроены тем, что недостатки не исчезают волшебным образом.

как программист, вы несете ответственность за сокрытие этого обратная сторона от менеджеров, и есть много способов сделать это. Однако создатели C# несут ответственность за правильную работу с плавающей точкой, и правильная плавающая точка иногда приводит к неправильной математике.

Так будет каждый другой метод хранения чисел, так как мы этого не делаем есть бесконечные биты. Наша работа как программистов заключается в работе с ограниченными ресурсами, чтобы сделать крутые вещи происходят. Они доставили тебя туда на 90%, просто доставь факел домой.

и 0,69 могут быть представлены в бинарные, одно двоичное число 69 и другой, чтобы обозначить положение decimal место.

Я думаю, что это распространенная ошибка - вы думаете о числах с плавающей запятой, как будто они являются базовыми-10 (т. е. десятичными - отсюда мой акцент).

Итак, вы думаете, что в этом двойнике есть две части целого числа: 69 и делим на 100 чтобы получить десятичное число место для перемещения - которое также может быть выражено как:
69 х 10 в степени -2.

однако поплавки хранят "положение точки" как база-2.

ваш поплавок фактически сохраняется как:
68999999999999995 x 2 в силу какого-то большого отрицательного числа

Это не так много проблем, как только вы привыкли к нему-большинство людей знают и ожидают, что 1/3 не может быть выражена точно в виде десятичной или процент. Просто дроби, которые не могут быть выражены в базе-2, разные.

но почему фреймворк не работает вокруг этого и не скрывает эту проблему от меня и не дает мне правильный ответ, 0.69!!!

потому что вы сказали ему использовать двоичная точка с плавающей запятой, и решение заключается в использовании десятичная точка с плавающей запятой, то есть вы предлагаете, чтобы фреймворк игнорировал указанный вами тип и использовал decimal вместо этого, что очень медленнее, потому что он непосредственно не реализован в аппаратура.

более эффективное решение состоит в том, чтобы не выводить полное значение представления и явно указывать точность, требуемую вашим выходом. Если вы отформатируете вывод до двух знаков после запятой, вы увидите ожидаемый результат. Однако если это финансовое приложение decimal это именно то, что вы должны использовать - вы видели Супермен III (и офисное пространство) не так ли;)

обратите внимание, что это все конечное приближение бесконечного диапазона, это разве что decimal и двойной используйте другой набор приближений. Преимущество decimal он производит те же приближения, что и вы, если бы вы выполняли расчет самостоятельно. Например, если вы рассчитали 1/3, вы в конечном итоге перестанете писать 3, когда это будет "достаточно хорошо".

по той же причине, что 1/3 в десятичных системах выходит как 0.333333333333333333333333333333333333333333333333 и не точная дробь, которая бесконечно длинна.

чтобы обойти это (например, для отображения на экране) попробуйте это:

double i = (double) Decimal.Multiply(10, (Decimal) 0.69);

Кажется, все ответили на ваш первый вопрос, но проигнорировали вторую часть.