Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fmt: sub-10 exponents in formatted floats are zero-padded to at least two digits #70862

Closed
hudlow opened this issue Dec 16, 2024 · 7 comments
Closed
Labels
Documentation Issues describing a change to documentation. NeedsFix The path to resolution is known, but the work has not been done.
Milestone

Comments

@hudlow
Copy link

hudlow commented Dec 16, 2024

Go version

go version go1.23.4 darwin/arm64

Output of go env in your module/workspace:

GO111MODULE=''
GOARCH='arm64'
GOBIN=''
GOCACHE='/Users/zoomzoom/Library/Caches/go-build'
GOENV='/Users/zoomzoom/Library/Application Support/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='arm64'
GOHOSTOS='darwin'
GOINSECURE=''
GOMODCACHE='/Users/zoomzoom/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='darwin'
GOPATH='/Users/zoomzoom/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/Users/zoomzoom/brew/Cellar/go/1.23.4/libexec'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='local'
GOTOOLDIR='/Users/zoomzoom/brew/Cellar/go/1.23.4/libexec/pkg/tool/darwin_arm64'
GOVCS=''
GOVERSION='go1.23.4'
GODEBUG=''
GOTELEMETRY='local'
GOTELEMETRYDIR='/Users/zoomzoom/Library/Application Support/go/telemetry'
GCCGO='gccgo'
GOARM64='v8.0'
AR='ar'
CC='cc'
CXX='c++'
CGO_ENABLED='1'
GOMOD='/dev/null'
GOWORK=''
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
PKG_CONFIG='pkg-config'
GOGCCFLAGS='-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -ffile-prefix-map=/tmp/go-build3247814003=/tmp/go-build -gno-record-gcc-switches -fno-common'

What did you do?

Using %e, %E, %x, or %X to format a floating-point value that ends up with an exponent between 0 and 9.

https://go.dev/play/p/oaSxLmPizik

fmt.Printf("%e, %E, %x, %X, %b\n", 1e0, 1e0, 1e0, 1e0, 5e+15)
fmt.Printf("%e, %E, %x, %X, %b\n", 1e1, 1e1, 1e1, 1e1, 1e+16)
fmt.Printf("%e, %E, %x, %X, %b\n", 1e10, 1e10, 1e10, 1e10, 1e20)
fmt.Printf("%e, %E, %x, %X, %b\n", 1e100, 1e100, 1e100, 1e100, 1e100)

What did you see happen?

The exponent value is zero-padded to two digits. Interestingly, %b does not exhibit this behavior.

1.000000e+00, 1.000000E+00, 0x1p+00, 0X1P+00, 5000000000000000p+0
1.000000e+01, 1.000000E+01, 0x1.4p+03, 0X1.4P+03, 5000000000000000p+1
1.000000e+10, 1.000000E+10, 0x1.2a05f2p+33, 0X1.2A05F2P+33, 6103515625000000p+14
1.000000e+100, 1.000000E+100, 0x1.249ad2594c37dp+332, 0X1.249AD2594C37DP+332, 5147557589468029p+280

What did you expect to see?

The exponent value is not zero-padded.

I realize it may be a bit cheeky to file this as a bug, given that the behavior seems deliberately coded. But, I couldn't find any documentation saying that it is correct behavior, and it doesn't seem to make much sense given that it does not result in a uniform length for exponents since they can also be three digits long.

I am also genuinely curious if it is intentional that %b behaves differently in this respect.

@robpike
Copy link
Contributor

robpike commented Dec 16, 2024

It's because that's what C does for the %e and %E formats:

% cat x.c
#include <stdio.h>

int main(void) {
   printf("%e\n", 13.0);
   return 0;
}
% gcc x.c
% a.out
1.300000e+01
% 

I suspect the behavior in Go for %b is more an accident then anything deliberate but probably won't change.

@meem
Copy link

meem commented Dec 16, 2024

FWIW, the C behavior (which does seem bizarre) is documented in the standard describing %e and %E (emphasis added):

A double argument representing a floating-point number is converted in the
style [−]d.ddd e±dd, where there is one digit (which is nonzero if the
argument is nonzero) before the decimal-point character and the number of
digits after it is equal to the precision; if the precision is missing, it is taken as
6; if the precision is zero and the # flag is not specified, no decimal-point
character appears. The value is rounded to the appropriate number of digits.
The E conversion specifier produces a number with E instead of e
introducing the exponent. The exponent always contains at least two digits,
and only as many more digits as necessary to represent the exponent.
If the
value is zero, the exponent is zero.

@hudlow
Copy link
Author

hudlow commented Dec 16, 2024

@robpike

It's because that's what C does for the %e and %E formats

I was holding out some hope this could be fixed since it's previously been stated that fmt is not beholden to C compatibility. But I assume at this point that changing this would run afoul of Hyrum's Law, and this should be considered a documentation bug?

@meem

FWIW, the C behavior (which does seem bizarre) is documented in the standard

I sort of have to imagine that this traces its lineage to a float formatter that didn't consider doubles? But ostensibly that would have been pre-C.

@robpike
Copy link
Contributor

robpike commented Dec 16, 2024

No, it's not beholden but it's also designed to be like it, especially when dealing with the same things. And because of the compatibility promise, the behavior is very unlikely to change. It's just too minor a thing to break compatibility with the past (and with C, to be honest).

@gopherbot
Copy link
Contributor

Change https://go.dev/cl/636915 mentions this issue: fmt, strconv: document that exponent is always two digits

@hudlow
Copy link
Author

hudlow commented Dec 17, 2024

Thank you @ianlancetaylor!

@dmitshur dmitshur added Documentation Issues describing a change to documentation. NeedsFix The path to resolution is known, but the work has not been done. labels Jan 8, 2025
@dmitshur dmitshur added this to the Go1.24 milestone Jan 8, 2025
wyf9661 pushed a commit to wyf9661/go that referenced this issue Jan 21, 2025
Except for %b where it is only one.

Fixes golang#70862

Change-Id: Ic423a799b73bfa534f4083f6544bb9cd639fef06
Reviewed-on: https://go-review.googlesource.com/c/go/+/636915
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Rob Pike <r@golang.org>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Documentation Issues describing a change to documentation. NeedsFix The path to resolution is known, but the work has not been done.
Projects
None yet
Development

No branches or pull requests

6 participants