Commit graph

241 commits

Author SHA1 Message Date
Mateusz Wos
447b833d1e
docs: changelog for v1.6.0 (#477) v1.6.0 2026-10-18 17:33:05 +02:00
Yusuf Efe
4ce352fe15
fix: reject overflowing division precision (#472)
Signed-off-by: Yusuf Efe <120668197+yuefdev@users.noreply.github.com>
Co-authored-by: mwoss <wos.mateusz16@gmail.com>
2026-10-18 17:29:12 +02:00
Mateusz Wos
540b915359
docs: add udecimal to the alternative libraries (#476) 2026-10-18 17:19:27 +02:00
Mateusz Wos
54748831b6
docs: show how to control the JSON format of one field (#475) 2026-10-18 17:16:13 +02:00
Mateusz Wos
ddb96d1ae7
fix: clearer error when scanning NULL into a Decimal (#474) 2026-10-18 16:56:12 +02:00
Ryoya Sekino
59f775d55c
README: Fix URLs for the official Go pages (#264)
Co-authored-by: mwoss <wos.mateusz16@gmail.com>
2026-10-18 16:47:19 +02:00
Mateusz Wos
100aebf14a
feat: add Root and RootRound (#473) 2026-10-18 16:44:29 +02:00
Mateusz Wos
bed77f5cb6
fix: Ln rounds correctly, computed with error bounds like Pow (#471)
Co-authored-by: vera-rubin <322284620+vera-rubin@users.noreply.github.com>
2026-10-17 23:45:12 +02:00
adam magued
37aad64c5a
feat: add NewFromBigFloat constructor (#457)
Co-authored-by: mwoss <wos.mateusz16@gmail.com>
2026-10-17 23:29:19 +02:00
Raiven Kao
78a38f8f6f
perf: NewFromFloat uses strconv, drop the vendored strconv copy (#431)
* perf: delegate NewFromFloat shortest-decimal conversion to strconv

NewFromFloat and NewFromFloat32 need the shortest decimal digit string
that round-trips back to the input float. strconv already computes
exactly that for FormatFloat with precision -1, but the library computes
it itself through decimal-go.go and rounding.go, a copy of the 2009
strconv/decimal.go: assign the mantissa into an 800-byte digit buffer,
shift it one binary bit at a time, then walk the digits against the two
neighbouring floats to find where they diverge.

Ask strconv for the value in 'e' format instead and read the digits back
out. The 'e' layout is [-]d[.ddd]e+dd, at most 24 bytes and trivial to
scan, unlike 'f' which can run past 750 bytes at the exponent extremes.
The result is identical, so no caller-visible behaviour changes.

Benchmarks (Ryzen 9 5900X, -benchtime 2s -count 5, median):

               go1.22           go1.27
  Float    366 -> 168 ns    332 ->  94 ns
  Float32  271 -> 130 ns    241 ->  92 ns

Allocations are unchanged at 2 / 40 B, both from the big.NewInt that
Decimal.value requires. The gap widens on go1.27 because that release
replaced strconv's shortest-float conversion with the uscale algorithm.

Before go1.13, strconv.FormatFloat could return a shortest form that was
not the nearest one (golang/go#29491, the bug behind the two test table
entries added for it), so the old path is kept behind a !go1.13 build
tag. Nothing changes for go1.10 through go1.12; once the module's
minimum Go version passes 1.13, decimal-go.go, rounding.go and
newfromfloat_legacy.go can be deleted outright, removing 575 lines.

Verified equivalent against the previous implementation on go1.13 and
go1.27 over all 4,278,190,078 non-zero finite float32 bit patterns and
578,922,574 float64 values (random bit patterns, every power of two and
its neighbours, and a dense subnormal sweep), with no mismatch.

Tested on go1.10.8, go1.11.13, go1.12.17, go1.13.15, go1.22.12 and
go1.27.0.

* refactor: use strconv on every Go version, drop the vendored strconv copy

Keeping the old implementation behind build tags for Go 1.10-1.12 meant maintaining two
copies of NewFromFloat. Those versions now go through strconv too, which there can pick a
different, still round-tripping shortest form in rare cases (golang/go#29491), so the two
test cases for that only run on Go 1.13 and later.

---------

Co-authored-by: mwoss <wos.mateusz16@gmail.com>
2026-10-17 23:21:43 +02:00
Mateusz Wos
4fef1ec699
fix: ExpHullAbrham returns the requested number of significant figures for large inputs (#470) 2026-10-17 21:32:15 +02:00
Bing Gao
77f8f075c2
fix: ExpHullAbrham drops significant figures for results below 1 (#429)
ExpHullAbrham is documented to return overallPrecision significant
figures, but its final rounding used a separate branch when the result
was < 1 and rounded to overallPrecision decimal places instead. That
discarded the leading-zero positions, so results below 0.1 lost
significant figures and collapsed to 0 once the leading-zero count
reached overallPrecision -- e.g. exp(-50).ExpHullAbrham(10) returned 0
(true value 1.93e-22).

The >=1 branch formula currentPrecision - resNumDigits - res.exp is the
significant-figure-correct rounding position in both cases, so drop the
branch. Positive arguments and results in [0.1,1) are unchanged.

Correct the negative rows of the ExpHullAbrham table (they encoded the
truncated values) and add a significant-figure sweep over the negative
half-line, checked against exp(x) to 40+ digits.

Co-authored-by: mwoss <wos.mateusz16@gmail.com>
2026-10-17 21:30:33 +02:00
Mateusz Wos
5bc569143a
feat: Scan accepts Decimal, big.Int and all integer sizes (#469)
Co-authored-by: Pavel Skorikov <5002158+it66ru@users.noreply.github.com>
Co-authored-by: Lucca Dukic <109136188+LuccaBitfly@users.noreply.github.com>
Co-authored-by: Anucha Petchagun <corelmax@gmail.com>
Co-authored-by: agammann <161159040+agammann@users.noreply.github.com>
2026-10-17 21:00:54 +02:00
Mateusz Wos
9e64f2e188
docs: fix doc examples that were wrong or didn't compile (#468)
Co-authored-by: Takamura <plehanov.v@gmail.com>
2026-10-17 20:47:30 +02:00
Mateusz Wos
175974ac6b
test: fix benchmarks that measured setup or the wrong function (#467)
Co-authored-by: Igor Mikushkin <igor.mikushkin@gmail.com>
2026-10-17 20:36:28 +02:00
cdpzyafk
1863390911
perf: use Sign() instead of Cmp(zeroInt) in IsInteger and Ceil
Co-authored-by: terry <terry@bituniverse.org>
Co-authored-by: mwoss <wos.mateusz16@gmail.com>
2026-10-16 23:15:40 +02:00
Mateusz Wos
0146aff76d
docs: warn that global settings are not goroutine-safe, list them in the README (#466) 2026-10-16 22:52:22 +02:00
Mateusz Wos
2d97fa9ba3
feat: add Sqrt and SqrtRound (#465) 2026-10-16 18:21:15 +02:00
Mateusz Wos
c5d65cf1e9
feat: add Normalize method (#464) 2026-10-16 14:43:08 +02:00
Mateusz Wos
ec4943b1a3
feat: implement fmt.Formatter (#463) 2026-10-15 20:05:04 +02:00
Mateusz Wos
e799c20820
feat: BSON Decimal128 support for the MongoDB Go driver v2 (#460) 2026-10-14 19:27:42 +02:00
Mateusz Wos
511ed65a12
chore: turn off the strings.ReplaceAll lint check, it needs Go 1.12 (#458) 2026-10-10 23:17:59 +02:00
Archit Goyal
970f0b7bae
fix: accept Unicode minus in NewFromString (#428)
Some locales and copy-paste sources use U+2212 (−) instead of ASCII '-'.
Normalize it before parsing so NewFromString accepts both.

Closes #318

Co-authored-by: Archit Goyal <jabstack@Archits-MacBook-Air.local>
Co-authored-by: mwoss <wos.mateusz16@gmail.com>
2026-10-10 23:17:16 +02:00
Mateusz Wos
f658fbf1eb
docs: changelog for v1.5.0 (#455) v1.5.0 2026-10-05 14:11:08 +02:00
Mateusz Wos
b2609858ef
ci: test on Go 1.26 and 1.27 instead of 1.22 and 1.23 (#454) 2026-10-05 13:53:53 +02:00
Mateusz Wos
d25658fa8d
chore: lint with golangci-lint in CI instead of Go Report Card (#453) 2026-10-05 13:53:41 +02:00
Mateusz Wos
fc257b4a95
chore: split decimal.go into math.go and encoding.go (#452)
decimal.go had grown to about 2,900 lines. This moves declarations,
byte for byte with their comments, into:

- math.go: power, exponential, logarithm and trigonometric functions
  and their helpers (Pow, PowWithPrecision, PowInt32, PowBigInt,
  ExpHullAbrham, ExpTaylor, Ln, Sin, Cos, Tan, Atan)
- encoding.go: JSON, text, binary, gob, SQL and Spanner methods, and
  NullDecimal
- const.go: internal constants and lookup tables (zeroInt to twentyInt,
  pow10Table, pow10Uint64, float64Pow10, pow5Int64, pow10, zeros)

Nothing else changes. The go doc -all output is the same.

To follow the history of moved code:

  git blame -C <file>
  git log -L :ExpTaylor:decimal.go aed8543
  git show --color-moved=zebra --color-moved-ws=no <this commit>
2026-10-05 13:05:34 +02:00
Mateusz Wos
aed8543466
fix: RoundCash with a low DivisionPrecision and NullDecimal.Valid after errors (#443) 2026-10-05 11:58:31 +02:00
Mateusz Wos
811854c508
perf: faster QuoRem, DivRound, Round, RoundBank, RoundUp, RoundCeil and RoundFloor (#446)
* perf: faster QuoRem, DivRound, Round, RoundBank, RoundUp, RoundCeil and RoundFloor

* fix: keep the zero representation of RoundCeil and RoundFloor results
2026-10-05 11:58:08 +02:00
Mateusz Wos
9b6d1186ce
perf: raise the ExpHullAbrham sum to its power by squaring (#450) 2026-10-05 11:57:46 +02:00
Mateusz Wos
cc8953c6b3
perf: build trig constants once (#449) 2026-10-05 11:57:34 +02:00
Mateusz Wos
84990cbfac
perf: faster String, MarshalJSON and NewFromString; reject a sign after the decimal point (#447) 2026-10-05 11:57:10 +02:00
Jake Wang
71ebcfdcdf
Fix the scale of the small-input exponential result (#433) 2026-10-05 10:13:05 +02:00
Mateusz Wos
f1d1c0012b
perf: int64 fast paths in NumDigits, IntPart, IsInteger and Float64 (#448) 2026-10-04 21:07:30 +02:00
Mateusz Wos
51fe3c95dc
fix: keep the zero representation of rescale results (#451) 2026-10-04 21:06:56 +02:00
Mateusz Wos
8a6d7582fa
perf: fewer allocations in Add, Sub, Cmp, Sum and Shift (#445)
* perf: fewer allocations in Add, Sub, Cmp, Sum and Shift
* fix: keep the zero representation of Shift and Sum results
* fix: Shift of zero keeps the zero representation
2026-10-04 21:06:15 +02:00
Mateusz Wos
e78fe0e8ac
perf: use cached powers of ten in rescale, Floor, Ceil and Rat (#444) 2026-10-04 19:56:28 +02:00
Sash
a37fbe42be
fix: panic when Shift overflows the exponent (#437)
* fix: panic when Shift overflows the exponent

Shift added the exponents as int32, so shifting 5 * 10^2147483647
up by one came back as 5 * 10^-2147483648. Mul already panics
when an exponent does not fit.

* Address the Shift overflow review.

The wrap comment was wrong, and the panic cases now use didPanic.
2026-10-04 17:31:52 +02:00
Mateusz Wos
f6cc580f80
docs: explain that NewFromFloat can change large whole numbers (#442) 2026-10-04 10:25:56 +02:00
Mateusz Wos
0911c5f1b5
fix: directed rounding always returns the requested exponent (#441) 2026-10-04 09:53:38 +02:00
Amit Mishra
fdefb63ebc
fix: normalize exponent in RoundUp/RoundDown/RoundFloor/RoundCeil and support negative precision in Truncate (#426)
RoundUp, RoundDown, RoundFloor, and RoundCeil all returned the original
decimal (with its original exponent) when the value was already exact at
the requested precision. This caused the result to carry a trailing
exponent that did not match the requested places.

For example, (100.0).RoundUp(0) returned a Decimal with exp=-1 instead
of exp=0, so StringFixedBank(-d.Exponent()) would produce "100.0" rather
than "100".

Fix: when the rescaled value equals the original, return the rescaled
form (which has the canonical exponent) instead of the original.

Truncate previously rejected negative precision values due to a
precision >= 0 guard, silently returning the input unchanged. The
rescale function already uses integer division (Quo, truncating toward
zero), so removing the guard is sufficient to make negative precision
work correctly.

For example, (5432).Truncate(-2) now returns 5400 instead of 5432.

Fixes #390
Fixes #406

Co-authored-by: Amit Mishra <amitmishraaa11@gmail.com>
2026-10-04 09:47:36 +02:00
Mateusz Wos
71ca20d594
fix: limit exponents accepted by NewFromString and UnmarshalBinary (#440)
* fix: limit exponents accepted by NewFromString and UnmarshalBinary
* fix: rename limit to MaxDecodeExponent and lower its default to 10000
2026-10-04 09:37:51 +02:00
phuoc14.dev
684fe9e21d
fix: Float64 hangs on decimals with huge exponents (#438)
* fix: Float64 hangs on decimals with huge exponents

Float64 went through Rat(), which builds 10^|exp| as a big.Int. With an
exponent like -1<<30 that never finishes, even when the coefficient is 0.

Zero and values whose magnitude is far outside the float64 range now
return 0 or +/-Inf directly, matching what big.Rat.Float64 would give.

Fixes #226

* docs: explain the Float64 magnitude bounds
2026-10-04 09:29:49 +02:00
Mateusz Wos
e0621cba7b
fix: correctly round Pow results and speed up Pow (#439) 2026-10-04 00:39:46 +02:00
natan streppel
ca47408237
fix: ExpTaylor race condition (#414) 2026-08-19 23:07:36 +02:00
Charlie Tonneslan
3090cc487f
fix: NumDigits underreports for some exact powers of ten (#425)
math.Log10(1eN) rounds down to N-1 for several N (15, 24, 28, ...)
because the exact decimal can't survive a float64 round-trip. The
fast path returned int(math.Log10(...)) + 1, so a coefficient like
1000000000000000 (16 digits) came back as 15.

Count digits via int64 division for the IsInt64 branch. The slow
big.Int path is unchanged.

Regression tests cover 1e15 and -1e15 (both via plain literal and
scientific-notation input) and 1<<53 (the old fast-path boundary).

Fixes #420

Signed-off-by: Charlie Tonneslan <cst0520@gmail.com>
2026-06-29 11:58:29 +02:00
Mateusz Wos
400829b4bf
chore: rename AvoidScientificNotation to UseScientificNotation (#416) 2026-03-15 23:07:00 +01:00
Mateusz Wos
6540310a7d
Add support for omitzero struct tag (#415) 2026-03-08 23:42:36 +01:00
Joseph Watson
9620fb7d07
Add Spanner support for Encode and Decode (#395) 2026-02-13 16:18:44 +01:00
John Dupuy
e1e92bff93
TrimTrailingZeros and AvoidScientificNotation bool variables (#389)
* Added varible TrimTrailingZeros
* Scientific Notation support on serialization to honor negative precision scenarios

---------

Co-authored-by: vasilbekk <vasilbekk@mail.ru>
Co-authored-by: vasilbekk <70901384+vasilbekk@users.noreply.github.com>
2025-12-25 23:58:32 +01:00