Проверив поведение float64, я обнаружил следующее.
100000
.1e+06
.package main
import "fmt"
func main() {
var a float64 = 100000
fmt.Println(a) // output: 100000
var b float64 = 1000000
fmt.Println(b) // output: 1e+06 (expected: 1000000)
}
Может кто-нибудь помочь мне, почему вывод отличается в зависимости от количества цифр.
Выполняет ли «Точность по умолчанию для %e, %f и %#g равна 6;» значит, %g это %.6g
верно?
Кстати, отметьте пользователя, которому вы отвечаете, используя @username
в комментариях, иначе пользователь не получит уведомление.
Нет, не совсем. Обратите внимание, что глагол %#g
отличается от %g
(#
в Go означает, так сказать, «более внутреннее» представление). Как указано, %g
— это %e
или %f
в зависимости от показателя степени (грубо и фактически неверно, но вы можете думать об этом так, как будто это количество цифр в числе). В вашем случае форматирование 1e5 с использованием %g
обнаруживает, что показатель степени мал, поэтому выбирает %f
в качестве фактического форматирования, которое, в свою очередь, использует «наименьшее количество цифр…» в качестве точности. В случае 1e6 выбирается %e
. Я понятия не имею, точно ли задокументированы критерии выбора между %e и %f.
Ну да, документация fmt
, я бы сказал, слишком сухая и нормативная ;-)
@kostix Извините, я забыл использовать тег, потому что это мой первый пост. ох, похоже, спецификация %g
сложная. Я бы сказал, что документацию fmt
тоже сложно читать:0 Спасибо за ответ!
См. также это.
@kostix Ну, буду иметь ввиду!
Вы наблюдаете поведение из-за форматирования Go по умолчанию для чисел с плавающей запятой. При выводе float64
Go пытается кратко представить число. Он печатает полное значение для меньших чисел (например, 100000
). Однако как только в числе появляется больше цифр (например, 1000000
), Go переключается на научную запись (1e+06
).
Если вы хотите, чтобы полное значение печаталось без научных обозначений, вы можете использовать fmt.Printf
с директивой форматирования:
package main
import "fmt"
func main() {
var a float64 = 100000
fmt.Printf("%.f\n", a)
var b float64 = 1000000
fmt.Printf("%.f\n", b)
}
Это напечатает оба числа без научных обозначений:
100000
1000000
Try on godbolt.org
Соответствующая функция, которая принимает это решение в научной записи, в исходном коде по адресу go.dev/src/strconv/ftoa.go по состоянию на 22 августа 2024 г.:
func formatDigits(dst []byte, shortest bool, neg bool, digs decimalSlice, prec int, fmt byte) []byte {
switch fmt {
case 'e', 'E':
return fmtE(dst, neg, digs, prec, fmt)
case 'f':
return fmtF(dst, neg, digs, prec)
case 'g', 'G':
// trailing fractional zeros in 'e' form will be trimmed.
eprec := prec
if eprec > digs.nd && digs.nd >= digs.dp {
eprec = digs.nd
}
// %e is used if the exponent from the conversion
// is less than -4 or greater than or equal to the precision.
// if precision was the shortest possible, use precision 6 for this decision.
if shortest {
eprec = 6
}
exp := digs.dp - 1
if exp < -4 || exp >= eprec {
if prec > digs.nd {
prec = digs.nd
}
return fmtE(dst, neg, digs, prec-1, fmt+'e'-'g')
}
if prec > digs.dp {
prec = digs.nd
}
return fmtF(dst, neg, digs, max(prec-digs.dp, 0))
}
// unknown format
return append(dst, '%', fmt)
}
Спасибо за ваш ответ и исходный код :) @Sash Sinha
Вы читали документацию к пакету fmt? Там указано: «Печать форматов, используя форматы по умолчанию для своих операндов». Затем вы можете выяснить, что форматом по умолчанию для
float64
является%g
, а затем прочитать, что %g — это «%e для больших показателей, %f в противном случае. Точность обсуждается ниже.», и, наконец, «Точность по умолчанию для %e, %f и %#g равна 6; для %g это наименьшее количество цифр, необходимое для однозначной идентификации значения.»