2015-01-07 2 views
9

Рассмотрим эти два случая:Почему эти два float64 имеют разные значения?

fmt.Println(912 * 0.01) 
fmt.Println(float64(912) * 0.01) 

(Go Playground link)

второй отпечатки 9.120000000000001, что на самом деле хорошо, I understand why that is happening.

Однако почему первая строка печатает 9.12, без ... 01 в конце? Does Go умножает две нетипизированные константы и просто заменяет их литералом 9.12 при компиляции?

+0

Возможный дубликат [Является ли математика с плавающей запятой?] (Http://stackoverflow.com/questions/588004/is-floating-point-math-broken) – asawyer

+1

@asawyer Не совсем. ОП задается вопросом, почему эти два дают разные результаты, а не почему один из результатов не совсем соответствует 9.12. – fuz

ответ

14

Согласно spec:

Константные выражения всегда оцениваются точно; промежуточным значениям и самим константам может потребоваться точность, значительно большая, чем поддерживается любым предписанным типом языка.

С

912 * 0.01 

является постоянное выражение, оно вычисляется точно. Таким образом, запись fmt.Println(912 * 0.01) имеет такой же эффект, что и запись fmt.Println(9.12). Когда вы наводите 912 на float64, другой операнд умножения с плавающей запятой неявно закрепляется на float64. Таким образом, выражение float64(912) * 0.01 ведет себя как float64(912) * float64(0.01). 0,01 не является точно представимым в float64, поэтому точность теряется в другом месте, чем в выражении float64(912 * 0.01), которое возникает в аргументе fmt.Println() в вашем первом примере, объясняя разные результаты.

6

Причиной другого выхода является то, что в первом случае 912 * 0.01 является умножение 2 нетипизированных постоянных значений, который является произвольной точностью, а только результат преобразуется в float64, когда значение передается Println(). (См Constant expressions раздела спецификации языка для деталей.)

Во втором случае float64(912) * 0.01 первого 912 преобразуется в float64, то нетипизированная константа 0.01 преобразуется в float64 и эти два значения того float64 умножается, который не является произвольным точность и не даст точного результата.

Примечание:

В первом случае результат будет преобразован в float64, когда передается Println():

fmt.Printf("%T %v\n", 912 * 0.01, 912 * 0.01) 

Выход:

float64 9.12 

Test it on Go Playground

+0

«В первом случае результат будет преобразован в' float64' при передаче в 'Println()') - вы имеете в виду результат умножения двух нетипизированных констант, правильно? –

+0

@AttilaO. Да, результат умножения. Когда он передается функции 'Println()', он должен быть преобразован в типизированное значение. Также отредактирован, чтобы добавить код, чтобы показать тип результата. – icza