From decc337c7c1606b49e477435ba73c969a8a3b617 Mon Sep 17 00:00:00 2001 From: nashit hayyat Date: Tue, 6 Oct 2026 05:13:17 +0530 Subject: [PATCH] fix int64 truncation in oomm for values past the largest prefix --- big.go | 7 ++++++- bigbytes_test.go | 31 +++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/big.go b/big.go index f49dc33..3d4e47b 100644 --- a/big.go +++ b/big.go @@ -15,7 +15,12 @@ func oomm(n, b *big.Int, maxmag int) (float64, int) { break } } - return float64(n.Int64()) + (float64(m.Int64()) / float64(b.Int64())), mag + // Stopping at maxmag leaves n unreduced, so it can be larger than an + // int64 and Int64 would return garbage. Convert through big.Float + // instead, which rounds the same way as float64(int64) does when the + // value fits. + val, _ := new(big.Float).SetInt(n).Float64() + return val + (float64(m.Int64()) / float64(b.Int64())), mag } // total order of magnitude diff --git a/bigbytes_test.go b/bigbytes_test.go index 59445ea..b94acf5 100644 --- a/bigbytes_test.go +++ b/bigbytes_test.go @@ -190,6 +190,37 @@ func TestVeryVeryBigBytes(t *testing.T) { } } +func TestBigBytesBeyondInt64(t *testing.T) { + // Past the largest prefix the quotient is no longer reduced, so it can + // exceed an int64. These used to come back negative or as 0.0. + tests := []struct { + in, exp, iexp string + }{ + // 2^63 QB + {"9223372036854775808000000000000000000000000000000", + "9223372036854775808 QB", "7275957614183426048 QiB"}, + // 2^64 QB + {"18446744073709551616000000000000000000000000000000", + "18446744073709551616 QB", "14551915228366852096 QiB"}, + // 2^164 = 2^64 QiB + {"23384026197294446691258957323460528314494920687616", + "23384026197294448640 QB", "18446744073709551616 QiB"}, + } + + for _, test := range tests { + b, ok := (&big.Int{}).SetString(test.in, 10) + if !ok { + t.Fatalf("Couldn't parse %q", test.in) + } + if s := BigBytes(b); s != test.exp { + t.Errorf("Expected %q for %v, got %q", test.exp, test.in, s) + } + if s := BigIBytes(b); s != test.iexp { + t.Errorf("Expected %q for %v, got %q", test.iexp, test.in, s) + } + } +} + func TestParseVeryBig(t *testing.T) { tests := []struct { in string