为什么 fmt.Println 对不同小数位数的 float64 值的格式不同?

问题描述 投票:0回答:1

当我检查了 float64 的行为时,我发现了以下行为。

  • 6位float64变量的输出是
    100000
  • 7位float64变量的输出是
    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)
}

有人可以帮我解释为什么输出会根据位数而不同吗?

go floating-point string-formatting
1个回答
2
投票

您正在观察由于 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

尝试godbolt.org

截至 2024 年 8 月 22 日,在 go.dev/src/strconv/ftoa.go 中做出此科学记数法决策的相关函数:

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)
}
© www.soinside.com 2019 - 2024. All rights reserved.