Repository: govalues/decimal
Branch: main
Commit: 377e9df6035e
Files: 13
Total size: 469.1 KB
Directory structure:
gitextract_p60hrgcs/
├── .github/
│ └── workflows/
│ └── go.yml
├── .gitignore
├── .golangci.yml
├── CHANGELOG.md
├── LICENSE
├── README.md
├── decimal.go
├── decimal_test.go
├── doc.go
├── doc_test.go
├── go.mod
├── integer.go
└── integer_test.go
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/workflows/go.yml
================================================
on:
push:
branches: [main]
pull_request:
branches: [main]
name: decimal
jobs:
test:
strategy:
matrix:
go-version: [oldstable, stable]
os: [ubuntu-latest, windows-latest, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}
cache: false
- name: Check out code
uses: actions/checkout@v4
- name: Verify code formatting
run: gofmt -s -w . && git diff --exit-code
- name: Verify dependency consistency
run: go get -u -t . && go mod tidy && git diff --exit-code
- name: Verify generated code
run: go generate ./... && git diff --exit-code
- name: Verify potential issues
uses: golangci/golangci-lint-action@v6
- name: Run tests with coverage
run: go test -race -shuffle=on -coverprofile="coverage.txt" -covermode=atomic ./...
- name: Upload test coverage
if: matrix.os == 'ubuntu-latest' && matrix.go-version == 'stable'
uses: codecov/codecov-action@v4
fuzz:
needs: test
runs-on: ubuntu-latest
steps:
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: stable
cache: false
- name: Check out code
uses: actions/checkout@v4
- name: Run fuzzing for string parsing
run: go test -fuzztime 20s -fuzz ^FuzzParse$
- name: Run fuzzing from BSON unmarshaling
run: go test -fuzztime 20s -fuzz ^FuzzBSON$
- name: Run fuzzing for string conversion
run: go test -fuzztime 20s -fuzz ^FuzzDecimal_String_Parse$
- name: Run fuzzing for IEEE 754-2008 conversion
run: go test -fuzztime 20s -fuzz ^FuzzDecimal_IEEE_ParseIEEE$
- name: Run fuzzing for binary-text interoperability
run: go test -fuzztime 20s -fuzz ^FuzzDecimal_Binary_Text$
- name: Run fuzzing for text-binary interoperability
run: go test -fuzztime 20s -fuzz ^FuzzDecimal_Text_Binary$
- name: Run fuzzing for float64 conversion
run: go test -fuzztime 20s -fuzz ^FuzzDecimal_Float64_NewFromFloat64$
- name: Run fuzzing for int64 conversion
run: go test -fuzztime 20s -fuzz ^FuzzDecimal_Int64_NewFromInt64$
- name: Run fuzzing for addition
run: go test -fuzztime 20s -fuzz ^FuzzDecimal_Add$
- name: Run fuzzing for multiplication
run: go test -fuzztime 20s -fuzz ^FuzzDecimal_Mul$
- name: Run fuzzing for fused multiply-addition
run: go test -fuzztime 60s -fuzz ^FuzzDecimal_AddMul$
- name: Run fuzzing for fused multiply-addition
run: go test -fuzztime 20s -fuzz ^FuzzDecimal_Add_AddMul$
- name: Run fuzzing for fused multiply-addition
run: go test -fuzztime 20s -fuzz ^FuzzDecimal_Mul_AddMul$
- name: Run fuzzing for summation
run: go test -fuzztime 20s -fuzz ^FuzzDecimal_Add_Sum$
- name: Run fuzzing for product
run: go test -fuzztime 20s -fuzz ^FuzzDecimal_Mul_Prod$
- name: Run fuzzing for division
run: go test -fuzztime 20s -fuzz ^FuzzDecimal_Quo$
- name: Run fuzzing for fused quotient-addition
run: go test -fuzztime 60s -fuzz ^FuzzDecimal_AddQuo$
- name: Run fuzzing for fused quotient-addition
run: go test -fuzztime 20s -fuzz ^FuzzDecimal_Add_AddQuo$
- name: Run fuzzing for fused quotient-addition
run: go test -fuzztime 20s -fuzz ^FuzzDecimal_Quo_AddQuo$
- name: Run fuzzing for integer division and remainder
run: go test -fuzztime 20s -fuzz ^FuzzDecimal_QuoRem$
- name: Run fuzzing for square root and integer power
run: go test -fuzztime 20s -fuzz ^FuzzDecimal_Sqrt_PowInt$
- name: Run fuzzing for square root and power
run: go test -fuzztime 20s -fuzz ^FuzzDecimal_Pow_Sqrt$
- name: Run fuzzing for power and integer power
run: go test -fuzztime 20s -fuzz ^FuzzDecimal_Pow_PowInt$
- name: Run fuzzing for exponential and power
run: go test -fuzztime 20s -fuzz ^FuzzDecimal_Pow_Exp$
- name: Run fuzzing for exponential and logarithm
run: go test -fuzztime 20s -fuzz ^FuzzDecimalp_Log_Exp$
- name: Run fuzzing for shifted exponential and exponential
run: go test -fuzztime 20s -fuzz ^FuzzDecimal_Expm1_Exp$
- name: Run fuzzing for shifted logarithm and logarithm
run: go test -fuzztime 20s -fuzz ^FuzzDecimal_Log1p_Log$
- name: Run fuzzing for comparison
run: go test -fuzztime 20s -fuzz ^FuzzDecimal_Cmp$
- name: Run fuzzing for comparison and subtraction
run: go test -fuzztime 20s -fuzz ^FuzzDecimal_Sub_Cmp$
- name: Run fuzzing for constructor
run: go test -fuzztime 20s -fuzz ^FuzzDecimal_New$
- name: Run fuzzing for trimming
run: go test -fuzztime 20s -fuzz ^FuzzDecimal_Trim$
- name: Run fuzzing for padding
run: go test -fuzztime 20s -fuzz ^FuzzDecimal_Pad$
================================================
FILE: .gitignore
================================================
*.exe
*.exe~
*.dll
*.so
*.dylib
*.test
*.out
coverage.txt
================================================
FILE: .golangci.yml
================================================
run:
timeout: 5m
linters:
enable:
- errcheck
- gosimple
- goimports
- govet
- ineffassign
- godot
- gosec
- misspell
- stylecheck
- revive
- staticcheck
- typecheck
- unused
- gocyclo
================================================
FILE: CHANGELOG.md
================================================
# Changelog
## [0.1.36] - 2025-01-19
### Added
- Implemented `Decimal.AppendText`, `Decimal.AppendBinary`, `Decimal.Expm1`, `Decimal.Log1p`.
## [0.1.35] - 2025-01-12
### Added
- Implemented `Decimal.UnmarshalJSON`, `Decimal.MarshalJSON`, `Decimal.UnmarshalBSONValue`, `Decimal.MarshalBSONValue`.
## [0.1.34] - 2024-12-27
### Added
- Implemented `Mean`, `Decimal.Pow`, `Decimal.Log2`, `Decimal.Log10`.
### !!! Breaking Change !!!
Due to wrong behaviour of some database drivers, the following changes were made:
- `Decimal.MarshalBinary` produces the same output as `Decimal.MarshalText`.
- `Decimal.UnmarshalBinary` expects the same input as `Decimal.UnmarshalText`.
All BCD encoding related code was removed.
## [0.1.33] - 2024-11-16
### Added
- Implemented `Sum`, `Prod`.
## [0.1.32] - 2024-09-28
### Added
- Implemented `Decimal.Log`.
### Changed
- `Decimal.PowInt` always correctly rounds the result.
## [0.1.31] - 2024-08-30
### Added
- Implemented `Decimal.SubMul`, `Decimal.SubQuo`, `Decimal.Equal`, `Decimal.Less`.
## [0.1.30] - 2024-08-29
### Added
- Implemented `Decimal.AddMul`, `Decimal.AddQuo`, `Decimal.Exp`.
### Changed
- Bumped go version to 1.22.
- Deprecated `Decimal.FMA`.
## [0.1.29] - 2024-06-29
### Changed
- Improved `Decimal.Sqrt` and `Decimal.QuoRem` performance.
## [0.1.28] - 2024-06-22
### Added
- Implemented `Decimal.Sqrt`.
## [0.1.27] - 2024-05-19
### Changed
- `Decimal.Pad`, `Decimal.Rescale`, and `Descimal.Quantize` do not return errors anymore.
## [0.1.25] - 2024-05-17
### Added
- Implemented binary marshaling.
## [0.1.24] - 2024-05-05
### Changed
- Bumped go version to 1.21.
- Improved documentation.
## [0.1.23] - 2024-03-04
### Changed
- Improved documentation.
## [0.1.22] - 2024-01-11
### Changed
- Supported MySQL in `Decimal.Scan`.
- Added examples for XML marshaling.
## [0.1.21] - 2024-01-05
### Changed
- Optimized parsing performance for long strings.
- Improved documentation.
## [0.1.20] - 2024-01-01
### Changed
- Eliminated heap allocations in big.Int arithmetic.
- Improved documentation.
## [0.1.19] - 2023-12-18
### Changed
- Improved table formatting in documentation.
## [0.1.18] - 2023-12-18
### Changed
- Improved examples and documentation.
## [0.1.17] - 2023-12-01
### Added
- Implemented `Decimal.SameScale`.
### Changed
- Improved examples and documentation.
## [0.1.16] - 2023-11-21
### Changed
- Improved examples and documentation.
- Improved test coverage.
## [0.1.15] - 2023-10-31
### Changed
- Improved examples and documentation.
## [0.1.14] - 2023-10-13
### Changed
- Improved examples and documentation.
## [0.1.13] - 2023-10-10
### Added
- Implemented `NullDecimal` type.
## [0.1.12] - 2023-10-01
### Changed
- Improved accuracy of `Decimal.PowInt` for negative powers.
- Reviewed and improved documentation.
## [0.1.11] - 2023-09-21
### Added
- Implemented `Decimal.Clamp`.
### Changed
- Reviewed and improved documentation.
## [0.1.10] - 2023-09-09
### Added
- Implemented `Decimal.SubAbs`, `Decimal.CmpAbs`, `Decimal.Inv`.
- Added `Decimal.Pi`, `Decimal.E`, `Decimal.NegOne`, `Decimal.Two`, `Decimal.Thousand`.
### Changed
- Reviewed descriptions of rounding methods.
## [0.1.9] - 2023-08-27
### Changed
- Reviewed error descriptions.
## [0.1.8] - 2023-08-23
### Changed
- Improved accuracy of `Decimal.PowInt`.
## [0.1.7] - 2023-08-20
### Changed
- Enabled `gocyclo` linter.
## [0.1.6] - 2023-08-19
### Added
- Implemented `Decimal.Scan` and `Decimal.Value`.
### Changed
- `Decimal.CopySign` treats 0 as a positive.
- Enabled `gosec`, `godot`, and `stylecheck` linters.
## [0.1.5] - 2023-08-12
### Added
- Implemented `NewFromFloat64`.
- Added fuzzing job to continuous integration.
### Changed
- `NewFromInt64` can round to nearest if coefficient is too large.
## [0.1.4] - 2023-08-04
### Changed
- Implemented `NewFromInt64`.
## [0.1.3] - 2023-08-03
### Changed
- Implemented scale argument for `Decimal.Int64`.
## [0.1.2] - 2023-06-17
### Changed
- `Rescale`, `ParseExact`, `MulExact`, `AddExact`, `FMAExact`, and `QuoExact`
return error if scale is out of range.
## [0.1.1] - 2023-06-10
### Changed
- `New` returns error if scale is out of range.
## [0.1.0] - 2023-06-03
### Changed
- All methods now return errors, instead of panicking.
- Implemented `Decimal.Pad`.
- Renamed `Decimal.Round` to `Decimal.Rescale`.
- Renamed `Decimal.Reduce` to `Decimal.Trim`.
## [0.0.13] - 2023-04-22
### Fixed
- Testing on Windows.
## [0.0.12] - 2023-04-21
### Changed
- Testing on Windows and macOS.
- Improved documentation.
## [0.0.11] - 2023-04-15
### Added
- Implemented `Decimal.Int64`, `Decimal.Float64`.
### Changed
- Reviewed and improved documentation.
## [0.0.10] - 2023-04-13
### Changed
- Reviewed and improved documentation.
- Improved continuous integration.
## [0.0.9] - 2023-04-05
### Added
- Implemented `Decimal.One`, `Decimal.Zero`.
### Changed
- Reduced memory consumption.
- Renamed `Decimal.LessThanOne` to `Decimal.WithinOne`.
### Deleted
- Removed `Decimal.WithScale`.
## [0.0.8] - 2023-03-25
### Changed
- Simplified `Decimal.Quo`.
## [0.0.7] - 2023-03-22
### Added
- Implemented `Decimal.CopySign`.
## [0.0.6] - 2023-03-21
### Added
- Implemented `Decimal.ULP`.
## [0.0.5] - 2023-03-19
### Added
- Polish notation calculator example.
- Benchmarks statistics.
## [0.0.4] - 2023-03-19
### Fixed
- Fixed index out of range in `Parse`.
- Rounding error in `Decimal.Quo`.
## [0.0.3] - 2023-03-18
### Changed
- Removed errors from public API.
- Renamed `Decimal.Fma` to `Decimal.FMA`.
## [0.0.2] - 2023-03-13
### Added
- Implemented `Decimal.Fma`.
## [0.0.1] - 2023-02-28
### Added
- Initial version.
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2023 govalues
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# decimal
[![githubb]][github]
[![codecovb]][codecov]
[![goreportb]][goreport]
[![godocb]][godoc]
[![licenseb]][license]
[![versionb]][version]
[![awesomeb]][awesome]
Package decimal implements correctly rounded decimal floating-point numbers for Go.
This package is designed specifically for use in transactional financial systems.
## Key Features
- **BSON, JSON, XML, SQL** - Implements the necessary interfaces for direct compatibility
with the [mongo-driver/bson], [encoding/json], [encoding/xml], and [database/sql] packages.
- **No Heap Allocations** - Optimized to avoid heap allocations,
preventing garbage collector impact during arithmetic operations.
- **Correct Rounding** - For all methods, the result is the one that would
be obtained if the true mathematical value were rounded to 19 digits of
precision using the [half-to-even] rounding (a.k.a. "banker's rounding").
- **No Panics** - All methods are panic-free, returning errors instead of crashing
your application in cases such as overflow or division by zero.
- **Immutability** - Once set, a decimal remains constant,
ensuring safe concurrent access across goroutines.
- **Simple String Representation** - Decimals are represented in a straightforward
format avoiding the complexities of scientific or engineering notations.
- **Rigorous Testing** - All methods are cross-validated against
the [cockroachdb/apd] and [shopspring/decimal] packages through extensive [fuzz testing].
## Getting Started
### Installation
To add the decimal package to your Go workspace:
```bash
go get github.com/govalues/decimal
```
### Basic Usage
Create decimal values using one of the constructors.
After creating a decimal, you can perform various operations as shown below:
```go
package main
import (
"fmt"
"github.com/govalues/decimal"
)
func main() {
// Constructors
d, _ := decimal.New(8, 0) // d = 8
e, _ := decimal.Parse("12.5") // e = 12.5
f, _ := decimal.NewFromFloat64(2.567) // f = 2.567
g, _ := decimal.NewFromInt64(7, 896, 3) // g = 7.896
// Arithmetic operations
fmt.Println(d.Add(e)) // 8 + 12.5
fmt.Println(d.Sub(e)) // 8 - 12.5
fmt.Println(d.SubAbs(e)) // abs(8 - 12.5)
fmt.Println(d.Mul(e)) // 8 * 12.5
fmt.Println(d.AddMul(e, f)) // 8 + 12.5 * 2.567
fmt.Println(d.SubMul(e, f)) // 8 - 12.5 * 2.567
fmt.Println(d.PowInt(2)) // 8²
fmt.Println(d.Quo(e)) // 8 / 12.5
fmt.Println(d.AddQuo(e, f)) // 8 + 12.5 / 2.567
fmt.Println(d.SubQuo(e, f)) // 8 - 12.5 / 2.567
fmt.Println(d.QuoRem(e)) // 8 div 12.5, 8 mod 12.5
fmt.Println(d.Inv()) // 1 / 8
fmt.Println(decimal.Sum(d, e, f)) // 8 + 12.5 + 2.567
fmt.Println(decimal.Mean(d, e, f)) // (8 + 12.5 + 2.567) / 3
fmt.Println(decimal.Prod(d, e, f)) // 8 * 12.5 * 2.567
// Transcendental functions
fmt.Println(e.Sqrt()) // √12.5
fmt.Println(e.Exp()) // exp(12.5)
fmt.Println(e.Expm1()) // exp(12.5) - 1
fmt.Println(e.Log()) // ln(12.5)
fmt.Println(e.Log1p()) // ln(12.5 + 1)
fmt.Println(e.Log2()) // log₂(12.5)
fmt.Println(e.Log10()) // log₁₀(12.5)
fmt.Println(e.Pow(d)) // 12.5⁸
// Rounding to 2 decimal places
fmt.Println(g.Round(2)) // 7.90
fmt.Println(g.Ceil(2)) // 7.90
fmt.Println(g.Floor(2)) // 7.89
fmt.Println(g.Trunc(2)) // 7.89
// Conversions
fmt.Println(f.Int64(9)) // 2 567000000
fmt.Println(f.Float64()) // 2.567
fmt.Println(f.String()) // 2.567
// Formatting
fmt.Printf("%.2f", f) // 2.57
fmt.Printf("%.2k", f) // 256.70%
}
```
## Documentation
For detailed documentation and additional examples, visit the package
[documentation](https://pkg.go.dev/github.com/govalues/decimal#section-documentation).
For examples related to financial calculations, see the `money` package
[documentation](https://pkg.go.dev/github.com/govalues/money#section-documentation).
## Comparison
Comparison with other popular packages:
| Feature | govalues | [cockroachdb/apd] v3.2.1 | [shopspring/decimal] v1.4.0 |
| -------------------- | --------- | ------------------------ | --------------------------- |
| Correctly Rounded | Yes | No | No |
| Speed | High | Medium | Low[^reason] |
| Heap Allocations | No | Medium | High |
| Precision | 19 digits | Arbitrary | Arbitrary |
| Panic Free | Yes | Yes | No[^divzero] |
| Mutability | Immutable | Mutable[^reason] | Immutable |
| Mathematical Context | Implicit | Explicit | Implicit |
[^reason]: decimal package was created simply because [shopspring/decimal] was
too slow and [cockroachdb/apd] was mutable.
[^divzero]: [shopspring/decimal] panics on division by zero.
### Benchmarks
```text
goos: linux
goarch: amd64
pkg: github.com/govalues/decimal-tests
cpu: AMD Ryzen 7 3700C with Radeon Vega Mobile Gfx
```
| Test Case | Expression | govalues | [cockroachdb/apd] v3.2.1 | [shopspring/decimal] v1.4.0 | govalues vs cockroachdb | govalues vs shopspring |
| --------- | --------------------- | -------: | -----------------------: | --------------------------: | ----------------------: | ---------------------: |
| Add | 5 + 6 | 16.06n | 74.88n | 140.90n | +366.22% | +777.33% |
| Mul | 2 * 3 | 16.93n | 62.20n | 146.00n | +267.40% | +762.37% |
| Quo | 2 / 4 (exact) | 59.52n | 176.95n | 657.40n | +197.30% | +1004.50% |
| Quo | 2 / 3 (inexact) | 391.60n | 976.80n | 2962.50n | +149.39% | +656.42% |
| PowInt | 1.1^60 | 950.90n | 3302.50n | 4599.50n | +247.32% | +383.73% |
| PowInt | 1.01^600 | 3.45µ | 10.67µ | 18.67µ | +209.04% | +440.89% |
| PowInt | 1.001^6000 | 5.94µ | 20.50µ | 722.22µ | +244.88% | +12052.44% |
| Sqrt | √2 | 3.40µ | 4.96µ | 2101.86µ | +46.00% | +61755.71% |
| Exp | exp(0.5) | 8.35µ | 39.28µ | 20.06µ | +370.58% | +140.32% |
| Log | ln(0.5) | 54.89µ | 129.01µ | 151.55µ | +135.03% | +176.10% |
| Parse | 1 | 16.52n | 76.30n | 136.55n | +362.00% | +726.82% |
| Parse | 123.456 | 47.37n | 176.90n | 242.60n | +273.44% | +412.14% |
| Parse | 123456789.1234567890 | 85.49n | 224.15n | 497.95n | +162.19% | +482.47% |
| String | 1 | 5.11n | 19.57n | 198.25n | +283.21% | +3783.07% |
| String | 123.456 | 35.78n | 77.12n | 228.85n | +115.52% | +539.51% |
| String | 123456789.1234567890 | 70.72n | 239.10n | 337.25n | +238.12% | +376.91% |
| Telco | (see [specification]) | 137.00n | 969.40n | 3981.00n | +607.33% | +2804.78% |
The benchmark results shown in the table are provided for informational purposes only and may vary depending on your specific use case.
[codecov]: https://codecov.io/gh/govalues/decimal
[codecovb]: https://img.shields.io/codecov/c/github/govalues/decimal/main?color=brightcolor
[goreport]: https://goreportcard.com/report/github.com/govalues/decimal
[goreportb]: https://goreportcard.com/badge/github.com/govalues/decimal
[github]: https://github.com/govalues/decimal/actions/workflows/go.yml
[githubb]: https://img.shields.io/github/actions/workflow/status/govalues/decimal/go.yml
[godoc]: https://pkg.go.dev/github.com/govalues/decimal#section-documentation
[godocb]: https://img.shields.io/badge/go.dev-reference-blue
[version]: https://go.dev/dl
[versionb]: https://img.shields.io/github/go-mod/go-version/govalues/decimal?label=go
[license]: https://en.wikipedia.org/wiki/MIT_License
[licenseb]: https://img.shields.io/github/license/govalues/decimal?color=blue
[awesome]: https://github.com/avelino/awesome-go#financial
[awesomeb]: https://awesome.re/mentioned-badge.svg
[cockroachdb/apd]: https://pkg.go.dev/github.com/cockroachdb/apd
[shopspring/decimal]: https://pkg.go.dev/github.com/shopspring/decimal
[mongo-driver/bson]: https://pkg.go.dev/go.mongodb.org/mongo-driver/v2/bson#ValueUnmarshaler
[encoding/json]: https://pkg.go.dev/encoding/json#Unmarshaler
[encoding/xml]: https://pkg.go.dev/encoding#TextUnmarshaler
[database/sql]: https://pkg.go.dev/database/sql#Scanner
[specification]: https://speleotrove.com/decimal/telcoSpec.html
[fuzz testing]: https://github.com/govalues/decimal-tests
[half-to-even]: https://en.wikipedia.org/wiki/Rounding#Rounding_half_to_even
================================================
FILE: decimal.go
================================================
package decimal
import (
"database/sql/driver"
"errors"
"fmt"
"math"
"strconv"
"unsafe"
)
// Decimal represents a finite floating-point decimal number.
// Its zero value corresponds to the numeric value of 0.
// Decimal is designed to be safe for concurrent use by multiple goroutines.
type Decimal struct {
neg bool // indicates whether the decimal is negative
scale int8 // position of the floating decimal point
coef fint // numeric value without decimal point
}
const (
MaxPrec = 19 // MaxPrec is the maximum length of the coefficient in decimal digits.
MinScale = 0 // MinScale is the minimum number of digits after the decimal point.
MaxScale = 19 // MaxScale is the maximum number of digits after the decimal point.
maxCoef = maxFint // maxCoef is the maximum absolute value of the coefficient, which is equal to (10^MaxPrec - 1).
)
var (
NegOne = MustNew(-1, 0) // NegOne represents the decimal value of -1.
Zero = MustNew(0, 0) // Zero represents the decimal value of 0. For comparison purposes, use the IsZero method.
One = MustNew(1, 0) // One represents the decimal value of 1.
Two = MustNew(2, 0) // Two represents the decimal value of 2.
Ten = MustNew(10, 0) // Ten represents the decimal value of 10.
Hundred = MustNew(100, 0) // Hundred represents the decimal value of 100.
Thousand = MustNew(1_000, 0) // Thousand represents the decimal value of 1,000.
E = MustNew(2_718_281_828_459_045_235, 18) // E represents Euler’s number rounded to 18 digits.
Pi = MustNew(3_141_592_653_589_793_238, 18) // Pi represents the value of π rounded to 18 digits.
errDecimalOverflow = errors.New("decimal overflow")
errInvalidDecimal = errors.New("invalid decimal")
errScaleRange = errors.New("scale out of range")
errInvalidOperation = errors.New("invalid operation")
errInexactDivision = errors.New("inexact division")
errDivisionByZero = errors.New("division by zero")
)
// newUnsafe creates a new decimal without checking the scale and coefficient.
// Use it only if you are absolutely sure that the arguments are valid.
func newUnsafe(neg bool, coef fint, scale int) Decimal {
if coef == 0 {
neg = false
}
//nolint:gosec
return Decimal{neg: neg, coef: coef, scale: int8(scale)}
}
// newSafe creates a new decimal and checks the scale and coefficient.
func newSafe(neg bool, coef fint, scale int) (Decimal, error) {
switch {
case scale < MinScale || scale > MaxScale:
return Decimal{}, errScaleRange
case coef > maxCoef:
return Decimal{}, errDecimalOverflow
}
return newUnsafe(neg, coef, scale), nil
}
// newFromFint creates a new decimal from a uint64 coefficient.
// This method does not use overflowError to return descriptive errors,
// as it must be as fast as possible.
func newFromFint(neg bool, coef fint, scale, minScale int) (Decimal, error) {
var ok bool
// Scale normalization
switch {
case scale < minScale:
coef, ok = coef.lsh(minScale - scale)
if !ok {
return Decimal{}, errDecimalOverflow
}
scale = minScale
case scale > MaxScale:
coef = coef.rshHalfEven(scale - MaxScale)
scale = MaxScale
}
return newSafe(neg, coef, scale)
}
// newFromBint creates a new decimal from a *big.Int coefficient.
// This method uses overflowError to return descriptive errors.
func newFromBint(neg bool, coef *bint, scale, minScale int) (Decimal, error) {
// Overflow validation
prec := coef.prec()
if prec-scale > MaxPrec-minScale {
return Decimal{}, overflowError(prec, scale, minScale)
}
// Scale normalization
switch {
case scale < minScale:
coef.lsh(coef, minScale-scale)
scale = minScale
case scale >= prec && scale > MaxScale: // no integer part
coef.rshHalfEven(coef, scale-MaxScale)
scale = MaxScale
case prec > scale && prec > MaxPrec: // there is an integer part
coef.rshHalfEven(coef, prec-MaxPrec)
scale = MaxPrec - prec + scale
}
// Handling the rare case when rshHalfEven rounded
// a 19-digit coefficient to a 20-digit coefficient.
if coef.hasPrec(MaxPrec + 1) {
return newFromBint(neg, coef, scale, minScale)
}
return newSafe(neg, coef.fint(), scale)
}
func overflowError(gotPrec, gotScale, wantScale int) error {
maxDigits := MaxPrec - wantScale
gotDigits := gotPrec - gotScale
switch wantScale {
case 0:
return fmt.Errorf("%w: the integer part of a %T can have at most %v digits, but it has %v digits", errDecimalOverflow, Decimal{}, maxDigits, gotDigits)
default:
return fmt.Errorf("%w: with %v significant digits after the decimal point, the integer part of a %T can have at most %v digits, but it has %v digits", errDecimalOverflow, wantScale, Decimal{}, maxDigits, gotDigits)
}
}
func unknownOverflowError() error {
return fmt.Errorf("%w: the integer part of a %T can have at most %v digits, but it has significantly more digits", errDecimalOverflow, Decimal{}, MaxPrec)
}
// MustNew is like [New] but panics if the decimal cannot be constructed.
// It simplifies safe initialization of global variables holding decimals.
func MustNew(value int64, scale int) Decimal {
d, err := New(value, scale)
if err != nil {
panic(fmt.Sprintf("New(%v, %v) failed: %v", value, scale, err))
}
return d
}
// New returns a decimal equal to value / 10^scale.
// New keeps trailing zeros in the fractional part to preserve scale.
//
// New returns an error if the scale is negative or greater than [MaxScale].
func New(value int64, scale int) (Decimal, error) {
var coef fint
var neg bool
if value >= 0 {
neg = false
coef = fint(value)
} else {
neg = true
if value == math.MinInt64 {
coef = fint(math.MaxInt64) + 1
} else {
coef = fint(-value)
}
}
return newSafe(neg, coef, scale)
}
// NewFromInt64 converts a pair of integers, representing the whole and
// fractional parts, to a (possibly rounded) decimal equal to whole + frac / 10^scale.
// NewFromInt64 removes all trailing zeros from the fractional part.
// This method is useful for converting amounts from [protobuf] format.
// See also method [Decimal.Int64].
//
// NewFromInt64 returns an error if:
// - the whole and fractional parts have different signs;
// - the scale is negative or greater than [MaxScale];
// - frac / 10^scale is not within the range (-1, 1).
//
// [protobuf]: https://github.com/googleapis/googleapis/blob/master/google/type/money.proto
func NewFromInt64(whole, frac int64, scale int) (Decimal, error) {
// Whole
d, err := New(whole, 0)
if err != nil {
return Decimal{}, fmt.Errorf("converting integers: %w", err) // should never happen
}
// Fraction
f, err := New(frac, scale)
if err != nil {
return Decimal{}, fmt.Errorf("converting integers: %w", err)
}
if !f.IsZero() {
if !d.IsZero() && d.Sign() != f.Sign() {
return Decimal{}, fmt.Errorf("converting integers: inconsistent signs")
}
if !f.WithinOne() {
return Decimal{}, fmt.Errorf("converting integers: inconsistent fraction")
}
f = f.Trim(0)
d, err = d.Add(f)
if err != nil {
return Decimal{}, fmt.Errorf("converting integers: %w", err) // should never happen
}
}
return d, nil
}
// Int64 returns a pair of integers representing the whole and
// (possibly rounded) fractional parts of the decimal.
// If given scale is greater than the scale of the decimal, then the fractional part
// is zero-padded to the right.
// If given scale is smaller than the scale of the decimal, then the fractional part
// is rounded using [rounding half to even] (banker's rounding).
// The relationship between the decimal and the returned values can be expressed
// as d = whole + frac / 10^scale.
// This method is useful for converting amounts to [protobuf] format.
// See also constructor [NewFromInt64].
//
// If the result cannot be represented as a pair of int64 values,
// then false is returned.
//
// [rounding half to even]: https://en.wikipedia.org/wiki/Rounding#Rounding_half_to_even
// [protobuf]: https://github.com/googleapis/googleapis/blob/master/google/type/money.proto
func (d Decimal) Int64(scale int) (whole, frac int64, ok bool) {
if scale < MinScale || scale > MaxScale {
return 0, 0, false
}
x := d.coef
y := pow10[d.Scale()]
if scale < d.Scale() {
x = x.rshHalfEven(d.Scale() - scale)
y = pow10[scale]
}
q, r, ok := x.quoRem(y)
if !ok {
return 0, 0, false // Should never happen
}
if scale > d.Scale() {
r, ok = r.lsh(scale - d.Scale())
if !ok {
return 0, 0, false // Should never happen
}
}
if d.IsNeg() {
if q > -math.MinInt64 || r > -math.MinInt64 {
return 0, 0, false
}
//nolint:gosec
return -int64(q), -int64(r), true
}
if q > math.MaxInt64 || r > math.MaxInt64 {
return 0, 0, false
}
//nolint:gosec
return int64(q), int64(r), true
}
// NewFromFloat64 converts a float to a (possibly rounded) decimal.
// See also method [Decimal.Float64].
//
// NewFromFloat64 returns an error if:
// - the float is a special value (NaN or Inf);
// - the integer part of the result has more than [MaxPrec] digits.
func NewFromFloat64(f float64) (Decimal, error) {
// Float
if math.IsNaN(f) || math.IsInf(f, 0) {
return Decimal{}, fmt.Errorf("converting float: special value %v", f)
}
text := make([]byte, 0, 32)
text = strconv.AppendFloat(text, f, 'f', -1, 64)
// Decimal
d, err := parse(text)
if err != nil {
return Decimal{}, fmt.Errorf("converting float: %w", err)
}
return d, nil
}
// Float64 returns the nearest binary floating-point number rounded
// using [rounding half to even] (banker's rounding).
// See also constructor [NewFromFloat64].
//
// This conversion may lose data, as float64 has a smaller precision
// than the decimal type.
//
// [rounding half to even]: https://en.wikipedia.org/wiki/Rounding#Rounding_half_to_even
func (d Decimal) Float64() (f float64, ok bool) {
s := d.String()
f, err := strconv.ParseFloat(s, 64)
if err != nil {
return 0, false
}
return f, true
}
// MustParse is like [Parse] but panics if the string cannot be parsed.
// It simplifies safe initialization of global variables holding decimals.
func MustParse(s string) Decimal {
d, err := Parse(s)
if err != nil {
panic(fmt.Sprintf("Parse(%q) failed: %v", s, err))
}
return d
}
// Parse converts a string to a (possibly rounded) decimal.
// The input string must be in one of the following formats:
//
// 1.234
// -1234
// +0.000001234
// 1.83e5
// 0.22e-9
//
// The formal EBNF grammar for the supported format is as follows:
//
// sign ::= '+' | '-'
// digits ::= { '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' }
// significand ::= digits '.' digits | '.' digits | digits '.' | digits
// exponent ::= ('e' | 'E') [sign] digits
// numeric-string ::= [sign] significand [exponent]
//
// Parse removes leading zeros from the integer part of the input string,
// but tries to maintain trailing zeros in the fractional part to preserve scale.
//
// Parse returns an error if:
// - the string contains any whitespaces;
// - the string is longer than 330 bytes;
// - the exponent is less than -330 or greater than 330;
// - the string does not represent a valid decimal number;
// - the integer part of the result has more than [MaxPrec] digits.
func Parse(s string) (Decimal, error) {
text := unsafe.Slice(unsafe.StringData(s), len(s))
return parseExact(text, 0)
}
func parse(text []byte) (Decimal, error) {
return parseExact(text, 0)
}
// ParseExact is similar to [Parse], but it allows you to specify how many digits
// after the decimal point should be considered significant.
// If any of the significant digits are lost during rounding, the method will return an error.
// This method is useful for parsing monetary amounts, where the scale should be
// equal to or greater than the currency's scale.
func ParseExact(s string, scale int) (Decimal, error) {
text := unsafe.Slice(unsafe.StringData(s), len(s))
return parseExact(text, scale)
}
func parseExact(text []byte, scale int) (Decimal, error) {
if len(text) > 330 {
return Decimal{}, fmt.Errorf("parsing decimal: %w", errInvalidDecimal)
}
if scale < MinScale || scale > MaxScale {
return Decimal{}, fmt.Errorf("parsing decimal: %w", errScaleRange)
}
d, err := parseFint(text, scale)
if err != nil {
d, err = parseBint(text, scale)
if err != nil {
return Decimal{}, fmt.Errorf("parsing decimal: %w", err)
}
}
return d, nil
}
// parseFint parses a decimal string using uint64 arithmetic.
// parseFint does not support exponential notation to make it as fast as possible.
//
//nolint:gocyclo
func parseFint(text []byte, minScale int) (Decimal, error) {
var pos int
width := len(text)
// Sign
var neg bool
switch {
case pos == width:
// skip
case text[pos] == '-':
neg = true
pos++
case text[pos] == '+':
pos++
}
// Coefficient
var coef fint
var scale int
var hasCoef, ok bool
// Integer
for pos < width && text[pos] >= '0' && text[pos] <= '9' {
coef, ok = coef.fsa(1, text[pos]-'0')
if !ok {
return Decimal{}, errDecimalOverflow
}
pos++
hasCoef = true
}
// Fraction
if pos < width && text[pos] == '.' {
pos++
for pos < width && text[pos] >= '0' && text[pos] <= '9' {
coef, ok = coef.fsa(1, text[pos]-'0')
if !ok {
return Decimal{}, errDecimalOverflow
}
pos++
scale++
hasCoef = true
}
}
if pos != width {
return Decimal{}, fmt.Errorf("%w: unexpected character %q", errInvalidDecimal, text[pos])
}
if !hasCoef {
return Decimal{}, fmt.Errorf("%w: no coefficient", errInvalidDecimal)
}
return newFromFint(neg, coef, scale, minScale)
}
// parseBint parses a decimal string using *big.Int arithmetic.
// parseBint supports exponential notation.
//
//nolint:gocyclo
func parseBint(text []byte, minScale int) (Decimal, error) {
var pos int
width := len(text)
// Sign
var neg bool
switch {
case pos == width:
// skip
case text[pos] == '-':
neg = true
pos++
case text[pos] == '+':
pos++
}
// Coefficient
bcoef := getBint()
defer putBint(bcoef)
var fcoef fint
var shift, scale int
var hasCoef, ok bool
bcoef.setFint(0)
// Algorithm:
// 1. Add as many digits as possible to the uint64 coefficient (fast).
// 2. Once the uint64 coefficient has reached its maximum value,
// add it to the *big.Int coefficient (slow).
// 3. Repeat until all digits are processed.
// Integer
for pos < width && text[pos] >= '0' && text[pos] <= '9' {
fcoef, ok = fcoef.fsa(1, text[pos]-'0')
if !ok {
return Decimal{}, errDecimalOverflow // Should never happen
}
pos++
shift++
hasCoef = true
if fcoef.hasPrec(MaxPrec) {
bcoef.fsa(bcoef, shift, fcoef)
fcoef, shift = 0, 0
}
}
// Fraction
if pos < width && text[pos] == '.' {
pos++
for pos < width && text[pos] >= '0' && text[pos] <= '9' {
fcoef, ok = fcoef.fsa(1, text[pos]-'0')
if !ok {
return Decimal{}, errDecimalOverflow // Should never happen
}
pos++
scale++
shift++
hasCoef = true
if fcoef.hasPrec(MaxPrec) {
bcoef.fsa(bcoef, shift, fcoef)
fcoef, shift = 0, 0
}
}
}
if shift > 0 {
bcoef.fsa(bcoef, shift, fcoef)
}
// Exponent
var exp int
var eneg, hasExp, hasE bool
if pos < width && (text[pos] == 'e' || text[pos] == 'E') {
pos++
hasE = true
// Sign
switch {
case pos == width:
// skip
case text[pos] == '-':
eneg = true
pos++
case text[pos] == '+':
pos++
}
// Integer
for pos < width && text[pos] >= '0' && text[pos] <= '9' {
exp = exp*10 + int(text[pos]-'0')
if exp > 330 {
return Decimal{}, errInvalidDecimal
}
pos++
hasExp = true
}
}
if pos != width {
return Decimal{}, fmt.Errorf("%w: unexpected character %q", errInvalidDecimal, text[pos])
}
if !hasCoef {
return Decimal{}, fmt.Errorf("%w: no coefficient", errInvalidDecimal)
}
if hasE && !hasExp {
return Decimal{}, fmt.Errorf("%w: no exponent", errInvalidDecimal)
}
if eneg {
scale = scale + exp
} else {
scale = scale - exp
}
return newFromBint(neg, bcoef, scale, minScale)
}
// String implements the [fmt.Stringer] interface and returns
// a string representation of the decimal.
// The returned string does not use scientific or engineering notation and is
// formatted according to the following formal EBNF grammar:
//
// sign ::= '-'
// digits ::= { '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' }
// significand ::= digits '.' digits | digits
// numeric-string ::= [sign] significand
//
// See also method [Decimal.Format].
//
// [fmt.Stringer]: https://pkg.go.dev/fmt#Stringer
func (d Decimal) String() string {
return string(d.bytes())
}
// bytes returns a string representation of the decimal as a byte slice.
func (d Decimal) bytes() []byte {
text := make([]byte, 0, 24)
return d.append(text)
}
// append appends a string representation of the decimal to the byte slice.
func (d Decimal) append(text []byte) []byte {
var buf [24]byte
pos := len(buf) - 1
coef := d.Coef()
scale := d.Scale()
// Coefficient
for {
buf[pos] = byte(coef%10) + '0'
pos--
coef /= 10
if scale > 0 {
scale--
// Decimal point
if scale == 0 {
buf[pos] = '.'
pos--
// Leading 0
if coef == 0 {
buf[pos] = '0'
pos--
}
}
}
if coef == 0 && scale == 0 {
break
}
}
// Sign
if d.IsNeg() {
buf[pos] = '-'
pos--
}
return append(text, buf[pos+1:]...)
}
// UnmarshalJSON implements the [json.Unmarshaler] interface.
// UnmarshalJSON supports the following types: [number] and [numeric string].
// See also constructor [Parse].
//
// [number]: https://datatracker.ietf.org/doc/html/rfc8259#section-6
// [numeric string]: https://datatracker.ietf.org/doc/html/rfc8259#section-7
// [json.Unmarshaler]: https://pkg.go.dev/encoding/json#Unmarshaler
func (d *Decimal) UnmarshalJSON(data []byte) error {
if string(data) == "null" {
return nil
}
if len(data) >= 2 && data[0] == '"' && data[len(data)-1] == '"' {
data = data[1 : len(data)-1]
}
var err error
*d, err = parse(data)
if err != nil {
return fmt.Errorf("unmarshaling %T: %w", Decimal{}, err)
}
return nil
}
// MarshalJSON implements the [json.Marshaler] interface.
// MarshalJSON always returns a [numeric string].
// See also method [Decimal.String].
//
// [numeric string]: https://datatracker.ietf.org/doc/html/rfc8259#section-7
// [json.Marshaler]: https://pkg.go.dev/encoding/json#Marshaler
func (d Decimal) MarshalJSON() ([]byte, error) {
text := make([]byte, 0, 26)
text = append(text, '"')
text = d.append(text)
text = append(text, '"')
return text, nil
}
// UnmarshalText implements the [encoding.TextUnmarshaler] interface.
// UnmarshalText supports only numeric strings.
// See also constructor [Parse].
//
// [encoding.TextUnmarshaler]: https://pkg.go.dev/encoding#TextUnmarshaler
func (d *Decimal) UnmarshalText(text []byte) error {
var err error
*d, err = parse(text)
if err != nil {
return fmt.Errorf("unmarshaling %T: %w", Decimal{}, err)
}
return nil
}
// AppendText implements the [encoding.TextAppender] interface.
// AppendText always appends a numeric string.
// See also method [Decimal.String].
//
// [encoding.TextAppender]: https://pkg.go.dev/encoding#TextAppender
func (d Decimal) AppendText(text []byte) ([]byte, error) {
return d.append(text), nil
}
// MarshalText implements the [encoding.TextMarshaler] interface.
// MarshalText always returns a numeric string.
// See also method [Decimal.String].
//
// [encoding.TextMarshaler]: https://pkg.go.dev/encoding#TextMarshaler
func (d Decimal) MarshalText() ([]byte, error) {
return d.bytes(), nil
}
// UnmarshalBinary implements the [encoding.BinaryUnmarshaler] interface.
// UnmarshalBinary supports only numeric strings.
// See also constructor [Parse].
//
// [encoding.BinaryUnmarshaler]: https://pkg.go.dev/encoding#BinaryUnmarshaler
func (d *Decimal) UnmarshalBinary(data []byte) error {
var err error
*d, err = parse(data)
if err != nil {
return fmt.Errorf("unmarshaling %T: %w", Decimal{}, err)
}
return nil
}
// AppendBinary implements the [encoding.BinaryAppender] interface.
// AppendBinary always appends a numeric string.
// See also method [Decimal.String].
//
// [encoding.BinaryAppender]: https://pkg.go.dev/encoding#BinaryAppender
func (d Decimal) AppendBinary(data []byte) ([]byte, error) {
return d.append(data), nil
}
// MarshalBinary implements the [encoding.BinaryMarshaler] interface.
// MarshalBinary always returns a numeric string.
// See also method [Decimal.String].
//
// [encoding.BinaryMarshaler]: https://pkg.go.dev/encoding#BinaryMarshaler
func (d Decimal) MarshalBinary() ([]byte, error) {
return d.bytes(), nil
}
// UnmarshalBSONValue implements the [v2/bson.ValueUnmarshaler] interface.
// UnmarshalBSONValue supports the following [types]: Double, String, 32-bit Integer, 64-bit Integer, and [Decimal128].
//
// [v2/bson.ValueUnmarshaler]: https://pkg.go.dev/go.mongodb.org/mongo-driver/v2/bson#ValueUnmarshaler
// [types]: https://bsonspec.org/spec.html
// [Decimal128]: https://github.com/mongodb/specifications/blob/master/source/bson-decimal128/decimal128.md
func (d *Decimal) UnmarshalBSONValue(typ byte, data []byte) error {
// constants are from https://bsonspec.org/spec.html
var err error
switch typ {
case 1:
*d, err = parseBSONFloat64(data)
case 2:
*d, err = parseBSONString(data)
case 10:
// null, do nothing
case 16:
*d, err = parseBSONInt32(data)
case 18:
*d, err = parseBSONInt64(data)
case 19:
*d, err = parseIEEEDecimal128(data)
default:
err = fmt.Errorf("BSON type %d is not supported", typ)
}
if err != nil {
err = fmt.Errorf("converting from BSON type %d to %T: %w", typ, Decimal{}, err)
}
return err
}
// MarshalBSONValue implements the [v2/bson.ValueMarshaler] interface.
// MarshalBSONValue always returns [Decimal128].
//
// [v2/bson.ValueMarshaler]: https://pkg.go.dev/go.mongodb.org/mongo-driver/v2/bson#ValueMarshaler
// [Decimal128]: https://github.com/mongodb/specifications/blob/master/source/bson-decimal128/decimal128.md
func (d Decimal) MarshalBSONValue() (typ byte, data []byte, err error) {
return 19, d.ieeeDecimal128(), nil
}
// parseBSONInt32 parses a BSON int32 to a decimal.
// The byte order of the input data must be little-endian.
func parseBSONInt32(data []byte) (Decimal, error) {
if len(data) != 4 {
return Decimal{}, fmt.Errorf("%w: invalid data length %v", errInvalidDecimal, len(data))
}
u := uint32(data[0])
u |= uint32(data[1]) << 8
u |= uint32(data[2]) << 16
u |= uint32(data[3]) << 24
i := int64(int32(u)) //nolint:gosec
return New(i, 0)
}
// parseBSONInt64 parses a BSON int64 to a decimal.
// The byte order of the input data must be little-endian.
func parseBSONInt64(data []byte) (Decimal, error) {
if len(data) != 8 {
return Decimal{}, fmt.Errorf("%w: invalid data length %v", errInvalidDecimal, len(data))
}
u := uint64(data[0])
u |= uint64(data[1]) << 8
u |= uint64(data[2]) << 16
u |= uint64(data[3]) << 24
u |= uint64(data[4]) << 32
u |= uint64(data[5]) << 40
u |= uint64(data[6]) << 48
u |= uint64(data[7]) << 56
i := int64(u) //nolint:gosec
return New(i, 0)
}
// parseBSONFloat64 parses a BSON float64 to a (possibly rounded) decimal.
// The byte order of the input data must be little-endian.
func parseBSONFloat64(data []byte) (Decimal, error) {
if len(data) != 8 {
return Decimal{}, fmt.Errorf("%w: invalid data length %v", errInvalidDecimal, len(data))
}
u := uint64(data[0])
u |= uint64(data[1]) << 8
u |= uint64(data[2]) << 16
u |= uint64(data[3]) << 24
u |= uint64(data[4]) << 32
u |= uint64(data[5]) << 40
u |= uint64(data[6]) << 48
u |= uint64(data[7]) << 56
f := math.Float64frombits(u)
return NewFromFloat64(f)
}
// parseBSONString parses a BSON string to a (possibly rounded) decimal.
// The byte order of the input data must be little-endian.
func parseBSONString(data []byte) (Decimal, error) {
if len(data) < 4 {
return Decimal{}, fmt.Errorf("%w: invalid data length %v", errInvalidDecimal, len(data))
}
u := uint32(data[0])
u |= uint32(data[1]) << 8
u |= uint32(data[2]) << 16
u |= uint32(data[3]) << 24
l := int(int32(u)) //nolint:gosec
if l < 1 || l > 330 || len(data) < l+4 {
return Decimal{}, fmt.Errorf("%w: invalid string length %v", errInvalidDecimal, l)
}
if data[l+4-1] != 0 {
return Decimal{}, fmt.Errorf("%w: invalid null terminator %v", errInvalidDecimal, data[l+4-1])
}
s := string(data[4 : l+4-1])
return Parse(s)
}
// parseIEEEDecimal128 converts a 128-bit IEEE 754-2008 decimal
// floating point with binary integer decimal encoding to
// a (possibly rounded) decimal.
// The byte order of the input data must be little-endian.
//
// parseIEEEDecimal128 returns an error if:
// - the data length is not equal to 16 bytes;
// - the decimal a special value (NaN or Inf);
// - the integer part of the result has more than [MaxPrec] digits.
func parseIEEEDecimal128(data []byte) (Decimal, error) {
if len(data) != 16 {
return Decimal{}, fmt.Errorf("%w: invalid data length %v", errInvalidDecimal, len(data))
}
if data[15]&0b0111_1100 == 0b0111_1100 {
return Decimal{}, fmt.Errorf("%w: special value NaN", errInvalidDecimal)
}
if data[15]&0b0111_1100 == 0b0111_1000 {
return Decimal{}, fmt.Errorf("%w: special value Inf", errInvalidDecimal)
}
if data[15]&0b0110_0000 == 0b0110_0000 {
return Decimal{}, fmt.Errorf("%w: unsupported encoding", errInvalidDecimal)
}
// Sign
neg := data[15]&0b1000_0000 == 0b1000_0000
// Scale
var scale int
scale |= int(data[14]) >> 1
scale |= int(data[15]&0b0111_1111) << 7
scale = 6176 - scale
// TODO fint optimization
// Coefficient
coef := getBint()
defer putBint(coef)
buf := make([]byte, 15)
for i := range 15 {
buf[i] = data[14-i]
}
buf[0] &= 0b0000_0001
coef.setBytes(buf)
// Scale normalization
if coef.sign() == 0 {
scale = max(scale, MinScale)
}
return newFromBint(neg, coef, scale, 0)
}
// ieeeDecimal128 returns a 128-bit IEEE 754-2008 decimal
// floating point with binary integer decimal encoding.
// The byte order of the result is little-endian.
func (d Decimal) ieeeDecimal128() []byte {
var buf [16]byte
scale := d.Scale()
coef := d.Coef()
// Sign
if d.IsNeg() {
buf[15] = 0b1000_0000
}
// Scale
scale = 6176 - scale
buf[15] |= byte((scale >> 7) & 0b0111_1111)
buf[14] |= byte((scale << 1) & 0b1111_1110)
// Coefficient
for i := range 8 {
buf[i] = byte(coef & 0b1111_1111)
coef >>= 8
}
return buf[:]
}
// Scan implements the [sql.Scanner] interface.
//
// [sql.Scanner]: https://pkg.go.dev/database/sql#Scanner
func (d *Decimal) Scan(value any) error {
var err error
switch value := value.(type) {
case string:
*d, err = Parse(value)
case int64:
*d, err = New(value, 0)
case float64:
*d, err = NewFromFloat64(value)
case []byte:
// Special case: MySQL driver sends DECIMAL as []byte
*d, err = parse(value)
case float32:
// Special case: MySQL driver sends FLOAT as float32
*d, err = NewFromFloat64(float64(value))
case uint64:
// Special case: ClickHouse driver sends 0 as uint64
*d, err = newSafe(false, fint(value), 0)
case nil:
err = fmt.Errorf("%T does not support null values, use %T or *%T", Decimal{}, NullDecimal{}, Decimal{})
default:
err = fmt.Errorf("type %T is not supported", value)
}
if err != nil {
err = fmt.Errorf("converting from %T to %T: %w", value, Decimal{}, err)
}
return err
}
// Value implements the [driver.Valuer] interface.
//
// [driver.Valuer]: https://pkg.go.dev/database/sql/driver#Valuer
func (d Decimal) Value() (driver.Value, error) {
return d.String(), nil
}
// Format implements the [fmt.Formatter] interface.
// The following [format verbs] are available:
//
// | Verb | Example | Description |
// | ---------- | ------- | -------------- |
// | %f, %s, %v | 5.67 | Decimal |
// | %q | "5.67" | Quoted decimal |
// | %k | 567% | Percentage |
//
// The following format flags can be used with all verbs: '+', ' ', '0', '-'.
//
// Precision is only supported for %f and %k verbs.
// For %f verb, the default precision is equal to the actual scale of the decimal,
// whereas, for verb %k the default precision is the actual scale of the decimal minus 2.
//
// [format verbs]: https://pkg.go.dev/fmt#hdr-Printing
// [fmt.Formatter]: https://pkg.go.dev/fmt#Formatter
//
//nolint:gocyclo
func (d Decimal) Format(state fmt.State, verb rune) {
var err error
// Percentage multiplier
if verb == 'k' || verb == 'K' {
d, err = d.Mul(Hundred)
if err != nil {
// This panic is handled inside the fmt package.
panic(fmt.Errorf("formatting percent: %w", err))
}
}
// Rescaling
var tzeros int
if verb == 'f' || verb == 'F' || verb == 'k' || verb == 'K' {
var scale int
switch p, ok := state.Precision(); {
case ok:
scale = p
case verb == 'k' || verb == 'K':
scale = d.Scale() - 2
case verb == 'f' || verb == 'F':
scale = d.Scale()
}
scale = max(scale, MinScale)
switch {
case scale < d.Scale():
d = d.Round(scale)
case scale > d.Scale():
tzeros = scale - d.Scale()
}
}
// Integer and fractional digits
var intdigs int
fracdigs := d.Scale()
if dprec := d.Prec(); dprec > fracdigs {
intdigs = dprec - fracdigs
}
if d.WithinOne() {
intdigs++ // leading 0
}
// Decimal point
var dpoint int
if fracdigs > 0 || tzeros > 0 {
dpoint = 1
}
// Arithmetic sign
var rsign int
if d.IsNeg() || state.Flag('+') || state.Flag(' ') {
rsign = 1
}
// Percentage sign
var psign int
if verb == 'k' || verb == 'K' {
psign = 1
}
// Openning and closing quotes
var lquote, tquote int
if verb == 'q' || verb == 'Q' {
lquote, tquote = 1, 1
}
// Calculating padding
width := lquote + rsign + intdigs + dpoint + fracdigs + tzeros + psign + tquote
var lspaces, tspaces, lzeros int
if w, ok := state.Width(); ok && w > width {
switch {
case state.Flag('-'):
tspaces = w - width
case state.Flag('0'):
lzeros = w - width
default:
lspaces = w - width
}
width = w
}
buf := make([]byte, width)
pos := width - 1
// Trailing spaces
for range tspaces {
buf[pos] = ' '
pos--
}
// Closing quote
for range tquote {
buf[pos] = '"'
pos--
}
// Percentage sign
for range psign {
buf[pos] = '%'
pos--
}
// Trailing zeros
for range tzeros {
buf[pos] = '0'
pos--
}
// Fractional digits
dcoef := d.Coef()
for range fracdigs {
buf[pos] = byte(dcoef%10) + '0'
pos--
dcoef /= 10
}
// Decimal point
for range dpoint {
buf[pos] = '.'
pos--
}
// Integer digits
for range intdigs {
buf[pos] = byte(dcoef%10) + '0'
pos--
dcoef /= 10
}
// Leading zeros
for range lzeros {
buf[pos] = '0'
pos--
}
// Arithmetic sign
for range rsign {
if d.IsNeg() {
buf[pos] = '-'
} else if state.Flag(' ') {
buf[pos] = ' '
} else {
buf[pos] = '+'
}
pos--
}
// Opening quote
for range lquote {
buf[pos] = '"'
pos--
}
// Leading spaces
for range lspaces {
buf[pos] = ' '
pos--
}
// Writing result
//nolint:errcheck
switch verb {
case 'q', 'Q', 's', 'S', 'v', 'V', 'f', 'F', 'k', 'K':
state.Write(buf)
default:
state.Write([]byte("%!"))
state.Write([]byte{byte(verb)})
state.Write([]byte("(decimal.Decimal="))
state.Write(buf)
state.Write([]byte(")"))
}
}
// Zero returns a decimal with a value of 0, having the same scale as decimal d.
// See also methods [Decimal.One], [Decimal.ULP].
func (d Decimal) Zero() Decimal {
return newUnsafe(false, 0, d.Scale())
}
// One returns a decimal with a value of 1, having the same scale as decimal d.
// See also methods [Decimal.Zero], [Decimal.ULP].
func (d Decimal) One() Decimal {
return newUnsafe(false, pow10[d.Scale()], d.Scale())
}
// ULP (Unit in the Last Place) returns the smallest representable positive
// difference between two decimals with the same scale as decimal d.
// It can be useful for implementing rounding and comparison algorithms.
// See also methods [Decimal.Zero], [Decimal.One].
func (d Decimal) ULP() Decimal {
return newUnsafe(false, 1, d.Scale())
}
// Prec returns the number of digits in the coefficient.
// See also method [Decimal.Coef].
func (d Decimal) Prec() int {
return d.coef.prec()
}
// Coef returns the coefficient of the decimal.
// See also method [Decimal.Prec].
func (d Decimal) Coef() uint64 {
return uint64(d.coef)
}
// Scale returns the number of digits after the decimal point.
// See also methods [Decimal.Prec], [Decimal.MinScale].
func (d Decimal) Scale() int {
return int(d.scale)
}
// MinScale returns the smallest scale that the decimal can be rescaled to
// without rounding.
// See also method [Decimal.Trim].
func (d Decimal) MinScale() int {
// Special case: zero
if d.IsZero() {
return MinScale
}
// General case
dcoef := d.coef
return max(MinScale, d.Scale()-dcoef.ntz())
}
// IsInt returns true if there are no significant digits after the decimal point.
func (d Decimal) IsInt() bool {
return d.Scale() == 0 || d.coef%pow10[d.Scale()] == 0
}
// IsOne returns:
//
// true if d = -1 or d = 1
// false otherwise
func (d Decimal) IsOne() bool {
return d.coef == pow10[d.Scale()]
}
// WithinOne returns:
//
// true if -1 < d < 1
// false otherwise
func (d Decimal) WithinOne() bool {
return d.coef < pow10[d.Scale()]
}
// Round returns a decimal rounded to the specified number of digits after
// the decimal point using [rounding half to even] (banker's rounding).
// If the given scale is negative, it is redefined to zero.
// For financial calculations, the scale should be equal to or greater than
// the scale of the currency.
// See also method [Decimal.Rescale].
//
// [rounding half to even]: https://en.wikipedia.org/wiki/Rounding#Rounding_half_to_even
func (d Decimal) Round(scale int) Decimal {
scale = max(scale, MinScale)
if scale >= d.Scale() {
return d
}
coef := d.coef
coef = coef.rshHalfEven(d.Scale() - scale)
return newUnsafe(d.IsNeg(), coef, scale)
}
// Pad returns a decimal zero-padded to the specified number of digits after
// the decimal point.
// The total number of digits in the result is limited by [MaxPrec].
// See also method [Decimal.Trim].
func (d Decimal) Pad(scale int) Decimal {
scale = min(scale, MaxScale, MaxPrec-d.Prec()+d.Scale())
if scale <= d.Scale() {
return d
}
coef := d.coef
coef, ok := coef.lsh(scale - d.Scale())
if !ok {
return d // Should never happen
}
return newUnsafe(d.IsNeg(), coef, scale)
}
// Rescale returns a decimal rounded or zero-padded to the given number of digits
// after the decimal point.
// If the given scale is negative, it is redefined to zero.
// For financial calculations, the scale should be equal to or greater than
// the scale of the currency.
// See also methods [Decimal.Round], [Decimal.Pad].
func (d Decimal) Rescale(scale int) Decimal {
if scale > d.Scale() {
return d.Pad(scale)
}
return d.Round(scale)
}
// Quantize returns a decimal rescaled to the same scale as decimal e.
// The sign and the coefficient of decimal e are ignored.
// See also methods [Decimal.SameScale] and [Decimal.Rescale].
func (d Decimal) Quantize(e Decimal) Decimal {
return d.Rescale(e.Scale())
}
// SameScale returns true if decimals have the same scale.
// See also methods [Decimal.Scale], [Decimal.Quantize].
func (d Decimal) SameScale(e Decimal) bool {
return d.Scale() == e.Scale()
}
// Trunc returns a decimal truncated to the specified number of digits
// after the decimal point using [rounding toward zero].
// If the given scale is negative, it is redefined to zero.
// For financial calculations, the scale should be equal to or greater than
// the scale of the currency.
//
// [rounding toward zero]: https://en.wikipedia.org/wiki/Rounding#Rounding_toward_zero
func (d Decimal) Trunc(scale int) Decimal {
scale = max(scale, MinScale)
if scale >= d.Scale() {
return d
}
coef := d.coef
coef = coef.rshDown(d.Scale() - scale)
return newUnsafe(d.IsNeg(), coef, scale)
}
// Trim returns a decimal with trailing zeros removed up to the given number of
// digits after the decimal point.
// If the given scale is negative, it is redefined to zero.
// See also method [Decimal.Pad].
func (d Decimal) Trim(scale int) Decimal {
if d.Scale() <= scale {
return d
}
scale = max(scale, d.MinScale())
return d.Trunc(scale)
}
// Ceil returns a decimal rounded up to the given number of digits
// after the decimal point using [rounding toward positive infinity].
// If the given scale is negative, it is redefined to zero.
// For financial calculations, the scale should be equal to or greater than
// the scale of the currency.
// See also method [Decimal.Floor].
//
// [rounding toward positive infinity]: https://en.wikipedia.org/wiki/Rounding#Rounding_up
func (d Decimal) Ceil(scale int) Decimal {
scale = max(scale, MinScale)
if scale >= d.Scale() {
return d
}
coef := d.coef
if d.IsNeg() {
coef = coef.rshDown(d.Scale() - scale)
} else {
coef = coef.rshUp(d.Scale() - scale)
}
return newUnsafe(d.IsNeg(), coef, scale)
}
// Floor returns a decimal rounded down to the specified number of digits
// after the decimal point using [rounding toward negative infinity].
// If the given scale is negative, it is redefined to zero.
// For financial calculations, the scale should be equal to or greater than
// the scale of the currency.
// See also method [Decimal.Ceil].
//
// [rounding toward negative infinity]: https://en.wikipedia.org/wiki/Rounding#Rounding_down
func (d Decimal) Floor(scale int) Decimal {
scale = max(scale, MinScale)
if scale >= d.Scale() {
return d
}
coef := d.coef
if d.IsNeg() {
coef = coef.rshUp(d.Scale() - scale)
} else {
coef = coef.rshDown(d.Scale() - scale)
}
return newUnsafe(d.IsNeg(), coef, scale)
}
// Neg returns a decimal with the opposite sign.
func (d Decimal) Neg() Decimal {
return newUnsafe(!d.IsNeg(), d.coef, d.Scale())
}
// Abs returns the absolute value of the decimal.
func (d Decimal) Abs() Decimal {
return newUnsafe(false, d.coef, d.Scale())
}
// CopySign returns a decimal with the same sign as decimal e.
// CopySign treates 0 as positive.
// See also method [Decimal.Sign].
func (d Decimal) CopySign(e Decimal) Decimal {
if d.IsNeg() == e.IsNeg() {
return d
}
return d.Neg()
}
// Sign returns:
//
// -1 if d < 0
// 0 if d = 0
// +1 if d > 0
//
// See also methods [Decimal.IsPos], [Decimal.IsNeg], [Decimal.IsZero].
func (d Decimal) Sign() int {
switch {
case d.neg:
return -1
case d.coef == 0:
return 0
}
return 1
}
// IsPos returns:
//
// true if d > 0
// false otherwise
func (d Decimal) IsPos() bool {
return d.coef != 0 && !d.neg
}
// IsNeg returns:
//
// true if d < 0
// false otherwise
func (d Decimal) IsNeg() bool {
return d.neg
}
// IsZero returns:
//
// true if d = 0
// false otherwise
func (d Decimal) IsZero() bool {
return d.coef == 0
}
// Prod returns the (possibly rounded) product of decimals.
// It computes d1 * d2 * ... * dn with at least double precision
// during the intermediate rounding.
//
// Prod returns an error if:
// - no arguments are provided;
// - the integer part of the result has more than [MaxPrec] digits.
func Prod(d ...Decimal) (Decimal, error) {
// Special cases
switch len(d) {
case 0:
return Decimal{}, fmt.Errorf("computing [prod([])]: %w", errInvalidOperation)
case 1:
return d[0], nil
}
// General case
e, err := prodFint(d...)
if err != nil {
e, err = prodBint(d...)
if err != nil {
return Decimal{}, fmt.Errorf("computing [prod(%v)]: %w", d, err)
}
}
return e, nil
}
// prodFint computes the product of decimals using uint64 arithmetic.
func prodFint(d ...Decimal) (Decimal, error) {
ecoef := One.coef
escale := One.Scale()
eneg := One.IsNeg()
for _, f := range d {
fcoef := f.coef
// Compute e = e * f
var ok bool
ecoef, ok = ecoef.mul(fcoef)
if !ok {
return Decimal{}, errDecimalOverflow
}
eneg = eneg != f.IsNeg()
escale = escale + f.Scale()
}
return newFromFint(eneg, ecoef, escale, 0)
}
// prodBint computes the product of decimals using *big.Int arithmetic.
func prodBint(d ...Decimal) (Decimal, error) {
ecoef := getBint()
defer putBint(ecoef)
fcoef := getBint()
defer putBint(fcoef)
ecoef.setFint(One.coef)
escale := One.Scale()
eneg := One.IsNeg()
for _, f := range d {
fcoef.setFint(f.coef)
// Compute e = e * f
ecoef.mul(ecoef, fcoef)
eneg = eneg != f.IsNeg()
escale = escale + f.Scale()
// Intermediate truncation
if escale > bscale {
ecoef.rshDown(ecoef, escale-bscale)
escale = bscale
}
// Check if e >= 10^59
if ecoef.hasPrec(len(bpow10)) {
return Decimal{}, unknownOverflowError()
}
}
return newFromBint(eneg, ecoef, escale, 0)
}
// Mean returns the (possibly rounded) mean of decimals.
// It computes (d1 + d2 + ... + dn) / n with at least double precision
// during the intermediate rounding.
//
// Mean returns an error if:
// - no arguments are provided;
// - the integer part of the result has more than [MaxPrec] digits.
func Mean(d ...Decimal) (Decimal, error) {
// Special cases
switch len(d) {
case 0:
return Decimal{}, fmt.Errorf("computing [mean([])]: %w", errInvalidOperation)
case 1:
return d[0], nil
}
// General case
e, err := meanFint(d...)
if err != nil {
e, err = meanBint(d...)
if err != nil {
return Decimal{}, fmt.Errorf("computing [mean(%v)]: %w", d, err)
}
}
// Preferred scale
scale := 0
for _, f := range d {
scale = max(scale, f.Scale())
}
e = e.Trim(scale)
return e, nil
}
// meanFint computes the mean of decimals using uint64 arithmetic.
func meanFint(d ...Decimal) (Decimal, error) {
ecoef := Zero.coef
escale := Zero.Scale()
eneg := Zero.IsNeg()
ncoef := fint(len(d))
for _, f := range d {
fcoef := f.coef
// Alignment
var ok bool
switch {
case escale > f.Scale():
fcoef, ok = fcoef.lsh(escale - f.Scale())
if !ok {
return Decimal{}, errDecimalOverflow
}
case escale < f.Scale():
ecoef, ok = ecoef.lsh(f.Scale() - escale)
if !ok {
return Decimal{}, errDecimalOverflow
}
escale = f.Scale()
}
// Compute e = e + f
if eneg == f.IsNeg() {
ecoef, ok = ecoef.add(fcoef)
if !ok {
return Decimal{}, errDecimalOverflow
}
} else {
if fcoef > ecoef {
eneg = f.IsNeg()
}
ecoef = ecoef.subAbs(fcoef)
}
}
// Alignment
var ok bool
if shift := MaxPrec - ecoef.prec(); shift > 0 {
ecoef, ok = ecoef.lsh(shift)
if !ok {
return Decimal{}, errDecimalOverflow // Should never happen
}
escale = escale + shift
}
// Compute e = e / n
ecoef, ok = ecoef.quo(ncoef)
if !ok {
return Decimal{}, errInexactDivision
}
return newFromFint(eneg, ecoef, escale, 0)
}
// meanBint computes the mean of decimals using *big.Int arithmetic.
func meanBint(d ...Decimal) (Decimal, error) {
ecoef := getBint()
defer putBint(ecoef)
fcoef := getBint()
defer putBint(fcoef)
ncoef := getBint()
defer putBint(ncoef)
ecoef.setFint(Zero.coef)
escale := Zero.Scale()
eneg := Zero.IsNeg()
ncoef.setInt64(int64(len(d)))
for _, f := range d {
fcoef.setFint(f.coef)
// Alignment
switch {
case escale > f.Scale():
fcoef.lsh(fcoef, escale-f.Scale())
case escale < f.Scale():
ecoef.lsh(ecoef, f.Scale()-escale)
escale = f.Scale()
}
// Compute e = e + f
if eneg == f.IsNeg() {
ecoef.add(ecoef, fcoef)
} else {
if fcoef.cmp(ecoef) > 0 {
eneg = f.IsNeg()
}
ecoef.subAbs(ecoef, fcoef)
}
}
// Alignment
ecoef.lsh(ecoef, bscale-escale)
// Compute e = e / n
ecoef.quo(ecoef, ncoef)
return newFromBint(eneg, ecoef, bscale, 0)
}
// Mul returns the (possibly rounded) product of decimals d and e.
//
// Mul returns an overflow error if the integer part of the result has
// more than [MaxPrec] digits.
func (d Decimal) Mul(e Decimal) (Decimal, error) {
return d.MulExact(e, 0)
}
// MulExact is similar to [Decimal.Mul], but it allows you to specify the number
// of digits after the decimal point that should be considered significant.
// If any of the significant digits are lost during rounding, the method will
// return an overflow error.
// This method is useful for financial calculations where the scale should be
// equal to or greater than the currency's scale.
func (d Decimal) MulExact(e Decimal, scale int) (Decimal, error) {
if scale < MinScale || scale > MaxScale {
return Decimal{}, fmt.Errorf("computing [%v * %v]: %w", d, e, errScaleRange)
}
// General case
f, err := d.mulFint(e, scale)
if err != nil {
f, err = d.mulBint(e, scale)
if err != nil {
return Decimal{}, fmt.Errorf("computing [%v * %v]: %w", d, e, err)
}
}
return f, nil
}
// mulFint computes the product of two decimals using uint64 arithmetic.
func (d Decimal) mulFint(e Decimal, minScale int) (Decimal, error) {
dcoef := d.coef
dscale := d.Scale()
dneg := d.IsNeg()
ecoef := e.coef
// Compute d = d * e
dcoef, ok := dcoef.mul(ecoef)
if !ok {
return Decimal{}, errDecimalOverflow
}
dscale = dscale + e.Scale()
dneg = dneg != e.IsNeg()
return newFromFint(dneg, dcoef, dscale, minScale)
}
// mulBint computes the product of two decimals using *big.Int arithmetic.
func (d Decimal) mulBint(e Decimal, minScale int) (Decimal, error) {
dcoef := getBint()
defer putBint(dcoef)
ecoef := getBint()
defer putBint(ecoef)
dcoef.setFint(d.coef)
dscale := d.Scale()
dneg := d.IsNeg()
ecoef.setFint(e.coef)
// Compute d = d * e
dcoef.mul(dcoef, ecoef)
dneg = dneg != e.IsNeg()
dscale = dscale + e.Scale()
return newFromBint(dneg, dcoef, dscale, minScale)
}
// Pow returns the (possibly rounded) decimal raised to the given decimal power.
// If zero is raised to zero power then the result is one.
//
// Pow returns an error if:
// - the integer part of the result has more than [MaxPrec] digits;
// - zero is raised to a negative power;
// - negative is raised to a fractional power.
func (d Decimal) Pow(e Decimal) (Decimal, error) {
// Special case: zero to a negative power
if e.IsNeg() && d.IsZero() {
return Decimal{}, fmt.Errorf("computing [%v^%v]: %w: zero to negative power", d, e, errInvalidOperation)
}
// Special case: integer power
if e.IsInt() {
power := e.Trunc(0).Coef()
f, err := d.powIntFint(power, e.IsNeg())
if err != nil {
f, err = d.powIntBint(power, e.IsNeg())
if err != nil {
return Decimal{}, fmt.Errorf("computing [%v^%v]: %w", d, e, err)
}
}
// Preferred scale
if e.IsNeg() {
f = f.Trim(0)
}
return f, nil
}
// Special case: zero to a fractional power
if d.IsZero() {
return newSafe(false, 0, 0)
}
// Special case: negative to a fractional power
if d.IsNeg() {
return Decimal{}, fmt.Errorf("computing [%v^%v]: %w: negative to fractional power", d, e, errInvalidOperation)
}
// General case
f, err := d.powBint(e)
if err != nil {
return Decimal{}, fmt.Errorf("computing [%v^%v]: %w", d, e, err)
}
return f, nil
}
// powBint computes the power of a decimal using *big.Int arithmetic.
func (d Decimal) powBint(e Decimal) (Decimal, error) {
dcoef := getBint()
defer putBint(dcoef)
ecoef := getBint()
defer putBint(ecoef)
fcoef := getBint()
defer putBint(fcoef)
dcoef.setFint(d.coef)
ecoef.setFint(e.coef)
inv := false
// Alignment
if d.WithinOne() {
// Compute d = ⌊1 / d⌋
dcoef.quo(bpow10[bscale+d.Scale()], dcoef)
inv = true
} else {
dcoef.lsh(dcoef, bscale-d.Scale())
}
// Compute f = log(d)
fcoef.log(dcoef)
// Compute f = ⌊f * e⌋
fcoef.mul(fcoef, ecoef)
fcoef.rshDown(fcoef, e.Scale())
inv = inv != e.IsNeg()
// Check if f <= -100 or f >= 100
if fcoef.hasPrec(3 + bscale) {
if !inv {
return Decimal{}, unknownOverflowError()
}
return newSafe(false, 0, MaxScale)
}
// Compute f = exp(f)
fcoef.exp(fcoef)
if inv {
// Compute f = ⌊1 / f⌋
fcoef.quo(bpow10[2*bscale], fcoef)
}
return newFromBint(false, fcoef, bscale, 0)
}
// PowInt returns the (possibly rounded) decimal raised to the given integer power.
// If zero is raised to zero power then the result is one.
//
// PowInt returns an error if:
// - the integer part of the result has more than [MaxPrec] digits;
// - zero is raised to a negative power.
func (d Decimal) PowInt(power int) (Decimal, error) {
var pow uint64
var neg bool
if power >= 0 {
neg = false
pow = uint64(power)
} else {
neg = true
if power == math.MinInt {
pow = uint64(math.MaxInt) + 1
} else {
pow = uint64(-power)
}
}
// Special case: zero to a negative power
if neg && d.IsZero() {
return Decimal{}, fmt.Errorf("computing [%v^%v]: %w: zero to negative power", d, power, errInvalidOperation)
}
// General case
e, err := d.powIntFint(pow, neg)
if err != nil {
e, err = d.powIntBint(pow, neg)
if err != nil {
return Decimal{}, fmt.Errorf("computing [%v^%v]: %w", d, power, err)
}
}
// Preferred scale
if neg {
e = e.Trim(0)
}
return e, nil
}
// powIntFint computes the integer power of a decimal using uint64 arithmetic.
// powIntFint does not support negative powers.
func (d Decimal) powIntFint(pow uint64, inv bool) (Decimal, error) {
if inv {
return Decimal{}, errInvalidOperation
}
dcoef := d.coef
dneg := d.IsNeg()
dscale := d.Scale()
ecoef := One.coef
eneg := One.IsNeg()
escale := One.Scale()
// Exponentiation by squaring
var ok bool
for pow > 0 {
if pow%2 == 1 {
pow = pow - 1
// Compute e = e * d
ecoef, ok = ecoef.mul(dcoef)
if !ok {
return Decimal{}, errDecimalOverflow
}
eneg = eneg != dneg
escale = escale + dscale
}
if pow > 0 {
pow = pow / 2
// Compute d = d * d
dcoef, ok = dcoef.mul(dcoef)
if !ok {
return Decimal{}, errDecimalOverflow
}
dneg = false
dscale = dscale * 2
}
}
return newFromFint(eneg, ecoef, escale, 0)
}
// powIntBint computes the integer power of a decimal using *big.Int arithmetic.
// powIntBint supports negative powers.
func (d Decimal) powIntBint(pow uint64, inv bool) (Decimal, error) {
dcoef := getBint()
defer putBint(dcoef)
ecoef := getBint()
defer putBint(ecoef)
dcoef.setFint(d.coef)
dneg := d.IsNeg()
dscale := d.Scale()
ecoef.setFint(One.coef)
eneg := One.IsNeg()
escale := One.Scale()
// Exponentiation by squaring
for pow > 0 {
if pow%2 == 1 {
pow = pow - 1
// Compute e = e * d
ecoef.mul(ecoef, dcoef)
eneg = eneg != dneg
escale = escale + dscale
// Intermediate truncation
if escale > bscale {
ecoef.rshDown(ecoef, escale-bscale)
escale = bscale
}
// Check if e <= -10^59 or e >= 10^59
if ecoef.hasPrec(len(bpow10)) {
if !inv {
return Decimal{}, unknownOverflowError()
}
return newSafe(false, 0, MaxScale)
}
}
if pow > 0 {
pow = pow / 2
// Compute d = d * d
dcoef.mul(dcoef, dcoef)
dneg = false
dscale = dscale * 2
// Intermediate truncation
if dscale > bscale {
dcoef.rshDown(dcoef, dscale-bscale)
dscale = bscale
}
// Check if d <= -10^59 or d >= 10^59
if dcoef.hasPrec(len(bpow10)) {
if !inv {
return Decimal{}, unknownOverflowError()
}
return newSafe(false, 0, MaxScale)
}
}
}
if inv {
if ecoef.sign() == 0 {
return Decimal{}, unknownOverflowError()
}
// Compute e = ⌊1 / e⌋
ecoef.quo(bpow10[bscale+escale], ecoef)
escale = bscale
}
return newFromBint(eneg, ecoef, escale, 0)
}
// Sqrt computes the (possibly rounded) square root of a decimal.
// d.Sqrt() is significantly faster than d.Pow(0.5).
//
// Sqrt returns an error if the decimal is negative.
func (d Decimal) Sqrt() (Decimal, error) {
// Special case: negative
if d.IsNeg() {
return Decimal{}, fmt.Errorf("computing sqrt(%v): %w: square root of negative", d, errInvalidOperation)
}
// Special case: zero
if d.IsZero() {
return newSafe(false, 0, d.Scale()/2)
}
// General case
e, err := d.sqrtBint()
if err != nil {
return Decimal{}, fmt.Errorf("computing sqrt(%v): %w", d, err)
}
// Preferred scale
e = e.Trim(d.Scale() / 2)
return e, nil
}
// sqrtBint computes the square root of a decimal using *big.Int arithmetic.
func (d Decimal) sqrtBint() (Decimal, error) {
dcoef := getBint()
defer putBint(dcoef)
ecoef := getBint()
defer putBint(ecoef)
fcoef := getBint()
defer putBint(fcoef)
dcoef.setFint(d.coef)
fcoef.setFint(0)
// Alignment
dcoef.lsh(dcoef, 2*bscale-d.Scale())
// Initial guess is calculated as 10^(n/2),
// where n is the position of the most significant digit.
n := dcoef.prec() - 2*bscale
ecoef.setBint(bpow10[n/2+bscale])
// Newton's method
for range 50 {
if ecoef.cmp(fcoef) == 0 {
break
}
fcoef.setBint(ecoef)
ecoef.quo(dcoef, ecoef)
ecoef.add(ecoef, fcoef)
ecoef.hlf(ecoef)
}
return newFromBint(false, ecoef, bscale, 0)
}
// Log2 returns the (possibly rounded) binary logarithm of a decimal.
//
// Log2 returns an error if the decimal is zero or negative.
func (d Decimal) Log2() (Decimal, error) {
// Special case: zero or negative
if !d.IsPos() {
return Decimal{}, fmt.Errorf("computing log2(%v): %w: logarithm of non-positive", d, errInvalidOperation)
}
// Special case: one
if d.IsOne() {
return newSafe(false, 0, 0)
}
// General case
e, err := d.log2Bint()
if err != nil {
return Decimal{}, fmt.Errorf("computing log2(%v): %w", d, err)
}
// Preferred scale
if e.IsInt() {
// According to the GDA, only integer powers of 2 should be trimmed to zero scale.
// However, such validation is slow, so we will trim all integers.
e = e.Trunc(0)
}
return e, nil
}
// log2Bint computes the binary logarithm of a decimal using *big.Int arithmetic.
func (d Decimal) log2Bint() (Decimal, error) {
dcoef := getBint()
defer putBint(dcoef)
ecoef := getBint()
defer putBint(ecoef)
dcoef.setFint(d.coef)
eneg := false
// Alignment
if d.WithinOne() {
// Compute d = ⌊1 / d⌋
dcoef.quo(bpow10[bscale+d.Scale()], dcoef)
eneg = true
} else {
dcoef.lsh(dcoef, bscale-d.Scale())
}
// Compute e = log(d)
ecoef.log(dcoef)
// Compute e = e / log(2)
ecoef.lsh(ecoef, bscale)
ecoef.quo(ecoef, blog[2])
return newFromBint(eneg, ecoef, bscale, 0)
}
// Log10 returns the (possibly rounded) decimal logarithm of a decimal.
//
// Log10 returns an error if the decimal is zero or negative.
func (d Decimal) Log10() (Decimal, error) {
// Special case: zero or negative
if !d.IsPos() {
return Decimal{}, fmt.Errorf("computing log10(%v): %w: logarithm of non-positive", d, errInvalidOperation)
}
// Special case: one
if d.IsOne() {
return newSafe(false, 0, 0)
}
// General case
e, err := d.log10Bint()
if err != nil {
return Decimal{}, fmt.Errorf("computing log10(%v): %w", d, err)
}
// Preferred scale
if e.IsInt() {
// According to the GDA, only integer powers of 10 should be trimmed to zero scale.
// However, such validation is slow, so we will trim all integers.
e = e.Trunc(0)
}
return e, nil
}
// log10Bint computes the decimal logarithm of a decimal using *big.Int arithmetic.
func (d Decimal) log10Bint() (Decimal, error) {
dcoef := getBint()
defer putBint(dcoef)
ecoef := getBint()
defer putBint(ecoef)
dcoef.setFint(d.coef)
eneg := false
// Alignment
if d.WithinOne() {
// Compute d = ⌊1 / d⌋
dcoef.quo(bpow10[bscale+d.Scale()], dcoef)
eneg = true
} else {
dcoef.lsh(dcoef, bscale-d.Scale())
}
// Compute e = log(d)
ecoef.log(dcoef)
// Compute e = ⌊e / log(10)⌋
ecoef.lsh(ecoef, bscale)
ecoef.quo(ecoef, blog[10])
return newFromBint(eneg, ecoef, bscale, 0)
}
// Log1p returns the (possibly rounded) shifted natural logarithm of a decimal.
//
// Log1p returns an error if the decimal is equal to or less than negative one.
func (d Decimal) Log1p() (Decimal, error) {
if d.IsNeg() && d.Cmp(NegOne) <= 0 {
return Decimal{}, fmt.Errorf("computing log1p(%v): %w: logarithm of a decimal less than or equal to -1", d, errInvalidOperation)
}
// Special case: zero
if d.IsZero() {
return newSafe(false, 0, 0)
}
// General case
e, err := d.log1pBint()
if err != nil {
return Decimal{}, fmt.Errorf("computing log1p(%v): %w", d, err)
}
return e, nil
}
// log1pBint computes the shifted natural logarithm of a decimal using *big.Int arithmetic.
func (d Decimal) log1pBint() (Decimal, error) {
dcoef := getBint()
defer putBint(dcoef)
ecoef := getBint()
defer putBint(ecoef)
dcoef.setFint(d.coef)
eneg := false
// Alignment
if d.IsNeg() {
// Compute d = ⌊1 / (d + 1)⌋
dcoef.subAbs(dcoef, bpow10[d.Scale()])
dcoef.quo(bpow10[bscale+d.Scale()], dcoef)
eneg = true
} else {
// Compute d = d + 1
dcoef.add(dcoef, bpow10[d.Scale()])
dcoef.lsh(dcoef, bscale-d.Scale())
}
// Compute e = log(d)
ecoef.log(dcoef)
return newFromBint(eneg, ecoef, bscale, 0)
}
// Log returns the (possibly rounded) natural logarithm of a decimal.
//
// Log returns an error if the decimal is zero or negative.
func (d Decimal) Log() (Decimal, error) {
// Special case: zero or negative
if !d.IsPos() {
return Decimal{}, fmt.Errorf("computing log(%v): %w: logarithm of non-positive", d, errInvalidOperation)
}
// Special case: one
if d.IsOne() {
return newSafe(false, 0, 0)
}
// General case
e, err := d.logBint()
if err != nil {
return Decimal{}, fmt.Errorf("computing log(%v): %w", d, err)
}
return e, nil
}
// logBint computes the natural logarithm of a decimal using *big.Int arithmetic.
func (d Decimal) logBint() (Decimal, error) {
dcoef := getBint()
defer putBint(dcoef)
ecoef := getBint()
defer putBint(ecoef)
dcoef.setFint(d.coef)
eneg := false
// Alignment
if d.WithinOne() {
// Compute d = ⌊1 / d⌋
dcoef.quo(bpow10[bscale+d.Scale()], dcoef)
eneg = true
} else {
dcoef.lsh(dcoef, bscale-d.Scale())
}
// Compute e = log(d)
ecoef.log(dcoef)
return newFromBint(eneg, ecoef, bscale, 0)
}
// log calculates z = log(x) using Halley's method.
// The argument x must satisfy x >= 1, otherwise the result is undefined.
// x must be represented as a big integer: round(x * 10^41).
// The result z is represented as a big integer: round(z * 10^41).
func (z *bint) log(x *bint) {
zcoef := getBint()
defer putBint(zcoef)
fcoef := getBint()
defer putBint(fcoef)
Ecoef := getBint()
defer putBint(Ecoef)
ncoef := getBint()
defer putBint(ncoef)
mcoef := getBint()
defer putBint(mcoef)
fcoef.setFint(0)
// The initial guess is calculated as n*ln(10),
// where n is the position of the most significant digit.
n := x.prec() - bscale
zcoef.setBint(bnlog10[n])
// Halley's method
for range 50 {
Ecoef.exp(zcoef)
ncoef.sub(Ecoef, x)
ncoef.dbl(ncoef)
mcoef.add(Ecoef, x)
ncoef.lsh(ncoef, bscale)
ncoef.quo(ncoef, mcoef)
fcoef.sub(zcoef, ncoef)
if zcoef.cmp(fcoef) == 0 {
break
}
zcoef.setBint(fcoef)
}
z.setBint(zcoef)
}
// Exp returns the (possibly rounded) exponential of a decimal.
//
// Exp returns an error if the integer part of the result has more than [MaxPrec] digits.
func (d Decimal) Exp() (Decimal, error) {
// Special case: zero
if d.IsZero() {
return newSafe(false, 1, 0)
}
// Special case: overflow
if d.CmpAbs(Hundred) >= 0 {
if !d.IsNeg() {
return Decimal{}, fmt.Errorf("computing exp(%v): %w", d, unknownOverflowError())
}
return newSafe(false, 0, MaxScale)
}
// General case
e, err := d.expBint()
if err != nil {
return Decimal{}, fmt.Errorf("computing exp(%v): %w", d, err)
}
return e, nil
}
// expBint computes exponential of a decimal using *big.Int arithmetic.
func (d Decimal) expBint() (Decimal, error) {
dcoef := getBint()
defer putBint(dcoef)
ecoef := getBint()
defer putBint(ecoef)
dcoef.setFint(d.coef)
// Alignment
dcoef.lsh(dcoef, bscale-d.Scale())
// Compute e = exp(d)
ecoef.exp(dcoef)
if d.IsNeg() {
if ecoef.sign() == 0 {
return Decimal{}, unknownOverflowError()
}
// Compute e = ⌊1 / e⌋
ecoef.quo(bpow10[2*bscale], ecoef)
}
return newFromBint(false, ecoef, bscale, 0)
}
// Expm1 returns the (possibly rounded) shifted exponential of a decimal.
//
// Expm1 returns an error if the integer part of the result has more than [MaxPrec] digits.
func (d Decimal) Expm1() (Decimal, error) {
// Special case: zero
if d.IsZero() {
return newSafe(false, 0, 0)
}
// Special case: overflow
if d.CmpAbs(Hundred) >= 0 {
if !d.IsNeg() {
return Decimal{}, fmt.Errorf("computing expm1(%v): %w", d, unknownOverflowError())
}
return newSafe(true, pow10[MaxScale-1], MaxScale-1)
}
// General case
e, err := d.expm1Bint()
if err != nil {
return Decimal{}, fmt.Errorf("computing expm1(%v): %w", d, err)
}
return e, nil
}
// expm1Bint computes shifted exponential of a decimal using *big.Int arithmetic.
func (d Decimal) expm1Bint() (Decimal, error) {
dcoef := getBint()
defer putBint(dcoef)
ecoef := getBint()
defer putBint(ecoef)
dcoef.setFint(d.coef)
// Alignment
dcoef.lsh(dcoef, bscale-d.Scale())
// Compute e = exp(d)
ecoef.exp(dcoef)
if d.IsNeg() {
if ecoef.sign() == 0 {
return Decimal{}, unknownOverflowError()
}
// Compute e = ⌊1 / e⌋
ecoef.quo(bpow10[2*bscale], ecoef)
}
// Compute e = e - 1
eneg := false
if ecoef.cmp(bpow10[bscale]) < 0 {
eneg = true
}
ecoef.subAbs(ecoef, bpow10[bscale])
return newFromBint(eneg, ecoef, bscale, 0)
}
// exp calculates z = exp(x) using Taylor series expansion.
// The argument x must satisfy 0 <= x < 100, otherwise the result is undefined.
// The argument x must be represented as a big integer: round(x * 10^41).
// The result z is represented as a big integer: round(z * 10^41).
func (z *bint) exp(x *bint) {
qcoef := getBint()
defer putBint(qcoef)
rcoef := getBint()
defer putBint(rcoef)
// Split x into integer part q and fractional part r
qcoef.quoRem(x, bpow10[bscale], rcoef)
// Retrieve z = exp(q) from precomputed cache
z.setBint(bexp[int(qcoef.fint())]) //nolint:gosec
if rcoef.sign() == 0 {
return
}
zcoef := getBint()
defer putBint(zcoef)
gcoef := getBint()
defer putBint(gcoef)
hcoef := getBint()
defer putBint(hcoef)
zcoef.setFint(0)
gcoef.setBint(bpow10[bscale])
// Compute exp(r) using Taylor series expansion
// exp(r) = r^0 / 0! + r^1 / 1! + ... + r^n / n!
for i := range len(bfact) {
hcoef.quo(gcoef, bfact[i])
if hcoef.sign() == 0 {
break
}
zcoef.add(zcoef, hcoef)
gcoef.mul(gcoef, rcoef)
gcoef.rshDown(gcoef, bscale)
}
// Compute z = z * exp(r)
z.mul(z, zcoef)
z.rshDown(z, bscale)
}
// Sum returns the (possibly rounded) sum of decimals.
// It computes d1 + d2 + ... + dn without intermediate rounding.
//
// Sum returns an error if:
// - no argements are provided;
// - the integer part of the result has more than [MaxPrec] digits.
func Sum(d ...Decimal) (Decimal, error) {
// Special cases
switch len(d) {
case 0:
return Decimal{}, fmt.Errorf("computing [sum([])]: %w", errInvalidOperation)
case 1:
return d[0], nil
}
// General case
e, err := sumFint(d...)
if err != nil {
e, err = sumBint(d...)
if err != nil {
return Decimal{}, fmt.Errorf("computing [sum(%v)]: %w", d, err)
}
}
return e, nil
}
// sumFint computes the sum of decimals using uint64 arithmetic.
func sumFint(d ...Decimal) (Decimal, error) {
ecoef := Zero.coef
escale := Zero.Scale()
eneg := Zero.IsNeg()
for _, f := range d {
fcoef := f.coef
// Alignment
var ok bool
switch {
case escale > f.Scale():
fcoef, ok = fcoef.lsh(escale - f.Scale())
if !ok {
return Decimal{}, errDecimalOverflow
}
case escale < f.Scale():
ecoef, ok = ecoef.lsh(f.Scale() - escale)
if !ok {
return Decimal{}, errDecimalOverflow
}
escale = f.Scale()
}
// Compute e = e + f
if eneg == f.IsNeg() {
ecoef, ok = ecoef.add(fcoef)
if !ok {
return Decimal{}, errDecimalOverflow
}
} else {
if fcoef > ecoef {
eneg = f.IsNeg()
}
ecoef = ecoef.subAbs(fcoef)
}
}
return newFromFint(eneg, ecoef, escale, 0)
}
// sumBint computes the sum of decimals using *big.Int arithmetic.
func sumBint(d ...Decimal) (Decimal, error) {
ecoef := getBint()
defer putBint(ecoef)
fcoef := getBint()
defer putBint(fcoef)
ecoef.setFint(Zero.coef)
escale := Zero.Scale()
eneg := Zero.IsNeg()
for _, f := range d {
fcoef.setFint(f.coef)
// Alignment
switch {
case escale > f.Scale():
fcoef.lsh(fcoef, escale-f.Scale())
case escale < f.Scale():
ecoef.lsh(ecoef, f.Scale()-escale)
escale = f.Scale()
}
// Compute e = e + f
if eneg == f.IsNeg() {
ecoef.add(ecoef, fcoef)
} else {
if fcoef.cmp(ecoef) > 0 {
eneg = f.IsNeg()
}
ecoef.subAbs(ecoef, fcoef)
}
}
return newFromBint(eneg, ecoef, escale, 0)
}
// SubAbs returns the (possibly rounded) absolute difference between decimals d and e.
//
// SubAbs returns an error if the integer part of the result has more than [MaxPrec] digits.
func (d Decimal) SubAbs(e Decimal) (Decimal, error) {
f, err := d.Sub(e)
if err != nil {
return Decimal{}, fmt.Errorf("computing [abs(%v - %v)]: %w", d, e, err)
}
return f.Abs(), nil
}
// Sub returns the (possibly rounded) difference between decimals d and e.
//
// Sub returns an error if the integer part of the result has more than [MaxPrec] digits.
func (d Decimal) Sub(e Decimal) (Decimal, error) {
return d.AddExact(e.Neg(), 0)
}
// SubExact is similar to [Decimal.Sub], but it allows you to specify the number of digits
// after the decimal point that should be considered significant.
// If any of the significant digits are lost during rounding, the method will return an error.
// This method is useful for financial calculations where the scale should be
// equal to or greater than the currency's scale.
func (d Decimal) SubExact(e Decimal, scale int) (Decimal, error) {
return d.AddExact(e.Neg(), scale)
}
// Add returns the (possibly rounded) sum of decimals d and e.
//
// Add returns an error if the integer part of the result has more than [MaxPrec] digits.
func (d Decimal) Add(e Decimal) (Decimal, error) {
return d.AddExact(e, 0)
}
// AddExact is similar to [Decimal.Add], but it allows you to specify the number of digits
// after the decimal point that should be considered significant.
// If any of the significant digits are lost during rounding, the method will return an error.
// This method is useful for financial calculations where the scale should be
// equal to or greater than the currency's scale.
func (d Decimal) AddExact(e Decimal, scale int) (Decimal, error) {
if scale < MinScale || scale > MaxScale {
return Decimal{}, fmt.Errorf("computing [%v + %v]: %w", d, e, errScaleRange)
}
// General case
f, err := d.addFint(e, scale)
if err != nil {
f, err = d.addBint(e, scale)
if err != nil {
return Decimal{}, fmt.Errorf("computing [%v + %v]: %w", d, e, err)
}
}
return f, nil
}
// addFint computes the sum of two decimals using uint64 arithmetic.
func (d Decimal) addFint(e Decimal, minScale int) (Decimal, error) {
dcoef := d.coef
dscale := d.Scale()
dneg := d.IsNeg()
ecoef := e.coef
// Alignment
var ok bool
switch {
case dscale > e.Scale():
ecoef, ok = ecoef.lsh(dscale - e.Scale())
if !ok {
return Decimal{}, errDecimalOverflow
}
case dscale < e.Scale():
dcoef, ok = dcoef.lsh(e.Scale() - dscale)
if !ok {
return Decimal{}, errDecimalOverflow
}
dscale = e.Scale()
}
// Compute d = d + e
if dneg == e.IsNeg() {
dcoef, ok = dcoef.add(ecoef)
if !ok {
return Decimal{}, errDecimalOverflow
}
} else {
if ecoef > dcoef {
dneg = e.IsNeg()
}
dcoef = dcoef.subAbs(ecoef)
}
return newFromFint(dneg, dcoef, dscale, minScale)
}
// addBint computes the sum of two decimals using *big.Int arithmetic.
func (d Decimal) addBint(e Decimal, minScale int) (Decimal, error) {
dcoef := getBint()
defer putBint(dcoef)
ecoef := getBint()
defer putBint(ecoef)
dcoef.setFint(d.coef)
dscale := d.Scale()
ecoef.setFint(e.coef)
dneg := d.IsNeg()
// Alignment
switch {
case dscale > e.Scale():
ecoef.lsh(ecoef, dscale-e.Scale())
case dscale < e.Scale():
dcoef.lsh(dcoef, e.Scale()-dscale)
dscale = e.Scale()
}
// Compute d = d + e
if dneg == e.IsNeg() {
dcoef.add(dcoef, ecoef)
} else {
if ecoef.cmp(dcoef) > 0 {
dneg = e.IsNeg()
}
dcoef.subAbs(dcoef, ecoef)
}
return newFromBint(dneg, dcoef, dscale, minScale)
}
// SubMul returns the (possibly rounded) [fused multiply-subtraction] of decimals d, e, and f.
// It computes d - e * f without any intermediate rounding.
// This method is useful for improving the accuracy and performance of algorithms
// that involve the accumulation of products, such as daily interest accrual.
//
// SubMul returns an error if the integer part of the result has more than [MaxPrec] digits.
//
// [fused multiply-subtraction]: https://en.wikipedia.org/wiki/Multiply%E2%80%93accumulate_operation#Fused_multiply%E2%80%93add
func (d Decimal) SubMul(e, f Decimal) (Decimal, error) {
return d.AddMulExact(e.Neg(), f, 0)
}
// SubMulExact is similar to [Decimal.SubMul], but it allows you to specify the number of digits
// after the decimal point that should be considered significant.
// If any of the significant digits are lost during rounding, the method will return an error.
// This method is useful for financial calculations where the scale should be
// equal to or greater than the currency's scale.
func (d Decimal) SubMulExact(e, f Decimal, scale int) (Decimal, error) {
return d.AddMulExact(e.Neg(), f, scale)
}
// AddMul returns the (possibly rounded) [fused multiply-addition] of decimals d, e, and f.
// It computes d + e * f without any intermediate rounding.
// This method is useful for improving the accuracy and performance of algorithms
// that involve the accumulation of products, such as daily interest accrual.
//
// AddMul returns an error if the integer part of the result has more than [MaxPrec] digits.
//
// [fused multiply-addition]: https://en.wikipedia.org/wiki/Multiply%E2%80%93accumulate_operation#Fused_multiply%E2%80%93add
func (d Decimal) AddMul(e, f Decimal) (Decimal, error) {
return d.AddMulExact(e, f, 0)
}
// AddMulExact is similar to [Decimal.AddMul], but it allows you to specify the number of digits
// after the decimal point that should be considered significant.
// If any of the significant digits are lost during rounding, the method will return an error.
// This method is useful for financial calculations where the scale should be
// equal to or greater than the currency's scale.
func (d Decimal) AddMulExact(e, f Decimal, scale int) (Decimal, error) {
if scale < MinScale || scale > MaxScale {
return Decimal{}, fmt.Errorf("computing [%v + %v * %v]: %w", d, e, f, errScaleRange)
}
// General case
g, err := d.addMulFint(e, f, scale)
if err != nil {
g, err = d.addMulBint(e, f, scale)
if err != nil {
return Decimal{}, fmt.Errorf("computing [%v + %v * %v]: %w", d, e, f, err)
}
}
return g, nil
}
// addMulFint computes the fused multiply-addition of three decimals using uint64 arithmetic.
func (d Decimal) addMulFint(e, f Decimal, minScale int) (Decimal, error) {
dcoef := d.coef
dscale := d.Scale()
dneg := d.IsNeg()
ecoef := e.coef
escale := e.Scale()
eneg := e.IsNeg()
fcoef := f.coef
// Compute e = e * f
var ok bool
ecoef, ok = ecoef.mul(fcoef)
if !ok {
return Decimal{}, errDecimalOverflow
}
escale = escale + f.Scale()
eneg = eneg != f.IsNeg()
// Alignment
switch {
case dscale > escale:
ecoef, ok = ecoef.lsh(dscale - escale)
if !ok {
return Decimal{}, errDecimalOverflow
}
case dscale < escale:
dcoef, ok = dcoef.lsh(escale - dscale)
if !ok {
return Decimal{}, errDecimalOverflow
}
dscale = escale
}
// Compute d = d + e
if dneg == eneg {
dcoef, ok = dcoef.add(ecoef)
if !ok {
return Decimal{}, errDecimalOverflow
}
} else {
if ecoef > dcoef {
dneg = eneg
}
dcoef = dcoef.subAbs(ecoef)
}
return newFromFint(dneg, dcoef, dscale, minScale)
}
// addMulBint computes the fused multiply-addition of three decimals using *big.Int arithmetic.
func (d Decimal) addMulBint(e, f Decimal, minScale int) (Decimal, error) {
dcoef := getBint()
defer putBint(dcoef)
ecoef := getBint()
defer putBint(ecoef)
fcoef := getBint()
defer putBint(fcoef)
dcoef.setFint(d.coef)
dscale := d.Scale()
dneg := d.IsNeg()
ecoef.setFint(e.coef)
escale := e.Scale()
eneg := e.IsNeg()
fcoef.setFint(f.coef)
// Compute e = e * f
ecoef.mul(ecoef, fcoef)
escale = escale + f.Scale()
eneg = eneg != f.IsNeg()
// Alignment
switch {
case dscale > escale:
ecoef.lsh(ecoef, dscale-escale)
case dscale < escale:
dcoef.lsh(dcoef, escale-d.Scale())
dscale = escale
}
// Compute d = d + e
if dneg == eneg {
dcoef.add(dcoef, ecoef)
} else {
if ecoef.cmp(dcoef) > 0 {
dneg = eneg
}
dcoef.subAbs(dcoef, ecoef)
}
return newFromBint(dneg, dcoef, dscale, minScale)
}
// SubQuo returns the (possibly rounded) fused quotient-subtraction of decimals d, e, and f.
// It computes d - e / f with at least double precision during intermediate rounding.
// This method is useful for improving the accuracy and performance of algorithms
// that involve the accumulation of quotients, such as internal rate of return.
//
// AddQuo returns an error if:
// - the divisor is 0;
// - the integer part of the result has more than [MaxPrec] digits.
func (d Decimal) SubQuo(e, f Decimal) (Decimal, error) {
return d.AddQuoExact(e.Neg(), f, 0)
}
// SubQuoExact is similar to [Decimal.SubQuo], but it allows you to specify the number of digits
// after the decimal point that should be considered significant.
// If any of the significant digits are lost during rounding, the method will return an error.
// This method is useful for financial calculations where the scale should be
// equal to or greater than the currency's scale.
func (d Decimal) SubQuoExact(e, f Decimal, scale int) (Decimal, error) {
return d.AddQuoExact(e.Neg(), f, scale)
}
// AddQuo returns the (possibly rounded) fused quotient-addition of decimals d, e, and f.
// It computes d + e / f with at least double precision during the intermediate rounding.
// This method is useful for improving the accuracy and performance of algorithms
// that involve the accumulation of quotients, such as internal rate of return.
//
// AddQuo returns an error if:
// - the divisor is 0;
// - the integer part of the result has more than [MaxPrec] digits.
func (d Decimal) AddQuo(e, f Decimal) (Decimal, error) {
return d.AddQuoExact(e, f, 0)
}
// AddQuoExact is similar to [Decimal.AddQuo], but it allows you to specify the number of digits
// after the decimal point that should be considered significant.
// If any of the significant digits are lost during rounding, the method will return an error.
// This method is useful for financial calculations where the scale should be
// equal to or greater than the currency's scale.
func (d Decimal) AddQuoExact(e, f Decimal, scale int) (Decimal, error) {
if scale < MinScale || scale > MaxScale {
return Decimal{}, fmt.Errorf("computing [%v + %v / %v]: %w", d, e, f, errScaleRange)
}
// Special case: zero divisor
if f.IsZero() {
return Decimal{}, fmt.Errorf("computing [%v + %v / %v]: %w", d, e, f, errDivisionByZero)
}
// Special case: zero dividend
if e.IsZero() {
scale = max(scale, e.Scale()-f.Scale())
return d.Pad(scale), nil
}
// General case
g, err := d.addQuoFint(e, f, scale)
if err != nil {
g, err = d.addQuoBint(e, f, scale)
if err != nil {
return Decimal{}, fmt.Errorf("computing [%v + %v / %v]: %w", d, e, f, err)
}
}
// Preferred scale
scale = max(scale, d.Scale(), e.Scale()-f.Scale())
g = g.Trim(scale)
return g, nil
}
// addQuoFint computes the fused quotient-addition of three decimals using uint64 arithmetic.
func (d Decimal) addQuoFint(e, f Decimal, minScale int) (Decimal, error) {
dcoef := d.coef
dscale := d.Scale()
dneg := d.IsNeg()
ecoef := e.coef
escale := e.Scale()
eneg := e.IsNeg()
fcoef := f.coef
// Alignment
var ok bool
if shift := MaxPrec - ecoef.prec(); shift > 0 {
ecoef, ok = ecoef.lsh(shift)
if !ok {
return Decimal{}, errDecimalOverflow // Should never happen
}
escale = escale + shift
}
if shift := fcoef.ntz(); shift > 0 {
fcoef = fcoef.rshDown(shift)
escale = escale + shift
}
// Compute e = e / f
ecoef, ok = ecoef.quo(fcoef)
if !ok {
return Decimal{}, errInexactDivision
}
escale = escale - f.Scale()
eneg = eneg != f.IsNeg()
// Alignment
switch {
case dscale > escale:
ecoef, ok = ecoef.lsh(dscale - escale)
if !ok {
return Decimal{}, errDecimalOverflow
}
case dscale < escale:
if shift := min(escale-e.Scale()+f.Scale(), escale-dscale, ecoef.ntz()); shift > 0 {
ecoef = ecoef.rshDown(shift)
escale = escale - shift
}
dcoef, ok = dcoef.lsh(escale - dscale)
if !ok {
return Decimal{}, errDecimalOverflow
}
dscale = escale
}
// Compute d = d + e
if dneg == eneg {
dcoef, ok = dcoef.add(ecoef)
if !ok {
return Decimal{}, errDecimalOverflow
}
} else {
if ecoef > dcoef {
dneg = eneg
}
dcoef = dcoef.subAbs(ecoef)
}
return newFromFint(dneg, dcoef, dscale, minScale)
}
// addQuoBint computes the fused quotient-addition of three decimals using *big.Int arithmetic.
func (d Decimal) addQuoBint(e, f Decimal, minScale int) (Decimal, error) {
dcoef := getBint()
defer putBint(dcoef)
ecoef := getBint()
defer putBint(ecoef)
fcoef := getBint()
defer putBint(fcoef)
dcoef.setFint(d.coef)
dneg := d.IsNeg()
ecoef.setFint(e.coef)
eneg := e.IsNeg()
fcoef.setFint(f.coef)
// Alignment
ecoef.lsh(ecoef, bscale-e.Scale()+f.Scale())
// Compute e = ⌊e / f⌋
ecoef.quo(ecoef, fcoef)
eneg = eneg != f.IsNeg()
// Alignment
dcoef.lsh(dcoef, bscale-d.Scale())
// Compute d = d + e
if dneg == eneg {
dcoef.add(dcoef, ecoef)
} else {
if ecoef.cmp(dcoef) > 0 {
dneg = eneg
}
dcoef.subAbs(dcoef, ecoef)
}
return newFromBint(dneg, dcoef, bscale, minScale)
}
// Inv returns the (possibly rounded) inverse of the decimal.
//
// Inv returns an error if:
// - the integer part of the result has more than [MaxPrec] digits;
// - the decimal is 0.
func (d Decimal) Inv() (Decimal, error) {
f, err := One.Quo(d)
if err != nil {
return Decimal{}, fmt.Errorf("inverting %v: %w", d, err)
}
return f, nil
}
// Quo returns the (possibly rounded) quotient of decimals d and e.
//
// Quo returns an error if:
// - the divisor is 0;
// - the integer part of the result has more than [MaxPrec] digits.
func (d Decimal) Quo(e Decimal) (Decimal, error) {
return d.QuoExact(e, 0)
}
// QuoExact is similar to [Decimal.Quo], but it allows you to specify the number of digits
// after the decimal point that should be considered significant.
// If any of the significant digits are lost during rounding, the method will return an error.
// This method is useful for financial calculations where the scale should be
// equal to or greater than the currency's scale.
func (d Decimal) QuoExact(e Decimal, scale int) (Decimal, error) {
if scale < MinScale || scale > MaxScale {
return Decimal{}, fmt.Errorf("computing [%v / %v]: %w", d, e, errScaleRange)
}
// Special case: zero divisor
if e.IsZero() {
return Decimal{}, fmt.Errorf("computing [%v / %v]: %w", d, e, errDivisionByZero)
}
// Special case: zero dividend
if d.IsZero() {
scale = max(scale, d.Scale()-e.Scale())
return newSafe(false, 0, scale)
}
// General case
f, err := d.quoFint(e, scale)
if err != nil {
f, err = d.quoBint(e, scale)
if err != nil {
return Decimal{}, fmt.Errorf("computing [%v / %v]: %w", d, e, err)
}
}
// Preferred scale
scale = max(scale, d.Scale()-e.Scale())
f = f.Trim(scale)
return f, nil
}
// quoFint computes the quotient of two decimals using uint64 arithmetic.
func (d Decimal) quoFint(e Decimal, minScale int) (Decimal, error) {
dcoef := d.coef
dscale := d.Scale()
dneg := d.IsNeg()
ecoef := e.coef
// Alignment
var ok bool
if shift := MaxPrec - dcoef.prec(); shift > 0 {
dcoef, ok = dcoef.lsh(shift)
if !ok {
return Decimal{}, errDecimalOverflow // Should never happen
}
dscale = dscale + shift
}
if shift := ecoef.ntz(); shift > 0 {
ecoef = ecoef.rshDown(shift)
dscale = dscale + shift
}
// Compute d = d / e
dcoef, ok = dcoef.quo(ecoef)
if !ok {
return Decimal{}, errInexactDivision
}
dscale = dscale - e.Scale()
dneg = dneg != e.IsNeg()
return newFromFint(dneg, dcoef, dscale, minScale)
}
// quoBint computes the quotient of two decimals using *big.Int arithmetic.
func (d Decimal) quoBint(e Decimal, minScale int) (Decimal, error) {
dcoef := getBint()
defer putBint(dcoef)
ecoef := getBint()
defer putBint(ecoef)
dcoef.setFint(d.coef)
dneg := d.IsNeg()
ecoef.setFint(e.coef)
// Alignment
dcoef.lsh(dcoef, bscale+e.Scale()-d.Scale())
// Compute d = ⌊d / e⌋
dcoef.quo(dcoef, ecoef)
dneg = dneg != e.IsNeg()
return newFromBint(dneg, dcoef, bscale, minScale)
}
// QuoRem returns the quotient q and remainder r of decimals d and e
// such that d = e * q + r, where q is an integer and the sign of the
// reminder r is the same as the sign of the dividend d.
//
// QuoRem returns an error if:
// - the divisor is 0;
// - the integer part of the quotient has more than [MaxPrec] digits.
func (d Decimal) QuoRem(e Decimal) (q, r Decimal, err error) {
// Special case: zero divisor
if e.IsZero() {
return Decimal{}, Decimal{}, fmt.Errorf("computing [%v div %v] and [%v mod %v]: %w", d, e, d, e, errDivisionByZero)
}
// General case
q, r, err = d.quoRemFint(e)
if err != nil {
q, r, err = d.quoRemBint(e)
if err != nil {
return Decimal{}, Decimal{}, fmt.Errorf("computing [%v div %v] and [%v mod %v]: %w", d, e, d, e, err)
}
}
return q, r, nil
}
// quoRemFint computes the quotient and remainder of two decimals using uint64 arithmetic.
func (d Decimal) quoRemFint(e Decimal) (q, r Decimal, err error) {
dcoef := d.coef
ecoef := e.coef
rscale := d.Scale()
// Alignment
var ok bool
switch {
case d.Scale() > e.Scale():
ecoef, ok = ecoef.lsh(d.Scale() - e.Scale())
if !ok {
return Decimal{}, Decimal{}, errDecimalOverflow
}
case d.Scale() < e.Scale():
dcoef, ok = dcoef.lsh(e.Scale() - d.Scale())
if !ok {
return Decimal{}, Decimal{}, errDecimalOverflow
}
rscale = e.Scale()
}
// Compute q = ⌊d / e⌋, r = d - e * q
qcoef, rcoef, ok := dcoef.quoRem(ecoef)
if !ok {
return Decimal{}, Decimal{}, errDivisionByZero // Should never happen
}
qsign := d.IsNeg() != e.IsNeg()
rsign := d.IsNeg()
q, err = newFromFint(qsign, qcoef, 0, 0)
if err != nil {
return Decimal{}, Decimal{}, err
}
r, err = newFromFint(rsign, rcoef, rscale, rscale)
if err != nil {
return Decimal{}, Decimal{}, err
}
return q, r, nil
}
// quoRemBint computes the quotient and remainder of two decimals using *big.Int arithmetic.
func (d Decimal) quoRemBint(e Decimal) (q, r Decimal, err error) {
dcoef := getBint()
defer putBint(dcoef)
ecoef := getBint()
defer putBint(ecoef)
qcoef := getBint()
defer putBint(qcoef)
rcoef := getBint()
defer putBint(rcoef)
dcoef.setFint(d.coef)
ecoef.setFint(e.coef)
rscale := d.Scale()
// Alignment
switch {
case d.Scale() > e.Scale():
ecoef.lsh(ecoef, d.Scale()-e.Scale())
case d.Scale() < e.Scale():
dcoef.lsh(dcoef, e.Scale()-d.Scale())
rscale = e.Scale()
}
// Compute q = ⌊d / e⌋, r = d - e * q
qcoef.quoRem(dcoef, ecoef, rcoef)
qsign := d.IsNeg() != e.IsNeg()
rsign := d.IsNeg()
q, err = newFromBint(qsign, qcoef, 0, 0)
if err != nil {
return Decimal{}, Decimal{}, err
}
r, err = newFromBint(rsign, rcoef, rscale, rscale)
if err != nil {
return Decimal{}, Decimal{}, err
}
return q, r, nil
}
// Max returns the larger decimal.
// See also method [Decimal.CmpTotal].
func (d Decimal) Max(e Decimal) Decimal {
if d.CmpTotal(e) >= 0 {
return d
}
return e
}
// Min returns the smaller decimal.
// See also method [Decimal.CmpTotal].
func (d Decimal) Min(e Decimal) Decimal {
if d.CmpTotal(e) <= 0 {
return d
}
return e
}
// Clamp compares decimals and returns:
//
// min if d < min
// max if d > max
// d otherwise
//
// See also method [Decimal.CmpTotal].
//
// Clamp returns an error if min is greater than max numerically.
//
//nolint:revive
func (d Decimal) Clamp(min, max Decimal) (Decimal, error) {
if min.Cmp(max) > 0 {
return Decimal{}, fmt.Errorf("clamping %v: invalid range", d)
}
if min.CmpTotal(max) > 0 {
// min and max are equal numerically but have different scales.
// Swaping min and max to ensure total ordering.
min, max = max, min
}
if d.CmpTotal(min) < 0 {
return min, nil
}
if d.CmpTotal(max) > 0 {
return max, nil
}
return d, nil
}
// CmpTotal compares decimal representations and returns:
//
// -1 if d < e
// -1 if d = e and d.scale > e.scale
// 0 if d = e and d.scale = e.scale
// +1 if d = e and d.scale < e.scale
// +1 if d > e
//
// See also method [Decimal.Cmp].
func (d Decimal) CmpTotal(e Decimal) int {
switch d.Cmp(e) {
case -1:
return -1
case 1:
return 1
}
switch {
case d.Scale() > e.Scale():
return -1
case d.Scale() < e.Scale():
return 1
}
return 0
}
// CmpAbs compares absolute values of decimals and returns:
//
// -1 if |d| < |e|
// 0 if |d| = |e|
// +1 if |d| > |e|
//
// See also method [Decimal.Cmp].
func (d Decimal) CmpAbs(e Decimal) int {
d, e = d.Abs(), e.Abs()
return d.Cmp(e)
}
// Equal compares decimals and returns:
//
// true if d = e
// false otherwise
//
// See also method [Decimal.Cmp].
func (d Decimal) Equal(e Decimal) bool {
return d.Cmp(e) == 0
}
// Less compares decimals and returns:
//
// true if d < e
// false otherwise
//
// See also method [Decimal.Cmp].
func (d Decimal) Less(e Decimal) bool {
return d.Cmp(e) < 0
}
// Cmp compares decimals and returns:
//
// -1 if d < e
// 0 if d = e
// +1 if d > e
//
// See also methods [Decimal.CmpAbs], [Decimal.CmpTotal].
func (d Decimal) Cmp(e Decimal) int {
// Special case: different signs
switch {
case d.Sign() > e.Sign():
return 1
case d.Sign() < e.Sign():
return -1
}
// General case
r, err := d.cmpFint(e)
if err != nil {
r = d.cmpBint(e)
}
return r
}
// cmpFint compares decimals using uint64 arithmetic.
func (d Decimal) cmpFint(e Decimal) (int, error) {
dcoef := d.coef
ecoef := e.coef
// Alignment
var ok bool
switch {
case d.Scale() > e.Scale():
ecoef, ok = ecoef.lsh(d.Scale() - e.Scale())
if !ok {
return 0, errDecimalOverflow
}
case d.Scale() < e.Scale():
dcoef, ok = dcoef.lsh(e.Scale() - d.Scale())
if !ok {
return 0, errDecimalOverflow
}
}
// Comparison
switch {
case dcoef > ecoef:
return d.Sign(), nil
case ecoef > dcoef:
return -e.Sign(), nil
}
return 0, nil
}
// cmpBint compares decimals using *big.Int arithmetic.
func (d Decimal) cmpBint(e Decimal) int {
dcoef := getBint()
defer putBint(dcoef)
ecoef := getBint()
defer putBint(ecoef)
dcoef.setFint(d.coef)
ecoef.setFint(e.coef)
// Alignment
switch {
case d.Scale() > e.Scale():
ecoef.lsh(ecoef, d.Scale()-e.Scale())
case d.Scale() < e.Scale():
dcoef.lsh(dcoef, e.Scale()-d.Scale())
}
// Comparison
switch dcoef.cmp(ecoef) {
case 1:
return d.Sign()
case -1:
return -e.Sign()
}
return 0
}
// NullDecimal represents a decimal that can be null.
// Its zero value is null.
// NullDecimal is not thread-safe.
type NullDecimal struct {
Decimal Decimal
Valid bool
}
// Scan implements the [sql.Scanner] interface.
// See also method [Decimal.Scan].
//
// [sql.Scanner]: https://pkg.go.dev/database/sql#Scanner
func (n *NullDecimal) Scan(value any) error {
if value == nil {
n.Decimal = Decimal{}
n.Valid = false
return nil
}
n.Valid = true
return n.Decimal.Scan(value)
}
// Value implements the [driver.Valuer] interface.
// See also method [Decimal.Value].
//
// [driver.Valuer]: https://pkg.go.dev/database/sql/driver#Valuer
func (n NullDecimal) Value() (driver.Value, error) {
if !n.Valid {
return nil, nil
}
return n.Decimal.Value()
}
// UnmarshalJSON implements the [json.Unmarshaler] interface.
// See also method [Decimal.UnmarshalJSON].
//
// [json.Unmarshaler]: https://pkg.go.dev/encoding/json#Unmarshaler
func (n *NullDecimal) UnmarshalJSON(data []byte) error {
if string(data) == "null" {
n.Decimal = Decimal{}
n.Valid = false
return nil
}
n.Valid = true
return n.Decimal.UnmarshalJSON(data)
}
// MarshalJSON implements the [json.Marshaler] interface.
// See also method [Decimal.MarshalJSON].
//
// [json.Marshaler]: https://pkg.go.dev/encoding/json#Marshaler
func (n NullDecimal) MarshalJSON() ([]byte, error) {
if !n.Valid {
return []byte("null"), nil
}
return n.Decimal.MarshalJSON()
}
// UnmarshalBSONValue implements the [v2/bson.ValueUnmarshaler] interface.
// UnmarshalBSONValue supports the following [types]: Null, Double, String, 32-bit Integer, 64-bit Integer, and [Decimal128].
// See also method [Decimal.UnmarshalBSONValue].
//
// [v2/bson.ValueUnmarshaler]: https://pkg.go.dev/go.mongodb.org/mongo-driver/v2/bson#ValueUnmarshaler
// [types]: https://bsonspec.org/spec.html
// [Decimal128]: https://github.com/mongodb/specifications/blob/master/source/bson-decimal128/decimal128.md
func (n *NullDecimal) UnmarshalBSONValue(typ byte, data []byte) error {
// constants are from https://bsonspec.org/spec.html
if typ == 10 {
n.Decimal = Decimal{}
n.Valid = false
return nil
}
n.Valid = true
return n.Decimal.UnmarshalBSONValue(typ, data)
}
// MarshalBSONValue implements the [v2/bson.ValueMarshaler] interface.
// MarshalBSONValue returns [Null] or [Decimal128].
// See also method [Decimal.MarshalBSONValue].
//
// [v2/bson.ValueMarshaler]: https://pkg.go.dev/go.mongodb.org/mongo-driver/v2/bson#ValueMarshaler
// [Null]: https://bsonspec.org/spec.html
// [Decimal128]: https://github.com/mongodb/specifications/blob/master/source/bson-decimal128/decimal128.md
func (n NullDecimal) MarshalBSONValue() (typ byte, data []byte, err error) {
// constants are from https://bsonspec.org/spec.html
if !n.Valid {
return 10, nil, nil
}
return n.Decimal.MarshalBSONValue()
}
================================================
FILE: decimal_test.go
================================================
package decimal
import (
"bytes"
"database/sql"
"database/sql/driver"
"encoding"
"encoding/json"
"fmt"
"math"
"math/big"
"testing"
"unsafe"
)
func TestDecimal_ZeroValue(t *testing.T) {
got := Decimal{}
want := MustNew(0, 0)
if got != want {
t.Errorf("Decimal{} = %q, want %q", got, want)
}
}
func TestDecimal_Size(t *testing.T) {
d := Decimal{}
got := unsafe.Sizeof(d)
want := uintptr(16)
if got != want {
t.Errorf("unsafe.Sizeof(%q) = %v, want %v", d, got, want)
}
}
func TestDecimal_Interfaces(t *testing.T) {
var d any
d = Decimal{}
_, ok := d.(fmt.Stringer)
if !ok {
t.Errorf("%T does not implement fmt.Stringer", d)
}
_, ok = d.(fmt.Formatter)
if !ok {
t.Errorf("%T does not implement fmt.Formatter", d)
}
_, ok = d.(json.Marshaler)
if !ok {
t.Errorf("%T does not implement json.Marshaler", d)
}
_, ok = d.(encoding.TextMarshaler)
if !ok {
t.Errorf("%T does not implement encoding.TextMarshaler", d)
}
_, ok = d.(encoding.BinaryMarshaler)
if !ok {
t.Errorf("%T does not implement encoding.BinaryMarshaler", d)
}
// Uncomment when Go 1.24 is minimum supported version.
// _, ok = d.(encoding.TextAppender)
// if !ok {
// t.Errorf("%T does not implement encoding.TextAppender", d)
// }
// _, ok = d.(encoding.BinaryAppender)
// if !ok {
// t.Errorf("%T does not implement encoding.BinaryAppender", d)
// }
_, ok = d.(driver.Valuer)
if !ok {
t.Errorf("%T does not implement driver.Valuer", d)
}
d = &Decimal{}
_, ok = d.(json.Unmarshaler)
if !ok {
t.Errorf("%T does not implement json.Unmarshaler", d)
}
_, ok = d.(encoding.TextUnmarshaler)
if !ok {
t.Errorf("%T does not implement encoding.TextUnmarshaler", d)
}
_, ok = d.(encoding.BinaryUnmarshaler)
if !ok {
t.Errorf("%T does not implement encoding.BinaryUnmarshaler", d)
}
_, ok = d.(sql.Scanner)
if !ok {
t.Errorf("%T does not implement sql.Scanner", d)
}
}
func TestNew(t *testing.T) {
t.Run("success", func(t *testing.T) {
tests := []struct {
value int64
scale int
want string
}{
{math.MinInt64, 0, "-9223372036854775808"},
{math.MinInt64, 1, "-922337203685477580.8"},
{math.MinInt64, 2, "-92233720368547758.08"},
{math.MinInt64, 19, "-0.9223372036854775808"},
{0, 0, "0"},
{0, 1, "0.0"},
{0, 2, "0.00"},
{0, 3, "0.000"},
{0, 19, "0.0000000000000000000"},
{1, 0, "1"},
{1, 1, "0.1"},
{1, 2, "0.01"},
{1, 19, "0.0000000000000000001"},
{math.MaxInt64, 0, "9223372036854775807"},
{math.MaxInt64, 1, "922337203685477580.7"},
{math.MaxInt64, 2, "92233720368547758.07"},
{math.MaxInt64, 19, "0.9223372036854775807"},
}
for _, tt := range tests {
got, err := New(tt.value, tt.scale)
if err != nil {
t.Errorf("New(%v, %v) failed: %v", tt.value, tt.scale, err)
continue
}
want := MustParse(tt.want)
if got != want {
t.Errorf("New(%v, %v) = %q, want %q", tt.value, tt.scale, got, want)
}
}
})
t.Run("error", func(t *testing.T) {
tests := map[string]struct {
value int64
scale int
}{
"scale range 1": {math.MinInt64, -1},
"scale range 2": {math.MaxInt64, -1},
"scale range 3": {0, -1},
"scale range 4": {1, -1},
"scale range 5": {math.MinInt64, 20},
"scale range 6": {math.MinInt64, 39},
"scale range 7": {math.MaxInt64, 20},
"scale range 8": {math.MaxInt64, 39},
}
for _, tt := range tests {
_, err := New(tt.value, tt.scale)
if err == nil {
t.Errorf("New(%v, %v) did not fail", tt.value, tt.scale)
}
}
})
}
func TestMustNew(t *testing.T) {
t.Run("error", func(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Errorf("MustNew(0, -1) did not panic")
}
}()
MustNew(0, -1)
})
}
func TestNewFromInt64(t *testing.T) {
t.Run("success", func(t *testing.T) {
tests := []struct {
whole, frac int64
scale int
want string
}{
// Zeros
{0, 0, 0, "0"},
{0, 0, 19, "0"},
// Negatives
{-1, -1, 1, "-1.1"},
{-1, -1, 2, "-1.01"},
{-1, -1, 3, "-1.001"},
{-1, -1, 18, "-1.000000000000000001"},
// Positives
{1, 1, 1, "1.1"},
{1, 1, 2, "1.01"},
{1, 1, 3, "1.001"},
{1, 100000000, 9, "1.1"},
{1, 1, 18, "1.000000000000000001"},
{100000000000000000, 100000000000000000, 18, "100000000000000000.1"},
{1, 1, 19, "1.000000000000000000"},
{999999999999999999, 9, 1, "999999999999999999.9"},
{999999999999999999, 99, 2, "1000000000000000000"},
{math.MaxInt64, math.MaxInt32, 10, "9223372036854775807"},
{math.MaxInt64, math.MaxInt64, 19, "9223372036854775808"},
}
for _, tt := range tests {
got, err := NewFromInt64(tt.whole, tt.frac, tt.scale)
if err != nil {
t.Errorf("NewFromInt64(%v, %v, %v) failed: %v", tt.whole, tt.frac, tt.scale, err)
continue
}
want := MustParse(tt.want)
if got != want {
t.Errorf("NewFromInt64(%v, %v, %v) = %q, want %q", tt.whole, tt.frac, tt.scale, got, want)
}
}
})
t.Run("error", func(t *testing.T) {
tests := map[string]struct {
whole, frac int64
scale int
}{
"different signs 1": {-1, 1, 0},
"fraction range 1": {1, 1, 0},
"scale range 1": {1, 1, -1},
"scale range 2": {1, 0, -1},
"scale range 3": {1, 1, 20},
"scale range 4": {1, 0, 20},
}
for name, tt := range tests {
t.Run(name, func(t *testing.T) {
_, err := NewFromInt64(tt.whole, tt.frac, tt.scale)
if err == nil {
t.Errorf("NewFromInt64(%v, %v, %v) did not fail", tt.whole, tt.frac, tt.scale)
}
})
}
})
}
func TestNewFromFloat64(t *testing.T) {
t.Run("success", func(t *testing.T) {
tests := []struct {
f float64
want string
}{
// Zeros
{-0, "0"},
{0, "0"},
{0.0, "0"},
{0.00, "0"},
{0.0000000000000000000, "0"},
// Smallest non-zero
{math.SmallestNonzeroFloat64, "0.0000000000000000000"},
// Powers of ten
{1e-21, "0.0000000000000000000"},
{1e-20, "0.0000000000000000000"},
{1e-19, "0.0000000000000000001"},
{1e-18, "0.000000000000000001"},
{1e-17, "0.00000000000000001"},
{1e-16, "0.0000000000000001"},
{1e-15, "0.000000000000001"},
{1e-14, "0.00000000000001"},
{1e-13, "0.0000000000001"},
{1e-12, "0.000000000001"},
{1e-11, "0.00000000001"},
{1e-10, "0.0000000001"},
{1e-9, "0.000000001"},
{1e-8, "0.00000001"},
{1e-7, "0.0000001"},
{1e-6, "0.000001"},
{1e-5, "0.00001"},
{1e-4, "0.0001"},
{1e-3, "0.001"},
{1e-2, "0.01"},
{1e-1, "0.1"},
{1e0, "1"},
{1e1, "10"},
{1e2, "100"},
{1e3, "1000"},
{1e4, "10000"},
{1e5, "100000"},
{1e6, "1000000"},
{1e7, "10000000"},
{1e8, "100000000"},
{1e9, "1000000000"},
{1e10, "10000000000"},
{1e11, "100000000000"},
{1e12, "1000000000000"},
{1e13, "10000000000000"},
{1e14, "100000000000000"},
{1e15, "1000000000000000"},
{1e16, "10000000000000000"},
{1e17, "100000000000000000"},
{1e18, "1000000000000000000"},
}
for _, tt := range tests {
got, err := NewFromFloat64(tt.f)
if err != nil {
t.Errorf("NewFromFloat64(%v) failed: %v", tt.f, err)
continue
}
want := MustParse(tt.want)
if got != want {
t.Errorf("NewFromFloat64(%v) = %q, want %q", tt.f, got, want)
}
}
})
t.Run("error", func(t *testing.T) {
tests := map[string]float64{
"overflow 1": 1e19,
"overflow 2": 1e20,
"overflow 3": math.MaxFloat64,
"overflow 4": -1e19,
"overflow 5": -1e20,
"overflow 6": -math.MaxFloat64,
"special value 1": math.NaN(),
"special value 2": math.Inf(1),
"special value 3": math.Inf(-1),
}
for name, tt := range tests {
t.Run(name, func(t *testing.T) {
_, err := NewFromFloat64(tt)
if err == nil {
t.Errorf("NewFromFloat64(%v) did not fail", tt)
}
})
}
})
}
func TestParse(t *testing.T) {
t.Run("success", func(t *testing.T) {
tests := []struct {
s string
wantNeg bool
wantCoef uint64
wantScale int
}{
{"-9999999999999999999.0", true, 9999999999999999999, 0},
{"-9999999999999999999", true, 9999999999999999999, 0},
{"-999999999999999999.9", true, 9999999999999999999, 1},
{"-99999999999999999.99", true, 9999999999999999999, 2},
{"-1000000000000000000.0", true, 1000000000000000000, 0},
{"-0.9999999999999999999", true, 9999999999999999999, 19},
{"-00000000000000000000000000000000000001", true, 1, 0},
{"-1", true, 1, 0},
{"-1.", true, 1, 0},
{"-.1", true, 1, 1},
{"-0.1", true, 1, 1},
{"-0.01", true, 1, 2},
{"-0.0000000000000000001", true, 1, 19},
{"-00000000000000000000000000000000000000", false, 0, 0},
{"+00000000000000000000000000000000000000", false, 0, 0},
{"0", false, 0, 0},
{"0.", false, 0, 0},
{".0", false, 0, 1},
{"0.0", false, 0, 1},
{"0.00", false, 0, 2},
{"0.000000000000000000", false, 0, 18},
{"0.0000000000000000000", false, 0, 19},
{"0.00000000000000000000", false, 0, 19},
{"00000000000000000000000000000000000001", false, 1, 0},
{"1", false, 1, 0},
{"1.", false, 1, 0},
{".1", false, 1, 1},
{"0.1", false, 1, 1},
{"0.01", false, 1, 2},
{"0.0000000000000000001", false, 1, 19},
{"1000000000000000000.0", false, 1000000000000000000, 0},
{"9999999999999999999.0", false, 9999999999999999999, 0},
{"9999999999999999999", false, 9999999999999999999, 0},
{"999999999999999999.9", false, 9999999999999999999, 1},
{"99999999999999999.99", false, 9999999999999999999, 2},
{"0.9999999999999999999", false, 9999999999999999999, 19},
// Rounding
{"-999999999999999999.99", true, 1000000000000000000, 0},
{"0.00000000000000000000000000000000000000", false, 0, 19},
{"0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", false, 0, 19},
{"-0.00000000000000000000000000000000000001", false, 0, 19},
{"0.00000000000000000000000000000000000001", false, 0, 19},
{"0.123456789012345678901234567890", false, 1234567890123456789, 19},
{"0.12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678", false, 1234567890123456789, 19},
// Exponential notation
{"0e9", false, 0, 0},
{"0e-9", false, 0, 9},
{"1.23e-12", false, 123, 14},
{"1.23e-5", false, 123, 7},
{"1.23e-4", false, 123, 6},
{"1.23e-3", false, 123, 5},
{"1.23e-2", false, 123, 4},
{"1.23e-1", false, 123, 3},
{"1.23e+0", false, 123, 2},
{"1.23e+1", false, 123, 1},
{"1.23e+2", false, 123, 0},
{"1.23e+3", false, 1230, 0},
{"1.23e+4", false, 12300, 0},
{"1.23e+5", false, 123000, 0},
{"1.23e+12", false, 1230000000000, 0},
{"0.0e-38", false, 0, 19},
{"0e-38", false, 0, 19},
{"1e-2", false, 1, 2},
{"1e-1", false, 1, 1},
{"1e0", false, 1, 0},
{"1e+1", false, 10, 0},
{"1e+2", false, 100, 0},
{"0.0000000000000000001e-19", false, 0, 19},
{"0.0000000000000000001e19", false, 1, 0},
{"1000000000000000000e-19", false, 1000000000000000000, 19},
{"1000000000000000000e-38", false, 0, 19},
{"10000000000000000000e-38", false, 1, 19},
{"100000000000000000000e-38", false, 10, 19},
{"10000000000000000000000000000000000000e-38", false, 1000000000000000000, 19},
{"1e+18", false, 1000000000000000000, 0},
{"0.0000000001e10", false, 1, 0},
{"10000000000e-10", false, 10000000000, 10},
{"4E9", false, 4000000000, 0},
{"0.73e-7", false, 73, 9},
}
for _, tt := range tests {
got, err := Parse(tt.s)
if err != nil {
t.Errorf("Parse(%q) failed: %v", tt.s, err)
continue
}
if got.IsNeg() != tt.wantNeg {
t.Errorf("Parse(%q).IsNeg() = %v, want %v", tt.s, got.IsNeg(), tt.wantNeg)
continue
}
if got.Coef() != tt.wantCoef {
t.Errorf("Parse(%q).Coef() = %v, want %v", tt.s, got.Coef(), tt.wantCoef)
continue
}
if got.Scale() != tt.wantScale {
t.Errorf("Parse(%q).Scale() = %v, want %v", tt.s, got.Scale(), tt.wantScale)
continue
}
}
})
t.Run("error", func(t *testing.T) {
tests := map[string]struct {
s string
scale int
}{
"missing digits 1": {"", 0},
"missing digits 2": {"+", 0},
"missing digits 3": {"-", 0},
"missing digits 4": {".", 0},
"missing digits 5": {"..", 0},
"missing digits 6": {".e", 0},
"missing digits 7": {"e1", 0},
"missing digits 8": {"+e", 0},
"missing digits 9": {"-e", 0},
"missing digits 10": {"e+", 0},
"missing digits 11": {"e-", 0},
"missing digits 12": {"e.0", 0},
"missing digits 13": {"e+1", 0},
"missing digits 14": {"e-1", 0},
"invalid char 1": {"a", 0},
"invalid char 2": {"1a", 0},
"invalid char 3": {"1.a", 0},
"invalid char 4": {" 1", 0},
"invalid char 5": {" +1", 0},
"invalid char 6": {" -1", 0},
"invalid char 7": {"1 ", 0},
"invalid char 8": {"+1 ", 0},
"invalid char 9": {"-1 ", 0},
"invalid char 10": {" 1 ", 0},
"invalid char 11": {" + 1", 0},
"invalid char 12": {" - 1", 0},
"invalid char 13": {"1,1", 0},
"missing exp 1": {"0.e", 0},
"missing exp 2": {"1e", 0},
"missing exp 3": {"1ee", 0},
"exp range 1": {"1e-331", 0},
"exp range 2": {"1e331", 0},
"double sign 1": {"++1", 0},
"double sign 2": {"--1", 0},
"double sign 3": {"+-1", 0},
"double sign 4": {"-+1", 0},
"double sign 5": {"-1.-1", 0},
"double sign 6": {"1.1-", 0},
"double sign 7": {"1e--1", 0},
"double sign 8": {"1e-+1", 0},
"double sign 9": {"1e+-1", 0},
"double sign 10": {"1e++1", 0},
"double sign 11": {"1e-1-", 0},
"double sign 12": {"-1-", 0},
"double dot 1": {"1.1.1", 0},
"double dot 2": {"..1", 0},
"double dot 3": {"1..1", 0},
"double dot 4": {".1.1", 0},
"double dot 5": {"1.1.", 0},
"double dot 6": {".1.", 0},
"special value 1": {"Inf", 0},
"special value 2": {"-infinity", 0},
"special value 3": {"NaN", 0},
"overflow 1": {"-10000000000000000000", 0},
"overflow 2": {"-99999999999999999990", 0},
"overflow 3": {"10000000000000000000", 0},
"overflow 4": {"99999999999999999990", 0},
"overflow 5": {"123456789012345678901234567890123456789", 0},
"many digits": {"0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 0},
"scale 1": {"0", MaxScale + 1},
"scale 2": {"10", MaxScale},
"scale 3": {"100", MaxScale - 1},
}
for name, tt := range tests {
t.Run(name, func(t *testing.T) {
_, err := ParseExact(tt.s, tt.scale)
if err == nil {
t.Errorf("ParseExact(%q, %v) did not fail", tt.s, tt.scale)
return
}
})
}
})
}
func TestMustParse(t *testing.T) {
t.Run("error", func(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Errorf("MustParse(\".\") did not panic")
}
}()
MustParse(".")
})
}
func TestDecimalUnmarshalText(t *testing.T) {
t.Run("error", func(t *testing.T) {
d := Decimal{}
err := d.UnmarshalText([]byte("1.1.1"))
if err == nil {
t.Errorf("UnmarshalText(\"1.1.1\") did not fail")
}
})
}
func TestDecimalUnmarshalBinary(t *testing.T) {
t.Run("error", func(t *testing.T) {
d := Decimal{}
err := d.UnmarshalBinary([]byte("1.1.1"))
if err == nil {
t.Errorf("UnmarshalBinary(\"1.1.1\") did not fail")
}
})
}
func TestDecimalUnmarshalJSON(t *testing.T) {
t.Run("success", func(t *testing.T) {
tests := []struct {
s string
want string
}{
{"null", "0"},
{"\"-9999999999999999999.0\"", "-9999999999999999999"},
{"\"-9999999999999999999\"", "-9999999999999999999"},
{"\"-999999999999999999.9\"", "-999999999999999999.9"},
{"\"-99999999999999999.99\"", "-99999999999999999.99"},
{"\"-1000000000000000000.0\"", "-1000000000000000000"},
{"\"-0.9999999999999999999\"", "-0.9999999999999999999"},
}
for _, tt := range tests {
var got Decimal
err := got.UnmarshalJSON([]byte(tt.s))
if err != nil {
t.Errorf("UnmarshalJSON(%q) failed: %v", tt.s, err)
continue
}
want := MustParse(tt.want)
if got != want {
t.Errorf("UnmarshalJSON(%q) = %q, want %q", tt.s, got, want)
}
}
})
t.Run("error", func(t *testing.T) {
d := Decimal{}
err := d.UnmarshalJSON([]byte("\"-1.1.1\""))
if err == nil {
t.Errorf("UnmarshalJSON(\"-1.1.1\") did not fail")
}
})
}
func TestDecimalUnmarshalBSONValue(t *testing.T) {
t.Run("success", func(t *testing.T) {
tests := []struct {
typ byte
data []byte
want string
}{
{1, []byte{0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0xf0, 0x3f}, "1.0001220703125"},
{2, []byte{0x15, 0x0, 0x0, 0x0, 0x2d, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x0}, "-9999999999999999999"},
{10, nil, "0"},
{16, []byte{0xff, 0xff, 0xff, 0x7f}, "2147483647"},
{18, []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f}, "9223372036854775807"},
{19, []byte{0xf1, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3a, 0x30}, "1.265"},
}
for _, tt := range tests {
got := Decimal{}
err := got.UnmarshalBSONValue(tt.typ, tt.data)
if err != nil {
t.Errorf("UnmarshalBSONValue(%v, % x) failed: %v", tt.typ, tt.data, err)
continue
}
want := MustParse(tt.want)
if got != want {
t.Errorf("UnmarshalBSONValue(%v, % x) = %q, want %q", tt.typ, tt.data, got, want)
}
}
})
t.Run("error", func(t *testing.T) {
d := Decimal{}
err := d.UnmarshalBSONValue(12, nil)
if err == nil {
t.Errorf("UnmarshalBSONValue(12, nil) did not fail")
}
})
}
func TestParseBSONFloat64(t *testing.T) {
t.Run("success", func(t *testing.T) {
tests := []struct {
b []byte
want string
}{
// Zero
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, "0"},
// Negative zero
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80}, "0"},
// Integers
{[]byte{0x2a, 0x1b, 0xf5, 0xf4, 0x10, 0x22, 0xb1, 0xc3}, "-1234567892123200000"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf0, 0xbf}, "-1"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf0, 0x3f}, "1"},
{[]byte{0x2a, 0x1b, 0xf5, 0xf4, 0x10, 0x22, 0xb1, 0x43}, "1234567892123200000"},
// Floats
{[]byte{0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0xf0, 0xbf}, "-1.0001220703125"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0xf0, 0x3f}, "1.0001220703125"},
}
for _, tt := range tests {
got, err := parseBSONFloat64(tt.b)
if err != nil {
t.Errorf("parseBSONFloat64(%v) failed: %v", tt.b, err)
continue
}
want := MustParse(tt.want)
if got != want {
t.Errorf("parseBSONFloat64(%v) = %q, want %q", tt.b, got, want)
}
}
})
t.Run("error", func(t *testing.T) {
tests := map[string][]byte{
"length 1": {},
"length 2": {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
"length 3": {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
"nan 1": {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf8, 0x7f},
"nan 2": {0x12, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf8, 0x7f},
"inf 1": {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf0, 0x7f},
"inf 2": {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf0, 0xff},
}
for name, tt := range tests {
t.Run(name, func(t *testing.T) {
_, err := parseBSONFloat64(tt)
if err == nil {
t.Errorf("parseBSONFloat64(%v) did not fail", tt)
}
})
}
})
}
func TestParseBSONString(t *testing.T) {
t.Run("success", func(t *testing.T) {
tests := []struct {
b []byte
want string
}{
{[]byte{0x15, 0x0, 0x0, 0x0, 0x2d, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x0}, "-9999999999999999999"},
{[]byte{0x17, 0x0, 0x0, 0x0, 0x2d, 0x30, 0x2e, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x0}, "-0.0000000000000000001"},
{[]byte{0x16, 0x0, 0x0, 0x0, 0x30, 0x2e, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x0}, "0.0000000000000000000"},
{[]byte{0x2, 0x0, 0x0, 0x0, 0x30, 0x0}, "0"},
{[]byte{0x16, 0x0, 0x0, 0x0, 0x30, 0x2e, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x0}, "0.0000000000000000001"},
{[]byte{0x2, 0x0, 0x0, 0x0, 0x31, 0x0}, "1"},
{[]byte{0x3, 0x0, 0x0, 0x0, 0x30, 0x31, 0x0}, "1"},
{[]byte{0x15, 0x0, 0x0, 0x0, 0x33, 0x2e, 0x31, 0x34, 0x31, 0x35, 0x39, 0x32, 0x36, 0x35, 0x33, 0x35, 0x38, 0x39, 0x37, 0x39, 0x33, 0x32, 0x33, 0x38, 0x0}, "3.141592653589793238"},
{[]byte{0x3, 0x0, 0x0, 0x0, 0x31, 0x30, 0x0}, "10"},
{[]byte{0x14, 0x0, 0x0, 0x0, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x0}, "9999999999999999999"},
}
for _, tt := range tests {
got, err := parseBSONString(tt.b)
if err != nil {
t.Errorf("parseBSONString(%v) failed: %v", tt.b, err)
continue
}
want := MustParse(tt.want)
if got != want {
t.Errorf("parseBSONString(%v) = %q, want %q", tt.b, got, want)
}
}
})
t.Run("error", func(t *testing.T) {
tests := map[string][]byte{
"length 1": {},
"length 2": {0x0, 0x0, 0x0, 0x0},
"length 3": {0x2, 0x0, 0x0, 0x0, 0x30},
"terminator 1": {0x2, 0x0, 0x0, 0x0, 0x30, 0x30},
}
for name, tt := range tests {
t.Run(name, func(t *testing.T) {
_, err := parseBSONString(tt)
if err == nil {
t.Errorf("parseBSONString(%v) did not fail", tt)
}
})
}
})
}
func TestParseBSONInt32(t *testing.T) {
t.Run("success", func(t *testing.T) {
tests := []struct {
b []byte
want string
}{
{[]byte{0x0, 0x0, 0x0, 0x80}, "-2147483648"},
{[]byte{0xff, 0xff, 0xff, 0xff}, "-1"},
{[]byte{0x0, 0x0, 0x0, 0x0}, "0"},
{[]byte{0x1, 0x0, 0x0, 0x0}, "1"},
{[]byte{0xff, 0xff, 0xff, 0x7f}, "2147483647"},
}
for _, tt := range tests {
got, err := parseBSONInt32(tt.b)
if err != nil {
t.Errorf("parseBSONInt32(%v) failed: %v", tt.b, err)
continue
}
want := MustParse(tt.want)
if got != want {
t.Errorf("parseBSONInt32(%v) = %q, want %q", tt.b, got, want)
}
}
})
t.Run("error", func(t *testing.T) {
tests := map[string][]byte{
"length 1": {},
"length 2": {0x0, 0x0, 0x0},
"length 3": {0x0, 0x0, 0x0, 0x0, 0x0},
}
for name, tt := range tests {
t.Run(name, func(t *testing.T) {
_, err := parseBSONInt32(tt)
if err == nil {
t.Errorf("parseBSONInt32(%v) did not fail", tt)
}
})
}
})
}
func TestParseBSONInt64(t *testing.T) {
t.Run("success", func(t *testing.T) {
tests := []struct {
b []byte
want string
}{
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80}, "-9223372036854775808"},
{[]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, "-1"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, "0"},
{[]byte{0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, "1"},
{[]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f}, "9223372036854775807"},
}
for _, tt := range tests {
got, err := parseBSONInt64(tt.b)
if err != nil {
t.Errorf("parseBSONInt64(%v) failed: %v", tt.b, err)
continue
}
want := MustParse(tt.want)
if got != want {
t.Errorf("parseBSONInt64(%v) = %q, want %q", tt.b, got, want)
}
}
})
t.Run("error", func(t *testing.T) {
tests := map[string][]byte{
"length 1": {},
"length 2": {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
"length 3": {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
}
for name, tt := range tests {
t.Run(name, func(t *testing.T) {
_, err := parseBSONInt64(tt)
if err == nil {
t.Errorf("parseBSONInt64(%v) did not fail", tt)
}
})
}
})
}
func TestParseIEEEDecimal128(t *testing.T) {
t.Run("success", func(t *testing.T) {
tests := []struct {
b []byte
want string
}{
// Zeros
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, "0.0000000000000000000"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7a, 0x2b}, "0.0000000000000000000"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2a, 0x30}, "0.00000000000"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2c, 0x30}, "0.0000000000"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2e, 0x30}, "0.000000000"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30, 0x30}, "0.00000000"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x32, 0x30}, "0.0000000"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x34, 0x30}, "0.000000"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x36, 0x30}, "0.00000"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x38, 0x30}, "0.0000"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3a, 0x30}, "0.000"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x30}, "0.00"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, 0x30}, "0.0"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "0"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x42, 0x30}, "0"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x44, 0x30}, "0"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46, 0x30}, "0"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x48, 0x30}, "0"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4a, 0x30}, "0"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4c, 0x30}, "0"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4e, 0x30}, "0"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x50, 0x30}, "0"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x52, 0x30}, "0"},
// Negative zeroes
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80}, "0.0000000000000000000"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2e, 0xb0}, "0.000000000"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30, 0xb0}, "0.00000000"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x32, 0xb0}, "0.0000000"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x34, 0xb0}, "0.000000"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x36, 0xb0}, "0.00000"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x38, 0xb0}, "0.0000"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3a, 0xb0}, "0.000"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c, 0xb0}, "0.00"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, 0xb0}, "0.0"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0xb0}, "0"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46, 0xb0}, "0"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x52, 0xb0}, "0"},
// Overflows with 0 coefficient
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x5f}, "0"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfe, 0x5f}, "0"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfe, 0xdf}, "0"},
// Underflows
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0a, 0x5b, 0xc1, 0x38, 0x93, 0x8d, 0x44, 0xc6, 0x4d, 0x31, 0x0, 0x0}, "0.0000000000000000000"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x0a, 0x5b, 0xc1, 0x38, 0x93, 0x8d, 0x44, 0xc6, 0x4d, 0x31, 0x0, 0x80}, "0.0000000000000000000"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x81, 0xef, 0xac, 0x85, 0x5b, 0x41, 0x6d, 0x2d, 0xee, 0x04, 0x0, 0x0}, "0.0000000000000000000"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x81, 0xef, 0xac, 0x85, 0x5b, 0x41, 0x6d, 0x2d, 0xee, 0x04, 0x0, 0x0}, "0.0000000000000000000"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x81, 0xef, 0xac, 0x85, 0x5b, 0x41, 0x6d, 0x2d, 0xee, 0x04, 0x0, 0x80}, "0.0000000000000000000"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x81, 0xef, 0xac, 0x85, 0x5b, 0x41, 0x6d, 0x2d, 0xee, 0x04, 0x0, 0x80}, "0.0000000000000000000"},
{[]byte{0x0, 0x0, 0x20, 0x3b, 0x9d, 0xb5, 0x05, 0x6f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x24}, "0.0000000000000000000"},
{[]byte{0x0, 0x0, 0xfe, 0xd8, 0x3f, 0x4e, 0x7c, 0x9f, 0xe4, 0xe2, 0x69, 0xe3, 0x8a, 0x5b, 0xcd, 0x17}, "0.0000000000000000000"},
{[]byte{0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, "0.0000000000000000000"},
{[]byte{0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, "0.0000000000000000000"},
{[]byte{0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, "0.0000000000000000000"},
{[]byte{0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, "0.0000000000000000000"},
{[]byte{0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, "0.0000000000000000000"},
{[]byte{0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80}, "0.0000000000000000000"},
{[]byte{0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80}, "0.0000000000000000000"},
{[]byte{0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80}, "0.0000000000000000000"},
{[]byte{0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80}, "0.0000000000000000000"},
{[]byte{0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x02, 0x0}, "0.0000000000000000000"},
{[]byte{0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x02, 0x0}, "0.0000000000000000000"},
{[]byte{0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x02, 0x80}, "0.0000000000000000000"},
{[]byte{0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x02, 0x80}, "0.0000000000000000000"},
{[]byte{0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x42, 0x0}, "0.0000000000000000000"},
{[]byte{0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x42, 0x80}, "0.0000000000000000000"},
{[]byte{0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x72, 0x28}, "0.0000000000000000000"},
{[]byte{0x01, 0x0, 0x0, 0x0, 0x0a, 0x5b, 0xc1, 0x38, 0x93, 0x8d, 0x44, 0xc6, 0x4d, 0x31, 0x0, 0x0}, "0.0000000000000000000"},
{[]byte{0x01, 0x0, 0x0, 0x0, 0x0a, 0x5b, 0xc1, 0x38, 0x93, 0x8d, 0x44, 0xc6, 0x4d, 0x31, 0x0, 0x80}, "0.0000000000000000000"},
{[]byte{0x0a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, "0.0000000000000000000"},
{[]byte{0x0a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, "0.0000000000000000000"},
{[]byte{0x0a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80}, "0.0000000000000000000"},
{[]byte{0x0a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80}, "0.0000000000000000000"},
{[]byte{0x3c, 0x17, 0x25, 0x84, 0x19, 0xd7, 0x10, 0xc4, 0x2f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x24}, "0.0000000000000000000"},
{[]byte{0xff, 0xff, 0xff, 0xff, 0x09, 0x5b, 0xc1, 0x38, 0x93, 0x8d, 0x44, 0xc6, 0x4d, 0x31, 0x0, 0x0}, "0.0000000000000000000"},
{[]byte{0xff, 0xff, 0xff, 0xff, 0x09, 0x5b, 0xc1, 0x38, 0x93, 0x8d, 0x44, 0xc6, 0x4d, 0x31, 0x0, 0x80}, "0.0000000000000000000"},
{[]byte{0xff, 0xff, 0xff, 0xff, 0x63, 0x8e, 0x8d, 0x37, 0xc0, 0x87, 0xad, 0xbe, 0x09, 0xed, 0x01, 0x0}, "0.0000000000000000000"},
// Powers of 10
{[]byte{0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0xb0}, "-1"},
{[]byte{0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, 0xb0}, "-1.0"},
{[]byte{0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, 0xb0}, "-0.1"},
{[]byte{0x64, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2c, 0xb0}, "-0.0000000100"},
{[]byte{0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x26, 0x30}, "0.0000000000010"},
{[]byte{0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x28, 0x30}, "0.000000000010"},
{[]byte{0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2a, 0x30}, "0.00000000010"},
{[]byte{0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2c, 0x30}, "0.0000000010"},
{[]byte{0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2e, 0x30}, "0.000000010"},
{[]byte{0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30, 0x30}, "0.00000010"},
{[]byte{0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x32, 0x30}, "0.0000010"},
{[]byte{0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x34, 0x30}, "0.000010"},
{[]byte{0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x36, 0x30}, "0.00010"},
{[]byte{0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x38, 0x30}, "0.0010"},
{[]byte{0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3a, 0x30}, "0.010"},
{[]byte{0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, 0x30}, "0.1"},
{[]byte{0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x30}, "0.10"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0xa, 0x5b, 0xc1, 0x38, 0x93, 0x8d, 0x44, 0xc6, 0x4d, 0x31, 0xfc, 0x2f}, "0.1000000000000000000"},
{[]byte{0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "1"},
{[]byte{0x64, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x30}, "1.00"},
{[]byte{0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, 0x30}, "1.0"},
{[]byte{0x64, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, 0x30}, "10.0"},
{[]byte{0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "10"},
{[]byte{0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x42, 0x30}, "100"},
{[]byte{0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46, 0x30}, "1000"},
{[]byte{0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x44, 0x30}, "1000"},
{[]byte{0xe8, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "1000"},
{[]byte{0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46, 0x30}, "10000"},
{[]byte{0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x48, 0x30}, "100000"},
{[]byte{0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4a, 0x30}, "1000000"},
{[]byte{0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4c, 0x30}, "10000000"},
{[]byte{0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4e, 0x30}, "100000000"},
{[]byte{0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x52, 0x30}, "1000000000"},
{[]byte{0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x50, 0x30}, "1000000000"},
{[]byte{0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x52, 0x30}, "10000000000"},
{[]byte{0x64, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x52, 0x30}, "100000000000"},
{[]byte{0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x54, 0x30}, "100000000000"},
{[]byte{0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x56, 0x30}, "1000000000000"},
{[]byte{0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x58, 0x30}, "10000000000000"},
// Integers
{[]byte{0xee, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0xb0}, "-750"},
{[]byte{0x7b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0xb0}, "-123"},
{[]byte{0x4c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0xb0}, "-76"},
{[]byte{0xc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0xb0}, "-12"},
{[]byte{0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0xb0}, "-1"},
{[]byte{0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "2"},
{[]byte{0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "7"},
{[]byte{0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "9"},
{[]byte{0xc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "12"},
{[]byte{0x11, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "17"},
{[]byte{0x13, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "19"},
{[]byte{0x14, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "20"},
{[]byte{0x1d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "29"},
{[]byte{0x1e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "30"},
{[]byte{0x27, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "39"},
{[]byte{0x28, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "40"},
{[]byte{0x2c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "44"},
{[]byte{0x31, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "49"},
{[]byte{0x32, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "50"},
{[]byte{0x3b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "59"},
{[]byte{0x3c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "60"},
{[]byte{0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "69"},
{[]byte{0x46, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "70"},
{[]byte{0x47, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "71"},
{[]byte{0x48, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "72"},
{[]byte{0x49, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "73"},
{[]byte{0x4a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "74"},
{[]byte{0x4b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "75"},
{[]byte{0x4c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "76"},
{[]byte{0x4d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "77"},
{[]byte{0x4e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "78"},
{[]byte{0x4f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "79"},
{[]byte{0x7b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "123"},
{[]byte{0x8, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "520"},
{[]byte{0x9, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "521"},
{[]byte{0x9, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "777"},
{[]byte{0xa, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "778"},
{[]byte{0x13, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "787"},
{[]byte{0x1f, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "799"},
{[]byte{0x6d, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "877"},
{[]byte{0x78, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "888"},
{[]byte{0x79, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "889"},
{[]byte{0x82, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "898"},
{[]byte{0x83, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "899"},
{[]byte{0xd3, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "979"},
{[]byte{0xdc, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "988"},
{[]byte{0xdd, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "989"},
{[]byte{0xe2, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "994"},
{[]byte{0xe3, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "995"},
{[]byte{0xe5, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "997"},
{[]byte{0xe6, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "998"},
{[]byte{0xe7, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "999"},
{[]byte{0x30, 0x75, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "30000"},
{[]byte{0x90, 0x94, 0xd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "890000"},
{[]byte{0xfe, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "4294967294"},
{[]byte{0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "4294967295"},
{[]byte{0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "4294967296"},
{[]byte{0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "4294967297"},
{[]byte{0x1, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0xb0}, "-2147483649"},
{[]byte{0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0xb0}, "-2147483648"},
{[]byte{0xff, 0xff, 0xff, 0x7f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0xb0}, "-2147483647"},
{[]byte{0xfe, 0xff, 0xff, 0x7f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0xb0}, "-2147483646"},
{[]byte{0xfe, 0xff, 0xff, 0x7f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "2147483646"},
{[]byte{0xff, 0xff, 0xff, 0x7f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "2147483647"},
{[]byte{0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "2147483648"},
{[]byte{0x1, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "2147483649"},
// 1265 multiplied by powers of 10
{[]byte{0xf1, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x30}, "0.0000000000000000000"},
{[]byte{0xf1, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x12, 0x30}, "0.0000000000000000000"},
{[]byte{0xf1, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x14, 0x30}, "0.0000000000000000001"},
{[]byte{0xf1, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x16, 0x30}, "0.0000000000000000013"},
{[]byte{0xf1, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18, 0x30}, "0.0000000000000000126"},
{[]byte{0xf1, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x28, 0x30}, "0.000000001265"},
{[]byte{0xf1, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2a, 0x30}, "0.00000001265"},
{[]byte{0xf1, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2c, 0x30}, "0.0000001265"},
{[]byte{0xf1, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2e, 0x30}, "0.000001265"},
{[]byte{0xf1, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30, 0x30}, "0.00001265"},
{[]byte{0xf1, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x32, 0x30}, "0.0001265"},
{[]byte{0xf1, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x34, 0x30}, "0.001265"},
{[]byte{0xf1, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x36, 0x30}, "0.01265"},
{[]byte{0xf1, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x38, 0x30}, "0.1265"},
{[]byte{0xf1, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3a, 0x30}, "1.265"},
{[]byte{0xf1, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x30}, "12.65"},
{[]byte{0xf1, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, 0x30}, "126.5"},
{[]byte{0xf1, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "1265"},
{[]byte{0xf1, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x42, 0x30}, "12650"},
{[]byte{0xf1, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x44, 0x30}, "126500"},
{[]byte{0xf1, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46, 0x30}, "1265000"},
{[]byte{0xf1, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x48, 0x30}, "12650000"},
{[]byte{0xf1, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4a, 0x30}, "126500000"},
{[]byte{0xf1, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4c, 0x30}, "1265000000"},
{[]byte{0xf1, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4e, 0x30}, "12650000000"},
{[]byte{0xf1, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x50, 0x30}, "126500000000"},
{[]byte{0xf1, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x52, 0x30}, "1265000000000"},
{[]byte{0xf1, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x54, 0x30}, "12650000000000"},
{[]byte{0xf1, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x56, 0x30}, "126500000000000"},
{[]byte{0xf1, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x58, 0x30}, "1265000000000000"},
{[]byte{0xf1, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5a, 0x30}, "12650000000000000"},
{[]byte{0xf1, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5c, 0x30}, "126500000000000000"},
{[]byte{0xf1, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5e, 0x30}, "1265000000000000000"},
// 7 multiplied by powers of 10
{[]byte{0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x26, 0x30}, "0.0000000000007"},
{[]byte{0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x28, 0x30}, "0.000000000007"},
{[]byte{0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2a, 0x30}, "0.00000000007"},
{[]byte{0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2c, 0x30}, "0.0000000007"},
{[]byte{0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2e, 0x30}, "0.000000007"},
{[]byte{0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30, 0x30}, "0.00000007"},
{[]byte{0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x32, 0x30}, "0.0000007"},
{[]byte{0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x34, 0x30}, "0.000007"},
{[]byte{0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x36, 0x30}, "0.00007"},
{[]byte{0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x38, 0x30}, "0.0007"},
{[]byte{0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3a, 0x30}, "0.007"},
{[]byte{0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x30}, "0.07"},
{[]byte{0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, 0x30}, "0.7"},
{[]byte{0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "7"},
{[]byte{0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x42, 0x30}, "70"},
{[]byte{0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x44, 0x30}, "700"},
{[]byte{0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46, 0x30}, "7000"},
{[]byte{0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x48, 0x30}, "70000"},
{[]byte{0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4a, 0x30}, "700000"},
{[]byte{0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4c, 0x30}, "7000000"},
{[]byte{0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4e, 0x30}, "70000000"},
{[]byte{0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x50, 0x30}, "700000000"},
{[]byte{0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x52, 0x30}, "7000000000"},
{[]byte{0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x52, 0x30}, "7000000000"},
{[]byte{0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x54, 0x30}, "70000000000"},
{[]byte{0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x56, 0x30}, "700000000000"},
{[]byte{0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x58, 0x30}, "7000000000000"},
{[]byte{0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5a, 0x30}, "70000000000000"},
{[]byte{0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5c, 0x30}, "700000000000000"},
{[]byte{0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5e, 0x30}, "7000000000000000"},
// Sequences of digits
{[]byte{0x18, 0x5c, 0xa, 0xce, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x38, 0xb0}, "-345678.5432"},
{[]byte{0x39, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0xb0}, "-12345"},
{[]byte{0xd2, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0xb0}, "-1234"},
{[]byte{0x39, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c, 0xb0}, "-123.45"},
{[]byte{0x7b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c, 0xb0}, "-1.23"},
{[]byte{0x15, 0xcd, 0x5b, 0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x30}, "0.0000000123456789"},
{[]byte{0x15, 0xcd, 0x5b, 0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x22, 0x30}, "0.000000123456789"},
{[]byte{0xf2, 0xaf, 0x96, 0x7e, 0xd0, 0x5c, 0x82, 0xde, 0x32, 0x97, 0xff, 0x6f, 0xde, 0x3c, 0xf0, 0x2f}, "0.0000001234567890123"},
{[]byte{0x15, 0xcd, 0x5b, 0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x24, 0x30}, "0.00000123456789"},
{[]byte{0x15, 0xcd, 0x5b, 0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x26, 0x30}, "0.0000123456789"},
{[]byte{0x40, 0xef, 0x5a, 0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2a, 0x30}, "0.00123400000"},
{[]byte{0x7b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3a, 0x30}, "0.123"},
{[]byte{0x78, 0xdf, 0xd, 0x86, 0x48, 0x70, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x22, 0x30}, "0.123456789012344"},
{[]byte{0x79, 0xdf, 0xd, 0x86, 0x48, 0x70, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x22, 0x30}, "0.123456789012345"},
{[]byte{0xf2, 0xaf, 0x96, 0x7e, 0xd0, 0x5c, 0x82, 0xde, 0x32, 0x97, 0xff, 0x6f, 0xde, 0x3c, 0xfc, 0x2f}, "0.1234567890123456789"},
{[]byte{0x7b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x30}, "1.23"},
{[]byte{0xd2, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3a, 0x30}, "1.234"},
{[]byte{0x39, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x30}, "123.45"},
{[]byte{0xd2, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "1234"},
{[]byte{0x39, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "12345"},
{[]byte{0x18, 0x5c, 0xa, 0xce, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x38, 0x30}, "345678.5432"},
{[]byte{0x6a, 0xf9, 0xb, 0x7c, 0x50, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x34, 0x30}, "345678.543210"},
{[]byte{0xf1, 0x98, 0x67, 0xc, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x36, 0x30}, "345678.54321"},
{[]byte{0x6a, 0x19, 0x56, 0x25, 0x22, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x34, 0x30}, "2345678.543210"},
{[]byte{0x6a, 0xb9, 0xc8, 0x73, 0x3a, 0xb, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x34, 0x30}, "12345678.543210"},
{[]byte{0x40, 0xaf, 0xd, 0x86, 0x48, 0x70, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x34, 0x30}, "123456789.000000"},
{[]byte{0x80, 0x91, 0xf, 0x86, 0x48, 0x70, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x34, 0x30}, "123456789.123456"},
{[]byte{0x80, 0x91, 0xf, 0x86, 0x48, 0x70, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}, "123456789123456"},
}
for _, tt := range tests {
got, err := parseIEEEDecimal128(tt.b)
if err != nil {
t.Errorf("parseIEEEDecimal128([% x]) failed: %v", tt.b, err)
continue
}
want := MustParse(tt.want)
if got != want {
t.Errorf("parseIEEEDecimal128([% x]) = %q, want %q", tt.b, got, want)
}
}
})
t.Run("error", func(t *testing.T) {
tests := map[string][]byte{
"length 1": {},
"length 2": {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
"length 3": {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
"inf 1": {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x78},
"inf 2": {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf8},
"nan 1": {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7c},
"nan 2": {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfc},
"nan 3": {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7e},
"nan 4": {0x12, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7e},
"nan 5": {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfe},
"overflow 1": {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x41, 0x30},
"overflow 2": {0x0, 0x0, 0x0, 0x0, 0xa, 0x5b, 0xc1, 0x38, 0x93, 0x8d, 0x44, 0xc6, 0x4d, 0x31, 0xcc, 0x37},
"overflow 3": {0x0, 0x0, 0x0, 0x0, 0xa, 0x5b, 0xc1, 0x38, 0x93, 0x8d, 0x44, 0xc6, 0x4d, 0x31, 0xfe, 0x5f},
"overflow 4": {0x0, 0x0, 0x0, 0x0, 0xa, 0x5b, 0xc1, 0x38, 0x93, 0x8d, 0x44, 0xc6, 0x4d, 0x31, 0xfe, 0xdf},
"overflow 5": {0x0, 0x0, 0x0, 0x0, 0x81, 0xef, 0xac, 0x85, 0x5b, 0x41, 0x6d, 0x2d, 0xee, 0x4, 0xfe, 0x5f},
"overflow 6": {0x0, 0x0, 0x0, 0x10, 0x61, 0x2, 0x25, 0x3e, 0x5e, 0xce, 0x4f, 0x20, 0x0, 0x0, 0xfe, 0x5f},
"overflow 7": {0x0, 0x0, 0x0, 0x40, 0xea, 0xed, 0x74, 0x46, 0xd0, 0x9c, 0x2c, 0x9f, 0xc, 0x0, 0xfe, 0x5f},
"overflow 8": {0x0, 0x0, 0x0, 0x4a, 0x48, 0x1, 0x14, 0x16, 0x95, 0x45, 0x8, 0x0, 0x0, 0x0, 0xfe, 0x5f},
"overflow 9": {0x0, 0x0, 0x0, 0x80, 0x26, 0x4b, 0x91, 0xc0, 0x22, 0x20, 0xbe, 0x37, 0x7e, 0x0, 0xfe, 0x5f},
"overflow 10": {0x0, 0x0, 0x0, 0x80, 0x7f, 0x1b, 0xcf, 0x85, 0xb2, 0x70, 0x59, 0xc8, 0xa4, 0x3c, 0xfe, 0x5f},
"overflow 11": {0x0, 0x0, 0x0, 0x80, 0x7f, 0x1b, 0xcf, 0x85, 0xb2, 0x70, 0x59, 0xc8, 0xa4, 0x3c, 0xfe, 0xdf},
"overflow 12": {0x0, 0x0, 0x0, 0xa0, 0xca, 0x17, 0x72, 0x6d, 0xae, 0xf, 0x1e, 0x43, 0x1, 0x0, 0xfe, 0x5f},
"overflow 13": {0x0, 0x0, 0x0, 0xa1, 0xed, 0xcc, 0xce, 0x1b, 0xc2, 0xd3, 0x0, 0x0, 0x0, 0x0, 0xfe, 0x5f},
"overflow 14": {0x0, 0x0, 0x0, 0xe4, 0xd2, 0xc, 0xc8, 0xdc, 0xd2, 0xb7, 0x52, 0x0, 0x0, 0x0, 0xfe, 0x5f},
"overflow 15": {0x0, 0x0, 0x0, 0xe8, 0x3c, 0x80, 0xd0, 0x9f, 0x3c, 0x2e, 0x3b, 0x3, 0x0, 0x0, 0xfe, 0x5f},
"overflow 16": {0x0, 0x0, 0x10, 0x63, 0x2d, 0x5e, 0xc7, 0x6b, 0x5, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfe, 0x5f},
"overflow 17": {0x0, 0x0, 0x40, 0xb2, 0xba, 0xc9, 0xe0, 0x19, 0x1e, 0x2, 0x0, 0x0, 0x0, 0x0, 0xfe, 0x5f},
"overflow 18": {0x0, 0x0, 0x64, 0xa7, 0xb3, 0xb6, 0xe0, 0xd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfe, 0x5f},
"overflow 19": {0x0, 0x0, 0x80, 0xf6, 0x4a, 0xe1, 0xc7, 0x2, 0x2d, 0x15, 0x0, 0x0, 0x0, 0x0, 0xfe, 0x5f},
"overflow 20": {0x0, 0x0, 0x8a, 0x5d, 0x78, 0x45, 0x63, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfe, 0x5f},
"overflow 21": {0x0, 0x0, 0xa0, 0xde, 0xc5, 0xad, 0xc9, 0x35, 0x36, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfe, 0x5f},
"overflow 22": {0x0, 0x0, 0xc1, 0x6f, 0xf2, 0x86, 0x23, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfe, 0x5f},
"overflow 23": {0x0, 0x0, 0xe8, 0x89, 0x4, 0x23, 0xc7, 0x8a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfe, 0x5f},
"overflow 24": {0x0, 0x10, 0xa5, 0xd4, 0xe8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfe, 0x5f},
"overflow 25": {0x0, 0x40, 0x7a, 0x10, 0xf3, 0x5a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfe, 0x5f},
"overflow 26": {0x0, 0x80, 0xc6, 0xa4, 0x7e, 0x8d, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfe, 0x5f},
"overflow 27": {0x0, 0xa0, 0x72, 0x4e, 0x18, 0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfe, 0x5f},
"overflow 28": {0x0, 0xca, 0x9a, 0x3b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfe, 0x5f},
"overflow 29": {0x0, 0xe1, 0xf5, 0x5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfe, 0x5f},
"overflow 30": {0x0, 0xe4, 0xb, 0x54, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfe, 0x5f},
"overflow 31": {0x0, 0xe8, 0x76, 0x48, 0x17, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfe, 0x5f},
"overflow 32": {0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf4, 0x30},
"overflow 33": {0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfc, 0x5f},
"overflow 34": {0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfe, 0x5f},
"overflow 35": {0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0x31},
"overflow 36": {0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, 0x38},
"overflow 37": {0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1e, 0x5f},
"overflow 38": {0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf4, 0x30},
"overflow 39": {0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfe, 0x5f},
"overflow 40": {0x10, 0x27, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfe, 0x5f},
"overflow 41": {0x40, 0x42, 0xf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfe, 0x5f},
"overflow 42": {0x64, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf4, 0x30},
"overflow 43": {0x64, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfe, 0x5f},
"overflow 44": {0x79, 0xd9, 0xe0, 0xf9, 0x76, 0x3a, 0xda, 0x42, 0x9d, 0x2, 0x0, 0x0, 0x0, 0x0, 0x58, 0x30},
"overflow 45": {0x80, 0x96, 0x98, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfe, 0x5f},
"overflow 46": {0xa0, 0x86, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfe, 0x5f},
"overflow 47": {0xc7, 0x71, 0x1c, 0xc7, 0xb5, 0x48, 0xf3, 0x77, 0xdc, 0x80, 0xa1, 0x31, 0xc8, 0x36, 0x40, 0x30},
"overflow 48": {0xe8, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfe, 0x5f},
"overflow 49": {0xf1, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x60, 0x30},
"overflow 50": {0xf1, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x62, 0x30},
"overflow 51": {0xf1, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x64, 0x30},
"overflow 52": {0xf1, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x68, 0x30},
"overflow 53": {0xf2, 0xaf, 0x96, 0x7e, 0xd0, 0x5c, 0x82, 0xde, 0x32, 0x97, 0xff, 0x6f, 0xde, 0x3c, 0x40, 0x30},
"overflow 54": {0xf2, 0xaf, 0x96, 0x7e, 0xd0, 0x5c, 0x82, 0xde, 0x32, 0x97, 0xff, 0x6f, 0xde, 0x3c, 0x40, 0xb0},
"overflow 55": {0xf2, 0xaf, 0x96, 0x7e, 0xd0, 0x5c, 0x82, 0xde, 0x32, 0x97, 0xff, 0x6f, 0xde, 0x3c, 0xfe, 0x5f},
"overflow 56": {0xf2, 0xaf, 0x96, 0x7e, 0xd0, 0x5c, 0x82, 0xde, 0x32, 0x97, 0xff, 0x6f, 0xde, 0x3c, 0xfe, 0xdf},
"overflow 57": {0xff, 0xff, 0xff, 0xff, 0x63, 0x8e, 0x8d, 0x37, 0xc0, 0x87, 0xad, 0xbe, 0x9, 0xed, 0x41, 0x30},
"overflow 58": {0xff, 0xff, 0xff, 0xff, 0x63, 0x8e, 0x8d, 0x37, 0xc0, 0x87, 0xad, 0xbe, 0x9, 0xed, 0xff, 0x5f},
"overflow 59": {0xff, 0xff, 0xff, 0xff, 0x63, 0x8e, 0x8d, 0x37, 0xc0, 0x87, 0xad, 0xbe, 0x9, 0xed, 0xff, 0xdf},
"overflow 60": {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x40, 0x30},
}
for name, tt := range tests {
t.Run(name, func(t *testing.T) {
_, err := parseIEEEDecimal128(tt)
if err == nil {
t.Errorf("parseIEEEDecimal128([% x]) did not fail", tt)
}
})
}
})
}
func TestDecimal_IEEEDecimal128(t *testing.T) {
t.Run("success", func(t *testing.T) {
tests := []struct {
d string
want []byte
}{
{"-9999999999999999999", []byte{0xff, 0xff, 0xe7, 0x89, 0x4, 0x23, 0xc7, 0x8a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0xb0}},
{"-999999999999999999.9", []byte{0xff, 0xff, 0xe7, 0x89, 0x4, 0x23, 0xc7, 0x8a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, 0xb0}},
{"-99999999999999999.99", []byte{0xff, 0xff, 0xe7, 0x89, 0x4, 0x23, 0xc7, 0x8a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c, 0xb0}},
{"-9999999999999999.999", []byte{0xff, 0xff, 0xe7, 0x89, 0x4, 0x23, 0xc7, 0x8a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3a, 0xb0}},
{"-0.9999999999999999999", []byte{0xff, 0xff, 0xe7, 0x89, 0x4, 0x23, 0xc7, 0x8a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1a, 0xb0}},
{"-1", []byte{0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0xb0}},
{"-0.1", []byte{0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, 0xb0}},
{"-0.01", []byte{0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c, 0xb0}},
{"-0.0000000000000000001", []byte{0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1a, 0xb0}},
{"0", []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}},
{"0.0", []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, 0x30}},
{"0.00", []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x30}},
{"0.0000000000000000000", []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1a, 0x30}},
{"0.0000000000000000001", []byte{0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1a, 0x30}},
{"0.01", []byte{0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x30}},
{"0.1", []byte{0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, 0x30}},
{"1", []byte{0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}},
{"0.9999999999999999999", []byte{0xff, 0xff, 0xe7, 0x89, 0x4, 0x23, 0xc7, 0x8a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1a, 0x30}},
{"9999999999999999.999", []byte{0xff, 0xff, 0xe7, 0x89, 0x4, 0x23, 0xc7, 0x8a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3a, 0x30}},
{"99999999999999999.99", []byte{0xff, 0xff, 0xe7, 0x89, 0x4, 0x23, 0xc7, 0x8a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x30}},
{"999999999999999999.9", []byte{0xff, 0xff, 0xe7, 0x89, 0x4, 0x23, 0xc7, 0x8a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, 0x30}},
{"9999999999999999999", []byte{0xff, 0xff, 0xe7, 0x89, 0x4, 0x23, 0xc7, 0x8a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}},
// Exported constants
{NegOne.String(), []byte{0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0xb0}},
{Zero.String(), []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}},
{One.String(), []byte{0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}},
{Two.String(), []byte{0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}},
{Ten.String(), []byte{0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}},
{Hundred.String(), []byte{0x64, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}},
{Thousand.String(), []byte{0xe8, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30}},
{E.String(), []byte{0x73, 0x61, 0xb3, 0xc0, 0xeb, 0x46, 0xb9, 0x25, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1c, 0x30}},
{Pi.String(), []byte{0xd6, 0x49, 0x32, 0xa2, 0xdf, 0x2d, 0x99, 0x2b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1c, 0x30}},
}
for _, tt := range tests {
d := MustParse(tt.d)
got := d.ieeeDecimal128()
if !bytes.Equal(got, tt.want) {
t.Errorf("%q.ieeeDecimal128() = [% x], want [% x]", d, got, tt.want)
}
}
})
}
func TestDecimal_String(t *testing.T) {
t.Run("success", func(t *testing.T) {
tests := []struct {
neg bool
coef fint
scale int
want string
}{
{true, maxCoef, 0, "-9999999999999999999"},
{true, maxCoef, 1, "-999999999999999999.9"},
{true, maxCoef, 2, "-99999999999999999.99"},
{true, maxCoef, 3, "-9999999999999999.999"},
{true, maxCoef, 19, "-0.9999999999999999999"},
{true, 1, 0, "-1"},
{true, 1, 1, "-0.1"},
{true, 1, 2, "-0.01"},
{true, 1, 19, "-0.0000000000000000001"},
{false, 0, 0, "0"},
{false, 0, 1, "0.0"},
{false, 0, 2, "0.00"},
{false, 0, 19, "0.0000000000000000000"},
{false, 1, 19, "0.0000000000000000001"},
{false, 1, 2, "0.01"},
{false, 1, 1, "0.1"},
{false, 1, 0, "1"},
{false, maxCoef, 19, "0.9999999999999999999"},
{false, maxCoef, 3, "9999999999999999.999"},
{false, maxCoef, 2, "99999999999999999.99"},
{false, maxCoef, 1, "999999999999999999.9"},
{false, maxCoef, 0, "9999999999999999999"},
// Exported constants
{NegOne.neg, NegOne.coef, NegOne.Scale(), "-1"},
{Zero.neg, Zero.coef, Zero.Scale(), "0"},
{One.neg, One.coef, One.Scale(), "1"},
{Two.neg, Two.coef, Two.Scale(), "2"},
{Ten.neg, Ten.coef, Ten.Scale(), "10"},
{Hundred.neg, Hundred.coef, Hundred.Scale(), "100"},
{Thousand.neg, Thousand.coef, Thousand.Scale(), "1000"},
{E.neg, E.coef, E.Scale(), "2.718281828459045235"},
{Pi.neg, Pi.coef, Pi.Scale(), "3.141592653589793238"},
}
for _, tt := range tests {
d, err := newSafe(tt.neg, tt.coef, tt.scale)
if err != nil {
t.Errorf("newDecimal(%v, %v, %v) failed: %v", tt.neg, tt.coef, tt.scale, err)
continue
}
got := d.String()
if got != tt.want {
t.Errorf("newDecimal(%v, %v, %v).String() = %q, want %q", tt.neg, tt.coef, tt.scale, got, tt.want)
}
}
})
}
func TestDecimal_Float64(t *testing.T) {
tests := []struct {
d string
wantFloat float64
wantOk bool
}{
{"-9999999999999999999", -9999999999999999999, true},
{"-1000000000000000000", -1000000000000000000, true},
{"-1", -1, true},
{"-0.9999999999999999999", -0.9999999999999999999, true},
{"-0.0000000000000000001", -0.0000000000000000001, true},
{"0.0000000000000000001", 0.0000000000000000001, true},
{"0.9999999999999999999", 0.9999999999999999999, true},
{"1", 1, true},
{"1000000000000000000", 1000000000000000000, true},
{"9999999999999999999", 9999999999999999999, true},
}
for _, tt := range tests {
d := MustParse(tt.d)
gotFloat, gotOk := d.Float64()
if gotFloat != tt.wantFloat || gotOk != tt.wantOk {
t.Errorf("%q.Float64() = [%v %v], want [%v %v]", d, gotFloat, gotOk, tt.wantFloat, tt.wantOk)
}
}
}
func TestDecimal_Int64(t *testing.T) {
tests := []struct {
d string
scale int
wantWhole, wantFrac int64
wantOk bool
}{
// Zeros
{"0.00", 2, 0, 0, true},
{"0.0", 1, 0, 0, true},
{"0", 0, 0, 0, true},
// Trailing zeros
{"0.1000", 4, 0, 1000, true},
{"0.100", 4, 0, 1000, true},
{"0.10", 4, 0, 1000, true},
{"0.1", 4, 0, 1000, true},
{"0.1000", 4, 0, 1000, true},
{"0.100", 3, 0, 100, true},
{"0.10", 2, 0, 10, true},
{"0.1", 1, 0, 1, true},
// Powers of ten
{"0.0001", 4, 0, 1, true},
{"0.0001", 4, 0, 1, true},
{"0.001", 4, 0, 10, true},
{"0.001", 3, 0, 1, true},
{"0.01", 4, 0, 100, true},
{"0.01", 2, 0, 1, true},
{"0.1", 4, 0, 1000, true},
{"0.1", 1, 0, 1, true},
{"1", 4, 1, 0, true},
{"1", 0, 1, 0, true},
{"10", 4, 10, 0, true},
{"10", 0, 10, 0, true},
{"100", 4, 100, 0, true},
{"100", 0, 100, 0, true},
{"1000", 4, 1000, 0, true},
{"1000", 0, 1000, 0, true},
// Signs
{"0.1", 1, 0, 1, true},
{"1.0", 1, 1, 0, true},
{"1.1", 1, 1, 1, true},
{"-0.1", 1, 0, -1, true},
{"-1.0", 1, -1, 0, true},
{"-1.1", 1, -1, -1, true},
// Rounding
{"5", 0, 5, 0, true},
{"5", 1, 5, 0, true},
{"5", 2, 5, 0, true},
{"5", 3, 5, 0, true},
{"0.5", 0, 0, 0, true},
{"0.5", 1, 0, 5, true},
{"0.5", 2, 0, 50, true},
{"0.5", 3, 0, 500, true},
{"0.05", 0, 0, 0, true},
{"0.05", 1, 0, 0, true},
{"0.05", 2, 0, 5, true},
{"0.05", 3, 0, 50, true},
{"0.005", 0, 0, 0, true},
{"0.005", 1, 0, 0, true},
{"0.005", 2, 0, 0, true},
{"0.005", 3, 0, 5, true},
{"0.51", 0, 1, 0, true},
{"0.051", 1, 0, 1, true},
{"0.0051", 2, 0, 1, true},
{"0.00051", 3, 0, 1, true},
{"0.9", 0, 1, 0, true},
{"0.9", 1, 0, 9, true},
{"0.9", 2, 0, 90, true},
{"0.9", 3, 0, 900, true},
{"0.9999999999999999999", 0, 1, 0, true},
{"0.9999999999999999999", 1, 1, 0, true},
{"0.9999999999999999999", 2, 1, 0, true},
{"0.9999999999999999999", 3, 1, 0, true},
// Edge cases
{"-9223372036854775808", 0, -9223372036854775808, 0, true},
{"-922337203685477580.9", 1, -922337203685477580, -9, true},
{"-9.223372036854775809", 18, -9, -223372036854775809, true},
{"-0.9223372036854775808", 19, 0, -9223372036854775808, true},
{"0.9223372036854775807", 19, 0, 9223372036854775807, true},
{"9.223372036854775808", 18, 9, 223372036854775808, true},
{"922337203685477580.8", 1, 922337203685477580, 8, true},
{"9223372036854775807", 0, 9223372036854775807, 0, true},
// Failures
{"-9999999999999999999", 0, 0, 0, false},
{"-9223372036854775809", 0, 0, 0, false},
{"-0.9999999999999999999", 19, 0, 0, false},
{"-0.9223372036854775809", 19, 0, 0, false},
{"0.1", -1, 0, 0, false},
{"0.1", 20, 0, 0, false},
{"0.9223372036854775808", 19, 0, 0, false},
{"0.9999999999999999999", 19, 0, 0, false},
{"9223372036854775808", 0, 0, 0, false},
{"9999999999999999999", 0, 0, 0, false},
}
for _, tt := range tests {
d := MustParse(tt.d)
gotWhole, gotFrac, gotOk := d.Int64(tt.scale)
if gotWhole != tt.wantWhole || gotFrac != tt.wantFrac || gotOk != tt.wantOk {
t.Errorf("%q.Int64(%v) = [%v %v %v], want [%v %v %v]", d, tt.scale, gotWhole, gotFrac, gotOk, tt.wantWhole, tt.wantFrac, tt.wantOk)
}
}
}
func TestDecimal_Scan(t *testing.T) {
t.Run("float64", func(t *testing.T) {
tests := []struct {
f float64
want string
}{
{math.SmallestNonzeroFloat64, "0.0000000000000000000"},
{1e-20, "0.0000000000000000000"},
{1e-19, "0.0000000000000000001"},
{1e-5, "0.00001"},
{1e-4, "0.0001"},
{1e-3, "0.001"},
{1e-2, "0.01"},
{1e-1, "0.1"},
{1e0, "1"},
{1e1, "10"},
{1e2, "100"},
{1e3, "1000"},
{1e4, "10000"},
{1e5, "100000"},
{1e18, "1000000000000000000"},
}
for _, tt := range tests {
got := Decimal{}
err := got.Scan(tt.f)
if err != nil {
t.Errorf("Scan(%v) failed: %v", tt.f, err)
continue
}
want := MustParse(tt.want)
if got != want {
t.Errorf("Scan(%v) = %v, want %v", tt.f, got, want)
}
}
})
t.Run("float32", func(t *testing.T) {
tests := []struct {
f float32
want string
}{
{math.SmallestNonzeroFloat32, "0.0000000000000000000"},
{1e-20, "0.0000000000000000000"},
{1e-19, "0.0000000000000000001"},
{1e-5, "0.0000099999997473788"},
{1e-4, "0.0000999999974737875"},
{1e-3, "0.0010000000474974513"},
{1e-2, "0.009999999776482582"},
{1e-1, "0.10000000149011612"},
{1e0, "1"},
{1e1, "10"},
{1e2, "100"},
{1e3, "1000"},
{1e4, "10000"},
{1e5, "100000"},
{1e18, "999999984306749400"},
}
for _, tt := range tests {
got := Decimal{}
err := got.Scan(tt.f)
if err != nil {
t.Errorf("Scan(%v) failed: %v", tt.f, err)
continue
}
want := MustParse(tt.want)
if got != want {
t.Errorf("Scan(%v) = %v, want %v", tt.f, got, want)
}
}
})
t.Run("int64", func(t *testing.T) {
tests := []struct {
i int64
want string
}{
{math.MinInt64, "-9223372036854775808"},
{0, "0"},
{math.MaxInt64, "9223372036854775807"},
}
for _, tt := range tests {
got := Decimal{}
err := got.Scan(tt.i)
if err != nil {
t.Errorf("Scan(%v) failed: %v", tt.i, err)
continue
}
want := MustParse(tt.want)
if got != want {
t.Errorf("Scan(%v) = %v, want %v", tt.i, got, want)
}
}
})
t.Run("uint64", func(t *testing.T) {
tests := []struct {
i uint64
want string
}{
{0, "0"},
{9999999999999999999, "9999999999999999999"},
}
for _, tt := range tests {
got := Decimal{}
err := got.Scan(tt.i)
if err != nil {
t.Errorf("Scan(%v) failed: %v", tt.i, err)
continue
}
want := MustParse(tt.want)
if got != want {
t.Errorf("Scan(%v) = %v, want %v", tt.i, got, want)
}
}
})
t.Run("[]byte", func(t *testing.T) {
tests := []struct {
b []byte
want string
}{
{[]byte("-9223372036854775808"), "-9223372036854775808"},
{[]byte("0"), "0"},
{[]byte("9223372036854775807"), "9223372036854775807"},
}
for _, tt := range tests {
got := Decimal{}
err := got.Scan(tt.b)
if err != nil {
t.Errorf("Scan(%v) failed: %v", tt.b, err)
continue
}
want := MustParse(tt.want)
if got != want {
t.Errorf("Scan(%v) = %v, want %v", tt.b, got, want)
}
}
})
t.Run("error", func(t *testing.T) {
tests := []any{
int8(123),
int16(123),
int32(123),
int(123),
uint8(123),
uint16(123),
uint32(123),
uint(123),
nil,
}
for _, tt := range tests {
got := Decimal{}
err := got.Scan(tt)
if err == nil {
t.Errorf("Scan(%v) did not fail", tt)
}
}
})
}
func TestDecimal_Format(t *testing.T) {
tests := []struct {
d, format, want string
}{
// %T verb
{"12.34", "%T", "decimal.Decimal"},
// %q verb
{"12.34", "%q", "\"12.34\""},
{"12.34", "%+q", "\"+12.34\""},
{"12.34", "%.6q", "\"12.34\""}, // precision is ignored
{"12.34", "%7q", "\"12.34\""},
{"12.34", "%8q", " \"12.34\""},
{"12.34", "%9q", " \"12.34\""},
{"12.34", "%10q", " \"12.34\""},
{"12.34", "%010q", "\"00012.34\""},
{"12.34", "%+10q", " \"+12.34\""},
{"12.34", "%-10q", "\"12.34\" "},
// %s verb
{"12.34", "%s", "12.34"},
{"12.34", "%+s", "+12.34"},
{"12.34", "%.6s", "12.34"}, // precision is ignored
{"12.34", "%7s", " 12.34"},
{"12.34", "%8s", " 12.34"},
{"12.34", "%9s", " 12.34"},
{"12.34", "%10s", " 12.34"},
{"12.34", "%010s", "0000012.34"},
{"12.34", "%+10s", " +12.34"},
{"12.34", "%-10s", "12.34 "},
// %v verb
{"12.34", "%v", "12.34"},
{"12.34", "% v", " 12.34"},
{"12.34", "%+v", "+12.34"},
{"12.34", "%.6v", "12.34"}, // precision is ignored
{"12.34", "%7v", " 12.34"},
{"12.34", "%8v", " 12.34"},
{"12.34", "%9v", " 12.34"},
{"12.34", "%10v", " 12.34"},
{"12.34", "%010v", "0000012.34"},
{"12.34", "%+10v", " +12.34"},
{"12.34", "%-10v", "12.34 "},
// %k verb
{"12.34", "%k", "1234%"},
{"12.34", "%+k", "+1234%"},
{"12.34", "%.1k", "1234.0%"},
{"12.34", "%.2k", "1234.00%"},
{"12.34", "%.3k", "1234.000%"},
{"12.34", "%.4k", "1234.0000%"},
{"12.34", "%.5k", "1234.00000%"},
{"12.34", "%.6k", "1234.000000%"},
{"12.34", "%7k", " 1234%"},
{"12.34", "%8k", " 1234%"},
{"12.34", "%9k", " 1234%"},
{"12.34", "%10k", " 1234%"},
{"12.34", "%010k", "000001234%"},
{"12.34", "%+10k", " +1234%"},
{"12.34", "%-10k", "1234% "},
{"2.3", "%k", "230%"},
{"0.23", "%k", "23%"},
{"0.023", "%k", "2.3%"},
{"2.30", "%k", "230%"},
{"0.230", "%k", "23.0%"},
{"0.0230", "%k", "2.30%"},
{"2.300", "%k", "230.0%"},
{"0.2300", "%k", "23.00%"},
{"0.02300", "%k", "2.300%"},
// %f verb
{"12.34", "%f", "12.34"},
{"12.34", "%+f", "+12.34"},
{"12.34", "%.1f", "12.3"},
{"12.34", "%.2f", "12.34"},
{"12.34", "%.3f", "12.340"},
{"12.34", "%.4f", "12.3400"},
{"12.34", "%.5f", "12.34000"},
{"12.34", "%.6f", "12.340000"},
{"12.34", "%7f", " 12.34"},
{"12.34", "%8f", " 12.34"},
{"12.34", "%9f", " 12.34"},
{"12.34", "%10f", " 12.34"},
{"12.34", "%010f", "0000012.34"},
{"12.34", "%+10f", " +12.34"},
{"12.34", "%-10f", "12.34 "},
{"12.34", "%.1f", "12.3"},
{"0", "%.2f", "0.00"},
{"0", "%5.2f", " 0.00"},
{"9.996208266660", "%.2f", "10.00"},
{"0.9996208266660", "%.2f", "1.00"},
{"0.09996208266660", "%.2f", "0.10"},
{"0.009996208266660", "%.2f", "0.01"},
{"500.44", "%6.1f", " 500.4"},
{"-404.040", "%-010.f", "-404 "},
{"-404.040", "%-10.f", "-404 "},
{"1", "%.20f", "1.00000000000000000000"},
{"1.000000000000000000", "%.20f", "1.00000000000000000000"},
{"9999999999999999999", "%.1f", "9999999999999999999.0"},
{"9999999999999999999", "%.2f", "9999999999999999999.00"},
{"9999999999999999999", "%.3f", "9999999999999999999.000"},
// Wrong verbs
{"12.34", "%b", "%!b(decimal.Decimal=12.34)"},
{"12.34", "%e", "%!e(decimal.Decimal=12.34)"},
{"12.34", "%E", "%!E(decimal.Decimal=12.34)"},
{"12.34", "%g", "%!g(decimal.Decimal=12.34)"},
{"12.34", "%G", "%!G(decimal.Decimal=12.34)"},
{"12.34", "%x", "%!x(decimal.Decimal=12.34)"},
{"12.34", "%X", "%!X(decimal.Decimal=12.34)"},
// Errors
{"9999999999999999999", "%k", "%!k(PANIC=Format method: formatting percent: computing [9999999999999999999 * 100]: decimal overflow: the integer part of a decimal.Decimal can have at most 19 digits, but it has 21 digits)"},
}
for _, tt := range tests {
d := MustParse(tt.d)
got := fmt.Sprintf(tt.format, d)
if got != tt.want {
t.Errorf("fmt.Sprintf(%q, %q) = %q, want %q", tt.format, tt.d, got, tt.want)
}
}
}
func TestDecimal_Prec(t *testing.T) {
tests := []struct {
d string
want int
}{
{"0000", 0},
{"000", 0},
{"00", 0},
{"0", 0},
{"0.000", 0},
{"0.00", 0},
{"0.0", 0},
{"0", 0},
{"0.0000000000000000001", 1},
{"0.000000000000000001", 1},
{"0.00000000000000001", 1},
{"0.0000000000000001", 1},
{"0.000000000000001", 1},
{"0.00000000000001", 1},
{"0.0000000000001", 1},
{"0.000000000001", 1},
{"0.00000000001", 1},
{"0.0000000001", 1},
{"0.000000001", 1},
{"0.00000001", 1},
{"0.0000001", 1},
{"0.000001", 1},
{"0.00001", 1},
{"0.0001", 1},
{"0.001", 1},
{"0.01", 1},
{"0.1", 1},
{"1", 1},
{"0.1000000000000000000", 19},
{"0.100000000000000000", 18},
{"0.10000000000000000", 17},
{"0.1000000000000000", 16},
{"0.100000000000000", 15},
{"0.10000000000000", 14},
{"0.1000000000000", 13},
{"0.100000000000", 12},
{"0.10000000000", 11},
{"0.1000000000", 10},
{"0.100000000", 9},
{"0.10000000", 8},
{"0.1000000", 7},
{"0.100000", 6},
{"0.10000", 5},
{"0.1000", 4},
{"0.100", 3},
{"0.10", 2},
{"0.1", 1},
{"1", 1},
{"10", 2},
{"100", 3},
{"1000", 4},
{"10000", 5},
{"100000", 6},
{"1000000", 7},
{"10000000", 8},
{"100000000", 9},
{"1000000000", 10},
{"10000000000", 11},
{"100000000000", 12},
{"1000000000000", 13},
{"10000000000000", 14},
{"100000000000000", 15},
{"1000000000000000", 16},
{"10000000000000000", 17},
{"100000000000000000", 18},
{"1000000000000000000", 19},
}
for _, tt := range tests {
d := MustParse(tt.d)
got := d.Prec()
if got != tt.want {
t.Errorf("%q.Prec() = %v, want %v", tt.d, got, tt.want)
}
}
}
func TestDecimal_Rescale(t *testing.T) {
tests := []struct {
d string
scale int
want string
}{
// Zeros
{"0", 0, "0"},
{"0", 1, "0.0"},
{"0", 2, "0.00"},
{"0", 19, "0.0000000000000000000"},
{"0.0", 1, "0.0"},
{"0.00", 2, "0.00"},
{"0.000000000", 19, "0.0000000000000000000"},
{"0.000000000", 0, "0"},
{"0.000000000", 1, "0.0"},
{"0.000000000", 2, "0.00"},
// Tests from GDA
{"2.17", 0, "2"},
{"2.17", 1, "2.2"},
{"2.17", 2, "2.17"},
{"2.17", 9, "2.170000000"},
{"1.2345", 2, "1.23"},
{"1.2355", 2, "1.24"},
{"1.2345", 9, "1.234500000"},
{"9.9999", 2, "10.00"},
{"0.0001", 2, "0.00"},
{"0.001", 2, "0.00"},
{"0.009", 2, "0.01"},
// Some extra tests
{"0.03", 2, "0.03"},
{"0.02", 2, "0.02"},
{"0.01", 2, "0.01"},
{"0.00", 2, "0.00"},
{"-0.01", 2, "-0.01"},
{"-0.02", 2, "-0.02"},
{"-0.03", 2, "-0.03"},
{"0.0049", 2, "0.00"},
{"0.0051", 2, "0.01"},
{"0.0149", 2, "0.01"},
{"0.0151", 2, "0.02"},
{"-0.0049", 2, "0.00"},
{"-0.0051", 2, "-0.01"},
{"-0.0149", 2, "-0.01"},
{"-0.0151", 2, "-0.02"},
{"0.0050", 2, "0.00"},
{"0.0150", 2, "0.02"},
{"0.0250", 2, "0.02"},
{"0.0350", 2, "0.04"},
{"-0.0050", 2, "0.00"},
{"-0.0150", 2, "-0.02"},
{"-0.0250", 2, "-0.02"},
{"-0.0350", 2, "-0.04"},
{"3.0448", 2, "3.04"},
{"3.0450", 2, "3.04"},
{"3.0452", 2, "3.05"},
{"3.0956", 2, "3.10"},
// Tests from Wikipedia
{"1.8", 0, "2"},
{"1.5", 0, "2"},
{"1.2", 0, "1"},
{"0.8", 0, "1"},
{"0.5", 0, "0"},
{"0.2", 0, "0"},
{"-0.2", 0, "0"},
{"-0.5", 0, "0"},
{"-0.8", 0, "-1"},
{"-1.2", 0, "-1"},
{"-1.5", 0, "-2"},
{"-1.8", 0, "-2"},
// Negative scale
{"1000000000000000000", -1, "1000000000000000000"},
// Padding overflow
{"1000000000000000000", 1, "1000000000000000000"},
{"100000000000000000", 2, "100000000000000000.0"},
{"10000000000000000", 3, "10000000000000000.00"},
{"1000000000000000", 4, "1000000000000000.000"},
{"100000000000000", 5, "100000000000000.0000"},
{"10000000000000", 6, "10000000000000.00000"},
{"1000000000000", 7, "1000000000000.000000"},
{"1", 19, "1.000000000000000000"},
{"0", 20, "0.0000000000000000000"},
}
for _, tt := range tests {
d := MustParse(tt.d)
got := d.Rescale(tt.scale)
want := MustParse(tt.want)
if got != want {
t.Errorf("%q.Rescale(%v) = %q, want %q", d, tt.scale, got, want)
}
}
}
func TestDecimal_Quantize(t *testing.T) {
tests := []struct {
d, e, want string
}{
{"0", "0", "0"},
{"0", "0.0", "0.0"},
{"0.0", "0", "0"},
{"0.0", "0.0", "0.0"},
{"0.0078", "0.00001", "0.00780"},
{"0.0078", "0.0001", "0.0078"},
{"0.0078", "0.001", "0.008"},
{"0.0078", "0.01", "0.01"},
{"0.0078", "0.1", "0.0"},
{"0.0078", "1", "0"},
{"-0.0078", "0.00001", "-0.00780"},
{"-0.0078", "0.0001", "-0.0078"},
{"-0.0078", "0.001", "-0.008"},
{"-0.0078", "0.01", "-0.01"},
{"-0.0078", "0.1", "0.0"},
{"-0.0078", "1", "0"},
{"0.6666666", "0.1", "0.7"},
{"9.9999", "1.00", "10.00"},
}
for _, tt := range tests {
d := MustParse(tt.d)
e := MustParse(tt.e)
got := d.Quantize(e)
want := MustParse(tt.want)
if got != want {
t.Errorf("%q.Quantize(%q) = %q, want %q", d, e, got, want)
}
}
}
func TestDecimal_Pad(t *testing.T) {
tests := []struct {
d string
scale int
want string
}{
// Zeros
{"0", 0, "0"},
{"0", 1, "0.0"},
{"0", 2, "0.00"},
{"0", 19, "0.0000000000000000000"},
{"0", 20, "0.0000000000000000000"},
{"0.000000000", 0, "0.000000000"},
{"0.000000000", 1, "0.000000000"},
{"0.000000000", 2, "0.000000000"},
{"0.000000000", 19, "0.0000000000000000000"},
{"0.000000000", 20, "0.0000000000000000000"},
// Tests from GDA
{"2.17", 0, "2.17"},
{"2.17", 1, "2.17"},
{"2.17", 2, "2.17"},
{"2.17", 9, "2.170000000"},
{"1.2345", 2, "1.2345"},
{"1.2355", 2, "1.2355"},
{"1.2345", 9, "1.234500000"},
{"9.9999", 2, "9.9999"},
{"0.0001", 2, "0.0001"},
{"0.001", 2, "0.001"},
{"0.009", 2, "0.009"},
// Negative scale
{"1000000000000000000", -1, "1000000000000000000"},
// Padding overflow
{"1000000000000000000", 1, "1000000000000000000"},
{"100000000000000000", 2, "100000000000000000.0"},
{"10000000000000000", 3, "10000000000000000.00"},
{"1000000000000000", 4, "1000000000000000.000"},
{"100000000000000", 5, "100000000000000.0000"},
{"10000000000000", 6, "10000000000000.00000"},
{"1000000000000", 7, "1000000000000.000000"},
{"-0.0000000000032", 63, "-0.0000000000032000000"},
}
for _, tt := range tests {
d := MustParse(tt.d)
got := d.Pad(tt.scale)
want := MustParse(tt.want)
if got != want {
t.Errorf("%q.Pad(%v) = %q, want %q", d, tt.scale, got, want)
}
}
}
func TestDecimal_Round(t *testing.T) {
tests := []struct {
d string
scale int
want string
}{
// Zeros
{"0", -1, "0"},
{"0", 0, "0"},
{"0", 1, "0"},
{"0", 2, "0"},
{"0", 19, "0"},
{"0.0", 1, "0.0"},
{"0.00", 2, "0.00"},
{"0.000000000", 19, "0.000000000"},
{"0.000000000", 0, "0"},
{"0.000000000", 1, "0.0"},
{"0.000000000", 2, "0.00"},
// Tests from GDA
{"2.17", -1, "2"},
{"2.17", 0, "2"},
{"2.17", 1, "2.2"},
{"2.17", 2, "2.17"},
{"2.17", 9, "2.17"},
{"1.2345", 2, "1.23"},
{"1.2355", 2, "1.24"},
{"1.2345", 9, "1.2345"},
{"9.9999", 2, "10.00"},
{"0.0001", 2, "0.00"},
{"0.001", 2, "0.00"},
{"0.009", 2, "0.01"},
// Some extra tests
{"0.03", 2, "0.03"},
{"0.02", 2, "0.02"},
{"0.01", 2, "0.01"},
{"0.00", 2, "0.00"},
{"-0.01", 2, "-0.01"},
{"-0.02", 2, "-0.02"},
{"-0.03", 2, "-0.03"},
{"0.0049", 2, "0.00"},
{"0.0050", 2, "0.00"},
{"0.0051", 2, "0.01"},
{"0.0149", 2, "0.01"},
{"0.0150", 2, "0.02"},
{"0.0151", 2, "0.02"},
{"0.0250", 2, "0.02"},
{"0.0350", 2, "0.04"},
{"-0.0049", 2, "0.00"},
{"-0.0051", 2, "-0.01"},
{"-0.0050", 2, "0.00"},
{"-0.0149", 2, "-0.01"},
{"-0.0151", 2, "-0.02"},
{"-0.0150", 2, "-0.02"},
{"-0.0250", 2, "-0.02"},
{"-0.0350", 2, "-0.04"},
{"3.0448", 2, "3.04"},
{"3.0450", 2, "3.04"},
{"3.0452", 2, "3.05"},
{"3.0956", 2, "3.10"},
// Tests from Wikipedia
{"1.8", 0, "2"},
{"1.5", 0, "2"},
{"1.2", 0, "1"},
{"0.8", 0, "1"},
{"0.5", 0, "0"},
{"0.2", 0, "0"},
{"-0.2", 0, "0"},
{"-0.5", 0, "0"},
{"-0.8", 0, "-1"},
{"-1.2", 0, "-1"},
{"-1.5", 0, "-2"},
{"-1.8", 0, "-2"},
}
for _, tt := range tests {
d := MustParse(tt.d)
got := d.Round(tt.scale)
want := MustParse(tt.want)
if got != want {
t.Errorf("%q.Round(%v) = %q, want %q", d, tt.scale, got, want)
}
}
}
func TestDecimal_Trunc(t *testing.T) {
tests := []struct {
d string
scale int
want string
}{
// Zeros
{"0", -1, "0"},
{"0", 0, "0"},
{"0", 1, "0"},
{"0", 2, "0"},
{"0", 19, "0"},
{"0.0", 1, "0.0"},
{"0.00", 2, "0.00"},
{"0.000000000", 19, "0.000000000"},
{"0.000000000", 0, "0"},
{"0.000000000", 1, "0.0"},
{"0.000000000", 2, "0.00"},
// Tests from GDA
{"2.17", 0, "2"},
{"2.17", 1, "2.1"},
{"2.17", 2, "2.17"},
{"2.17", 9, "2.17"},
{"1.2345", 2, "1.23"},
{"1.2355", 2, "1.23"},
{"1.2345", 9, "1.2345"},
{"9.9999", 2, "9.99"},
{"0.0001", 2, "0.00"},
{"0.001", 2, "0.00"},
{"0.009", 2, "0.00"},
// Some extra tests
{"0.03", 2, "0.03"},
{"0.02", 2, "0.02"},
{"0.01", 2, "0.01"},
{"0.00", 2, "0.00"},
{"-0.01", 2, "-0.01"},
{"-0.02", 2, "-0.02"},
{"-0.03", 2, "-0.03"},
{"0.0049", 2, "0.00"},
{"0.0051", 2, "0.00"},
{"0.0149", 2, "0.01"},
{"0.0151", 2, "0.01"},
{"-0.0049", 2, "0.00"},
{"-0.0051", 2, "-0.00"},
{"-0.0149", 2, "-0.01"},
{"-0.0151", 2, "-0.01"},
{"0.0050", 2, "0.00"},
{"0.0150", 2, "0.01"},
{"0.0250", 2, "0.02"},
{"0.0350", 2, "0.03"},
{"-0.0050", 2, "0.00"},
{"-0.0150", 2, "-0.01"},
{"-0.0250", 2, "-0.02"},
{"-0.0350", 2, "-0.03"},
{"3.0448", 2, "3.04"},
{"3.0450", 2, "3.04"},
{"3.0452", 2, "3.04"},
{"3.0956", 2, "3.09"},
// Tests from Wikipedia
{"1.8", 0, "1"},
{"1.5", 0, "1"},
{"1.2", 0, "1"},
{"0.8", 0, "0"},
{"0.5", 0, "0"},
{"0.2", 0, "0"},
{"-0.2", 0, "0"},
{"-0.5", 0, "0"},
{"-0.8", 0, "0"},
{"-1.2", 0, "-1"},
{"-1.5", 0, "-1"},
{"-1.8", 0, "-1"},
}
for _, tt := range tests {
d := MustParse(tt.d)
got := d.Trunc(tt.scale)
want := MustParse(tt.want)
if got != want {
t.Errorf("%q.Trunc(%v) = %q, want %q", d, tt.scale, got, want)
}
}
}
func TestDecimal_Ceil(t *testing.T) {
tests := []struct {
d string
scale int
want string
}{
// Zeros
{"0", -1, "0"},
{"0", 0, "0"},
{"0", 1, "0"},
{"0", 2, "0"},
{"0", 19, "0"},
{"0.0", 1, "0.0"},
{"0.00", 2, "0.00"},
{"0.000000000", 19, "0.000000000"},
{"0.000000000", 0, "0"},
{"0.000000000", 1, "0.0"},
{"0.000000000", 2, "0.00"},
// Tests from GDA
{"2.17", 0, "3"},
{"2.17", 1, "2.2"},
{"2.17", 2, "2.17"},
{"2.17", 9, "2.17"},
{"1.2345", 2, "1.24"},
{"1.2355", 2, "1.24"},
{"1.2345", 9, "1.2345"},
{"9.9999", 2, "10.00"},
{"0.0001", 2, "0.01"},
{"0.001", 2, "0.01"},
{"0.009", 2, "0.01"},
{"-2.17", 0, "-2"},
{"-2.17", 1, "-2.1"},
{"-2.17", 2, "-2.17"},
{"-2.17", 9, "-2.17"},
{"-1.2345", 2, "-1.23"},
{"-1.2355", 2, "-1.23"},
{"-1.2345", 9, "-1.2345"},
{"-9.9999", 2, "-9.99"},
{"-0.0001", 2, "0.00"},
{"-0.001", 2, "0.00"},
{"-0.009", 2, "0.00"},
// Some extra tests
{"0.03", 2, "0.03"},
{"0.02", 2, "0.02"},
{"0.01", 2, "0.01"},
{"0.00", 2, "0.00"},
{"-0.01", 2, "-0.01"},
{"-0.02", 2, "-0.02"},
{"-0.03", 2, "-0.03"},
{"0.0049", 2, "0.01"},
{"0.0051", 2, "0.01"},
{"0.0149", 2, "0.02"},
{"0.0151", 2, "0.02"},
{"-0.0049", 2, "0.00"},
{"-0.0051", 2, "0.00"},
{"-0.0149", 2, "-0.01"},
{"-0.0151", 2, "-0.01"},
{"0.0050", 2, "0.01"},
{"0.0150", 2, "0.02"},
{"0.0250", 2, "0.03"},
{"0.0350", 2, "0.04"},
{"-0.0050", 2, "0.00"},
{"-0.0150", 2, "-0.01"},
{"-0.0250", 2, "-0.02"},
{"-0.0350", 2, "-0.03"},
{"3.0448", 2, "3.05"},
{"3.0450", 2, "3.05"},
{"3.0452", 2, "3.05"},
{"3.0956", 2, "3.10"},
// Tests from Wikipedia
{"1.8", 0, "2"},
{"1.5", 0, "2"},
{"1.2", 0, "2"},
{"0.8", 0, "1"},
{"0.5", 0, "1"},
{"0.2", 0, "1"},
{"-0.2", 0, "0"},
{"-0.5", 0, "0"},
{"-0.8", 0, "0"},
{"-1.2", 0, "-1"},
{"-1.5", 0, "-1"},
{"-1.8", 0, "-1"},
}
for _, tt := range tests {
d := MustParse(tt.d)
got := d.Ceil(tt.scale)
want := MustParse(tt.want)
if got != want {
t.Errorf("%q.Ceil(%v) = %q, want %q", d, tt.scale, got, want)
}
}
}
func TestDecimal_Floor(t *testing.T) {
tests := []struct {
d string
scale int
want string
}{
// Zeros
{"0", -1, "0"},
{"0", 0, "0"},
{"0", 1, "0"},
{"0", 2, "0"},
{"0", 19, "0"},
{"0.0", 1, "0.0"},
{"0.00", 2, "0.00"},
{"0.000000000", 19, "0.000000000"},
{"0.000000000", 0, "0"},
{"0.000000000", 1, "0.0"},
{"0.000000000", 2, "0.00"},
// Tests from GDA
{"2.17", 0, "2"},
{"2.17", 1, "2.1"},
{"2.17", 2, "2.17"},
{"2.17", 9, "2.17"},
{"1.2345", 2, "1.23"},
{"1.2355", 2, "1.23"},
{"1.2345", 9, "1.2345"},
{"9.9999", 2, "9.99"},
{"0.0001", 2, "0.00"},
{"0.001", 2, "0.00"},
{"0.009", 2, "0.00"},
{"-2.17", 0, "-3"},
{"-2.17", 1, "-2.2"},
{"-2.17", 2, "-2.17"},
{"-2.17", 9, "-2.17"},
{"-1.2345", 2, "-1.24"},
{"-1.2355", 2, "-1.24"},
{"-1.2345", 9, "-1.2345"},
{"-9.9999", 2, "-10.00"},
{"-0.0001", 2, "-0.01"},
{"-0.001", 2, "-0.01"},
{"-0.009", 2, "-0.01"},
// Some extra tests
{"0.03", 2, "0.03"},
{"0.02", 2, "0.02"},
{"0.01", 2, "0.01"},
{"0.00", 2, "0.00"},
{"-0.01", 2, "-0.01"},
{"-0.02", 2, "-0.02"},
{"-0.03", 2, "-0.03"},
{"0.0049", 2, "0.00"},
{"0.0051", 2, "0.00"},
{"0.0149", 2, "0.01"},
{"0.0151", 2, "0.01"},
{"-0.0049", 2, "-0.01"},
{"-0.0051", 2, "-0.01"},
{"-0.0149", 2, "-0.02"},
{"-0.0151", 2, "-0.02"},
{"0.0050", 2, "0.00"},
{"0.0150", 2, "0.01"},
{"0.0250", 2, "0.02"},
{"0.0350", 2, "0.03"},
{"-0.0050", 2, "-0.01"},
{"-0.0150", 2, "-0.02"},
{"-0.0250", 2, "-0.03"},
{"-0.0350", 2, "-0.04"},
{"3.0448", 2, "3.04"},
{"3.0450", 2, "3.04"},
{"3.0452", 2, "3.04"},
{"3.0956", 2, "3.09"},
// Tests from Wikipedia
{"1.8", 0, "1"},
{"1.5", 0, "1"},
{"1.2", 0, "1"},
{"0.8", 0, "0"},
{"0.5", 0, "0"},
{"0.2", 0, "0"},
{"-0.2", 0, "-1"},
{"-0.5", 0, "-1"},
{"-0.8", 0, "-1"},
{"-1.2", 0, "-2"},
{"-1.5", 0, "-2"},
{"-1.8", 0, "-2"},
}
for _, tt := range tests {
d := MustParse(tt.d)
got := d.Floor(tt.scale)
want := MustParse(tt.want)
if got != want {
t.Errorf("%q.Floor(%v) = %q, want %q", d, tt.scale, got, want)
}
}
}
func TestDecimal_MinScale(t *testing.T) {
t.Run("success", func(t *testing.T) {
tests := []struct {
d string
want int
}{
{"0", 0},
{"0.0", 0},
{"1", 0},
{"1.000000000", 0},
{"0.100000000", 1},
{"0.010000000", 2},
{"0.001000000", 3},
{"0.000100000", 4},
{"0.000010000", 5},
{"0.000001000", 6},
{"0.000000100", 7},
{"0.000000010", 8},
{"0.000000001", 9},
{"0.000000000", 0},
{"0.0000000000000000000", 0},
{"0.1000000000000000000", 1},
{"0.0000000000000000001", 19},
{"0.9999999999999999999", 19},
}
for _, tt := range tests {
d := MustParse(tt.d)
got := d.MinScale()
if got != tt.want {
t.Errorf("%q.MinScale() = %v, want %v", d, got, tt.want)
}
}
})
}
func TestDecimal_Trim(t *testing.T) {
tests := []struct {
d string
scale int
want string
}{
{"0.000000", 0, "0"},
{"0.000000", 2, "0.00"},
{"0.000000", 4, "0.0000"},
{"0.000000", 6, "0.000000"},
{"0.000000", 8, "0.000000"},
{"-10.00", 0, "-10"},
{"10.00", 0, "10"},
{"0.000001", 0, "0.000001"},
{"0.0000010", 0, "0.000001"},
{"-0.000001", 0, "-0.000001"},
{"-0.0000010", 0, "-0.000001"},
}
for _, tt := range tests {
d := MustParse(tt.d)
got := d.Trim(tt.scale)
want := MustParse(tt.want)
if got != want {
t.Errorf("%q.Trim(%v) = %q, want %q", d, tt.scale, got, want)
}
}
}
func TestSum(t *testing.T) {
t.Run("success", func(t *testing.T) {
tests := []struct {
d []string
want string
}{
{[]string{"0"}, "0"},
{[]string{"1"}, "1"},
{[]string{"1", "1"}, "2"},
{[]string{"2", "3"}, "5"},
{[]string{"5.75", "3.3"}, "9.05"},
{[]string{"5", "-3"}, "2"},
{[]string{"-5", "-3"}, "-8"},
{[]string{"-7", "2.5"}, "-4.5"},
{[]string{"0.7", "0.3"}, "1.0"},
{[]string{"1.25", "1.25"}, "2.50"},
{[]string{"1.1", "0.11"}, "1.21"},
{[]string{"1.234567890", "1.000000000"}, "2.234567890"},
{[]string{"1.234567890", "1.000000110"}, "2.234568000"},
{[]string{"0.9998", "0.0000"}, "0.9998"},
{[]string{"0.9998", "0.0001"}, "0.9999"},
{[]string{"0.9998", "0.0002"}, "1.0000"},
{[]string{"0.9998", "0.0003"}, "1.0001"},
{[]string{"999999999999999999", "1"}, "1000000000000000000"},
{[]string{"99999999999999999", "1"}, "100000000000000000"},
{[]string{"9999999999999999", "1"}, "10000000000000000"},
{[]string{"999999999999999", "1"}, "1000000000000000"},
{[]string{"99999999999999", "1"}, "100000000000000"},
{[]string{"9999999999999", "1"}, "10000000000000"},
{[]string{"999999999999", "1"}, "1000000000000"},
{[]string{"99999999999", "1"}, "100000000000"},
{[]string{"9999999999", "1"}, "10000000000"},
{[]string{"999999999", "1"}, "1000000000"},
{[]string{"99999999", "1"}, "100000000"},
{[]string{"9999999", "1"}, "10000000"},
{[]string{"999999", "1"}, "1000000"},
{[]string{"99999", "1"}, "100000"},
{[]string{"9999", "1"}, "10000"},
{[]string{"999", "1"}, "1000"},
{[]string{"99", "1"}, "100"},
{[]string{"9", "1"}, "10"},
{[]string{"100000000000", "0.00000000"}, "100000000000.0000000"},
{[]string{"100000000000", "0.00000001"}, "100000000000.0000000"},
{[]string{"0.0", "0"}, "0.0"},
{[]string{"0.00", "0"}, "0.00"},
{[]string{"0.000", "0"}, "0.000"},
{[]string{"0.0000000", "0"}, "0.0000000"},
{[]string{"0", "0.0"}, "0.0"},
{[]string{"0", "0.00"}, "0.00"},
{[]string{"0", "0.000"}, "0.000"},
{[]string{"0", "0.0000000"}, "0.0000000"},
{[]string{"9999999999999999999", "0.4"}, "9999999999999999999"},
{[]string{"-9999999999999999999", "-0.4"}, "-9999999999999999999"},
{[]string{"1", "-9999999999999999999"}, "-9999999999999999998"},
{[]string{"9999999999999999999", "-1"}, "9999999999999999998"},
}
for _, tt := range tests {
d := make([]Decimal, len(tt.d))
for i, s := range tt.d {
d[i] = MustParse(s)
}
got, err := Sum(d...)
if err != nil {
t.Errorf("Sum(%v) failed: %v", d, err)
}
want := MustParse(tt.want)
if got != want {
t.Errorf("Sum(%v) = %q, want %q", d, got, want)
}
}
})
t.Run("error", func(t *testing.T) {
tests := map[string][]string{
"no arguments": {},
"overflow 1": {"9999999999999999999", "1"},
"overflow 2": {"9999999999999999999", "0.6"},
"overflow 3": {"-9999999999999999999", "-1"},
"overflow 4": {"-9999999999999999999", "-0.6"},
}
for name, ss := range tests {
t.Run(name, func(t *testing.T) {
d := make([]Decimal, len(ss))
for i, s := range ss {
d[i] = MustParse(s)
}
_, err := Sum(d...)
if err == nil {
t.Errorf("Sum(%v) did not fail", d)
}
})
}
})
}
func TestDecimal_Add(t *testing.T) {
t.Run("success", func(t *testing.T) {
tests := []struct {
d, e, want string
}{
{"1", "1", "2"},
{"2", "3", "5"},
{"5.75", "3.3", "9.05"},
{"5", "-3", "2"},
{"-5", "-3", "-8"},
{"-7", "2.5", "-4.5"},
{"0.7", "0.3", "1.0"},
{"1.25", "1.25", "2.50"},
{"1.1", "0.11", "1.21"},
{"1.234567890", "1.000000000", "2.234567890"},
{"1.234567890", "1.000000110", "2.234568000"},
{"0.9998", "0.0000", "0.9998"},
{"0.9998", "0.0001", "0.9999"},
{"0.9998", "0.0002", "1.0000"},
{"0.9998", "0.0003", "1.0001"},
{"999999999999999999", "1", "1000000000000000000"},
{"99999999999999999", "1", "100000000000000000"},
{"9999999999999999", "1", "10000000000000000"},
{"999999999999999", "1", "1000000000000000"},
{"99999999999999", "1", "100000000000000"},
{"9999999999999", "1", "10000000000000"},
{"999999999999", "1", "1000000000000"},
{"99999999999", "1", "100000000000"},
{"9999999999", "1", "10000000000"},
{"999999999", "1", "1000000000"},
{"99999999", "1", "100000000"},
{"9999999", "1", "10000000"},
{"999999", "1", "1000000"},
{"99999", "1", "100000"},
{"9999", "1", "10000"},
{"999", "1", "1000"},
{"99", "1", "100"},
{"9", "1", "10"},
{"100000000000", "0.00000000", "100000000000.0000000"},
{"100000000000", "0.00000001", "100000000000.0000000"},
{"0.0", "0", "0.0"},
{"0.00", "0", "0.00"},
{"0.000", "0", "0.000"},
{"0.0000000", "0", "0.0000000"},
{"0", "0.0", "0.0"},
{"0", "0.00", "0.00"},
{"0", "0.000", "0.000"},
{"0", "0.0000000", "0.0000000"},
{"9999999999999999999", "0.4", "9999999999999999999"},
{"-9999999999999999999", "-0.4", "-9999999999999999999"},
{"1", "-9999999999999999999", "-9999999999999999998"},
{"9999999999999999999", "-1", "9999999999999999998"},
}
for _, tt := range tests {
d := MustParse(tt.d)
e := MustParse(tt.e)
got, err := d.Add(e)
if err != nil {
t.Errorf("%q.Add(%q) failed: %v", d, e, err)
continue
}
want := MustParse(tt.want)
if got != want {
t.Errorf("%q.Add(%q) = %q, want %q", d, e, got, want)
}
}
})
t.Run("error", func(t *testing.T) {
tests := map[string]struct {
d, e string
scale int
}{
"overflow 1": {"9999999999999999999", "1", 0},
"overflow 2": {"9999999999999999999", "0.6", 0},
"overflow 3": {"-9999999999999999999", "-1", 0},
"overflow 4": {"-9999999999999999999", "-0.6", 0},
"scale 1": {"1", "1", MaxScale},
"scale 2": {"0", "0", MaxScale + 1},
}
for _, tt := range tests {
d := MustParse(tt.d)
e := MustParse(tt.e)
_, err := d.AddExact(e, tt.scale)
if err == nil {
t.Errorf("%q.AddExact(%q, %v) did not fail", d, e, tt.scale)
}
}
})
}
func TestDecimal_Sub(t *testing.T) {
t.Run("success", func(t *testing.T) {
tests := []struct {
d, e, want string
}{
// Signs
{"5", "3", "2"},
{"3", "5", "-2"},
{"-5", "-3", "-2"},
{"-3", "-5", "2"},
{"-5", "3", "-8"},
{"-3", "5", "-8"},
{"5", "-3", "8"},
{"3", "-5", "8"},
}
for _, tt := range tests {
d := MustParse(tt.d)
e := MustParse(tt.e)
got, err := d.Sub(e)
if err != nil {
t.Errorf("%q.Sub(%q) failed: %v", d, e, err)
continue
}
want := MustParse(tt.want)
if got != want {
t.Errorf("%q.Sub(%q) = %q, want %q", d, e, got, want)
}
}
})
}
func TestDecimal_SubAbs(t *testing.T) {
t.Run("success", func(t *testing.T) {
tests := []struct {
d, e, want string
}{
// Signs
{"5", "3", "2"},
{"3", "5", "2"},
{"-5", "-3", "2"},
{"-3", "-5", "2"},
{"-5", "3", "8"},
{"-3", "5", "8"},
{"5", "-3", "8"},
{"3", "-5", "8"},
}
for _, tt := range tests {
d := MustParse(tt.d)
e := MustParse(tt.e)
got, err := d.SubAbs(e)
if err != nil {
t.Errorf("%q.SubAbs(%q) failed: %v", d, e, err)
continue
}
want := MustParse(tt.want)
if got != want {
t.Errorf("%q.SubAbs(%q) = %q, want %q", d, e, got, want)
}
}
})
t.Run("error", func(t *testing.T) {
tests := map[string]struct {
d, e string
}{
"overflow 1": {"1", "-9999999999999999999"},
"overflow 2": {"9999999999999999999", "-1"},
"overflow 3": {"9999999999999999999", "-9999999999999999999"},
}
for _, tt := range tests {
d := MustParse(tt.d)
e := MustParse(tt.e)
_, err := d.SubAbs(e)
if err == nil {
t.Errorf("%q.SubAbs(%q) did not fail", d, e)
}
}
})
}
func TestProd(t *testing.T) {
t.Run("success", func(t *testing.T) {
tests := []struct {
d []string
want string
}{
{[]string{"0"}, "0"},
{[]string{"1"}, "1"},
{[]string{"2", "2"}, "4"},
{[]string{"2", "3"}, "6"},
{[]string{"5", "1"}, "5"},
{[]string{"5", "2"}, "10"},
{[]string{"1.20", "2"}, "2.40"},
{[]string{"1.20", "0"}, "0.00"},
{[]string{"1.20", "-2"}, "-2.40"},
{[]string{"-1.20", "2"}, "-2.40"},
{[]string{"-1.20", "0"}, "0.00"},
{[]string{"-1.20", "-2"}, "2.40"},
{[]string{"5.09", "7.1"}, "36.139"},
{[]string{"2.5", "4"}, "10.0"},
{[]string{"2.50", "4"}, "10.00"},
{[]string{"0.70", "1.05"}, "0.7350"},
{[]string{"1.000000000", "1"}, "1.000000000"},
{[]string{"1.23456789", "1.00000000"}, "1.2345678900000000"},
{[]string{"1.000000000000000000", "1.000000000000000000"}, "1.000000000000000000"},
{[]string{"1.000000000000000001", "1.000000000000000001"}, "1.000000000000000002"},
{[]string{"9.999999999999999999", "9.999999999999999999"}, "99.99999999999999998"},
{[]string{"0.0000000000000000001", "0.0000000000000000001"}, "0.0000000000000000000"},
{[]string{"0.0000000000000000001", "0.9999999999999999999"}, "0.0000000000000000001"},
{[]string{"0.0000000000000000003", "0.9999999999999999999"}, "0.0000000000000000003"},
{[]string{"0.9999999999999999999", "0.9999999999999999999"}, "0.9999999999999999998"},
{[]string{"0.9999999999999999999", "0.9999999999999999999", "0.9999999999999999999"}, "0.9999999999999999997"},
{[]string{"6963.788300835654596", "0.001436"}, "10.00000000000000000"},
// Captured during fuzzing
{[]string{"92233720368547757.26", "0.0000000000000000002"}, "0.0184467440737095515"},
{[]string{"9223372036854775.807", "-0.0000000000000000013"}, "-0.0119903836479112085"},
}
for _, tt := range tests {
d := make([]Decimal, len(tt.d))
for i, s := range tt.d {
d[i] = MustParse(s)
}
got, err := Prod(d...)
if err != nil {
t.Errorf("Prod(%v) failed: %v", d, err)
}
want := MustParse(tt.want)
if got != want {
t.Errorf("Prod(%v) = %q, want %q", d, got, want)
}
}
})
t.Run("error", func(t *testing.T) {
tests := map[string][]string{
"no arguments": {},
"overflow 1": {"10000000000", "1000000000"},
"overflow 2": {"1000000000000000000", "10"},
"overflow 3": {"4999999999999999995", "-2.000000000000000002"},
"overflow 4": {
"9999999999999999999", "9999999999999999999",
"9999999999999999999", "9999999999999999999",
"9999999999999999999", "9999999999999999999",
"9999999999999999999", "9999999999999999999",
},
}
for name, ss := range tests {
t.Run(name, func(t *testing.T) {
d := make([]Decimal, len(ss))
for i, s := range ss {
d[i] = MustParse(s)
}
_, err := Prod(d...)
if err == nil {
t.Errorf("Prod(%v) did not fail", d)
}
})
}
})
}
func TestMean(t *testing.T) {
t.Run("success", func(t *testing.T) {
tests := []struct {
d []string
want string
}{
{[]string{"1"}, "1"},
{[]string{"1", "1"}, "1"},
{[]string{"2", "3"}, "2.5"},
{[]string{"5.75", "3.3"}, "4.525"},
{[]string{"5", "-3"}, "1"},
{[]string{"-5", "-3"}, "-4"},
{[]string{"-7", "2.5"}, "-2.25"},
{[]string{"0.7", "0.3"}, "0.5"},
{[]string{"1.25", "1.25"}, "1.25"},
{[]string{"1.1", "0.11"}, "0.605"},
{[]string{"1.234567890", "1.000000000"}, "1.117283945"},
{[]string{"1.234567890", "1.000000110"}, "1.117284000"},
{[]string{"0.9998", "0.0000"}, "0.4999"},
{[]string{"0.9998", "0.0001"}, "0.49995"},
{[]string{"0.9998", "0.0002"}, "0.5000"},
{[]string{"0.9998", "0.0003"}, "0.50005"},
{[]string{"999999999999999999", "1"}, "500000000000000000"},
{[]string{"99999999999999999", "1"}, "50000000000000000"},
{[]string{"9999999999999999", "1"}, "5000000000000000"},
{[]string{"999999999999999", "1"}, "500000000000000"},
{[]string{"99999999999999", "1"}, "50000000000000"},
{[]string{"9999999999999", "1"}, "5000000000000"},
{[]string{"999999999999", "1"}, "500000000000"},
{[]string{"99999999999", "1"}, "50000000000"},
{[]string{"9999999999", "1"}, "5000000000"},
{[]string{"999999999", "1"}, "500000000"},
{[]string{"99999999", "1"}, "50000000"},
{[]string{"9999999", "1"}, "5000000"},
{[]string{"999999", "1"}, "500000"},
{[]string{"99999", "1"}, "50000"},
{[]string{"9999", "1"}, "5000"},
{[]string{"999", "1"}, "500"},
{[]string{"99", "1"}, "50"},
{[]string{"9", "1"}, "5"},
{[]string{"100000000000", "0.00000000"}, "50000000000.00000000"},
{[]string{"100000000000", "0.00000001"}, "50000000000.00000000"},
{[]string{"0.0", "0"}, "0.0"},
{[]string{"0.00", "0"}, "0.00"},
{[]string{"0.000", "0"}, "0.000"},
{[]string{"0.0000000", "0"}, "0.0000000"},
{[]string{"0", "0.0"}, "0.0"},
{[]string{"0", "0.00"}, "0.00"},
{[]string{"0", "0.000"}, "0.000"},
{[]string{"0", "0.0000000"}, "0.0000000"},
{[]string{"9999999999999999999", "0.4"}, "5000000000000000000"},
{[]string{"-9999999999999999999", "-0.4"}, "-5000000000000000000"},
{[]string{"1", "-9999999999999999999"}, "-4999999999999999999"},
{[]string{"9999999999999999999", "-1"}, "4999999999999999999"},
// Smallest and largest numbers
{[]string{"-0.0000000000000000001", "-0.0000000000000000001"}, "-0.0000000000000000001"},
{[]string{"0.0000000000000000001", "0.0000000000000000001"}, "0.0000000000000000001"},
{[]string{"-9999999999999999999", "-9999999999999999999"}, "-9999999999999999999"},
{[]string{"9999999999999999999", "9999999999999999999"}, "9999999999999999999"},
// Captured during fuzzing
{[]string{"9223372036854775807", "9223372036854775807", "922337203685477580.7"}, "6456360425798343065"},
{[]string{"922.3372036854775807", "2", "-3000000000"}, "-999999691.8875987715"},
{[]string{"0.5", "0.3", "0.2"}, "0.3333333333333333333"},
}
for _, tt := range tests {
d := make([]Decimal, len(tt.d))
for i, s := range tt.d {
d[i] = MustParse(s)
}
got, err := Mean(d...)
if err != nil {
t.Errorf("Mean(%v) failed: %v", d, err)
}
want := MustParse(tt.want)
if got != want {
t.Errorf("Mean(%v) = %q, want %q", d, got, want)
}
}
})
t.Run("error", func(t *testing.T) {
tests := map[string][]string{
"no arguments": {},
}
for name, ss := range tests {
t.Run(name, func(t *testing.T) {
d := make([]Decimal, len(ss))
for i, s := range ss {
d[i] = MustParse(s)
}
_, err := Mean(d...)
if err == nil {
t.Errorf("Mean(%v) did not fail", d)
}
})
}
})
}
func TestDecimal_Mul(t *testing.T) {
t.Run("success", func(t *testing.T) {
tests := []struct {
d, e, want string
}{
{"2", "2", "4"},
{"2", "3", "6"},
{"5", "1", "5"},
{"5", "2", "10"},
{"1.20", "2", "2.40"},
{"1.20", "0", "0.00"},
{"1.20", "-2", "-2.40"},
{"-1.20", "2", "-2.40"},
{"-1.20", "0", "0.00"},
{"-1.20", "-2", "2.40"},
{"5.09", "7.1", "36.139"},
{"2.5", "4", "10.0"},
{"2.50", "4", "10.00"},
{"0.70", "1.05", "0.7350"},
{"1.000000000", "1", "1.000000000"},
{"1.23456789", "1.00000000", "1.2345678900000000"},
{"1.000000000000000000", "1.000000000000000000", "1.000000000000000000"},
{"1.000000000000000001", "1.000000000000000001", "1.000000000000000002"},
{"9.999999999999999999", "9.999999999999999999", "99.99999999999999998"},
{"0.0000000000000000001", "0.0000000000000000001", "0.0000000000000000000"},
{"0.0000000000000000001", "0.9999999999999999999", "0.0000000000000000001"},
{"0.0000000000000000003", "0.9999999999999999999", "0.0000000000000000003"},
{"0.9999999999999999999", "0.9999999999999999999", "0.9999999999999999998"},
{"6963.788300835654596", "0.001436", "10.00000000000000000"},
// Captured during fuzzing
{"92233720368547757.26", "0.0000000000000000002", "0.0184467440737095515"},
{"9223372036854775.807", "-0.0000000000000000013", "-0.0119903836479112085"},
}
for _, tt := range tests {
d := MustParse(tt.d)
e := MustParse(tt.e)
got, err := d.Mul(e)
if err != nil {
t.Errorf("%q.Mul(%q) failed: %v", d, e, err)
continue
}
want := MustParse(tt.want)
if got != want {
t.Errorf("%q.Mul(%q) = %q, want %q", d, e, got, want)
}
}
})
t.Run("error", func(t *testing.T) {
tests := map[string]struct {
d, e string
scale int
}{
"overflow 1": {"10000000000", "1000000000", 0},
"overflow 2": {"1000000000000000000", "10", 0},
"overflow 3": {"4999999999999999995", "-2.000000000000000002", 0},
"scale 1": {"1", "1", MaxScale},
"scale 2": {"0", "0", MaxScale + 1},
}
for _, tt := range tests {
d := MustParse(tt.d)
e := MustParse(tt.e)
_, err := d.MulExact(e, tt.scale)
if err == nil {
t.Errorf("%q.MulExact(%q, %v) did not fail", d, e, tt.scale)
}
}
})
}
func TestDecimal_AddMul(t *testing.T) {
t.Run("success", func(t *testing.T) {
tests := []struct {
d, e, f, want string
}{
// Signs
{"4", "2", "3", "10"},
{"-4", "2", "3", "2"},
{"4", "2", "-3", "-2"},
{"-4", "2", "-3", "-10"},
{"4", "-2", "3", "-2"},
{"-4", "-2", "3", "-10"},
{"4", "-2", "-3", "10"},
{"-4", "-2", "-3", "2"},
// Addition tests
{"1", "1", "1", "2"},
{"3", "1", "2", "5"},
{"3.3", "1", "5.75", "9.05"},
{"-3", "1", "5", "2"},
{"-3", "1", "-5", "-8"},
{"2.5", "1", "-7", "-4.5"},
{"0.3", "1", "0.7", "1.0"},
{"1.25", "1", "1.25", "2.50"},
{"0.11", "1", "1.1", "1.21"},
{"1.000000000", "1", "1.234567890", "2.234567890"},
{"1.000000110", "1", "1.234567890", "2.234568000"},
{"0.0000", "1", "0.9998", "0.9998"},
{"0.0001", "1", "0.9998", "0.9999"},
{"0.0002", "1", "0.9998", "1.0000"},
{"0.0003", "1", "0.9998", "1.0001"},
{"1", "1", "999999999999999999", "1000000000000000000"},
{"1", "1", "99999999999999999", "100000000000000000"},
{"1", "1", "9999999999999999", "10000000000000000"},
{"1", "1", "999999999999999", "1000000000000000"},
{"1", "1", "99999999999999", "100000000000000"},
{"1", "1", "9999999999999", "10000000000000"},
{"1", "1", "999999999999", "1000000000000"},
{"1", "1", "99999999999", "100000000000"},
{"1", "1", "9999999999", "10000000000"},
{"1", "1", "999999999", "1000000000"},
{"1", "1", "99999999", "100000000"},
{"1", "1", "9999999", "10000000"},
{"1", "1", "999999", "1000000"},
{"1", "1", "99999", "100000"},
{"1", "1", "9999", "10000"},
{"1", "1", "999", "1000"},
{"1", "1", "99", "100"},
{"1", "1", "9", "10"},
{"0.00000000", "1", "100000000000", "100000000000.0000000"},
{"0.00000001", "1", "100000000000", "100000000000.0000000"},
{"0", "1", "0.0", "0.0"},
{"0", "1", "0.00", "0.00"},
{"0", "1", "0.000", "0.000"},
{"0", "1", "0.0000000", "0.0000000"},
{"0.0", "1", "0", "0.0"},
{"0.00", "1", "0", "0.00"},
{"0.000", "1", "0", "0.000"},
{"0.0000000", "1", "0", "0.0000000"},
{"0.4", "1", "9999999999999999999", "9999999999999999999"},
{"-0.4", "1", "-9999999999999999999", "-9999999999999999999"},
{"-9999999999999999999", "1", "1", "-9999999999999999998"},
{"-1", "1", "9999999999999999999", "9999999999999999998"},
// Multiplication tests
{"0", "2", "2", "4"},
{"0", "2", "3", "6"},
{"0", "5", "1", "5"},
{"0", "5", "2", "10"},
{"0", "1.20", "2", "2.40"},
{"0", "1.20", "0", "0.00"},
{"0", "1.20", "-2", "-2.40"},
{"0", "-1.20", "2", "-2.40"},
{"0", "-1.20", "0", "0.00"},
{"0", "-1.20", "-2", "2.40"},
{"0", "5.09", "7.1", "36.139"},
{"0", "2.5", "4", "10.0"},
{"0", "2.50", "4", "10.00"},
{"0", "0.70", "1.05", "0.7350"},
{"0", "1.000000000", "1", "1.000000000"},
{"0", "1.23456789", "1.00000000", "1.2345678900000000"},
{"0", "1.000000000000000000", "1.000000000000000000", "1.000000000000000000"},
{"0", "1.000000000000000001", "1.000000000000000001", "1.000000000000000002"},
{"0", "9.999999999999999999", "9.999999999999999999", "99.99999999999999998"},
{"0", "0.0000000000000000001", "0.0000000000000000001", "0.0000000000000000000"},
{"0", "0.0000000000000000001", "0.9999999999999999999", "0.0000000000000000001"},
{"0", "0.0000000000000000003", "0.9999999999999999999", "0.0000000000000000003"},
{"0", "0.9999999999999999999", "0.9999999999999999999", "0.9999999999999999998"},
{"0", "6963.788300835654596", "0.001436", "10.00000000000000000"},
// Captured during fuzzing
{"0.0000000000000000121", "0.0000000000000000127", "12.5", "0.0000000000000001708"},
{"-9.3", "0.0000000203", "-0.0000000116", "-9.300000000000000235"},
{"5.8", "-0.0000000231", "0.0000000166", "5.799999999999999617"},
// Tests from GDA
{"2593183.42371", "27583489.6645", "2582471078.04", "71233564292579696.34"},
{"2032.013252", "24280.355566", "939577.397653", "22813275328.80506589"},
{"137903.517909", "7848976432", "-2586831.2281", "-20303977342780612.62"},
{"339337.123410", "56890.388731", "35872030.4255", "2040774094814.077745"},
{"5073392.31638", "7533543.57445", "360317763928", "2714469575205049785"},
{"894450638.442", "437484.00601", "598906432790", "262011986336578659.5"},
{"153127.446727", "203258304486", "-8628278.8066", "-1753769320861850379"},
{"178277.96377", "42560533.1774", "-3643605282.86", "-155073783526334663.6"},
}
for _, tt := range tests {
d := MustParse(tt.d)
e := MustParse(tt.e)
f := MustParse(tt.f)
got, err := d.AddMul(e, f)
if err != nil {
t.Errorf("%q.AddMul(%q, %q) failed: %v", d, e, f, err)
continue
}
want := MustParse(tt.want)
if got != want {
t.Errorf("%q.AddMul(%q, %q) = %q, want %q", d, e, f, got, want)
}
}
})
t.Run("error", func(t *testing.T) {
tests := map[string]struct {
d, f, e string
scale int
}{
"overflow 1": {"1", "1", "9999999999999999999", 0},
"overflow 2": {"0.6", "1", "9999999999999999999", 0},
"overflow 3": {"-1", "1", "-9999999999999999999", 0},
"overflow 4": {"-0.6", "1", "-9999999999999999999", 0},
"overflow 5": {"0", "10000000000", "1000000000", 0},
"overflow 6": {"0", "1000000000000000000", "10", 0},
"scale 1": {"1", "1", "1", MaxScale},
"scale 2": {"0", "0", "0", MaxScale + 1},
}
for _, tt := range tests {
d := MustParse(tt.d)
e := MustParse(tt.e)
f := MustParse(tt.f)
_, err := d.AddMulExact(e, f, tt.scale)
if err == nil {
t.Errorf("%q.AddMulExact(%q, %q, %v) did not fail", d, e, f, tt.scale)
}
}
})
}
func TestDecimal_AddQuo(t *testing.T) {
t.Run("success", func(t *testing.T) {
tests := []struct {
d, e, f, want string
}{
// Signs
{"3", "4", "2", "5"},
{"3", "-4", "2", "1"},
{"-3", "4", "2", "-1"},
{"-3", "-4", "2", "-5"},
{"3", "4", "-2", "1"},
{"3", "-4", "-2", "5"},
{"-3", "4", "-2", "-5"},
{"-3", "-4", "-2", "-1"},
// Addition tests
{"1", "1", "1", "2"},
{"3", "2", "1", "5"},
{"3.3", "5.75", "1", "9.05"},
{"-3", "5", "1", "2"},
{"-3", "-5", "1", "-8"},
{"2.5", "-7", "1", "-4.5"},
{"0.3", "0.7", "1", "1.0"},
{"1.25", "1.25", "1", "2.50"},
{"0.11", "1.1", "1", "1.21"},
{"1.000000000", "1.234567890", "1", "2.234567890"},
{"1.000000110", "1.234567890", "1", "2.234568000"},
{"0.0000", "0.9998", "1", "0.9998"},
{"0.0001", "0.9998", "1", "0.9999"},
{"0.0002", "0.9998", "1", "1.0000"},
{"0.0003", "0.9998", "1", "1.0001"},
{"1", "999999999999999999", "1", "1000000000000000000"},
{"1", "99999999999999999", "1", "100000000000000000"},
{"1", "9999999999999999", "1", "10000000000000000"},
{"1", "999999999999999", "1", "1000000000000000"},
{"1", "99999999999999", "1", "100000000000000"},
{"1", "9999999999999", "1", "10000000000000"},
{"1", "999999999999", "1", "1000000000000"},
{"1", "99999999999", "1", "100000000000"},
{"1", "9999999999", "1", "10000000000"},
{"1", "999999999", "1", "1000000000"},
{"1", "99999999", "1", "100000000"},
{"1", "9999999", "1", "10000000"},
{"1", "999999", "1", "1000000"},
{"1", "99999", "1", "100000"},
{"1", "9999", "1", "10000"},
{"1", "999", "1", "1000"},
{"1", "99", "1", "100"},
{"1", "9", "1", "10"},
{"0.00000000", "100000000000", "1", "100000000000.0000000"},
{"0.00000001", "100000000000", "1", "100000000000.0000000"},
{"0", "0.0", "1", "0.0"},
{"0", "0.00", "1", "0.00"},
{"0", "0.000", "1", "0.000"},
{"0", "0.0000000", "1", "0.0000000"},
{"0.0", "0", "1", "0.0"},
{"0.00", "0", "1", "0.00"},
{"0.000", "0", "1", "0.000"},
{"0.0000000", "0", "1", "0.0000000"},
{"0.4", "9999999999999999999", "1", "9999999999999999999"},
{"-0.4", "-9999999999999999999", "1", "-9999999999999999999"},
{"-9999999999999999999", "1", "1", "-9999999999999999998"},
{"-1", "9999999999999999999", "1", "9999999999999999998"},
// Division tests
{"0", "9223372036854775807", "-9223372036854775808", "-0.9999999999999999999"},
{"0", "0.000000000000000001", "20", "0.000000000000000000"},
{"0", "105", "0.999999999999999990", "105.0000000000000011"},
{"0", "0.05", "999999999999999954", "0.0000000000000000001"},
{"0", "9.99999999999999998", "185", "0.0540540540540540539"},
{"0", "7", "2.000000000000000002", "3.499999999999999997"},
{"0", "0.000000009", "999999999999999999", "0.000000000"},
{"0", "0.0000000000000000001", "9999999999999999999", "0.0000000000000000000"},
{"0", "9999999999999999999", "2", "5000000000000000000"},
{"0", "9999999999999999999", "5000000000000000000", "2"},
// Captured during fuzzing
{"47", "-126", "110", "45.85454545454545455"},
{"-92", "94", "76", "-90.76315789473684211"},
{"5", "-40", "139", "4.712230215827338129"},
{"-3", "3", "0.9999999999999999999", "0.0000000000000000003"},
{"-0.0000000000000000001", "1", "0.9999999999999999999", "1.000000000000000000"},
{"0.00000000053", "4.3", "0.00000000071", "6056338028.169014085"},
{"8.9", "0.0000000000082", "-0.000000110", "8.899925454545454545"},
{"0.000000000000000", "0.9999999999999999940", "1", "0.9999999999999999940"},
}
for _, tt := range tests {
d := MustParse(tt.d)
e := MustParse(tt.e)
f := MustParse(tt.f)
got, err := d.AddQuo(e, f)
if err != nil {
t.Errorf("%q.AddQuo(%q, %q) failed: %v", d, e, f, err)
continue
}
want := MustParse(tt.want)
if got.CmpTotal(want) != 0 {
t.Errorf("%q.AddQuo(%q, %q) = %q, want %q", d, e, f, got, want)
}
}
})
t.Run("error", func(t *testing.T) {
tests := map[string]struct {
d, e, f string
scale int
}{
"overflow 1": {"9999999999999999999", "1", "1", 0},
"overflow 2": {"9999999999999999999", "0.6", "1", 0},
"overflow 3": {"-9999999999999999999", "-1", "1", 0},
"overflow 4": {"-9999999999999999999", "-0.6", "1", 0},
"overflow 5": {"0", "10000000000", "0.000000001", 0},
"overflow 6": {"0", "1000000000000000000", "0.1", 0},
"zero 1": {"1", "1", "0", 0},
"scale 1": {"1", "1", "1", MaxScale},
"scale 2": {"0", "0", "1", MaxScale + 1},
}
for _, tt := range tests {
d := MustParse(tt.d)
e := MustParse(tt.e)
f := MustParse(tt.f)
_, err := d.AddQuoExact(e, f, tt.scale)
if err == nil {
t.Errorf("%q.AddQuoExact(%q, %q, %v) did not fail", d, e, f, tt.scale)
}
}
})
}
func TestDecimal_Pow(t *testing.T) {
t.Run("success", func(t *testing.T) {
tests := []struct {
d, e, want string
}{
//////////////////////
// Fractional Powers
//////////////////////
{"0.0", "0.0", "1"},
{"0.0", "0.5", "0"},
{"4.0", "-0.5", "0.5000000000000000000"},
{"4.0", "0.0", "1"},
{"4.0", "0.5", "2.000000000000000000"},
{"0.0000001", "0.0000001", "0.9999983881917338685"},
{"0.003", "0.0000001", "0.9999994190858696993"},
{"0.7", "0.0000001", "0.9999999643325062422"},
{"1.2", "0.0000001", "1.000000018232155846"},
{"71", "0.0000001", "1.000000426268078556"},
{"9000000000", "0.0000001", "1.000002292051668175"},
{"0.0000001", "0.003", "0.9527961640236518859"},
{"0.003", "0.003", "0.9827235503366796915"},
{"0.7", "0.003", "0.9989305474406207158"},
{"1.2", "0.003", "1.000547114282833519"},
{"71", "0.003", "1.012870156273545212"},
{"9000000000", "0.003", "1.071180671278787089"},
{"0.0000001", "0.7", "0.0000125892541179417"},
{"0.003", "0.7", "0.0171389763028103005"},
{"0.7", "0.7", "0.7790559126704490940"},
{"1.2", "0.7", "1.136126977198888691"},
{"71", "0.7", "19.76427300093869501"},
{"9000000000", "0.7", "9289016.976853710315"},
{"0.0000001", "1.2", "0.0000000039810717055"},
{"0.003", "1.2", "0.0009387403933595694"},
{"0.7", "1.2", "0.6518049405663863819"},
{"1.2", "1.2", "1.244564747203977722"},
{"71", "1.2", "166.5367244638552138"},
{"9000000000", "1.2", "881233526124.8791107"},
// Natural numbers
{"10", "0.0000000000000000000", "1"},
{"10", "0.3010299956639811952", "2.000000000000000000"},
{"10", "0.4771212547196624373", "3.000000000000000000"},
{"10", "0.6020599913279623904", "4.000000000000000000"},
{"10", "0.6989700043360188048", "5.000000000000000000"},
{"10", "0.7781512503836436325", "6.000000000000000000"},
{"10", "0.8450980400142568307", "7.000000000000000000"},
{"10", "0.9030899869919435856", "7.999999999999999999"},
{"10", "0.9542425094393248746", "9.000000000000000000"},
{"10", "1", "10"},
{"10", "1.041392685158225041", "11.00000000000000001"},
{"10", "1.079181246047624828", "12.00000000000000001"},
{"10", "1.113943352306836769", "12.99999999999999999"},
{"10", "1.146128035678238026", "14.00000000000000000"},
{"10", "1.176091259055681242", "15.00000000000000000"},
{"10", "1.204119982655924781", "16.00000000000000001"},
{"10", "1.230448921378273929", "17.00000000000000002"},
{"10", "1.255272505103306070", "18.00000000000000001"},
{"10", "1.278753600952828962", "19.00000000000000002"},
{"10", "1.301029995663981195", "19.99999999999999999"},
// e^e
{E.String(), E.String(), "15.15426224147926418"},
// Closer and closer to e
{"10", "0.4342944819032518275", "2.718281828459045234"},
{"10", "0.4342944819032518276", "2.718281828459045235"},
{"10", "0.4342944819032518277", "2.718281828459045236"},
{"10", "0.4342944819032518278", "2.718281828459045236"},
{"10", "0.4342944819032518279", "2.718281828459045237"},
// Closer and closer to 1000
{"10", "2.999999999999999998", "999.9999999999999954"},
{"10", "2.999999999999999999", "999.9999999999999977"},
{"10", "3", "1000"},
{"10", "3.000000000000000001", "1000.000000000000002"},
{"10", "3.000000000000000002", "1000.000000000000005"},
// Captured during fuzzing
{"1.000000000000000001", "9223372036854775807", "10131.16947077036074"},
{"1.000000000000000001", "922337203685477580.7", "2.515161971551883079"},
{"1.000000000000000001", "92233720368547758.07", "1.096621094818009214"},
{"999999999.999999999", "-999999999.999999999", "0.0000000000000000000"},
{"0.060", "0.999999999999999944", "0.0600000000000000095"},
{"0.0000000091", "0.23", "0.0141442368531557249"},
/////////////////
// Square Roots
/////////////////
// Zeros
{"0.00000000", "0.5", "0"},
{"0.0000000", "0.5", "0"},
{"0.000000", "0.5", "0"},
{"0.00000", "0.5", "0"},
{"0.0000", "0.5", "0"},
{"0.000", "0.5", "0"},
{"0.00", "0.5", "0"},
{"0.0", "0.5", "0"},
{"0", "0.5", "0"},
// Trailing zeros
{"0.010000000", "0.5", "0.1000000000000000000"},
{"0.01000000", "0.5", "0.1000000000000000000"},
{"0.0100000", "0.5", "0.1000000000000000000"},
{"0.010000", "0.5", "0.1000000000000000000"},
{"0.01000", "0.5", "0.1000000000000000000"},
{"0.0100", "0.5", "0.1000000000000000000"},
{"0.010", "0.5", "0.1000000000000000000"},
{"0.01", "0.5", "0.1000000000000000000"},
// Powers of ten
{"0.00000001", "0.5", "0.0001000000000000000"},
{"0.0000001", "0.5", "0.0003162277660168379"},
{"0.000001", "0.5", "0.0010000000000000000"},
{"0.00001", "0.5", "0.0031622776601683793"},
{"0.0001", "0.5", "0.0100000000000000000"},
{"0.001", "0.5", "0.0316227766016837933"},
{"0.01", "0.5", "0.1000000000000000000"},
{"0.1", "0.5", "0.3162277660168379332"},
{"1", "0.5", "1.00000000000000000000"},
{"10", "0.5", "3.162277660168379332"},
{"100", "0.5", "10.00000000000000000"},
{"1000", "0.5", "31.62277660168379332"},
{"10000", "0.5", "100.0000000000000000"},
{"100000", "0.5", "316.2277660168379332"},
{"1000000", "0.5", "1000.000000000000000"},
{"10000000", "0.5", "3162.277660168379332"},
{"100000000", "0.5", "10000.00000000000000"},
// Natural numbers
{"0", "0.5", "0"},
{"1", "0.5", "1.000000000000000000"},
{"2", "0.5", "1.414213562373095049"},
{"3", "0.5", "1.732050807568877294"},
{"4", "0.5", "2.000000000000000000"},
{"5", "0.5", "2.236067977499789696"},
{"6", "0.5", "2.449489742783178098"},
{"7", "0.5", "2.645751311064590591"},
{"8", "0.5", "2.828427124746190098"},
{"9", "0.5", "3.000000000000000000"},
{"10", "0.5", "3.162277660168379332"},
{"11", "0.5", "3.316624790355399849"},
{"12", "0.5", "3.464101615137754587"},
{"13", "0.5", "3.605551275463989293"},
{"14", "0.5", "3.741657386773941386"},
{"15", "0.5", "3.872983346207416885"},
{"16", "0.5", "4.000000000000000000"},
{"17", "0.5", "4.123105625617660550"},
{"18", "0.5", "4.242640687119285146"},
{"19", "0.5", "4.358898943540673552"},
{"20", "0.5", "4.472135954999579393"},
{"21", "0.5", "4.582575694955840007"},
{"22", "0.5", "4.690415759823429555"},
{"23", "0.5", "4.795831523312719542"},
{"24", "0.5", "4.898979485566356196"},
{"25", "0.5", "5.000000000000000000"},
// Well-known squares
{"1", "0.5", "1.000000000000000000"},
{"4", "0.5", "2.000000000000000000"},
{"9", "0.5", "3.000000000000000000"},
{"16", "0.5", "4.000000000000000000"},
{"25", "0.5", "5.000000000000000000"},
{"36", "0.5", "6.000000000000000000"},
{"49", "0.5", "7.000000000000000000"},
{"64", "0.5", "8.000000000000000000"},
{"81", "0.5", "9.000000000000000000"},
{"100", "0.5", "10.00000000000000000"},
{"121", "0.5", "11.00000000000000000"},
{"144", "0.5", "12.00000000000000000"},
{"169", "0.5", "13.00000000000000000"},
{"256", "0.5", "16.00000000000000000"},
{"1024", "0.5", "32.00000000000000000"},
{"4096", "0.5", "64.00000000000000000"},
{"0.01", "0.5", "0.1000000000000000000"},
{"0.04", "0.5", "0.2000000000000000000"},
{"0.09", "0.5", "0.3000000000000000000"},
{"0.16", "0.5", "0.4000000000000000000"},
{"0.25", "0.5", "0.5000000000000000000"},
{"0.36", "0.5", "0.6000000000000000000"},
{"0.49", "0.5", "0.7000000000000000000"},
{"0.64", "0.5", "0.8000000000000000000"},
{"0.81", "0.5", "0.9000000000000000000"},
{"1.00", "0.5", "1.000000000000000000"},
{"1.21", "0.5", "1.100000000000000000"},
{"1.44", "0.5", "1.200000000000000000"},
{"1.69", "0.5", "1.300000000000000000"},
{"2.56", "0.5", "1.600000000000000000"},
{"10.24", "0.5", "3.200000000000000000"},
{"40.96", "0.5", "6.400000000000000000"},
// Smallest and largest numbers
{"0.0000000000000000001", "0.5", "0.0000000003162277660"},
{"9999999999999999999", "0.5", "3162277660.168379332"},
// Captured during fuzzing
{"1.000000000000000063", "0.5", "1.000000000000000031"},
{"0.000000272", "0.5", "0.0005215361924162119"},
{"0.9999999999999999999", "0.5", "0.9999999999999999999"},
///////////////////
// Integer Powers
///////////////////
// Zeros
{"0", "0", "1"},
{"0", "1", "0"},
{"0", "2", "0"},
// Ones
{"-1", "-2", "1"},
{"-1", "-1", "-1"},
{"-1", "0", "1"},
{"-1", "1", "-1"},
{"-1", "2", "1"},
// One tenths
{"0.1", "-18", "1000000000000000000"},
{"0.1", "-10", "10000000000"},
{"0.1", "-9", "1000000000"},
{"0.1", "-8", "100000000"},
{"0.1", "-7", "10000000"},
{"0.1", "-6", "1000000"},
{"0.1", "-5", "100000"},
{"0.1", "-4", "10000"},
{"0.1", "-3", "1000"},
{"0.1", "-2", "100"},
{"0.1", "-1", "10"},
{"0.1", "0", "1"},
{"0.1", "1", "0.1"},
{"0.1", "2", "0.01"},
{"0.1", "3", "0.001"},
{"0.1", "4", "0.0001"},
{"0.1", "5", "0.00001"},
{"0.1", "6", "0.000001"},
{"0.1", "7", "0.0000001"},
{"0.1", "8", "0.00000001"},
{"0.1", "9", "0.000000001"},
{"0.1", "10", "0.0000000001"},
{"0.1", "18", "0.000000000000000001"},
{"0.1", "19", "0.0000000000000000001"},
{"0.1", "20", "0.0000000000000000000"},
{"0.1", "40", "0.0000000000000000000"},
// Negative one tenths
{"-0.1", "-18", "1000000000000000000"},
{"-0.1", "-10", "10000000000"},
{"-0.1", "-9", "-1000000000"},
{"-0.1", "-8", "100000000"},
{"-0.1", "-7", "-10000000"},
{"-0.1", "-6", "1000000"},
{"-0.1", "-5", "-100000"},
{"-0.1", "-4", "10000"},
{"-0.1", "-3", "-1000"},
{"-0.1", "-2", "100"},
{"-0.1", "-1", "-10"},
{"-0.1", "0", "1"},
{"-0.1", "1", "-0.1"},
{"-0.1", "2", "0.01"},
{"-0.1", "3", "-0.001"},
{"-0.1", "4", "0.0001"},
{"-0.1", "5", "-0.00001"},
{"-0.1", "6", "0.000001"},
{"-0.1", "7", "-0.0000001"},
{"-0.1", "8", "0.00000001"},
{"-0.1", "9", "-0.000000001"},
{"-0.1", "10", "0.0000000001"},
{"-0.1", "18", "0.000000000000000001"},
{"-0.1", "19", "-0.0000000000000000001"},
{"-0.1", "20", "0.0000000000000000000"},
{"-0.1", "40", "0.0000000000000000000"},
// Twos
{"2", "-64", "0.0000000000000000001"},
{"2", "-63", "0.0000000000000000001"},
{"2", "-32", "0.0000000002328306437"},
{"2", "-16", "0.0000152587890625"},
{"2", "-9", "0.001953125"},
{"2", "-8", "0.00390625"},
{"2", "-7", "0.0078125"},
{"2", "-6", "0.015625"},
{"2", "-5", "0.03125"},
{"2", "-4", "0.0625"},
{"2", "-3", "0.125"},
{"2", "-2", "0.25"},
{"2", "-1", "0.5"},
{"2", "0", "1"},
{"2", "1", "2"},
{"2", "2", "4"},
{"2", "3", "8"},
{"2", "4", "16"},
{"2", "5", "32"},
{"2", "6", "64"},
{"2", "7", "128"},
{"2", "8", "256"},
{"2", "9", "512"},
{"2", "16", "65536"},
{"2", "32", "4294967296"},
{"2", "63", "9223372036854775808"},
// Negative twos
{"-2", "-64", "0.0000000000000000001"},
{"-2", "-63", "-0.0000000000000000001"},
{"-2", "-32", "0.0000000002328306437"},
{"-2", "-16", "0.0000152587890625"},
{"-2", "-9", "-0.001953125"},
{"-2", "-8", "0.00390625"},
{"-2", "-7", "-0.0078125"},
{"-2", "-6", "0.015625"},
{"-2", "-5", "-0.03125"},
{"-2", "-4", "0.0625"},
{"-2", "-3", "-0.125"},
{"-2", "-2", "0.25"},
{"-2", "-1", "-0.5"},
{"-2", "0", "1"},
{"-2", "1", "-2"},
{"-2", "2", "4"},
{"-2", "3", "-8"},
{"-2", "4", "16"},
{"-2", "5", "-32"},
{"-2", "6", "64"},
{"-2", "7", "-128"},
{"-2", "8", "256"},
{"-2", "9", "-512"},
{"-2", "16", "65536"},
{"-2", "32", "4294967296"},
{"-2", "63", "-9223372036854775808"},
// Squares
{"-3", "2", "9"},
{"-2", "2", "4"},
{"-1", "2", "1"},
{"0", "2", "0"},
{"1", "2", "1"},
{"2", "2", "4"},
{"3", "2", "9"},
{"4", "2", "16"},
{"5", "2", "25"},
{"6", "2", "36"},
{"7", "2", "49"},
{"8", "2", "64"},
{"9", "2", "81"},
{"10", "2", "100"},
{"11", "2", "121"},
{"12", "2", "144"},
{"13", "2", "169"},
{"14", "2", "196"},
{"-0.3", "2", "0.09"},
{"-0.2", "2", "0.04"},
{"-0.1", "2", "0.01"},
{"0.0", "2", "0.00"},
{"0.1", "2", "0.01"},
{"0.2", "2", "0.04"},
{"0.3", "2", "0.09"},
{"0.4", "2", "0.16"},
{"0.5", "2", "0.25"},
{"0.6", "2", "0.36"},
{"0.7", "2", "0.49"},
{"0.8", "2", "0.64"},
{"0.9", "2", "0.81"},
{"1.0", "2", "1.00"},
{"1.1", "2", "1.21"},
{"1.2", "2", "1.44"},
{"1.3", "2", "1.69"},
{"1.4", "2", "1.96"},
{"0.000000000316227766", "2", "0.0000000000000000001"},
{"3162277660.168379331", "2", "9999999999999999994"},
// Cubes
{"-3", "3", "-27"},
{"-2", "3", "-8"},
{"-1", "3", "-1"},
{"0", "3", "0"},
{"1", "3", "1"},
{"2", "3", "8"},
{"3", "3", "27"},
{"4", "3", "64"},
{"5", "3", "125"},
{"6", "3", "216"},
{"7", "3", "343"},
{"8", "3", "512"},
{"9", "3", "729"},
{"10", "3", "1000"},
{"11", "3", "1331"},
{"12", "3", "1728"},
{"13", "3", "2197"},
{"14", "3", "2744"},
{"-0.3", "3", "-0.027"},
{"-0.2", "3", "-0.008"},
{"-0.1", "3", "-0.001"},
{"0.0", "3", "0.000"},
{"0.1", "3", "0.001"},
{"0.2", "3", "0.008"},
{"0.3", "3", "0.027"},
{"0.4", "3", "0.064"},
{"0.5", "3", "0.125"},
{"0.6", "3", "0.216"},
{"0.7", "3", "0.343"},
{"0.8", "3", "0.512"},
{"0.9", "3", "0.729"},
{"1.0", "3", "1.000"},
{"1.1", "3", "1.331"},
{"1.2", "3", "1.728"},
{"1.3", "3", "2.197"},
{"1.4", "3", "2.744"},
{"0.000000464158883361", "3", "0.0000000000000000001"},
{"2154434.690031883721", "3", "9999999999999999989"},
// Interest accrual
{"1.1", "60", "304.4816395414180996"}, // no error
{"1.01", "600", "391.5833969993197743"}, // no error
{"1.001", "6000", "402.2211245663552923"}, // no error
{"1.0001", "60000", "403.3077910727185433"}, // no error
{"1.00001", "600000", "403.4166908911542153"}, // no error
// Captured during fuzzing
{"0.85", "-267", "7000786514887173012"},
{"0.066", "-16", "7714309010612096020"},
{"-0.9223372036854775808", "-128", "31197.15320234751783"},
{"999999999.999999999", "-9223372036854775808", "0"},
{"-0.9223372036854775807", "-541", "-9877744411719625497"},
{"0.9223372036854775702", "-540", "9110611159425388150"},
}
for _, tt := range tests {
d := MustParse(tt.d)
e := MustParse(tt.e)
got, err := d.Pow(e)
if err != nil {
t.Errorf("%q.Pow(%q) failed: %v", d, e, err)
continue
}
want := MustParse(tt.want)
if got != want {
t.Errorf("%q.Pow(%q) = %q, want %q", d, e, got, want)
}
}
})
t.Run("error", func(t *testing.T) {
tests := map[string]struct {
d, e string
}{
"overflow 1": {"2", "64"},
"overflow 2": {"0.5", "-64"},
"overflow 3": {"10", "19"},
"overflow 4": {"0.1", "-19"},
"overflow 5": {"0.0000000000000000001", "-3"},
"overflow 6": {"999999999.999999999", "999999999.999999999"},
"zero 1": {"0", "-1"},
"negative 1": {"-1", "0.1"},
}
for name, tt := range tests {
t.Run(name, func(t *testing.T) {
d := MustParse(tt.d)
e := MustParse(tt.e)
_, err := d.Pow(e)
if err == nil {
t.Errorf("%q.Pow(%d) did not fail", d, e)
}
})
}
})
}
func TestDecimal_PowInt(t *testing.T) {
t.Run("success", func(t *testing.T) {
tests := []struct {
d string
power int
want string
}{
// Zeros
{"0", 0, "1"},
{"0", 1, "0"},
{"0", 2, "0"},
// Ones
{"-1", -2, "1"},
{"-1", -1, "-1"},
{"-1", 0, "1"},
{"-1", 1, "-1"},
{"-1", 2, "1"},
// One tenths
{"0.1", -18, "1000000000000000000"},
{"0.1", -10, "10000000000"},
{"0.1", -9, "1000000000"},
{"0.1", -8, "100000000"},
{"0.1", -7, "10000000"},
{"0.1", -6, "1000000"},
{"0.1", -5, "100000"},
{"0.1", -4, "10000"},
{"0.1", -3, "1000"},
{"0.1", -2, "100"},
{"0.1", -1, "10"},
{"0.1", 0, "1"},
{"0.1", 1, "0.1"},
{"0.1", 2, "0.01"},
{"0.1", 3, "0.001"},
{"0.1", 4, "0.0001"},
{"0.1", 5, "0.00001"},
{"0.1", 6, "0.000001"},
{"0.1", 7, "0.0000001"},
{"0.1", 8, "0.00000001"},
{"0.1", 9, "0.000000001"},
{"0.1", 10, "0.0000000001"},
{"0.1", 18, "0.000000000000000001"},
{"0.1", 19, "0.0000000000000000001"},
{"0.1", 20, "0.0000000000000000000"},
{"0.1", 40, "0.0000000000000000000"},
// Negative one tenths
{"-0.1", -18, "1000000000000000000"},
{"-0.1", -10, "10000000000"},
{"-0.1", -9, "-1000000000"},
{"-0.1", -8, "100000000"},
{"-0.1", -7, "-10000000"},
{"-0.1", -6, "1000000"},
{"-0.1", -5, "-100000"},
{"-0.1", -4, "10000"},
{"-0.1", -3, "-1000"},
{"-0.1", -2, "100"},
{"-0.1", -1, "-10"},
{"-0.1", 0, "1"},
{"-0.1", 1, "-0.1"},
{"-0.1", 2, "0.01"},
{"-0.1", 3, "-0.001"},
{"-0.1", 4, "0.0001"},
{"-0.1", 5, "-0.00001"},
{"-0.1", 6, "0.000001"},
{"-0.1", 7, "-0.0000001"},
{"-0.1", 8, "0.00000001"},
{"-0.1", 9, "-0.000000001"},
{"-0.1", 10, "0.0000000001"},
{"-0.1", 18, "0.000000000000000001"},
{"-0.1", 19, "-0.0000000000000000001"},
{"-0.1", 20, "0.0000000000000000000"},
{"-0.1", 40, "0.0000000000000000000"},
// Twos
{"2", -64, "0.0000000000000000001"},
{"2", -63, "0.0000000000000000001"},
{"2", -32, "0.0000000002328306437"},
{"2", -16, "0.0000152587890625"},
{"2", -9, "0.001953125"},
{"2", -8, "0.00390625"},
{"2", -7, "0.0078125"},
{"2", -6, "0.015625"},
{"2", -5, "0.03125"},
{"2", -4, "0.0625"},
{"2", -3, "0.125"},
{"2", -2, "0.25"},
{"2", -1, "0.5"},
{"2", 0, "1"},
{"2", 1, "2"},
{"2", 2, "4"},
{"2", 3, "8"},
{"2", 4, "16"},
{"2", 5, "32"},
{"2", 6, "64"},
{"2", 7, "128"},
{"2", 8, "256"},
{"2", 9, "512"},
{"2", 16, "65536"},
{"2", 32, "4294967296"},
{"2", 63, "9223372036854775808"},
// Negative twos
{"-2", -64, "0.0000000000000000001"},
{"-2", -63, "-0.0000000000000000001"},
{"-2", -32, "0.0000000002328306437"},
{"-2", -16, "0.0000152587890625"},
{"-2", -9, "-0.001953125"},
{"-2", -8, "0.00390625"},
{"-2", -7, "-0.0078125"},
{"-2", -6, "0.015625"},
{"-2", -5, "-0.03125"},
{"-2", -4, "0.0625"},
{"-2", -3, "-0.125"},
{"-2", -2, "0.25"},
{"-2", -1, "-0.5"},
{"-2", 0, "1"},
{"-2", 1, "-2"},
{"-2", 2, "4"},
{"-2", 3, "-8"},
{"-2", 4, "16"},
{"-2", 5, "-32"},
{"-2", 6, "64"},
{"-2", 7, "-128"},
{"-2", 8, "256"},
{"-2", 9, "-512"},
{"-2", 16, "65536"},
{"-2", 32, "4294967296"},
{"-2", 63, "-9223372036854775808"},
// Squares
{"-3", 2, "9"},
{"-2", 2, "4"},
{"-1", 2, "1"},
{"0", 2, "0"},
{"1", 2, "1"},
{"2", 2, "4"},
{"3", 2, "9"},
{"4", 2, "16"},
{"5", 2, "25"},
{"6", 2, "36"},
{"7", 2, "49"},
{"8", 2, "64"},
{"9", 2, "81"},
{"10", 2, "100"},
{"11", 2, "121"},
{"12", 2, "144"},
{"13", 2, "169"},
{"14", 2, "196"},
{"-0.3", 2, "0.09"},
{"-0.2", 2, "0.04"},
{"-0.1", 2, "0.01"},
{"0.0", 2, "0.00"},
{"0.1", 2, "0.01"},
{"0.2", 2, "0.04"},
{"0.3", 2, "0.09"},
{"0.4", 2, "0.16"},
{"0.5", 2, "0.25"},
{"0.6", 2, "0.36"},
{"0.7", 2, "0.49"},
{"0.8", 2, "0.64"},
{"0.9", 2, "0.81"},
{"1.0", 2, "1.00"},
{"1.1", 2, "1.21"},
{"1.2", 2, "1.44"},
{"1.3", 2, "1.69"},
{"1.4", 2, "1.96"},
{"0.000000000316227766", 2, "0.0000000000000000001"},
{"3162277660.168379331", 2, "9999999999999999994"},
// Cubes
{"-3", 3, "-27"},
{"-2", 3, "-8"},
{"-1", 3, "-1"},
{"0", 3, "0"},
{"1", 3, "1"},
{"2", 3, "8"},
{"3", 3, "27"},
{"4", 3, "64"},
{"5", 3, "125"},
{"6", 3, "216"},
{"7", 3, "343"},
{"8", 3, "512"},
{"9", 3, "729"},
{"10", 3, "1000"},
{"11", 3, "1331"},
{"12", 3, "1728"},
{"13", 3, "2197"},
{"14", 3, "2744"},
{"-0.3", 3, "-0.027"},
{"-0.2", 3, "-0.008"},
{"-0.1", 3, "-0.001"},
{"0.0", 3, "0.000"},
{"0.1", 3, "0.001"},
{"0.2", 3, "0.008"},
{"0.3", 3, "0.027"},
{"0.4", 3, "0.064"},
{"0.5", 3, "0.125"},
{"0.6", 3, "0.216"},
{"0.7", 3, "0.343"},
{"0.8", 3, "0.512"},
{"0.9", 3, "0.729"},
{"1.0", 3, "1.000"},
{"1.1", 3, "1.331"},
{"1.2", 3, "1.728"},
{"1.3", 3, "2.197"},
{"1.4", 3, "2.744"},
{"0.000000464158883361", 3, "0.0000000000000000001"},
{"2154434.690031883721", 3, "9999999999999999989"},
// Interest accrual
{"1.1", 60, "304.4816395414180996"}, // no error
{"1.01", 600, "391.5833969993197743"}, // no error
{"1.001", 6000, "402.2211245663552923"}, // no error
{"1.0001", 60000, "403.3077910727185433"}, // no error
{"1.00001", 600000, "403.4166908911542153"}, // no error
// Captured during fuzzing
{"-0.9223372036854775807", -541, "-9877744411719625497"},
{"999999999.999999999", math.MinInt, "0"},
{"-0.9223372036854775808", -128, "31197.15320234751783"},
{"0.85", -267, "7000786514887173012"},
{"0.066", -16, "7714309010612096020"},
{"0.9223372036854775702", -540, "9110611159425388150"},
}
for _, tt := range tests {
d := MustParse(tt.d)
got, err := d.PowInt(tt.power)
if err != nil {
t.Errorf("%q.PowInt(%d) failed: %v", d, tt.power, err)
continue
}
want := MustParse(tt.want)
if got != want {
t.Errorf("%q.PowInt(%d) = %q, want %q", d, tt.power, got, want)
}
}
})
t.Run("error", func(t *testing.T) {
tests := map[string]struct {
d string
power int
}{
"overflow 1": {"2", 64},
"overflow 2": {"0.5", -64},
"overflow 3": {"10", 19},
"overflow 4": {"0.1", -19},
"overflow 5": {"0.0000000000000000001", -3},
"overflow 6": {"999999999.999999999", math.MaxInt},
"zero 1": {"0", -1},
}
for name, tt := range tests {
t.Run(name, func(t *testing.T) {
d := MustParse(tt.d)
_, err := d.PowInt(tt.power)
if err == nil {
t.Errorf("%q.PowInt(%d) did not fail", d, tt.power)
}
})
}
})
}
func TestDecimal_Sqrt(t *testing.T) {
t.Run("success", func(t *testing.T) {
tests := []struct {
d, want string
}{
// Zeros
{"0.00000000", "0.0000"},
{"0.0000000", "0.000"},
{"0.000000", "0.000"},
{"0.00000", "0.00"},
{"0.0000", "0.00"},
{"0.000", "0.0"},
{"0.00", "0.0"},
{"0.0", "0"},
{"0", "0"},
// Trailing zeros
{"0.010000000", "0.1000"},
{"0.01000000", "0.1000"},
{"0.0100000", "0.100"},
{"0.010000", "0.100"},
{"0.01000", "0.10"},
{"0.0100", "0.10"},
{"0.010", "0.1"},
{"0.01", "0.1"},
// Powers of ten
{"0.00000001", "0.0001"},
{"0.0000001", "0.0003162277660168379"},
{"0.000001", "0.001"},
{"0.00001", "0.0031622776601683793"},
{"0.0001", "0.01"},
{"0.001", "0.0316227766016837933"},
{"0.01", "0.1"},
{"0.1", "0.3162277660168379332"},
{"1", "1"},
{"10", "3.162277660168379332"},
{"100", "10"},
{"1000", "31.62277660168379332"},
{"10000", "100"},
{"100000", "316.2277660168379332"},
{"1000000", "1000"},
{"10000000", "3162.277660168379332"},
{"100000000", "10000"},
// Natural numbers
{"0", "0"},
{"1", "1"},
{"2", "1.414213562373095049"},
{"3", "1.732050807568877294"},
{"4", "2"},
{"5", "2.236067977499789696"},
{"6", "2.449489742783178098"},
{"7", "2.645751311064590591"},
{"8", "2.828427124746190098"},
{"9", "3"},
{"10", "3.162277660168379332"},
{"11", "3.316624790355399849"},
{"12", "3.464101615137754587"},
{"13", "3.605551275463989293"},
{"14", "3.741657386773941386"},
{"15", "3.872983346207416885"},
{"16", "4"},
{"17", "4.12310562561766055"},
{"18", "4.242640687119285146"},
{"19", "4.358898943540673552"},
{"20", "4.472135954999579393"},
{"21", "4.582575694955840007"},
{"22", "4.690415759823429555"},
{"23", "4.795831523312719542"},
{"24", "4.898979485566356196"},
{"25", "5"},
// Well-known squares
{"1", "1"},
{"4", "2"},
{"9", "3"},
{"16", "4"},
{"25", "5"},
{"36", "6"},
{"49", "7"},
{"64", "8"},
{"81", "9"},
{"100", "10"},
{"121", "11"},
{"144", "12"},
{"169", "13"},
{"256", "16"},
{"1024", "32"},
{"4096", "64"},
{"0.01", "0.1"},
{"0.04", "0.2"},
{"0.09", "0.3"},
{"0.16", "0.4"},
{"0.25", "0.5"},
{"0.36", "0.6"},
{"0.49", "0.7"},
{"0.64", "0.8"},
{"0.81", "0.9"},
{"1.00", "1.0"},
{"1.21", "1.1"},
{"1.44", "1.2"},
{"1.69", "1.3"},
{"2.56", "1.6"},
{"10.24", "3.2"},
{"40.96", "6.4"},
// Smallest and largest numbers
{"0.0000000000000000001", "0.000000000316227766"},
{"9999999999999999999", "3162277660.168379332"},
// Captured during fuzzing
{"1.000000000000000063", "1.000000000000000031"},
{"0.000000272", "0.0005215361924162119"},
{"0.9999999999999999999", "0.9999999999999999999"},
}
for _, tt := range tests {
d := MustParse(tt.d)
got, err := d.Sqrt()
if err != nil {
t.Errorf("%q.Sqrt() failed: %v", d, err)
continue
}
want := MustParse(tt.want)
if got != want {
t.Errorf("%q.Sqrt() = %q, want %q", d, got, want)
}
}
})
t.Run("error", func(t *testing.T) {
tests := map[string]string{
"negative": "-1",
}
for name, d := range tests {
t.Run(name, func(t *testing.T) {
d := MustParse(d)
_, err := d.Sqrt()
if err == nil {
t.Errorf("%q.Sqrt() did not fail", d)
}
})
}
})
}
func TestDecimal_Exp(t *testing.T) {
t.Run("success", func(t *testing.T) {
tests := []struct {
d, want string
}{
// Zeros
{"0", "1"},
{"0.0", "1"},
{"0.00", "1"},
{"0.000", "1"},
{"0.0000", "1"},
{"0.00000", "1"},
// Ones
{"1", E.String()},
{"1.0", E.String()},
{"1.00", E.String()},
{"1.000", E.String()},
{"1.0000", E.String()},
{"1.00000", E.String()},
// Closer and closer to negative one
{"-0.9", "0.4065696597405991119"},
{"-0.99", "0.3715766910220456905"},
{"-0.999", "0.3682475046136629212"},
{"-0.9999", "0.3679162309550179865"},
{"-0.99999", "0.3678831199842480694"},
{"-0.999999", "0.3678798090510674328"},
{"-0.9999999", "0.3678794779593882781"},
{"-0.99999999", "0.3678794448502367517"},
{"-0.999999999", "0.3678794415393217630"},
{"-0.9999999999", "0.3678794412082302657"},
{"-0.99999999999", "0.3678794411751211160"},
{"-0.999999999999", "0.3678794411718102010"},
{"-0.9999999999999", "0.3678794411714791095"},
{"-0.99999999999999", "0.3678794411714460004"},
{"-0.999999999999999", "0.3678794411714426895"},
{"-0.9999999999999999", "0.3678794411714423584"},
{"-0.99999999999999999", "0.3678794411714423253"},
{"-0.999999999999999999", "0.3678794411714423220"},
{"-1", "0.3678794411714423216"},
{"-1.000000000000000001", "0.3678794411714423212"},
{"-1.00000000000000001", "0.3678794411714423179"},
{"-1.0000000000000001", "0.3678794411714422848"},
{"-1.000000000000001", "0.3678794411714419537"},
{"-1.00000000000001", "0.3678794411714386428"},
{"-1.0000000000001", "0.3678794411714055337"},
{"-1.000000000001", "0.3678794411710744422"},
{"-1.00000000001", "0.3678794411677635272"},
{"-1.0000000001", "0.3678794411346543775"},
{"-1.000000001", "0.3678794408035628806"},
{"-1.00000001", "0.3678794374926479283"},
{"-1.0000001", "0.3678794043835000438"},
{"-1.000001", "0.3678790732921850898"},
{"-1.00001", "0.3678757623954245179"},
{"-1.0001", "0.3678426550666610715"},
{"-1.001", "0.3675117456086935500"},
{"-1.01", "0.3642189795715233198"},
{"-1.1", "0.3328710836980795533"},
// Closer and closer to zero
{"-0.1", "0.9048374180359595732"},
{"-0.01", "0.9900498337491680536"},
{"-0.001", "0.9990004998333749917"},
{"-0.0001", "0.9999000049998333375"},
{"-0.00001", "0.9999900000499998333"},
{"-0.000001", "0.9999990000004999998"},
{"-0.0000001", "0.9999999000000050000"},
{"-0.00000001", "0.9999999900000000500"},
{"-0.000000001", "0.9999999990000000005"},
{"-0.0000000001", "0.9999999999000000000"},
{"-0.00000000001", "0.9999999999900000000"},
{"-0.000000000001", "0.9999999999990000000"},
{"-0.0000000000001", "0.9999999999999000000"},
{"-0.00000000000001", "0.9999999999999900000"},
{"-0.000000000000001", "0.9999999999999990000"},
{"-0.0000000000000001", "0.9999999999999999000"},
{"-0.00000000000000001", "0.9999999999999999900"},
{"-0.000000000000000001", "0.9999999999999999990"},
{"-0.0000000000000000001", "0.9999999999999999999"},
{"0", "1"},
{"0.0000000000000000001", "1.000000000000000000"},
{"0.000000000000000001", "1.000000000000000001"},
{"0.00000000000000001", "1.000000000000000010"},
{"0.0000000000000001", "1.000000000000000100"},
{"0.000000000000001", "1.000000000000001000"},
{"0.00000000000001", "1.000000000000010000"},
{"0.0000000000001", "1.000000000000100000"},
{"0.000000000001", "1.000000000001000000"},
{"0.00000000001", "1.000000000010000000"},
{"0.0000000001", "1.000000000100000000"},
{"0.000000001", "1.000000001000000001"},
{"0.00000001", "1.000000010000000050"},
{"0.0000001", "1.000000100000005000"},
{"0.000001", "1.000001000000500000"},
{"0.00001", "1.000010000050000167"},
{"0.0001", "1.000100005000166671"},
{"0.001", "1.001000500166708342"},
{"0.01", "1.010050167084168058"},
{"0.1", "1.105170918075647625"},
// Closer and closer to one
{"0.9", "2.459603111156949664"},
{"0.99", "2.691234472349262289"},
{"0.999", "2.715564905318566687"},
{"0.9999", "2.718010013867155437"},
{"0.99999", "2.718254645776674283"},
{"0.999999", "2.718279110178575917"},
{"0.9999999", "2.718281556630875981"},
{"0.99999999", "2.718281801276227087"},
{"0.999999999", "2.718281825740763408"},
{"0.9999999999", "2.718281828187217053"},
{"0.99999999999", "2.718281828431862417"},
{"0.999999999999", "2.718281828456326954"},
{"0.9999999999999", "2.718281828458773407"},
{"0.99999999999999", "2.718281828459018053"},
{"0.999999999999999", "2.718281828459042517"},
{"0.9999999999999999", "2.718281828459044964"},
{"0.99999999999999999", "2.718281828459045208"},
{"0.999999999999999999", "2.718281828459045233"},
{"0.9999999999999999999", "2.718281828459045235"},
{"1", E.String()},
{"1.000000000000000001", "2.718281828459045238"},
{"1.00000000000000001", "2.718281828459045263"},
{"1.0000000000000001", "2.718281828459045507"},
{"1.000000000000001", "2.718281828459047954"},
{"1.00000000000001", "2.718281828459072418"},
{"1.0000000000001", "2.718281828459317064"},
{"1.000000000001", "2.718281828461763517"},
{"1.00000000001", "2.718281828486228054"},
{"1.0000000001", "2.718281828730873418"},
{"1.000000001", "2.718281831177327065"},
{"1.00000001", "2.718281855641863656"},
{"1.0000001", "2.718282100287241673"},
{"1.000001", "2.718284546742232836"},
{"1.00001", "2.718309011413244370"},
{"1.0001", "2.718553670233753340"},
{"1.001", "2.721001469881578766"},
{"1.01", "2.745601015016916494"},
{"1.1", "3.004166023946433112"},
// Negated powers of ten
{"-10000", "0.0000000000000000000"},
{"-1000", "0.0000000000000000000"},
{"-100", "0.0000000000000000000"},
{"-10", "0.00004539992976248489"},
{"-1", "0.3678794411714423216"},
{"-0.1", "0.9048374180359595732"},
{"-0.01", "0.9900498337491680536"},
{"-0.001", "0.9990004998333749917"},
{"-0.0001", "0.9999000049998333375"},
{"-0.00001", "0.9999900000499998333"},
{"-0.000001", "0.9999990000004999998"},
{"-0.0000001", "0.9999999000000050000"},
{"-0.00000001", "0.9999999900000000500"},
{"-0.000000001", "0.9999999990000000005"},
{"-0.0000000001", "0.9999999999000000000"},
{"-0.00000000001", "0.9999999999900000000"},
{"-0.000000000001", "0.9999999999990000000"},
{"-0.0000000000001", "0.9999999999999000000"},
{"-0.00000000000001", "0.9999999999999900000"},
{"-0.000000000000001", "0.9999999999999990000"},
{"-0.0000000000000001", "0.9999999999999999000"},
{"-0.00000000000000001", "0.9999999999999999900"},
{"-0.000000000000000001", "0.9999999999999999990"},
{"-0.0000000000000000001", "0.9999999999999999999"},
// Powers of ten
{"0.0000000000000000001", "1.000000000000000000"},
{"0.000000000000000001", "1.000000000000000001"},
{"0.00000000000000001", "1.000000000000000010"},
{"0.0000000000000001", "1.000000000000000100"},
{"0.000000000000001", "1.000000000000001000"},
{"0.00000000000001", "1.000000000000010000"},
{"0.0000000000001", "1.000000000000100000"},
{"0.000000000001", "1.000000000001000000"},
{"0.00000000001", "1.000000000010000000"},
{"0.0000000001", "1.000000000100000000"},
{"0.000000001", "1.000000001000000001"},
{"0.00000001", "1.000000010000000050"},
{"0.0000001", "1.000000100000005000"},
{"0.000001", "1.000001000000500000"},
{"0.00001", "1.000010000050000167"},
{"0.0001", "1.000100005000166671"},
{"0.001", "1.001000500166708342"},
{"0.01", "1.010050167084168058"},
{"0.1", "1.105170918075647625"},
{"1", E.String()},
{"10", "22026.46579480671652"},
// Logarithms of powers of ten
{"-50.65687204586900505", "0.0000000000000000000"},
{"-48.35428695287495936", "0.0000000000000000000"},
{"-46.05170185988091368", "0.0000000000000000000"},
{"-43.74911676688686799", "0.0000000000000000001"},
{"-41.44653167389282231", "0.0000000000000000010"},
{"-39.14394658089877663", "0.0000000000000000100"},
{"-36.84136148790473094", "0.0000000000000001000"},
{"-34.53877639491068526", "0.0000000000000010000"},
{"-32.23619130191663958", "0.0000000000000100000"},
{"-29.93360620892259389", "0.0000000000001000000"},
{"-27.63102111592854821", "0.0000000000010000000"},
{"-25.32843602293450252", "0.0000000000100000000"},
{"-23.02585092994045684", "0.0000000001000000000"},
{"-20.72326583694641116", "0.0000000010000000000"},
{"-18.42068074395236547", "0.0000000100000000000"},
{"-16.11809565095831979", "0.0000001000000000000"},
{"-13.81551055796427410", "0.0000010000000000000"},
{"-11.51292546497022842", "0.0000100000000000000"},
{"-9.210340371976182736", "0.0001000000000000000"},
{"-6.907755278982137052", "0.0010000000000000000"},
{"-4.605170185988091368", "0.0100000000000000000"},
{"-2.302585092994045684", "0.1000000000000000000"},
{"0", "1"},
{"2.302585092994045684", "10.00000000000000000"},
{"4.605170185988091368", "100.0000000000000000"},
{"6.907755278982137052", "999.9999999999999999"},
{"9.210340371976182736", "9999.999999999999999"},
{"11.51292546497022842", "99999.99999999999999"},
{"13.81551055796427410", "999999.9999999999959"},
{"16.11809565095831979", "10000000.00000000002"},
{"18.42068074395236547", "99999999.99999999979"},
{"20.72326583694641116", "1000000000.000000004"},
{"23.02585092994045684", "9999999999.999999998"},
{"25.32843602293450252", "99999999999.99999958"},
{"27.63102111592854821", "1000000000000.000002"},
{"29.93360620892259389", "9999999999999.999978"},
{"32.23619130191663958", "100000000000000.0004"},
{"34.53877639491068526", "999999999999999.9997"},
{"36.84136148790473094", "9999999999999999.957"},
{"39.14394658089877663", "100000000000000000.2"},
{"41.44653167389282231", "999999999999999997.7"},
{"43.74911676688686799", "9999999999999999937"},
// Negative numbers
{"-101", "0.0000000000000000000"},
{"-100", "0.0000000000000000000"},
{"-99", "0.0000000000000000000"},
{"-50", "0.0000000000000000000"},
{"-45", "0.0000000000000000000"},
{"-44", "0.0000000000000000001"},
{"-43", "0.0000000000000000002"},
// Natural numbers
{"1", E.String()},
{"2", "7.389056098930650227"},
{"3", "20.08553692318766774"},
{"4", "54.59815003314423908"},
{"5", "148.4131591025766034"},
{"6", "403.4287934927351226"},
{"7", "1096.633158428458599"},
{"8", "2980.957987041728275"},
{"9", "8103.083927575384008"},
{"10", "22026.46579480671652"},
{"11", "59874.14171519781846"},
{"12", "162754.7914190039208"},
{"13", "442413.3920089205033"},
{"14", "1202604.284164776778"},
{"15", "3269017.372472110639"},
{"16", "8886110.520507872637"},
{"17", "24154952.75357529821"},
{"18", "65659969.13733051114"},
{"19", "178482300.9631872608"},
{"20", "485165195.4097902780"},
{"21", "1318815734.483214697"},
{"22", "3584912846.131591562"},
{"23", "9744803446.248902600"},
{"24", "26489122129.84347229"},
{"25", "72004899337.38587252"},
{"26", "195729609428.8387643"},
{"27", "532048240601.7986167"},
{"28", "1446257064291.475174"},
{"29", "3931334297144.042074"},
{"30", "10686474581524.46215"},
{"31", "29048849665247.42523"},
{"32", "78962960182680.69516"},
{"33", "214643579785916.0646"},
{"34", "583461742527454.8814"},
{"35", "1586013452313430.728"},
{"36", "4311231547115195.227"},
{"37", "11719142372802611.31"},
{"38", "31855931757113756.22"},
{"39", "86593400423993746.95"},
{"40", "235385266837019985.4"},
{"41", "639843493530054949.2"},
{"42", "1739274941520501047"},
{"43", "4727839468229346561"},
// Captured during fuzzing
{"-2.999999999999999852", "0.0497870683678639503"},
}
for _, tt := range tests {
d := MustParse(tt.d)
got, err := d.Exp()
if err != nil {
t.Errorf("%q.Exp() failed: %v", d, err)
continue
}
want := MustParse(tt.want)
if got != want {
t.Errorf("%q.Exp() = %q, want %q", d, got, want)
}
}
})
t.Run("error", func(t *testing.T) {
tests := map[string]string{
"overflow 1": "49",
"overflow 2": "50",
}
for name, d := range tests {
t.Run(name, func(t *testing.T) {
d := MustParse(d)
_, err := d.Exp()
if err == nil {
t.Errorf("%q.Exp() did not fail", d)
}
})
}
})
}
func TestDecimal_Expm1(t *testing.T) {
t.Run("success", func(t *testing.T) {
tests := []struct {
d, want string
}{
// Zeros
{"0", "0"},
{"0.0", "0"},
{"0.00", "0"},
{"0.000", "0"},
{"0.0000", "0"},
{"0.00000", "0"},
// Ones
{"1", "1.718281828459045235"},
{"1.0", "1.718281828459045235"},
{"1.00", "1.718281828459045235"},
{"1.000", "1.718281828459045235"},
{"1.0000", "1.718281828459045235"},
{"1.00000", "1.718281828459045235"},
// Closer and closer to negative one
{"-0.9", "-0.5934303402594008881"},
{"-0.99", "-0.6284233089779543095"},
{"-0.999", "-0.6317524953863370788"},
{"-0.9999", "-0.6320837690449820135"},
{"-0.99999", "-0.6321168800157519306"},
{"-0.999999", "-0.6321201909489325672"},
{"-0.9999999", "-0.6321205220406117219"},
{"-0.99999999", "-0.6321205551497632483"},
{"-0.999999999", "-0.6321205584606782370"},
{"-0.9999999999", "-0.6321205587917697343"},
{"-0.99999999999", "-0.6321205588248788840"},
{"-0.999999999999", "-0.6321205588281897990"},
{"-0.9999999999999", "-0.6321205588285208905"},
{"-0.99999999999999", "-0.6321205588285539996"},
{"-0.999999999999999", "-0.6321205588285573105"},
{"-0.9999999999999999", "-0.6321205588285576416"},
{"-0.99999999999999999", "-0.6321205588285576747"},
{"-0.999999999999999999", "-0.6321205588285576780"},
{"-1", "-0.6321205588285576784"},
{"-1.000000000000000001", "-0.6321205588285576788"},
{"-1.00000000000000001", "-0.6321205588285576821"},
{"-1.0000000000000001", "-0.6321205588285577152"},
{"-1.000000000000001", "-0.6321205588285580463"},
{"-1.00000000000001", "-0.6321205588285613572"},
{"-1.0000000000001", "-0.6321205588285944663"},
{"-1.000000000001", "-0.6321205588289255578"},
{"-1.00000000001", "-0.6321205588322364728"},
{"-1.0000000001", "-0.6321205588653456225"},
{"-1.000000001", "-0.6321205591964371194"},
{"-1.00000001", "-0.6321205625073520717"},
{"-1.0000001", "-0.6321205956164999562"},
{"-1.000001", "-0.6321209267078149102"},
{"-1.00001", "-0.6321242376045754821"},
{"-1.0001", "-0.6321573449333389285"},
{"-1.001", "-0.6324882543913064500"},
{"-1.01", "-0.6357810204284766802"},
{"-1.1", "-0.6671289163019204467"},
// Closer and closer to zero
{"-0.1", "-0.0951625819640404268"},
{"-0.01", "-0.0099501662508319464"},
{"-0.001", "-0.0009995001666250083"},
{"-0.0001", "-0.0000999950001666625"},
{"-0.00001", "-0.0000099999500001667"},
{"-0.000001", "-0.0000009999995000002"},
{"-0.0000001", "-0.0000000999999950000"},
{"-0.00000001", "-0.0000000099999999500"},
{"-0.000000001", "-0.0000000009999999995"},
{"-0.0000000001", "-0.0000000001000000000"},
{"-0.00000000001", "-0.0000000000100000000"},
{"-0.000000000001", "-0.0000000000010000000"},
{"-0.0000000000001", "-0.0000000000001000000"},
{"-0.00000000000001", "-0.0000000000000100000"},
{"-0.000000000000001", "-0.0000000000000010000"},
{"-0.0000000000000001", "-0.0000000000000001000"},
{"-0.00000000000000001", "-0.0000000000000000100"},
{"-0.000000000000000001", "-0.0000000000000000010"},
{"-0.0000000000000000001", "-0.0000000000000000001"},
{"0", "0"},
{"0.0000000000000000001", "0.0000000000000000001"},
{"0.000000000000000001", "0.0000000000000000010"},
{"0.00000000000000001", "0.0000000000000000100"},
{"0.0000000000000001", "0.0000000000000001000"},
{"0.000000000000001", "0.0000000000000010000"},
{"0.00000000000001", "0.0000000000000100000"},
{"0.0000000000001", "0.0000000000001000000"},
{"0.000000000001", "0.0000000000010000000"},
{"0.00000000001", "0.0000000000100000000"},
{"0.0000000001", "0.0000000001000000000"},
{"0.000000001", "0.0000000010000000005"},
{"0.00000001", "0.0000000100000000500"},
{"0.0000001", "0.0000001000000050000"},
{"0.000001", "0.0000010000005000002"},
{"0.00001", "0.0000100000500001667"},
{"0.0001", "0.0001000050001666708"},
{"0.001", "0.0010005001667083417"},
{"0.01", "0.0100501670841680575"},
{"0.1", "0.1051709180756476248"},
// Closer and closer to one
{"0.9", "1.459603111156949664"},
{"0.99", "1.691234472349262289"},
{"0.999", "1.715564905318566687"},
{"0.9999", "1.718010013867155437"},
{"0.99999", "1.718254645776674283"},
{"0.999999", "1.718279110178575917"},
{"0.9999999", "1.718281556630875981"},
{"0.99999999", "1.718281801276227087"},
{"0.999999999", "1.718281825740763408"},
{"0.9999999999", "1.718281828187217053"},
{"0.99999999999", "1.718281828431862417"},
{"0.999999999999", "1.718281828456326954"},
{"0.9999999999999", "1.718281828458773407"},
{"0.99999999999999", "1.718281828459018053"},
{"0.999999999999999", "1.718281828459042517"},
{"0.9999999999999999", "1.718281828459044964"},
{"0.99999999999999999", "1.718281828459045208"},
{"0.999999999999999999", "1.718281828459045233"},
{"0.9999999999999999999", "1.718281828459045235"},
{"1", "1.718281828459045235"},
{"1.000000000000000001", "1.718281828459045238"},
{"1.00000000000000001", "1.718281828459045263"},
{"1.0000000000000001", "1.718281828459045507"},
{"1.000000000000001", "1.718281828459047954"},
{"1.00000000000001", "1.718281828459072418"},
{"1.0000000000001", "1.718281828459317064"},
{"1.000000000001", "1.718281828461763517"},
{"1.00000000001", "1.718281828486228054"},
{"1.0000000001", "1.718281828730873418"},
{"1.000000001", "1.718281831177327065"},
{"1.00000001", "1.718281855641863656"},
{"1.0000001", "1.718282100287241673"},
{"1.000001", "1.718284546742232836"},
{"1.00001", "1.718309011413244370"},
{"1.0001", "1.718553670233753340"},
{"1.001", "1.721001469881578766"},
{"1.01", "1.745601015016916494"},
{"1.1", "2.004166023946433112"},
// Negated powers of ten
{"-10000", "-1.000000000000000000"},
{"-1000", "-1.000000000000000000"},
{"-100", "-1.000000000000000000"},
{"-10", "-0.9999546000702375151"},
{"-1", "-0.6321205588285576784"},
{"-0.1", "-0.0951625819640404268"},
{"-0.01", "-0.0099501662508319464"},
{"-0.001", "-0.0009995001666250083"},
{"-0.0001", "-0.0000999950001666625"},
{"-0.00001", "-0.0000099999500001667"},
{"-0.000001", "-0.0000009999995000002"},
{"-0.0000001", "-0.0000000999999950000"},
{"-0.00000001", "-0.0000000099999999500"},
{"-0.000000001", "-0.0000000009999999995"},
{"-0.0000000001", "-0.0000000001000000000"},
{"-0.00000000001", "-0.0000000000100000000"},
{"-0.000000000001", "-0.0000000000010000000"},
{"-0.0000000000001", "-0.0000000000001000000"},
{"-0.00000000000001", "-0.0000000000000100000"},
{"-0.000000000000001", "-0.0000000000000010000"},
{"-0.0000000000000001", "-0.0000000000000001000"},
{"-0.00000000000000001", "-0.0000000000000000100"},
{"-0.000000000000000001", "-0.0000000000000000010"},
{"-0.0000000000000000001", "-0.0000000000000000001"},
// Powers of ten
{"0.0000000000000000001", "0.0000000000000000001"},
{"0.000000000000000001", "0.0000000000000000010"},
{"0.00000000000000001", "0.0000000000000000100"},
{"0.0000000000000001", "0.0000000000000001000"},
{"0.000000000000001", "0.0000000000000010000"},
{"0.00000000000001", "0.0000000000000100000"},
{"0.0000000000001", "0.0000000000001000000"},
{"0.000000000001", "0.0000000000010000000"},
{"0.00000000001", "0.0000000000100000000"},
{"0.0000000001", "0.0000000001000000000"},
{"0.000000001", "0.0000000010000000005"},
{"0.00000001", "0.0000000100000000500"},
{"0.0000001", "0.0000001000000050000"},
{"0.000001", "0.0000010000005000002"},
{"0.00001", "0.0000100000500001667"},
{"0.0001", "0.0001000050001666708"},
{"0.001", "0.0010005001667083417"},
{"0.01", "0.0100501670841680575"},
{"0.1", "0.1051709180756476248"},
{"1", "1.718281828459045235"},
{"10", "22025.46579480671652"},
// Negative numbers
{"-101", "-1.000000000000000000"},
{"-100", "-1.000000000000000000"},
{"-99", "-1.000000000000000000"},
{"-50", "-1.000000000000000000"},
{"-45", "-1.000000000000000000"},
{"-44", "-0.9999999999999999999"},
{"-43", "-0.9999999999999999998"},
// Natural numbers
{"1", "1.718281828459045235"},
{"2", "6.389056098930650227"},
{"3", "19.08553692318766774"},
{"4", "53.59815003314423908"},
{"5", "147.4131591025766034"},
{"6", "402.4287934927351226"},
{"7", "1095.633158428458599"},
{"8", "2979.957987041728275"},
{"9", "8102.083927575384008"},
{"10", "22025.46579480671652"},
{"11", "59873.14171519781846"},
{"12", "162753.7914190039208"},
{"13", "442412.3920089205033"},
{"14", "1202603.284164776778"},
{"15", "3269016.372472110639"},
{"16", "8886109.520507872637"},
{"17", "24154951.75357529821"},
{"18", "65659968.13733051114"},
{"19", "178482299.9631872608"},
{"20", "485165194.4097902780"},
{"21", "1318815733.483214697"},
{"22", "3584912845.131591562"},
{"23", "9744803445.248902600"},
{"24", "26489122128.84347229"},
{"25", "72004899336.38587252"},
{"26", "195729609427.8387643"},
{"27", "532048240600.7986167"},
{"28", "1446257064290.475174"},
{"29", "3931334297143.042074"},
{"30", "10686474581523.46215"},
{"31", "29048849665246.42523"},
{"32", "78962960182679.69516"},
{"33", "214643579785915.0646"},
{"34", "583461742527453.8814"},
{"35", "1586013452313429.728"},
{"36", "4311231547115194.227"},
{"37", "11719142372802610.31"},
{"38", "31855931757113755.22"},
{"39", "86593400423993745.95"},
{"40", "235385266837019984.4"},
{"41", "639843493530054948.2"},
{"42", "1739274941520501046"},
{"43", "4727839468229346560"},
}
for _, tt := range tests {
d := MustParse(tt.d)
got, err := d.Expm1()
if err != nil {
t.Errorf("%q.Expm1() failed: %v", d, err)
continue
}
want := MustParse(tt.want)
if got != want {
t.Errorf("%q.Expm1() = %q, want %q", d, got, want)
}
}
})
t.Run("error", func(t *testing.T) {
tests := map[string]string{
"overflow 1": "49",
"overflow 2": "50",
}
for name, d := range tests {
t.Run(name, func(t *testing.T) {
d := MustParse(d)
_, err := d.Expm1()
if err == nil {
t.Errorf("%q.Expm1() did not fail", d)
}
})
}
})
}
func TestDecimal_Log(t *testing.T) {
t.Run("success", func(t *testing.T) {
tests := []struct {
d, want string
}{
// Ones
{"1", "0"},
{"1.0", "0"},
{"1.00", "0"},
{"1.000", "0"},
// Powers of Euler's number
{"0.0000000000000000002", "-43.05596958632692269"},
{"0.0000000000000000006", "-41.95735729765881300"},
{"0.0000000000000000016", "-40.97652804464708676"},
{"0.0000000000000000042", "-40.01144714860349969"},
{"0.0000000000000000115", "-39.00418463852361793"},
{"0.0000000000000000314", "-37.99972378097861463"},
{"0.0000000000000000853", "-37.00035721939518888"},
{"0.0000000000000002320", "-35.99979430222651236"},
{"0.0000000000000006305", "-35.00001851848784806"},
{"0.0000000000000017139", "-34.00000491949429577"},
{"0.0000000000000046589", "-32.99999702613981757"},
{"0.0000000000000126642", "-31.99999727965819527"},
{"0.0000000000000344248", "-30.99999916004414320"},
{"0.0000000000000935762", "-30.00000031726440095"},
{"0.0000000000002543666", "-28.99999986137208992"},
{"0.0000000000006914400", "-28.00000001546630253"},
{"0.0000000000018795288", "-27.00000000879959021"},
{"0.0000000000051090890", "-26.00000000549282360"},
{"0.0000000000138879439", "-24.99999999747723783"},
{"0.0000000000377513454", "-24.00000000113349543"},
{"0.0000000001026187963", "-23.00000000016584587"},
{"0.0000000002789468093", "-21.99999999995301069"},
{"0.0000000007582560428", "-20.99999999998838212"},
{"0.0000000020611536224", "-20.00000000001870692"},
{"0.0000000056027964375", "-19.00000000000665160"},
{"0.0000000152299797447", "-18.00000000000082918"},
{"0.0000000413993771879", "-16.99999999999883251"},
{"0.0000001125351747193", "-15.99999999999963669"},
{"0.0000003059023205018", "-15.00000000000008430"},
{"0.0000008315287191036", "-13.99999999999996138"},
{"0.0000022603294069811", "-12.99999999999997979"},
{"0.0000061442123533282", "-12.00000000000000159"},
{"0.0000167017007902457", "-10.99999999999999756"},
{"0.0000453999297624849", "-9.999999999999998933"},
{"0.0001234098040866795", "-9.000000000000000401"},
{"0.0003354626279025118", "-8.000000000000000116"},
{"0.0009118819655545162", "-7.000000000000000009"},
{"0.0024787521766663584", "-6.000000000000000009"},
{"0.0067379469990854671", "-5.000000000000000000"},
{"0.0183156388887341803", "-4.000000000000000000"},
{"0.0497870683678639430", "-3.000000000000000000"},
{"0.1353352832366126919", "-2.000000000000000000"},
{"0.3678794411714423216", "-1.000000000000000000"},
{"1", "0"},
{E.String(), "0.9999999999999999999"},
{"7.389056098930650227", "2.000000000000000000"},
{"20.08553692318766774", "3.000000000000000000"},
{"54.59815003314423908", "4.000000000000000000"},
{"148.4131591025766034", "5.000000000000000000"},
{"403.4287934927351226", "6.000000000000000000"},
{"1096.633158428458599", "7.000000000000000000"},
{"2980.957987041728275", "8.000000000000000000"},
{"8103.083927575384008", "9.000000000000000000"},
{"22026.46579480671652", "10.00000000000000000"},
{"59874.14171519781846", "11.00000000000000000"},
{"162754.7914190039208", "12.00000000000000000"},
{"442413.3920089205033", "13.00000000000000000"},
{"1202604.284164776778", "14.00000000000000000"},
{"3269017.372472110639", "15.00000000000000000"},
{"8886110.520507872637", "16.00000000000000000"},
{"24154952.75357529821", "17.00000000000000000"},
{"65659969.13733051114", "18.00000000000000000"},
{"178482300.9631872608", "19.00000000000000000"},
{"485165195.4097902780", "20.00000000000000000"},
{"1318815734.483214697", "21.00000000000000000"},
{"3584912846.131591562", "22.00000000000000000"},
{"9744803446.248902600", "23.00000000000000000"},
{"26489122129.84347229", "24.00000000000000000"},
{"72004899337.38587252", "25.00000000000000000"},
{"195729609428.8387643", "26.00000000000000000"},
{"532048240601.7986167", "27.00000000000000000"},
{"1446257064291.475174", "28.00000000000000000"},
{"3931334297144.042074", "29.00000000000000000"},
{"10686474581524.46215", "30.00000000000000000"},
{"29048849665247.42523", "31.00000000000000000"},
{"78962960182680.69516", "32.00000000000000000"},
{"214643579785916.0646", "33.00000000000000000"},
{"583461742527454.8814", "34.00000000000000000"},
{"1586013452313430.728", "35.00000000000000000"},
{"4311231547115195.227", "36.00000000000000000"},
{"11719142372802611.31", "37.00000000000000000"},
{"31855931757113756.22", "38.00000000000000000"},
{"86593400423993746.95", "39.00000000000000000"},
{"235385266837019985.4", "40.00000000000000000"},
{"639843493530054949.2", "41.00000000000000000"},
{"1739274941520501047", "42.00000000000000000"},
{"4727839468229346561", "43.00000000000000000"},
// Closer and closer to Euler's number
{"2.7", "0.9932517730102833902"},
{"2.71", "0.9969486348916095321"},
{"2.718", "0.9998963157289519689"},
{"2.7182", "0.9999698965391098865"},
{"2.71828", "0.9999993273472820032"},
{"2.718281", "0.9999996952269029621"},
{"2.7182818", "0.9999999895305022877"},
{"2.71828182", "0.9999999968880911611"},
{"2.718281828", "0.9999999998311266953"},
{"2.7182818284", "0.9999999999782784718"},
{"2.71828182845", "0.9999999999966724439"},
{"2.718281828459", "0.9999999999999833588"},
{"2.7182818284590", "0.9999999999999833588"},
{"2.71828182845904", "0.9999999999999980740"},
{"2.718281828459045", "0.9999999999999999134"},
{"2.7182818284590452", "0.9999999999999999870"},
{"2.71828182845904523", "0.9999999999999999980"},
{"2.718281828459045234", "0.9999999999999999995"},
{E.String(), "0.9999999999999999999"},
{"2.718281828459045236", "1.000000000000000000"},
{"2.71828182845904524", "1.000000000000000002"},
{"2.7182818284590453", "1.000000000000000024"},
{"2.718281828459046", "1.000000000000000281"},
{"2.71828182845905", "1.000000000000001753"},
{"2.7182818284591", "1.000000000000020147"},
{"2.718281828460", "1.000000000000351238"},
{"2.71828182846", "1.000000000000351238"},
{"2.7182818285", "1.000000000015066416"},
{"2.718281829", "1.000000000199006136"},
{"2.71828183", "1.000000000566885578"},
{"2.7182819", "1.000000026318446113"},
{"2.718282", "1.000000063106388586"},
{"2.71829", "1.000003006137401513"},
{"2.7183", "1.000006684913987575"},
{"2.719", "1.000264165650333661"},
{"2.72", "1.000631880307905950"},
{"2.8", "1.029619417181158240"},
// Closer and closer to one
{"0.9", "-0.1053605156578263012"},
{"0.99", "-0.0100503358535014412"},
{"0.999", "-0.0010005003335835335"},
{"0.9999", "-0.0001000050003333583"},
{"0.99999", "-0.0000100000500003333"},
{"0.999999", "-0.0000010000005000003"},
{"0.9999999", "-0.0000001000000050000"},
{"0.99999999", "-0.0000000100000000500"},
{"0.999999999", "-0.0000000010000000005"},
{"0.9999999999", "-0.0000000001000000000"},
{"0.99999999999", "-0.0000000000100000000"},
{"0.999999999999", "-0.0000000000010000000"},
{"0.9999999999999", "-0.0000000000001000000"},
{"0.99999999999999", "-0.0000000000000100000"},
{"0.999999999999999", "-0.0000000000000010000"},
{"0.9999999999999999", "-0.0000000000000001000"},
{"0.99999999999999999", "-0.0000000000000000100"},
{"0.999999999999999999", "-0.0000000000000000010"},
{"0.9999999999999999999", "-0.0000000000000000001"},
{"1", "0"},
{"1.000000000000000001", "0.0000000000000000010"},
{"1.00000000000000001", "0.0000000000000000100"},
{"1.0000000000000001", "0.0000000000000001000"},
{"1.000000000000001", "0.0000000000000010000"},
{"1.00000000000001", "0.0000000000000100000"},
{"1.0000000000001", "0.0000000000001000000"},
{"1.000000000001", "0.0000000000010000000"},
{"1.00000000001", "0.0000000000100000000"},
{"1.0000000001", "0.0000000001000000000"},
{"1.000000001", "0.0000000009999999995"},
{"1.00000001", "0.0000000099999999500"},
{"1.0000001", "0.0000000999999950000"},
{"1.000001", "0.0000009999995000003"},
{"1.00001", "0.0000099999500003333"},
{"1.0001", "0.0000999950003333083"},
{"1.001", "0.0009995003330835332"},
{"1.01", "0.0099503308531680828"},
{"1.1", "0.0953101798043248600"},
// Closer and closer to zero
{"0.0000000000000000001", "-43.74911676688686800"},
{"0.000000000000000001", "-41.44653167389282231"},
{"0.00000000000000001", "-39.14394658089877663"},
{"0.0000000000000001", "-36.84136148790473094"},
{"0.000000000000001", "-34.53877639491068526"},
{"0.00000000000001", "-32.23619130191663958"},
{"0.0000000000001", "-29.93360620892259389"},
{"0.000000000001", "-27.63102111592854821"},
{"0.00000000001", "-25.32843602293450252"},
{"0.0000000001", "-23.02585092994045684"},
{"0.000000001", "-20.72326583694641116"},
{"0.00000001", "-18.42068074395236547"},
{"0.0000001", "-16.11809565095831979"},
{"0.000001", "-13.81551055796427410"},
{"0.00001", "-11.51292546497022842"},
{"0.0001", "-9.210340371976182736"},
{"0.001", "-6.907755278982137052"},
{"0.01", "-4.605170185988091368"},
{"0.1", "-2.302585092994045684"},
// Natural numbers
{"1", "0"},
{"2", "0.6931471805599453094"},
{"3", "1.098612288668109691"},
{"4", "1.386294361119890619"},
{"5", "1.609437912434100375"},
{"6", "1.791759469228055001"},
{"7", "1.945910149055313305"},
{"8", "2.079441541679835928"},
{"9", "2.197224577336219383"},
{"10", "2.302585092994045684"},
{"11", "2.397895272798370544"},
{"12", "2.484906649788000310"},
{"13", "2.564949357461536736"},
{"14", "2.639057329615258615"},
{"15", "2.708050201102210066"},
{"16", "2.772588722239781238"},
{"17", "2.833213344056216080"},
{"18", "2.890371757896164692"},
{"19", "2.944438979166440460"},
{"20", "2.995732273553990993"},
// Smallest and largest numbers
{"0.0000000000000000001", "-43.74911676688686800"},
{"9999999999999999999", "43.74911676688686800"},
// Captured during fuzzing
{"0.0000000000000097", "-32.26665050940134812"},
{"0.00000000000018", "-29.34581954402047488"},
{"0.00444", "-5.417100902538003665"},
{"562", "6.331501849893691075"},
}
for _, tt := range tests {
d := MustParse(tt.d)
got, err := d.Log()
if err != nil {
t.Errorf("%q.Log() failed: %v", d, err)
continue
}
want := MustParse(tt.want)
if got != want {
t.Errorf("%q.Log() = %q, want %q", d, got, want)
}
}
})
t.Run("error", func(t *testing.T) {
tests := map[string]string{
"negative": "-1",
"zero": "0",
}
for name, d := range tests {
t.Run(name, func(t *testing.T) {
d := MustParse(d)
_, err := d.Log()
if err == nil {
t.Errorf("%q.Log() did not fail", d)
}
})
}
})
}
func TestDecimal_Log1p(t *testing.T) {
t.Run("success", func(t *testing.T) {
tests := []struct {
d, want string
}{
// Zeros
{"0", "0"},
{"0.0", "0"},
{"0.00", "0"},
{"0.000", "0"},
// Ones
{"1", "0.6931471805599453094"},
{"1.0", "0.6931471805599453094"},
{"1.00", "0.6931471805599453094"},
{"1.000", "0.6931471805599453094"},
// Closer and closer to one
{"0.9", "0.6418538861723947760"},
{"0.99", "0.6881346387364010274"},
{"0.999", "0.6926470555182630115"},
{"0.9999", "0.6930971793099036412"},
{"0.99999", "0.6931421805474452678"},
{"0.999999", "0.6931466805598203094"},
{"0.9999999", "0.6931471305599440594"},
{"0.99999999", "0.6931471755599452969"},
{"0.999999999", "0.6931471800599453093"},
{"0.9999999999", "0.6931471805099453094"},
{"0.99999999999", "0.6931471805549453094"},
{"0.999999999999", "0.6931471805594453094"},
{"0.9999999999999", "0.6931471805598953094"},
{"0.99999999999999", "0.6931471805599403094"},
{"0.999999999999999", "0.6931471805599448094"},
{"0.9999999999999999", "0.6931471805599452594"},
{"0.99999999999999999", "0.6931471805599453044"},
{"0.999999999999999999", "0.6931471805599453089"},
{"0.9999999999999999999", "0.6931471805599453094"},
{"1", "0.6931471805599453094"},
{"1.000000000000000001", "0.6931471805599453099"},
{"1.00000000000000001", "0.6931471805599453144"},
{"1.0000000000000001", "0.6931471805599453594"},
{"1.000000000000001", "0.6931471805599458094"},
{"1.00000000000001", "0.6931471805599503094"},
{"1.0000000000001", "0.6931471805599953094"},
{"1.000000000001", "0.6931471805604453094"},
{"1.00000000001", "0.6931471805649453094"},
{"1.0000000001", "0.6931471806099453094"},
{"1.000000001", "0.6931471810599453093"},
{"1.00000001", "0.6931471855599452969"},
{"1.0000001", "0.6931472305599440594"},
{"1.000001", "0.6931476805598203095"},
{"1.00001", "0.6931521805474453511"},
{"1.0001", "0.6931971793099869745"},
{"1.001", "0.6936470556015963573"},
{"1.01", "0.6981347220709843830"},
{"1.1", "0.7419373447293773125"},
// Closer and closer to zero
{"-0.1", "-0.1053605156578263012"},
{"-0.01", "-0.0100503358535014412"},
{"-0.001", "-0.0010005003335835335"},
{"-0.0001", "-0.0001000050003333583"},
{"-0.00001", "-0.0000100000500003333"},
{"-0.000001", "-0.0000010000005000003"},
{"-0.0000001", "-0.0000001000000050000"},
{"-0.00000001", "-0.0000000100000000500"},
{"-0.000000001", "-0.0000000010000000005"},
{"-0.0000000001", "-0.0000000001000000000"},
{"-0.00000000001", "-0.0000000000100000000"},
{"-0.000000000001", "-0.0000000000010000000"},
{"-0.0000000000001", "-0.0000000000001000000"},
{"-0.00000000000001", "-0.0000000000000100000"},
{"-0.000000000000001", "-0.0000000000000010000"},
{"-0.0000000000000001", "-0.0000000000000001000"},
{"-0.00000000000000001", "-0.0000000000000000100"},
{"-0.000000000000000001", "-0.0000000000000000010"},
{"-0.0000000000000000001", "-0.0000000000000000001"},
{"0", "0"},
{"0.0000000000000000001", "0.0000000000000000001"},
{"0.000000000000000001", "0.0000000000000000010"},
{"0.00000000000000001", "0.0000000000000000100"},
{"0.0000000000000001", "0.0000000000000001000"},
{"0.000000000000001", "0.0000000000000010000"},
{"0.00000000000001", "0.0000000000000100000"},
{"0.0000000000001", "0.0000000000001000000"},
{"0.000000000001", "0.0000000000010000000"},
{"0.00000000001", "0.0000000000100000000"},
{"0.0000000001", "0.0000000001000000000"},
{"0.000000001", "0.0000000009999999995"},
{"0.00000001", "0.0000000099999999500"},
{"0.0000001", "0.0000000999999950000"},
{"0.000001", "0.0000009999995000003"},
{"0.00001", "0.0000099999500003333"},
{"0.0001", "0.0000999950003333083"},
{"0.001", "0.0009995003330835332"},
{"0.01", "0.0099503308531680828"},
{"0.1", "0.0953101798043248600"},
// Closer and closer to negative one
{"-0.9999999999999999999", "-43.74911676688686800"},
{"-0.999999999999999999", "-41.44653167389282231"},
{"-0.99999999999999999", "-39.14394658089877663"},
{"-0.9999999999999999", "-36.84136148790473094"},
{"-0.999999999999999", "-34.53877639491068526"},
{"-0.99999999999999", "-32.23619130191663958"},
{"-0.9999999999999", "-29.93360620892259389"},
{"-0.999999999999", "-27.63102111592854821"},
{"-0.99999999999", "-25.32843602293450252"},
{"-0.9999999999", "-23.02585092994045684"},
{"-0.999999999", "-20.72326583694641116"},
{"-0.99999999", "-18.42068074395236547"},
{"-0.9999999", "-16.11809565095831979"},
{"-0.999999", "-13.81551055796427410"},
{"-0.99999", "-11.51292546497022842"},
{"-0.9999", "-9.210340371976182736"},
{"-0.999", "-6.907755278982137052"},
{"-0.99", "-4.605170185988091368"},
{"-0.9", "-2.302585092994045684"},
// Natural numbers
{"0", "0"},
{"1", "0.6931471805599453094"},
{"2", "1.098612288668109691"},
{"3", "1.386294361119890619"},
{"4", "1.609437912434100375"},
{"5", "1.791759469228055001"},
{"6", "1.945910149055313305"},
{"7", "2.079441541679835928"},
{"8", "2.197224577336219383"},
{"9", "2.302585092994045684"},
{"10", "2.397895272798370544"},
{"11", "2.484906649788000310"},
{"12", "2.564949357461536736"},
{"13", "2.639057329615258615"},
{"14", "2.708050201102210066"},
{"15", "2.772588722239781238"},
{"16", "2.833213344056216080"},
{"17", "2.890371757896164692"},
{"18", "2.944438979166440460"},
{"19", "2.995732273553990993"},
{"20", "3.044522437723422997"},
// Smallest and largest numbers
{"0.0000000000000000001", "0.0000000000000000001"},
{"9999999999999999999", "43.74911676688686800"},
}
for _, tt := range tests {
d := MustParse(tt.d)
got, err := d.Log1p()
if err != nil {
t.Errorf("%q.Log1p() failed: %v", d, err)
continue
}
want := MustParse(tt.want)
if got != want {
t.Errorf("%q.Log1p() = %q, want %q", d, got, want)
}
}
})
t.Run("error", func(t *testing.T) {
tests := map[string]string{
"negative": "-1",
}
for name, d := range tests {
t.Run(name, func(t *testing.T) {
d := MustParse(d)
_, err := d.Log1p()
if err == nil {
t.Errorf("%q.Log1p() did not fail", d)
}
})
}
})
}
func TestDecimal_Log2(t *testing.T) {
t.Run("success", func(t *testing.T) {
tests := []struct {
d, want string
}{
// Ones
{"1", "0"},
{"1.0", "0"},
{"1.00", "0"},
{"1.000", "0"},
// Powers of two
{"0.0000000000000000001", "-63.11663380285988461"},
{"0.0000000000000000002", "-62.11663380285988461"},
{"0.0000000000000000004", "-61.11663380285988461"},
{"0.0000000000000000009", "-59.94670880141757225"},
{"0.0000000000000000017", "-59.02917096160954520"},
{"0.0000000000000000035", "-57.98735078591491815"},
{"0.0000000000000000069", "-57.00810934608171556"},
{"0.0000000000000000139", "-55.99769273013637718"},
{"0.0000000000000000278", "-54.99769273013637718"},
{"0.0000000000000000555", "-54.00028984162241630"},
{"0.0000000000000001110", "-53.00028984162241630"},
{"0.0000000000000002220", "-52.00028984162241630"},
{"0.0000000000000004441", "-50.99996494689277185"},
{"0.0000000000000008882", "-49.99996494689277185"},
{"0.0000000000000017764", "-48.99996494689277185"},
{"0.0000000000000035527", "-48.00000555473292341"},
{"0.0000000000000071054", "-47.00000555473292341"},
{"0.0000000000000142109", "-45.99999540266572901"},
{"0.0000000000000284217", "-45.00000047869039635"},
{"0.0000000000000568434", "-44.00000047869039635"},
{"0.0000000000001136868", "-43.00000047869039635"},
{"0.0000000000002273737", "-41.99999984418633623"},
{"0.0000000000004547474", "-40.99999984418633623"},
{"0.0000000000009094947", "-40.00000000281232510"},
{"0.0000000000018189894", "-39.00000000281232510"},
{"0.0000000000036379788", "-38.00000000281232510"},
{"0.0000000000072759576", "-37.00000000281232510"},
{"0.0000000000145519152", "-36.00000000281232510"},
{"0.0000000000291038305", "-34.99999999785526269"},
{"0.0000000000582076609", "-34.00000000033379389"},
{"0.0000000001164153218", "-33.00000000033379389"},
{"0.0000000002328306437", "-31.99999999971416109"},
{"0.0000000004656612873", "-31.00000000002397749"},
{"0.0000000009313225746", "-30.00000000002397749"},
{"0.0000000018626451492", "-29.00000000002397749"},
{"0.0000000037252902985", "-27.99999999998525044"},
{"0.0000000074505805969", "-27.00000000000461396"},
{"0.0000000149011611938", "-26.00000000000461396"},
{"0.0000000298023223877", "-24.99999999999977308"},
{"0.0000000596046447754", "-23.99999999999977308"},
{"0.0000001192092895508", "-22.99999999999977308"},
{"0.0000002384185791016", "-21.99999999999977308"},
{"0.0000004768371582031", "-21.00000000000007564"},
{"0.0000009536743164062", "-20.00000000000007564"},
{"0.0000019073486328125", "-19"},
{"0.000003814697265625", "-18"},
{"0.00000762939453125", "-17"},
{"0.0000152587890625", "-16"},
{"0.000030517578125", "-15"},
{"0.00006103515625", "-14"},
{"0.0001220703125", "-13"},
{"0.000244140625", "-12"},
{"0.00048828125", "-11"},
{"0.0009765625", "-10"},
{"0.001953125", "-9"},
{"0.00390625", "-8"},
{"0.0078125", "-7"},
{"0.015625", "-6"},
{"0.03125", "-5"},
{"0.0625", "-4"},
{"0.125", "-3"},
{"0.25", "-2"},
{"0.5", "-1"},
{"1", "0"},
{"2", "1"},
{"4", "2"},
{"8", "3"},
{"16", "4"},
{"32", "5"},
{"64", "6"},
{"128", "7"},
{"256", "8"},
{"512", "9"},
{"1024", "10"},
{"2048", "11"},
{"4096", "12"},
{"8192", "13"},
{"16384", "14"},
{"32768", "15"},
{"65536", "16"},
{"131072", "17"},
{"262144", "18"},
{"524288", "19"},
{"1048576", "20"},
{"2097152", "21"},
{"4194304", "22"},
{"8388608", "23"},
{"16777216", "24"},
{"33554432", "25"},
{"67108864", "26"},
{"134217728", "27"},
{"268435456", "28"},
{"536870912", "29"},
{"1073741824", "30"},
{"2147483648", "31"},
{"4294967296", "32"},
{"8589934592", "33"},
{"17179869184", "34"},
{"34359738368", "35"},
{"68719476736", "36"},
{"137438953472", "37"},
{"274877906944", "38"},
{"549755813888", "39"},
{"1099511627776", "40"},
{"2199023255552", "41"},
{"4398046511104", "42"},
{"8796093022208", "43"},
{"17592186044416", "44"},
{"35184372088832", "45"},
{"70368744177664", "46"},
{"140737488355328", "47"},
{"281474976710656", "48"},
{"562949953421312", "49"},
{"1125899906842624", "50"},
{"2251799813685248", "51"},
{"4503599627370496", "52"},
{"9007199254740992", "53"},
{"18014398509481984", "54"},
{"36028797018963968", "55"},
{"72057594037927936", "56"},
{"144115188075855872", "57"},
{"288230376151711744", "58"},
{"576460752303423488", "59"},
{"1152921504606846976", "60"},
{"2305843009213693952", "61"},
{"4611686018427387904", "62"},
{"9223372036854775808", "63"},
// Closer and closer to two
{"1.9", "0.9259994185562231459"},
{"1.99", "0.9927684307689241428"},
{"1.999", "0.9992784720825405627"},
{"1.9999", "0.9999278634445266362"},
{"1.99999", "0.9999927865067618071"},
{"1.999999", "0.9999992786522992186"},
{"1.9999999", "0.9999999278652461522"},
{"1.99999999", "0.9999999927865247775"},
{"1.999999999", "0.9999999992786524794"},
{"1.9999999999", "0.9999999999278652480"},
{"1.99999999999", "0.9999999999927865248"},
{"1.999999999999", "0.9999999999992786525"},
{"1.9999999999999", "0.9999999999999278652"},
{"1.99999999999999", "0.9999999999999927865"},
{"1.999999999999999", "0.9999999999999992787"},
{"1.9999999999999999", "0.9999999999999999279"},
{"1.99999999999999999", "0.9999999999999999928"},
{"2", "1"},
{"2.00000000000000001", "1.000000000000000007"},
{"2.0000000000000001", "1.000000000000000072"},
{"2.000000000000001", "1.000000000000000721"},
{"2.00000000000001", "1.000000000000007213"},
{"2.0000000000001", "1.000000000000072135"},
{"2.000000000001", "1.000000000000721348"},
{"2.00000000001", "1.000000000007213475"},
{"2.0000000001", "1.000000000072134752"},
{"2.000000001", "1.000000000721347520"},
{"2.00000001", "1.000000007213475186"},
{"2.0000001", "1.000000072134750241"},
{"2.000001", "1.000000721347340108"},
{"2.00001", "1.000007213457170817"},
{"2.0001", "1.000072132948735757"},
{"2.001", "1.000721167243654131"},
{"2.1", "1.070389327891397941"},
// Closer and closer to one
{"0.9", "-0.1520030934450499850"},
{"0.99", "-0.0144995696951150766"},
{"0.999", "-0.0014434168696687174"},
{"0.9999", "-0.0001442767180450352"},
{"0.99999", "-0.0000144270225441226"},
{"0.999999", "-0.0000014426957622370"},
{"0.9999999", "-0.0000001442695113024"},
{"0.99999999", "-0.0000000144269504810"},
{"0.999999999", "-0.0000000014426950416"},
{"0.9999999999", "-0.0000000001442695041"},
{"0.99999999999", "-0.0000000000144269504"},
{"0.999999999999", "-0.0000000000014426950"},
{"0.9999999999999", "-0.0000000000001442695"},
{"0.99999999999999", "-0.0000000000000144270"},
{"0.999999999999999", "-0.0000000000000014427"},
{"0.9999999999999999", "-0.0000000000000001443"},
{"0.99999999999999999", "-0.0000000000000000144"},
{"0.999999999999999999", "-0.0000000000000000014"},
{"1", "0"},
{"1.000000000000000001", "0.0000000000000000014"},
{"1.00000000000000001", "0.0000000000000000144"},
{"1.0000000000000001", "0.0000000000000001443"},
{"1.000000000000001", "0.0000000000000014427"},
{"1.00000000000001", "0.0000000000000144270"},
{"1.0000000000001", "0.0000000000001442695"},
{"1.000000000001", "0.0000000000014426950"},
{"1.00000000001", "0.0000000000144269504"},
{"1.0000000001", "0.0000000001442695041"},
{"1.000000001", "0.0000000014426950402"},
{"1.00000001", "0.0000000144269503368"},
{"1.0000001", "0.0000001442694968754"},
{"1.000001", "0.0000014426943195419"},
{"1.00001", "0.0000144268782746185"},
{"1.0001", "0.0001442622910945542"},
{"1.001", "0.0014419741739064804"},
{"1.01", "0.0143552929770700414"},
{"1.1", "0.1375035237499349083"},
// Natural numbers
{"1", "0"},
{"2", "1"},
{"3", "1.584962500721156181"},
{"4", "2"},
{"5", "2.321928094887362348"},
{"6", "2.584962500721156181"},
{"7", "2.807354922057604107"},
{"8", "3"},
{"9", "3.169925001442312363"},
{"10", "3.321928094887362348"},
{"11", "3.459431618637297256"},
{"12", "3.584962500721156181"},
{"13", "3.700439718141092160"},
{"14", "3.807354922057604107"},
{"15", "3.906890595608518529"},
{"16", "4"},
{"17", "4.087462841250339408"},
{"18", "4.169925001442312363"},
{"19", "4.247927513443585494"},
{"20", "4.321928094887362348"},
// Smallest and largest numbers
{"0.0000000000000000001", "-63.11663380285988461"},
{"9999999999999999999", "63.11663380285988461"},
// Captured during fuzzing
{"0.00375", "-8.058893689053568514"},
{"9223372036854.775784", "43.06843143067582591"},
}
for _, tt := range tests {
d := MustParse(tt.d)
got, err := d.Log2()
if err != nil {
t.Errorf("%q.Log2() failed: %v", d, err)
continue
}
want := MustParse(tt.want)
if got != want {
t.Errorf("%q,%q, want %q", d, got, want)
}
}
})
t.Run("error", func(t *testing.T) {
tests := map[string]string{
"negative": "-1",
"zero": "0",
}
for name, d := range tests {
t.Run(name, func(t *testing.T) {
d := MustParse(d)
_, err := d.Log2()
if err == nil {
t.Errorf("%q.Log2() did not fail", d)
}
})
}
})
}
func TestDecimal_Log10(t *testing.T) {
t.Run("success", func(t *testing.T) {
tests := []struct {
d, want string
}{
// Ones
{"1", "0"},
{"1.0", "0"},
{"1.00", "0"},
{"1.000", "0"},
// Powers of ten
{"0.0000000000000000001", "-19"},
{"0.000000000000000001", "-18"},
{"0.00000000000000001", "-17"},
{"0.0000000000000001", "-16"},
{"0.000000000000001", "-15"},
{"0.00000000000001", "-14"},
{"0.0000000000001", "-13"},
{"0.000000000001", "-12"},
{"0.00000000001", "-11"},
{"0.0000000001", "-10"},
{"0.000000001", "-9"},
{"0.00000001", "-8"},
{"0.0000001", "-7"},
{"0.000001", "-6"},
{"0.00001", "-5"},
{"0.0001", "-4"},
{"0.001", "-3"},
{"0.01", "-2"},
{"0.1", "-1"},
{"1", "0"},
{"10", "1"},
{"100", "2"},
{"1000", "3"},
{"10000", "4"},
{"100000", "5"},
{"1000000", "6"},
{"10000000", "7"},
{"100000000", "8"},
{"1000000000", "9"},
{"10000000000", "10"},
{"100000000000", "11"},
{"1000000000000", "12"},
{"10000000000000", "13"},
{"100000000000000", "14"},
{"1000000000000000", "15"},
{"10000000000000000", "16"},
{"100000000000000000", "17"},
{"1000000000000000000", "18"},
// Closer and closer to ten
{"9.9", "0.9956351945975499153"},
{"9.99", "0.9995654882259823087"},
{"9.999", "0.9999565683801924896"},
{"9.9999", "0.9999956570334660986"},
{"9.99999", "0.9999995657053009494"},
{"9.999999", "0.9999999565705496382"},
{"9.9999999", "0.9999999956570551593"},
{"9.99999999", "0.9999999995657055179"},
{"9.999999999", "0.9999999999565705518"},
{"9.9999999999", "0.9999999999956570552"},
{"9.99999999999", "0.9999999999995657055"},
{"9.999999999999", "0.9999999999999565706"},
{"9.9999999999999", "0.9999999999999956571"},
{"9.99999999999999", "0.9999999999999995657"},
{"9.999999999999999", "0.9999999999999999566"},
{"9.9999999999999999", "0.9999999999999999957"},
{"9.99999999999999999", "0.9999999999999999996"},
{"9.999999999999999999", "1"},
{"10", "1"},
{"10.00000000000000001", "1"},
{"10.0000000000000001", "1.000000000000000004"},
{"10.000000000000001", "1.000000000000000043"},
{"10.00000000000001", "1.000000000000000434"},
{"10.0000000000001", "1.000000000000004343"},
{"10.000000000001", "1.000000000000043429"},
{"10.00000000001", "1.000000000000434294"},
{"10.0000000001", "1.000000000004342945"},
{"10.000000001", "1.000000000043429448"},
{"10.00000001", "1.000000000434294482"},
{"10.0000001", "1.000000004342944797"},
{"10.000001", "1.000000043429446019"},
{"10.00001", "1.000000434294264756"},
{"10.0001", "1.000004342923104453"},
{"10.001", "1.000043427276862670"},
{"10.01", "1.000434077479318641"},
{"10.1", "1.004321373782642574"},
// Closer and closer to one
{"0.9", "-0.0457574905606751254"},
{"0.99", "-0.0043648054024500847"},
{"0.999", "-0.0004345117740176913"},
{"0.9999", "-0.0000434316198075104"},
{"0.99999", "-0.0000043429665339014"},
{"0.999999", "-0.0000004342946990506"},
{"0.9999999", "-0.0000000434294503618"},
{"0.99999999", "-0.0000000043429448407"},
{"0.999999999", "-0.0000000004342944821"},
{"0.9999999999", "-0.0000000000434294482"},
{"0.99999999999", "-0.0000000000043429448"},
{"0.999999999999", "-0.0000000000004342945"},
{"0.9999999999999", "-0.0000000000000434294"},
{"0.99999999999999", "-0.0000000000000043429"},
{"0.999999999999999", "-0.0000000000000004343"},
{"0.9999999999999999", "-0.0000000000000000434"},
{"0.99999999999999999", "-0.0000000000000000043"},
{"0.999999999999999999", "-0.0000000000000000004"},
{"0.9999999999999999999", "0"},
{"1", "0"},
{"1.000000000000000001", "0.0000000000000000004"},
{"1.00000000000000001", "0.0000000000000000043"},
{"1.0000000000000001", "0.0000000000000000434"},
{"1.000000000000001", "0.0000000000000004343"},
{"1.00000000000001", "0.0000000000000043429"},
{"1.0000000000001", "0.0000000000000434294"},
{"1.000000000001", "0.0000000000004342945"},
{"1.00000000001", "0.0000000000043429448"},
{"1.0000000001", "0.0000000000434294482"},
{"1.000000001", "0.0000000004342944817"},
{"1.00000001", "0.0000000043429447973"},
{"1.0000001", "0.0000000434294460189"},
{"1.000001", "0.0000004342942647562"},
{"1.00001", "0.0000043429231044532"},
{"1.0001", "0.0000434272768626696"},
{"1.001", "0.0004340774793186407"},
{"1.01", "0.0043213737826425743"},
{"1.1", "0.0413926851582250408"},
// Natural numbers
{"1", "0"},
{"2", "0.3010299956639811952"},
{"3", "0.4771212547196624373"},
{"4", "0.6020599913279623904"},
{"5", "0.6989700043360188048"},
{"6", "0.7781512503836436325"},
{"7", "0.8450980400142568307"},
{"8", "0.9030899869919435856"},
{"9", "0.9542425094393248746"},
{"10", "1"},
{"11", "1.041392685158225041"},
{"12", "1.079181246047624828"},
{"13", "1.113943352306836769"},
{"14", "1.146128035678238026"},
{"15", "1.176091259055681242"},
{"16", "1.204119982655924781"},
{"17", "1.230448921378273929"},
{"18", "1.255272505103306070"},
{"19", "1.278753600952828962"},
{"20", "1.301029995663981195"},
// Smallest and largest numbers
{"0.0000000000000000001", "-19"},
{"9999999999999999999", "19"},
// Captured during fuzzing
{"0.00000000373", "-8.428291168191312394"},
{"1.048", "0.0203612826477078465"},
}
for _, tt := range tests {
d := MustParse(tt.d)
got, err := d.Log10()
if err != nil {
t.Errorf("%q.Log10() failed: %v", d, err)
continue
}
want := MustParse(tt.want)
if got != want {
t.Errorf("%q.Log10() = %q, want %q", d, got, want)
}
}
})
t.Run("error", func(t *testing.T) {
tests := map[string]string{
"negative": "-1",
"zero": "0",
}
for name, d := range tests {
t.Run(name, func(t *testing.T) {
d := MustParse(d)
_, err := d.Log10()
if err == nil {
t.Errorf("%q.Log10() did not fail", d)
}
})
}
})
}
func TestDecimal_Abs(t *testing.T) {
tests := []struct {
d, want string
}{
{"1", "1"},
{"-1", "1"},
{"1.00", "1.00"},
{"-1.00", "1.00"},
{"0", "0"},
{"0.0", "0.0"},
{"0.00", "0.00"},
}
for _, tt := range tests {
d := MustParse(tt.d)
got := d.Abs()
want := MustParse(tt.want)
if got != want {
t.Errorf("%q.Abs() = %q, want %q", d, got, want)
}
}
}
func TestDecimal_CopySign(t *testing.T) {
tests := []struct {
d, e, want string
}{
{"10", "1", "10"},
{"10", "0", "10"},
{"10", "-1", "-10"},
{"0", "1", "0"},
{"0", "0", "0"},
{"0", "-1", "0"},
{"-10", "1", "10"},
{"-10", "0", "10"},
{"-10", "-1", "-10"},
}
for _, tt := range tests {
d := MustParse(tt.d)
e := MustParse(tt.e)
got := d.CopySign(e)
want := MustParse(tt.want)
if got != want {
t.Errorf("%q.CopySign(%q) = %q, want %q", d, e, got, want)
}
}
}
func TestDecimal_Neg(t *testing.T) {
tests := []struct {
d, want string
}{
{"1", "-1"},
{"-1", "1"},
{"1.00", "-1.00"},
{"-1.00", "1.00"},
{"0", "0"},
{"0.0", "0.0"},
{"0.00", "0.00"},
}
for _, tt := range tests {
d := MustParse(tt.d)
got := d.Neg()
want := MustParse(tt.want)
if got != want {
t.Errorf("%q.Neg() = %q, want %q", d, got, want)
}
}
}
func TestDecimal_Quo(t *testing.T) {
t.Run("success", func(t *testing.T) {
tests := []struct {
d, e, want string
}{
// Zeros
{"0", "1.000", "0"},
{"0.0", "1.000", "0"},
{"0.00", "1.000", "0"},
{"0.000", "1.000", "0"},
{"0.0000", "1.000", "0.0"},
{"0.00000", "1.000", "0.00"},
{"0.000", "1", "0.000"},
{"0.000", "1.0", "0.00"},
{"0.000", "1.00", "0.0"},
{"0.000", "1.000", "0"},
{"0.000", "1.0000", "0"},
{"0.000", "1.00000", "0"},
// Ones
{"1", "1.000", "1"},
{"1.0", "1.000", "1"},
{"1.00", "1.000", "1"},
{"1.000", "1.000", "1"},
{"1.0000", "1.000", "1.0"},
{"1.00000", "1.000", "1.00"},
{"1.000", "1", "1.000"},
{"1.000", "1.0", "1.00"},
{"1.000", "1.00", "1.0"},
{"1.000", "1.000", "1"},
{"1.000", "1.0000", "1"},
{"1.000", "1.00000", "1"},
// Simple cases
{"1", "1", "1"},
{"2", "1", "2"},
{"1", "2", "0.5"},
{"2", "2", "1"},
{"0", "1", "0"},
{"0", "2", "0"},
{"1.5", "3", "0.5"},
{"3", "3", "1"},
{"9999999999999999999", "1", "9999999999999999999"},
{"9999999999999999999", "9999999999999999999", "1"},
// Signs
{"2.4", "1", "2.4"},
{"2.4", "-1", "-2.4"},
{"-2.4", "1", "-2.4"},
{"-2.4", "-1", "2.4"},
// Scales
{"2.40", "1", "2.40"},
{"2.400", "1", "2.400"},
{"2.4", "2", "1.2"},
{"2.400", "2", "1.200"},
// 1 divided by digits
{"1", "1", "1"},
{"1", "2", "0.5"},
{"1", "3", "0.3333333333333333333"},
{"1", "4", "0.25"},
{"1", "5", "0.2"},
{"1", "6", "0.1666666666666666667"},
{"1", "7", "0.1428571428571428571"},
{"1", "8", "0.125"},
{"1", "9", "0.1111111111111111111"},
// 2 divided by digits
{"2", "1", "2"},
{"2", "2", "1"},
{"2", "3", "0.6666666666666666667"},
{"2", "4", "0.5"},
{"2", "5", "0.4"},
{"2", "6", "0.3333333333333333333"},
{"2", "7", "0.2857142857142857143"},
{"2", "8", "0.25"},
{"2", "9", "0.2222222222222222222"},
// 2 divided by 3
{"0.0000000000000000002", "3", "0.0000000000000000001"},
{"0.0000000000000000002", "3.000000000000000000", "0.0000000000000000001"},
{"2", "3", "0.6666666666666666667"},
{"2.000000000000000000", "3", "0.6666666666666666667"},
{"2", "3.000000000000000000", "0.6666666666666666667"},
{"2.000000000000000000", "3.000000000000000000", "0.6666666666666666667"},
{"0.0000000000000000002", "0.0000000000000000003", "0.6666666666666666667"},
{"2", "0.0000000000000000003", "6666666666666666667"},
{"2.000000000000000000", "0.0000000000000000003", "6666666666666666667"},
// Interest accrual
{"0.0001", "365", "0.0000002739726027397"}, // no error
{"0.0001", "366", "0.0000002732240437158"}, // no error
// Captured during fuzzing
{"9223372036854775807", "-9223372036854775808", "-0.9999999999999999999"},
{"0.000000000000000001", "20", "0.000000000000000000"},
{"105", "0.999999999999999990", "105.0000000000000011"},
{"0.05", "999999999999999954", "0.0000000000000000001"},
{"9.99999999999999998", "185", "0.0540540540540540539"},
{"7", "2.000000000000000002", "3.499999999999999997"},
{"0.000000009", "999999999999999999", "0.000000000"},
{"0.0000000000000000001", "9999999999999999999", "0.0000000000000000000"},
{"9999999999999999999", "2", "5000000000000000000"},
{"9999999999999999999", "5000000000000000000", "2"},
{"1.000000000000000049", "-99.9999999999999924", "-0.0100000000000000013"},
}
for _, tt := range tests {
d := MustParse(tt.d)
e := MustParse(tt.e)
got, err := d.Quo(e)
if err != nil {
t.Errorf("%q.Quo(%q) failed: %v", d, e, err)
continue
}
want := MustParse(tt.want)
if got != want {
t.Errorf("%q.Quo(%q) = %q, want %q", d, e, got, want)
}
}
})
t.Run("error", func(t *testing.T) {
tests := map[string]struct {
d, e string
scale int
}{
"zero 1": {"1", "0", 0},
"overflow 1": {"9999999999999999999", "0.001", 0},
"scale 1": {"1", "1", MaxScale},
"scale 2": {"0", "1", MaxScale + 1},
}
for _, tt := range tests {
d := MustParse(tt.d)
e := MustParse(tt.e)
_, err := d.QuoExact(e, tt.scale)
if err == nil {
t.Errorf("%q.QuoExact(%q, %v) did not fail", d, e, tt.scale)
}
}
})
}
func TestDecimal_Inv(t *testing.T) {
t.Run("success", func(t *testing.T) {
tests := []struct {
d, want string
}{
{"0.1", "10"},
{"1", "1"},
{"10", "0.1"},
{"2", "0.5"},
{"2.0", "0.5"},
{"2.00", "0.5"},
}
for _, tt := range tests {
d := MustParse(tt.d)
got, err := d.Inv()
if err != nil {
t.Errorf("%q.Inv() failed: %v", d, err)
continue
}
want := MustParse(tt.want)
if got != want {
t.Errorf("%q.Inv() = %q, want %q", d, got, want)
}
}
})
t.Run("error", func(t *testing.T) {
tests := map[string]struct {
d string
}{
"zero 1": {"0"},
"overflow 1": {"0.0000000000000000001"},
}
for _, tt := range tests {
d := MustParse(tt.d)
_, err := d.Inv()
if err == nil {
t.Errorf("%q.Inv() did not fail", d)
}
}
})
}
func TestDecimal_QuoRem(t *testing.T) {
t.Run("success", func(t *testing.T) {
tests := []struct {
d, e, wantQuo, wantRem string
}{
// Zeros
{"0", "1.000", "0", "0.000"},
{"0.0", "1.000", "0", "0.000"},
{"0.00", "1.000", "0", "0.000"},
{"0.000", "1.000", "0", "0.000"},
{"0.0000", "1.000", "0", "0.0000"},
{"0.00000", "1.000", "0", "0.00000"},
{"0.000", "1", "0", "0.000"},
{"0.000", "1.0", "0", "0.000"},
{"0.000", "1.00", "0", "0.000"},
{"0.000", "1.000", "0", "0.000"},
{"0.000", "1.0000", "0", "0.0000"},
{"0.000", "1.00000", "0", "0.00000"},
// Ones
{"1", "1.000", "1", "0.000"},
{"1.0", "1.000", "1", "0.000"},
{"1.00", "1.000", "1", "0.000"},
{"1.000", "1.000", "1", "0.000"},
{"1.0000", "1.000", "1", "0.0000"},
{"1.00000", "1.000", "1", "0.00000"},
{"1.000", "1", "1", "0.000"},
{"1.000", "1.0", "1", "0.000"},
{"1.000", "1.00", "1", "0.000"},
{"1.000", "1.000", "1", "0.000"},
{"1.000", "1.0000", "1", "0.0000"},
{"1.000", "1.00000", "1", "0.00000"},
// Signs
{"2.4", "1", "2", "0.4"},
{"2.4", "-1", "-2", "0.4"},
{"-2.4", "1", "-2", "-0.4"},
{"-2.4", "-1", "2", "-0.4"},
// Scales
{"2.40", "1", "2", "0.40"},
{"2.400", "1", "2", "0.400"},
{"2.4", "2", "1", "0.4"},
{"2.400", "2", "1", "0.400"},
// 1 divided by natural numbers
{"1", "1", "1", "0"},
{"1", "2", "0", "1"},
{"1", "3", "0", "1"},
{"1", "4", "0", "1"},
{"1", "5", "0", "1"},
{"1", "6", "0", "1"},
{"1", "7", "0", "1"},
{"1", "8", "0", "1"},
{"1", "9", "0", "1"},
// 2 divided by natural numbers
{"2", "1", "2", "0"},
{"2", "2", "1", "0"},
{"2", "3", "0", "2"},
{"2", "4", "0", "2"},
{"2", "5", "0", "2"},
{"2", "6", "0", "2"},
{"2", "7", "0", "2"},
{"2", "8", "0", "2"},
{"2", "9", "0", "2"},
// Closer and closer to five
{"12345", "4.9", "2519", "1.9"},
{"12345", "4.99", "2473", "4.73"},
{"12345", "4.999", "2469", "2.469"},
{"12345", "4.9999", "2469", "0.2469"},
{"12345", "4.99999", "2469", "0.02469"},
{"12345", "4.999999", "2469", "0.002469"},
{"12345", "4.9999999", "2469", "0.0002469"},
{"12345", "4.99999999", "2469", "0.00002469"},
{"12345", "4.999999999", "2469", "0.000002469"},
{"12345", "4.9999999999", "2469", "0.0000002469"},
{"12345", "4.99999999999", "2469", "0.00000002469"},
{"12345", "4.999999999999", "2469", "0.000000002469"},
{"12345", "4.9999999999999", "2469", "0.0000000002469"},
{"12345", "4.99999999999999", "2469", "0.00000000002469"},
{"12345", "4.999999999999999", "2469", "0.000000000002469"},
{"12345", "4.9999999999999999", "2469", "0.0000000000002469"},
{"12345", "4.99999999999999999", "2469", "0.00000000000002469"},
{"12345", "4.999999999999999999", "2469", "0.000000000000002469"},
{"12345", "5", "2469", "0"},
{"12345", "5.000000000000000001", "2468", "4.999999999999997532"},
{"12345", "5.00000000000000001", "2468", "4.99999999999997532"},
{"12345", "5.0000000000000001", "2468", "4.9999999999997532"},
{"12345", "5.000000000000001", "2468", "4.999999999997532"},
{"12345", "5.00000000000001", "2468", "4.99999999997532"},
{"12345", "5.0000000000001", "2468", "4.9999999997532"},
{"12345", "5.000000000001", "2468", "4.999999997532"},
{"12345", "5.00000000001", "2468", "4.99999997532"},
{"12345", "5.0000000001", "2468", "4.9999997532"},
{"12345", "5.000000001", "2468", "4.999997532"},
{"12345", "5.00000001", "2468", "4.99997532"},
{"12345", "5.0000001", "2468", "4.9997532"},
{"12345", "5.000001", "2468", "4.997532"},
{"12345", "5.00001", "2468", "4.97532"},
{"12345", "5.0001", "2468", "4.7532"},
{"12345", "5.001", "2468", "2.532"},
{"12345", "5.01", "2464", "0.36"},
{"12345", "5.1", "2420", "3.0"},
// Other tests
{"41", "21", "1", "20"},
{"4.2", "3.1000003", "1", "1.0999997"},
{"1.000000000000000000", "0.000000000000000003", "333333333333333333", "0.000000000000000001"},
{"1.000000000000000001", "0.000000000000000003", "333333333333333333", "0.000000000000000002"},
{"3", "0.9999999999999999999", "3", "0.0000000000000000003"},
{"0.9999999999999999999", "3", "0", "0.9999999999999999999"},
}
for _, tt := range tests {
d := MustParse(tt.d)
e := MustParse(tt.e)
gotQuo, gotRem, err := d.QuoRem(e)
if err != nil {
t.Errorf("%q.QuoRem(%q) failed: %v", d, e, err)
continue
}
wantQuo := MustParse(tt.wantQuo)
wantRem := MustParse(tt.wantRem)
if gotQuo != wantQuo || gotRem != wantRem {
t.Errorf("%q.QuoRem(%q) = (%q, %q), want (%q, %q)", d, e, gotQuo, gotRem, wantQuo, wantRem)
}
}
})
t.Run("error", func(t *testing.T) {
tests := map[string]struct {
d, e string
}{
"zero 1": {"1", "0"},
"overflow 1": {"9999999999999999999", "0.0000000000000000001"},
}
for _, tt := range tests {
d := MustParse(tt.d)
e := MustParse(tt.e)
_, _, err := d.QuoRem(e)
if err == nil {
t.Errorf("%q.QuoRem(%q) did not fail", d, e)
}
}
})
}
func TestDecimal_Cmp(t *testing.T) {
tests := []struct {
d, e string
want int
}{
{"-2", "-2", 0},
{"-2", "-1", -1},
{"-2", "0", -1},
{"-2", "1", -1},
{"-2", "2", -1},
{"-1", "-2", 1},
{"-1", "-1", 0},
{"-1", "0", -1},
{"-1", "1", -1},
{"-1", "2", -1},
{"0", "-2", 1},
{"0", "-1", 1},
{"0", "0", 0},
{"0", "1", -1},
{"0", "2", -1},
{"1", "-2", 1},
{"1", "-1", 1},
{"1", "0", 1},
{"1", "1", 0},
{"1", "2", -1},
{"2", "-2", 1},
{"2", "-1", 1},
{"2", "0", 1},
{"2", "1", 1},
{"2", "2", 0},
{"2", "2.0", 0},
{"2", "2.00", 0},
{"2", "2.000", 0},
{"2", "2.0000", 0},
{"2", "2.00000", 0},
{"2", "2.000000", 0},
{"2", "2.0000000", 0},
{"2", "2.00000000", 0},
{"9999999999999999999", "0.9999999999999999999", 1},
{"0.9999999999999999999", "9999999999999999999", -1},
}
for _, tt := range tests {
d := MustParse(tt.d)
e := MustParse(tt.e)
got := d.Cmp(e)
if got != tt.want {
t.Errorf("%q.Cmp(%q) = %v, want %v", d, e, got, tt.want)
}
}
}
func TestDecimal_Max(t *testing.T) {
tests := []struct {
d, e, want string
}{
{"-2", "-2", "-2"},
{"-2", "-1", "-1"},
{"-2", "0", "0"},
{"-2", "1", "1"},
{"-2", "2", "2"},
{"-1", "-2", "-1"},
{"-1", "-1", "-1"},
{"-1", "0", "0"},
{"-1", "1", "1"},
{"-1", "2", "2"},
{"0", "-2", "0"},
{"0", "-1", "0"},
{"0", "0", "0"},
{"0", "1", "1"},
{"0", "2", "2"},
{"1", "-2", "1"},
{"1", "-1", "1"},
{"1", "0", "1"},
{"1", "1", "1"},
{"1", "2", "2"},
{"2", "-2", "2"},
{"2", "-1", "2"},
{"2", "0", "2"},
{"2", "1", "2"},
{"2", "2", "2"},
{"0.000", "0.0", "0.0"},
{"0.0", "0.000", "0.0"},
{"-0.000", "-0.0", "0.0"},
{"-0.0", "-0.000", "0.0"},
{"1.23", "1.2300", "1.23"},
{"1.2300", "1.23", "1.23"},
{"-1.23", "-1.2300", "-1.23"},
{"-1.2300", "-1.23", "-1.23"},
}
for _, tt := range tests {
d := MustParse(tt.d)
e := MustParse(tt.e)
got := d.Max(e)
want := MustParse(tt.want)
if got != want {
t.Errorf("%q.Max(%q) = %q, want %q", d, e, got, want)
}
}
}
func TestDecimal_Min(t *testing.T) {
tests := []struct {
d, e, want string
}{
{"-2", "-2", "-2"},
{"-2", "-1", "-2"},
{"-2", "0", "-2"},
{"-2", "1", "-2"},
{"-2", "2", "-2"},
{"-1", "-2", "-2"},
{"-1", "-1", "-1"},
{"-1", "0", "-1"},
{"-1", "1", "-1"},
{"-1", "2", "-1"},
{"0", "-2", "-2"},
{"0", "-1", "-1"},
{"0", "0", "0"},
{"0", "1", "0"},
{"0", "2", "0"},
{"1", "-2", "-2"},
{"1", "-1", "-1"},
{"1", "0", "0"},
{"1", "1", "1"},
{"1", "2", "1"},
{"2", "-2", "-2"},
{"2", "-1", "-1"},
{"2", "0", "0"},
{"2", "1", "1"},
{"2", "2", "2"},
{"0.000", "0.0", "0.000"},
{"0.0", "0.000", "0.000"},
{"-0.000", "-0.0", "0.000"},
{"-0.0", "-0.000", "0.000"},
{"1.23", "1.2300", "1.2300"},
{"1.2300", "1.23", "1.2300"},
{"-1.23", "-1.2300", "-1.2300"},
{"-1.2300", "-1.23", "-1.2300"},
}
for _, tt := range tests {
d := MustParse(tt.d)
e := MustParse(tt.e)
got := d.Min(e)
want := MustParse(tt.want)
if got != want {
t.Errorf("%q.Min(%q) = %q, want %q", d, e, got, want)
}
}
}
//nolint:revive
func TestDecimal_Clamp(t *testing.T) {
t.Run("success", func(t *testing.T) {
tests := []struct {
d, min, max, want string
}{
{"0", "-2", "-1", "-1"},
{"0", "-1", "1", "0"},
{"0", "1", "2", "1"},
{"0.000", "0.0", "0.000", "0.000"},
{"0.000", "0.000", "0.0", "0.000"},
{"0.0", "0.0", "0.000", "0.0"},
{"0.0", "0.000", "0.0", "0.0"},
{"0.000", "0.000", "1", "0.000"},
{"0.000", "0.0", "1", "0.0"},
{"0.0", "0.000", "1", "0.0"},
{"0.0", "0.0", "1", "0.0"},
{"0.000", "-1", "0.000", "0.000"},
{"0.000", "-1", "0.0", "0.000"},
{"0.0", "-1", "0.000", "0.000"},
{"0.0", "-1", "0.0", "0.0"},
{"1.2300", "1.2300", "2", "1.2300"},
{"1.2300", "1.23", "2", "1.23"},
{"1.23", "1.2300", "2", "1.23"},
{"1.23", "1.23", "2", "1.23"},
{"1.2300", "1", "1.2300", "1.2300"},
{"1.2300", "1", "1.23", "1.2300"},
{"1.23", "1", "1.2300", "1.2300"},
{"1.23", "1", "1.23", "1.23"},
}
for _, tt := range tests {
d := MustParse(tt.d)
min := MustParse(tt.min)
max := MustParse(tt.max)
got, err := d.Clamp(min, max)
if err != nil {
t.Errorf("%q.Clamp(%q, %q) failed: %v", d, min, max, err)
continue
}
want := MustParse(tt.want)
if got != want {
t.Errorf("%q.Clamp(%q, %q) = %q, want %q", d, min, max, got, want)
}
}
})
t.Run("error", func(t *testing.T) {
tests := []struct {
d, min, max string
}{
{"0", "1", "-1"},
}
for _, tt := range tests {
d := MustParse(tt.d)
min := MustParse(tt.min)
max := MustParse(tt.max)
_, err := d.Clamp(min, max)
if err == nil {
t.Errorf("%q.Clamp(%q, %q) did not fail", d, min, max)
}
}
})
}
func TestNullDecimal_Interfaces(t *testing.T) {
var n any = NullDecimal{}
_, ok := n.(driver.Valuer)
if !ok {
t.Errorf("%T does not implement driver.Valuer", n)
}
n = &NullDecimal{}
_, ok = n.(sql.Scanner)
if !ok {
t.Errorf("%T does not implement sql.Scanner", n)
}
}
func TestNullDecimal_Scan(t *testing.T) {
t.Run("[]byte", func(t *testing.T) {
tests := []string{"."}
for _, tt := range tests {
got := NullDecimal{}
err := got.Scan([]byte(tt))
if err == nil {
t.Errorf("Scan(%q) did not fail", tt)
}
}
})
}
/******************************************************
* Fuzzing
******************************************************/
var corpus = []struct {
neg bool
scale int
coef uint64
}{
// zero
{false, 0, 0},
// positive
{false, 0, 1},
{false, 0, 3},
{false, 0, 9999999999999999999},
{false, 19, 3},
{false, 19, 1},
{false, 19, 9999999999999999999},
// negative
{true, 0, 1},
{true, 0, 3},
{true, 0, 9999999999999999999},
{true, 19, 1},
{true, 19, 3},
{true, 19, 9999999999999999999},
}
func FuzzParse(f *testing.F) {
for _, c := range corpus {
for s := range MaxScale + 1 {
d, err := newSafe(c.neg, fint(c.coef), c.scale)
if err != nil {
continue
}
f.Add(d.bytes(), s)
}
}
f.Fuzz(
func(t *testing.T, text []byte, scale int) {
got, err := parseFint(text, scale)
if err != nil {
t.Skip()
return
}
want, err := parseBint(text, scale)
if err != nil {
t.Errorf("parseBint(%q) failed: %v", text, err)
return
}
if got.CmpTotal(want) != 0 {
t.Errorf("parseBint(%q) = %q, whereas parseFint(%q) = %q", text, want, text, got)
}
},
)
}
func FuzzBSON(f *testing.F) {
for _, c := range corpus {
d := newUnsafe(c.neg, fint(c.coef), c.scale)
f.Add(byte(19), d.ieeeDecimal128())
}
f.Fuzz(
func(_ *testing.T, typ byte, data []byte) {
var d Decimal
_ = d.UnmarshalBSONValue(typ, data)
},
)
}
func FuzzDecimal_String_Parse(f *testing.F) {
for _, d := range corpus {
f.Add(d.neg, d.scale, d.coef)
}
f.Fuzz(
func(t *testing.T, neg bool, scale int, coef uint64) {
d, err := newSafe(neg, fint(coef), scale)
if err != nil {
t.Skip()
return
}
s := d.String()
got, err := Parse(s)
if err != nil {
t.Errorf("Parse(%q) failed: %v", s, err)
return
}
want := d
if got.CmpTotal(want) != 0 {
t.Errorf("Parse(%q) = %v, want %v", s, got, want)
return
}
},
)
}
func FuzzDecimal_IEEE_ParseIEEE(f *testing.F) {
for _, d := range corpus {
f.Add(d.neg, d.scale, d.coef)
}
f.Fuzz(
func(t *testing.T, neg bool, scale int, coef uint64) {
d, err := newSafe(neg, fint(coef), scale)
if err != nil {
t.Skip()
return
}
b := d.ieeeDecimal128()
got, err := parseIEEEDecimal128(b)
if err != nil {
t.Logf("%q.ieeeDecimal128() = % x", d, b)
t.Errorf("parseIEEEDecimal128(% x) failed: %v", b, err)
return
}
want := d
if got.CmpTotal(want) != 0 {
t.Logf("%q.ieeeDecimal128() = % x", d, b)
t.Errorf("parseIEEEDecimal128(% x) = %v, want %v", b, got, want)
return
}
},
)
}
func FuzzDecimal_Binary_Text(f *testing.F) {
for _, d := range corpus {
f.Add(d.neg, d.scale, d.coef)
}
f.Fuzz(
func(t *testing.T, neg bool, scale int, coef uint64) {
d, err := newSafe(neg, fint(coef), scale)
if err != nil {
t.Skip()
return
}
b, err := d.MarshalBinary()
if err != nil {
t.Errorf("%q.MarshalBinary() failed: %v", d, err)
return
}
var got Decimal
err = got.UnmarshalText(b)
if err != nil {
t.Logf("%q.MarshalBinary() = % x", d, b)
t.Errorf("UnmarshalText(% x) failed: %v", b, err)
return
}
want := d
if got.CmpTotal(want) != 0 {
t.Logf("%q.MarshalBinary() = % x", d, b)
t.Errorf("UnmarshalText(% x) = %v, want %v", b, got, want)
return
}
},
)
}
func FuzzDecimal_Text_Binary(f *testing.F) {
for _, d := range corpus {
f.Add(d.neg, d.scale, d.coef)
}
f.Fuzz(
func(t *testing.T, neg bool, scale int, coef uint64) {
d, err := newSafe(neg, fint(coef), scale)
if err != nil {
t.Skip()
return
}
b, err := d.MarshalText()
if err != nil {
t.Errorf("%q.MarshalText() failed: %v", d, err)
return
}
var got Decimal
err = got.UnmarshalBinary(b)
if err != nil {
t.Logf("%q.MarshalText() = % x", d, b)
t.Errorf("UnmarshalBinary(% x) failed: %v", b, err)
return
}
want := d
if got.CmpTotal(want) != 0 {
t.Logf("%q.MarshalText() = % x", d, b)
t.Errorf("UnmarshalBinary(% x) = %v, want %v", b, got, want)
return
}
},
)
}
func FuzzDecimal_Int64_NewFromInt64(f *testing.F) {
for _, d := range corpus {
for s := range MaxScale + 1 {
f.Add(d.neg, d.scale, d.coef, s)
}
}
f.Fuzz(
func(t *testing.T, dneg bool, dscale int, dcoef uint64, scale int) {
d, err := newSafe(dneg, fint(dcoef), dscale)
if err != nil {
t.Skip()
return
}
w, f, ok := d.Int64(scale)
if !ok {
t.Skip()
return
}
got, err := NewFromInt64(w, f, scale)
if err != nil {
t.Logf("%q.Int64(%v) = (%v, %v)", d, scale, w, f)
t.Errorf("NewFromInt64(%v, %v, %v) failed: %v", w, f, scale, err)
return
}
want := d.Round(scale)
if got.Cmp(want) != 0 {
t.Logf("%q.Int64(%v) = (%v, %v)", d, scale, w, f)
t.Errorf("NewFromInt64(%v, %v, %v) = %v, want %v", w, f, scale, got, want)
return
}
},
)
}
func FuzzDecimal_Float64_NewFromFloat64(f *testing.F) {
for _, d := range corpus {
f.Add(d.neg, d.scale, d.coef)
}
f.Fuzz(
func(t *testing.T, dneg bool, dscale int, dcoef uint64) {
d, err := newSafe(dneg, fint(dcoef), dscale)
if err != nil || d.Prec() > 17 {
t.Skip()
return
}
f, ok := d.Float64()
if !ok {
t.Errorf("%q.Float64() failed", d)
return
}
got, err := NewFromFloat64(f)
if err != nil {
t.Logf("%q.Float64() = %v", d, f)
t.Errorf("NewFromFloat64(%v) failed: %v", f, err)
return
}
want := d
if got.Cmp(want) != 0 {
t.Errorf("NewFromFloat64(%v) = %v, want %v", f, got, want)
return
}
},
)
}
func FuzzDecimal_Mul(f *testing.F) {
for _, d := range corpus {
for _, e := range corpus {
for s := range MaxScale + 1 {
f.Add(d.neg, d.scale, d.coef, e.neg, e.scale, e.coef, s)
}
}
}
f.Fuzz(
func(t *testing.T, dneg bool, dscale int, dcoef uint64, eneg bool, escale int, ecoef uint64, scale int) {
d, err := newSafe(dneg, fint(dcoef), dscale)
if err != nil {
t.Skip()
return
}
e, err := newSafe(eneg, fint(ecoef), escale)
if err != nil {
t.Skip()
return
}
got, err := d.mulFint(e, scale)
if err != nil {
t.Skip()
return
}
want, err := d.mulBint(e, scale)
if err != nil {
t.Errorf("mulBint(%q, %q, %v) failed: %v", d, e, scale, err)
return
}
if got.CmpTotal(want) != 0 {
t.Errorf("mulBint(%q, %q, %v) = %q, whereas mulFint(%q, %q, %v) = %q", d, e, scale, want, d, e, scale, got)
}
},
)
}
func FuzzDecimal_Mul_Prod(f *testing.F) {
for _, d := range corpus {
for _, e := range corpus {
f.Add(d.neg, d.scale, d.coef, e.neg, e.scale, e.coef)
}
}
f.Fuzz(
func(t *testing.T, dneg bool, dscale int, dcoef uint64, eneg bool, escale int, ecoef uint64) {
d, err := newSafe(dneg, fint(dcoef), dscale)
if err != nil {
t.Skip()
return
}
e, err := newSafe(eneg, fint(ecoef), escale)
if err != nil {
t.Skip()
return
}
got, err := d.Mul(e)
if err != nil {
t.Skip()
return
}
want, err := Prod(d, e)
if err != nil {
t.Errorf("Prod(%q, %q) failed: %v", d, e, err)
return
}
if got.CmpTotal(want) != 0 {
t.Errorf("Prod(%q, %q) = %q, whereas Mul(%q, %q) = %q", d, e, want, d, e, got)
}
},
)
}
func FuzzDecimal_AddMul(f *testing.F) {
for _, d := range corpus {
for _, e := range corpus {
for _, g := range corpus {
for s := range MaxScale + 1 {
f.Add(d.neg, d.scale, d.coef, e.neg, e.scale, e.coef, g.neg, g.scale, g.coef, s)
}
}
}
}
f.Fuzz(
func(t *testing.T, dneg bool, dscale int, dcoef uint64, eneg bool, escale int, ecoef uint64, gneg bool, gscale int, gcoef uint64, scale int) {
d, err := newSafe(dneg, fint(dcoef), dscale)
if err != nil {
t.Skip()
return
}
e, err := newSafe(eneg, fint(ecoef), escale)
if err != nil {
t.Skip()
return
}
g, err := newSafe(gneg, fint(gcoef), gscale)
if err != nil {
t.Skip()
return
}
got, err := d.addMulFint(e, g, scale)
if err != nil {
t.Skip()
return
}
want, err := d.addMulBint(e, g, scale)
if err != nil {
t.Errorf("addMulBint(%q, %q, %q, %v) failed: %v", d, e, g, scale, err)
return
}
if got.CmpTotal(want) != 0 {
t.Errorf("addMulBint(%q, %q, %q, %v) = %q, whereas addMulFint(%q, %q, %q, %v) = %q", d, e, g, scale, want, d, e, g, scale, got)
}
},
)
}
func FuzzDecimal_Add_AddMul(f *testing.F) {
for _, d := range corpus {
for _, e := range corpus {
for s := range MaxScale + 1 {
f.Add(d.neg, d.scale, d.coef, e.neg, e.scale, e.coef, s)
}
}
}
f.Fuzz(
func(t *testing.T, dneg bool, dscale int, dcoef uint64, eneg bool, escale int, ecoef uint64, scale int) {
d, err := newSafe(dneg, fint(dcoef), dscale)
if err != nil {
t.Skip()
return
}
e, err := newSafe(eneg, fint(ecoef), escale)
if err != nil {
t.Skip()
return
}
got, err := d.AddExact(e, scale)
if err != nil {
t.Skip()
return
}
want, err := d.AddMulExact(e, One, scale)
if err != nil {
t.Errorf("AddMulExact(%q, %q, %v) failed: %v", d, e, scale, err)
return
}
if got.CmpTotal(want) != 0 {
t.Errorf("AddMulExact(%q, %q, %q, %v) = %q, whereas AddExact(%q, %q, %v) = %q", d, e, One, scale, want, d, e, scale, got)
return
}
},
)
}
func FuzzDecimal_Mul_AddMul(f *testing.F) {
for _, d := range corpus {
for _, e := range corpus {
for s := range MaxScale + 1 {
f.Add(d.neg, d.scale, d.coef, e.neg, e.scale, e.coef, s)
}
}
}
f.Fuzz(
func(t *testing.T, dneg bool, dscale int, dcoef uint64, eneg bool, escale int, ecoef uint64, scale int) {
d, err := newSafe(dneg, fint(dcoef), dscale)
if err != nil {
t.Skip()
return
}
e, err := newSafe(eneg, fint(ecoef), escale)
if err != nil {
t.Skip()
return
}
got, err := d.MulExact(e, scale)
if err != nil {
t.Skip()
return
}
want, err := Zero.AddMulExact(d, e, scale)
if err != nil {
t.Errorf("AddMulExact(%q, %q, %v) failed: %v", d, e, scale, err)
return
}
if got.CmpTotal(want) != 0 {
t.Errorf("AddMulExact(%q, %q, %q, %v) = %q, whereas MulExact(%q, %q, %v) = %q", Zero, d, e, scale, want, d, e, scale, got)
}
},
)
}
func FuzzDecimal_AddQuo(f *testing.F) {
for _, d := range corpus {
for _, e := range corpus {
for _, g := range corpus {
for s := range MaxScale + 1 {
f.Add(d.neg, d.scale, d.coef, e.neg, e.scale, e.coef, g.neg, g.scale, g.coef, s)
}
}
}
}
f.Fuzz(
func(t *testing.T, dneg bool, dscale int, dcoef uint64, eneg bool, escale int, ecoef uint64, gneg bool, gscale int, gcoef uint64, scale int) {
d, err := newSafe(dneg, fint(dcoef), dscale)
if err != nil {
t.Skip()
return
}
e, err := newSafe(eneg, fint(ecoef), escale)
if err != nil {
t.Skip()
return
}
g, err := newSafe(gneg, fint(gcoef), gscale)
if err != nil {
t.Skip()
return
}
got, err := d.addQuoFint(e, g, scale)
if err != nil {
t.Skip()
return
}
want, err := d.addQuoBint(e, g, scale)
if err != nil {
t.Errorf("addQuoBint(%q, %q, %q, %v) failed: %v", d, e, g, scale, err)
return
}
if got.Cmp(want) != 0 {
t.Errorf("addQuoBint(%q, %q, %q, %v) = %q, whereas addQuoFint(%q, %q, %q, %v) = %q", d, e, g, scale, want, d, e, g, scale, got)
}
},
)
}
func FuzzDecimal_Add_AddQuo(f *testing.F) {
for _, d := range corpus {
for _, e := range corpus {
for s := range MaxScale + 1 {
f.Add(d.neg, d.scale, d.coef, e.neg, e.scale, e.coef, s)
}
}
}
f.Fuzz(
func(t *testing.T, dneg bool, dscale int, dcoef uint64, eneg bool, escale int, ecoef uint64, scale int) {
d, err := newSafe(dneg, fint(dcoef), dscale)
if err != nil {
t.Skip()
return
}
e, err := newSafe(eneg, fint(ecoef), escale)
if err != nil {
t.Skip()
return
}
got, err := d.AddExact(e, scale)
if err != nil {
t.Skip()
return
}
want, err := d.AddQuoExact(e, One, scale)
if err != nil {
t.Errorf("AddQuoExact(%q, %q, %v) failed: %v", d, e, scale, err)
return
}
if got.CmpTotal(want) != 0 {
t.Errorf("AddQuoExact(%q, %q, %q, %v) = %q, whereas AddExact(%q, %q, %v) = %q", d, e, One, scale, want, d, e, scale, got)
return
}
},
)
}
func FuzzDecimal_Quo_AddQuo(f *testing.F) {
for _, d := range corpus {
for _, e := range corpus {
for s := 0; s <= MaxScale; s++ {
f.Add(d.neg, d.scale, d.coef, e.neg, e.scale, e.coef, s)
}
}
}
f.Fuzz(
func(t *testing.T, dneg bool, dscale int, dcoef uint64, eneg bool, escale int, ecoef uint64, scale int) {
d, err := newSafe(dneg, fint(dcoef), dscale)
if err != nil {
t.Skip()
return
}
e, err := newSafe(eneg, fint(ecoef), escale)
if err != nil {
t.Skip()
return
}
got, err := d.QuoExact(e, scale)
if err != nil {
t.Skip()
return
}
want, err := Zero.AddQuoExact(d, e, scale)
if err != nil {
t.Errorf("AddQuoExact(%q, %q, %v) failed: %v", d, e, scale, err)
return
}
if got.CmpTotal(want) != 0 {
t.Errorf("AddQuoExact(%q, %q, %q, %v) = %q, whereas QuoExact(%q, %q, %v) = %q", Zero, d, e, scale, want, d, e, scale, got)
}
},
)
}
func FuzzDecimal_Add(f *testing.F) {
for _, d := range corpus {
for _, e := range corpus {
for s := range MaxScale + 1 {
f.Add(d.neg, d.scale, d.coef, e.neg, e.scale, e.coef, s)
}
}
}
f.Fuzz(
func(t *testing.T, dneg bool, dscale int, dcoef uint64, eneg bool, escale int, ecoef uint64, scale int) {
d, err := newSafe(dneg, fint(dcoef), dscale)
if err != nil {
t.Skip()
return
}
e, err := newSafe(eneg, fint(ecoef), escale)
if err != nil {
t.Skip()
return
}
got, err := d.addFint(e, scale)
if err != nil {
t.Skip()
return
}
want, err := d.addBint(e, scale)
if err != nil {
t.Errorf("addBint(%q, %q, %v) failed: %v", d, e, scale, err)
return
}
if got.Cmp(want) != 0 {
t.Errorf("addBint(%q, %q, %v) = %q, whereas addFint(%q, %q, %v) = %q", d, e, scale, want, d, e, scale, got)
}
},
)
}
func FuzzDecimal_Add_Sum(f *testing.F) {
for _, d := range corpus {
for _, e := range corpus {
f.Add(d.neg, d.scale, d.coef, e.neg, e.scale, e.coef)
}
}
f.Fuzz(
func(t *testing.T, dneg bool, dscale int, dcoef uint64, eneg bool, escale int, ecoef uint64) {
d, err := newSafe(dneg, fint(dcoef), dscale)
if err != nil {
t.Skip()
return
}
e, err := newSafe(eneg, fint(ecoef), escale)
if err != nil {
t.Skip()
return
}
got, err := d.Add(e)
if err != nil {
t.Skip()
return
}
want, err := Sum(d, e)
if err != nil {
t.Errorf("Sum(%q, %q) failed: %v", d, e, err)
return
}
if got.CmpTotal(want) != 0 {
t.Errorf("Sum(%q, %q) = %q, whereas Add(%q, %q) = %q", d, e, want, d, e, got)
}
},
)
}
func FuzzDecimal_Quo(f *testing.F) {
for _, d := range corpus {
for _, e := range corpus {
for s := range MaxScale + 1 {
f.Add(d.neg, d.scale, d.coef, e.neg, e.scale, e.coef, s)
}
}
}
f.Fuzz(
func(t *testing.T, dneg bool, dscale int, dcoef uint64, eneg bool, escale int, ecoef uint64, scale int) {
d, err := newSafe(dneg, fint(dcoef), dscale)
if err != nil {
t.Skip()
return
}
e, err := newSafe(eneg, fint(ecoef), escale)
if err != nil {
t.Skip()
return
}
got, err := d.quoFint(e, scale)
if err != nil {
t.Skip()
return
}
want, err := d.quoBint(e, scale)
if err != nil {
t.Errorf("quoBint(%q, %q, %v) failed: %v", d, e, scale, err)
return
}
if got.Cmp(want) != 0 {
t.Errorf("quoBint(%q, %q, %v) = %q, whereas quoFint(%q, %q, %v) = %q", d, e, scale, want, d, e, scale, got)
}
},
)
}
func FuzzDecimal_QuoRem(f *testing.F) {
for _, d := range corpus {
for _, e := range corpus {
f.Add(d.neg, d.scale, d.coef, e.neg, e.scale, e.coef)
}
}
f.Fuzz(
func(t *testing.T, dneg bool, dscale int, dcoef uint64, eneg bool, escale int, ecoef uint64) {
d, err := newSafe(dneg, fint(dcoef), dscale)
if err != nil {
t.Skip()
return
}
e, err := newSafe(eneg, fint(ecoef), escale)
if err != nil {
t.Skip()
return
}
gotQuo, gotRem, err := d.quoRemFint(e)
if err != nil {
t.Skip()
return
}
if gotQuo.Scale() != 0 {
t.Errorf("quoRemFint(%q, %q) = (%q, _), expected integer quotient", d, e, gotQuo)
}
if gotRem.Scale() != max(d.Scale(), e.Scale()) {
t.Errorf("quoRemFint(%q, %q) = (_, %q), expected remainder with scale %d", d, e, gotRem, max(d.Scale(), e.Scale()))
}
if !gotRem.IsZero() && gotRem.Sign() != d.Sign() {
t.Errorf("quoRemFint(%q, %q) = (_, %q), expected remainder with the same sign as the dividend", d, e, gotRem)
}
wantQuo, wantRem, err := d.quoRemBint(e)
if err != nil {
t.Errorf("quoRemBint(%q, %q) failed: %v", d, e, err)
return
}
if gotQuo.CmpTotal(wantQuo) != 0 || gotRem.CmpTotal(wantRem) != 0 {
t.Errorf("quoRemBint(%q, %q) = (%q, %q), whereas quoRemFint(%q, %q) = (%q, %q)", d, e, wantQuo, wantRem, d, e, gotQuo, gotRem)
}
},
)
}
func FuzzDecimal_Cmp(f *testing.F) {
for _, d := range corpus {
for _, e := range corpus {
f.Add(d.neg, d.scale, d.coef, e.neg, e.scale, e.coef)
}
}
f.Fuzz(
func(t *testing.T, dneg bool, dscale int, dcoef uint64, eneg bool, escale int, ecoef uint64) {
d, err := newSafe(dneg, fint(dcoef), dscale)
if err != nil {
t.Skip()
return
}
e, err := newSafe(eneg, fint(ecoef), escale)
if err != nil {
t.Skip()
return
}
got, err := d.cmpFint(e)
if err != nil {
t.Skip()
return
}
want := d.cmpBint(e)
if got != want {
t.Errorf("cmpBint(%q, %q) = %v, whereas cmpFint(%q, %q) = %v", d, e, want, d, e, got)
return
}
},
)
}
func FuzzDecimal_Sqrt_PowInt(f *testing.F) {
for _, d := range corpus {
f.Add(d.neg, d.scale, d.coef)
}
f.Fuzz(
func(t *testing.T, neg bool, scale int, coef uint64) {
d, err := newSafe(neg, fint(coef), scale)
if err != nil {
t.Skip()
return
}
got, err := d.Sqrt()
if err != nil {
t.Skip()
return
}
got, err = got.PowInt(2)
if err != nil {
t.Skip()
return
}
want := d
if cmp, err := cmpULP(got, want, 3); err != nil {
t.Errorf("cmpULP(%q, %q) failed: %v", got, want, err)
} else if cmp != 0 {
t.Errorf("%q.Sqrt().PowInt(2) = %q, want %q", want, got, want)
return
}
},
)
}
func FuzzDecimal_Pow_Sqrt(f *testing.F) {
for _, d := range corpus {
f.Add(d.neg, d.scale, d.coef)
}
f.Fuzz(
func(t *testing.T, neg bool, scale int, coef uint64) {
d, err := newSafe(neg, fint(coef), scale)
if err != nil {
t.Skip()
return
}
half := MustNew(5, 1)
got, err := d.Pow(half)
if err != nil {
t.Skip()
return
}
want, err := d.Sqrt()
if err != nil {
t.Errorf("%q.Sqrt() failed: %v", d, err)
return
}
if got.Cmp(want) != 0 {
t.Errorf("%q.Pow(%v) = %q, whereas %q.Sqrt() = %q", d, half, got, d, want)
return
}
},
)
}
func FuzzDecimal_Pow_PowInt(f *testing.F) {
for _, d := range corpus {
for _, e := range []int{-10, -5, -1, 1, 5, 10} {
f.Add(d.neg, d.scale, d.coef, e)
}
}
f.Fuzz(
func(t *testing.T, neg bool, scale int, coef uint64, power int) {
d, err := newSafe(neg, fint(coef), scale)
if err != nil {
t.Skip()
return
}
e, err := New(int64(power), 0)
if err != nil {
t.Skip()
return
}
got, err := d.Pow(e)
if err != nil {
t.Skip()
return
}
want, err := d.PowInt(power)
if err != nil {
t.Errorf("%q.PowInt(%v) failed: %v", d, power, err)
return
}
if got.CmpTotal(want) != 0 {
t.Errorf("%q.Pow(%v) = %q, whereas %q.PowInt(%v) = %q", d, power, got, d, power, want)
return
}
},
)
}
func FuzzDecimal_Pow_Exp(f *testing.F) {
for _, d := range corpus {
f.Add(d.neg, d.scale, d.coef)
}
f.Fuzz(
func(t *testing.T, neg bool, scale int, coef uint64) {
d, err := newSafe(neg, fint(coef), scale)
if err != nil {
t.Skip()
return
}
got, err := E.Pow(d)
if err != nil {
t.Skip()
return
}
want, err := d.Exp()
if err != nil {
t.Errorf("%q.Exp() failed: %v", d, err)
return
}
if cmp, err := cmpULP(got, want, 55); err != nil {
t.Errorf("cmpULP(%q, %q) failed: %v", got, want, err)
} else if cmp != 0 {
t.Errorf("%v.Pow(%q) = %q, whereas %q.Exp() = %q", E, d, got, d, want)
return
}
},
)
}
func FuzzDecimal_Log_Exp(f *testing.F) {
for _, d := range corpus {
f.Add(d.neg, d.scale, d.coef)
}
f.Fuzz(
func(t *testing.T, neg bool, scale int, coef uint64) {
d, err := newSafe(neg, fint(coef), scale)
if err != nil {
t.Skip()
return
}
got, err := d.Log()
if err != nil {
t.Skip()
return
}
got, err = got.Exp()
if err != nil {
t.Skip()
return
}
want := d
if cmp, err := cmpULP(got, want, 70); err != nil {
t.Errorf("cmpULP(%q, %q) failed: %v", got, want, err)
return
} else if cmp != 0 {
t.Errorf("%q.Log().Exp() = %q, want %q", want, got, want)
return
}
},
)
}
func FuzzDecimal_Expm1_Exp(f *testing.F) {
for _, d := range corpus {
f.Add(d.neg, d.scale, d.coef)
}
f.Fuzz(
func(t *testing.T, neg bool, scale int, coef uint64) {
d, err := newSafe(neg, fint(coef), scale)
if err != nil {
t.Skip()
return
}
got, err := d.Exp()
if err != nil {
t.Skip()
return
}
got, err = got.Sub(One)
if err != nil {
t.Skip()
return
}
want, err := d.Expm1()
if err != nil {
t.Skip()
return
}
if cmp, err := cmpULP(got, want, 5); err != nil {
t.Errorf("cmpULP(%q, %q) failed: %v", got, want, err)
return
} else if cmp != 0 {
t.Errorf("%q.Exp().Sub(1) = %q, whereas %q.Expm1() = %q", d, got, d, want)
return
}
},
)
}
func FuzzDecimal_Log1p_Log(f *testing.F) {
for _, d := range corpus {
f.Add(d.neg, d.scale, d.coef)
}
f.Fuzz(
func(t *testing.T, neg bool, scale int, coef uint64) {
d, err := newSafe(neg, fint(coef), scale)
if err != nil {
t.Skip()
return
}
got, err := d.Add(One)
if err != nil {
t.Skip()
return
}
got, err = got.Log()
if err != nil {
t.Skip()
return
}
want, err := d.Log1p()
if err != nil {
t.Skip()
return
}
if cmp, err := cmpULP(got, want, 5); err != nil {
t.Errorf("cmpULP(%q, %q) failed: %v", got, want, err)
return
} else if cmp != 0 {
t.Errorf("%q.Add(1).Log() = %q, whereas %q.Log1p() = %q", d, got, d, want)
return
}
},
)
}
// cmpULP compares decimals and returns 0 if they are within specified number of ULPs.
func cmpULP(d, e Decimal, ulps int) (int, error) {
n, err := New(int64(ulps), 0)
if err != nil {
return 0, err
}
dist, err := d.SubAbs(e)
if err != nil {
return 0, err
}
ulp := d.ULP().Min(e.ULP())
tlr, err := ulp.Mul(n)
if err != nil {
return 0, err
}
if dist.Cmp(tlr) <= 0 {
return 0, nil
}
return d.Cmp(e), nil
}
func FuzzDecimal_Sub_Cmp(f *testing.F) {
for _, d := range corpus {
for _, e := range corpus {
f.Add(d.neg, d.scale, d.coef, e.neg, e.scale, e.coef)
}
}
f.Fuzz(
func(t *testing.T, dneg bool, dscale int, dcoef uint64, eneg bool, escale int, ecoef uint64) {
d, err := newSafe(dneg, fint(dcoef), dscale)
if err != nil {
t.Skip()
return
}
e, err := newSafe(eneg, fint(ecoef), escale)
if err != nil {
t.Skip()
return
}
f, err := d.Sub(e)
if err != nil {
t.Skip()
return
}
got := f.Sign()
want := d.Cmp(e)
if want != got {
t.Errorf("%q.Cmp(%q) = %v, whereas %q.Sub(%q).Sign() = %v", d, e, want, d, e, got)
return
}
},
)
}
func FuzzDecimal_New(f *testing.F) {
for _, d := range corpus {
f.Add(d.neg, d.scale, d.coef)
}
toBint := func(coef uint64) *bint {
b := new(big.Int)
b.SetUint64(coef)
return (*bint)(b)
}
f.Fuzz(
func(t *testing.T, neg bool, scale int, coef uint64) {
got, err := newFromFint(neg, fint(coef), scale, 0)
if err != nil {
t.Skip()
return
}
want, err := newFromBint(neg, toBint(coef), scale, 0)
if err != nil {
t.Errorf("newDecimalFromBint(%v, %v, %v, 0) failed: %v", neg, coef, scale, err)
return
}
if got.CmpTotal(want) != 0 {
t.Errorf("newDecimalFromFint(%v, %v, %v, 0) = %q, whereas newDecimalFromBint(%v, %v, %v, 0) = %q", neg, coef, scale, got, neg, coef, scale, want)
}
},
)
}
func FuzzDecimal_Pad(f *testing.F) {
for _, d := range corpus {
for s := range MaxScale + 1 {
f.Add(d.neg, d.scale, d.coef, s)
}
}
f.Fuzz(
func(t *testing.T, dneg bool, dscale int, dcoef uint64, scale int) {
d, err := newSafe(dneg, fint(dcoef), dscale)
if err != nil {
t.Skip()
return
}
got := d.Pad(scale)
want := d
if got.Cmp(want) != 0 {
t.Errorf("%q.Pad(%v) = %q", d, scale, got)
return
}
if got.Scale() > MaxScale {
t.Errorf("%q.Pad(%v).Scale() = %v", d, scale, got.Scale())
return
}
},
)
}
func FuzzDecimal_Trim(f *testing.F) {
for _, d := range corpus {
for s := range MaxScale + 1 {
f.Add(d.neg, d.scale, d.coef, s)
}
}
f.Fuzz(
func(t *testing.T, dneg bool, dscale int, dcoef uint64, scale int) {
d, err := newSafe(dneg, fint(dcoef), dscale)
if err != nil {
t.Skip()
return
}
got := d.Trim(scale)
want := d
if got.Cmp(want) != 0 {
t.Errorf("%q.Trim(%v) = %q", d, scale, got)
return
}
if got.Scale() < MinScale {
t.Errorf("%q.Trim(%v).Scale() = %v", d, scale, got.Scale())
return
}
},
)
}
================================================
FILE: doc.go
================================================
/*
Package decimal implements decimal floating-point numbers with correct rounding.
It is specifically designed for transactional financial systems and adheres
to the principles set by [ANSI X3.274-1996].
# Internal Representation
Decimal is a struct with three fields:
- Sign:
A boolean indicating whether the decimal is negative.
- Coefficient:
An unsigned integer representing the numeric value of the decimal without
the decimal point.
- Scale:
A non-negative integer indicating the position of the decimal point
within the coefficient.
For example, a decimal with a coefficient of 12345 and a scale of 2 represents
the value 123.45.
Conceptually, the scale can be understood as the inverse of the exponent in
scientific notation.
For example, a scale of 2 corresponds to an exponent of -2.
The range of allowed values for the scale is from 0 to 19.
The numerical value of a decimal is calculated as follows:
- -Coefficient / 10^Scale if Sign is true.
- Coefficient / 10^Scale if Sign is false.
This approach allows the same numeric value to have multiple representations,
for example, 1, 1.0, and 1.00, which represent the same value but have different
scales and coefficients.
# Constraints Overview
The range of a decimal is determined by its scale.
Here are the ranges for frequently used scales:
| Example | Scale | Minimum | Maximum |
| ------------ | ----- | ------------------------------------ | ----------------------------------- |
| Japanese Yen | 0 | -9,999,999,999,999,999,999 | 9,999,999,999,999,999,999 |
| US Dollar | 2 | -99,999,999,999,999,999.99 | 99,999,999,999,999,999.99 |
| Omani Rial | 3 | -9,999,999,999,999,999.999 | 9,999,999,999,999,999.999 |
| Bitcoin | 8 | -99,999,999,999.99999999 | 99,999,999,999.99999999 |
| Ethereum | 9 | -9,999,999,999.999999999 | 9,999,999,999.999999999 |
[Subnormal numbers] are not supported to ensure peak performance.
Consequently, decimals between -0.00000000000000000005 and 0.00000000000000000005
inclusive, are rounded to 0.
Special values such as [NaN], [Infinity], or [negative zeros] are not supported.
This ensures that arithmetic operations always produce either valid decimals
or errors.
# Arithmetic Operations
Each arithmetic operation occurs in two steps:
1. The operation is initially performed using uint64 arithmetic.
If no overflow occurs, the exact result is immediately returned.
If overflow occurs, the operation proceeds to step 2.
2. The operation is repeated with at least double precision using [big.Int] arithmetic.
The result is then rounded to 19 digits.
If no significant digits are lost during rounding, the inexact result is returned.
If any significant digit is lost, an overflow error is returned.
Step 1 improves performance by avoiding the performance impact associated with [big.Int] arithmetic.
It is expected that, in transactional financial systems, most arithmetic operations
will compute an exact result during step 1.
The following rules determine the significance of digits during step 2:
- For [Decimal.Add], [Decimal.Sub], [Decimal.Mul], [Decimal.Quo], [Decimal.QuoRem], [Decimal.Inv],
[Decimal.AddMul], [Decimal.AddQuo], [Decimal.SubMul], [Decimal.SubQuo], [Decimal.SubAbs],
[Decimal.PowInt], [Sum], [Mean], [Prod]:
All digits in the integer part are significant, while digits in the
fractional part are considered insignificant.
- For [Decimal.AddExact], [Decimal.SubExact], [Decimal.MulExact], [Decimal.QuoExact],
[Decimal.AddMulExact], [Decimal.AddQuoExact], [Decimal.SubMulExact], [Decimal.SubQuoExact]:
All digits in the integer part are significant. The significance of digits
in the fractional part is determined by the scale argument, which is typically
equal to the scale of the currency.
# Transcendental Functions
All transcendental functions are always computed with at least double precision using [big.Int] arithmetic.
The result is then rounded to 19 digits.
If no significant digits are lost during rounding, the inexact result is returned.
If any significant digit is lost, an overflow error is returned.
The following rules determine the significance of digits:
- For [Decimal.Sqrt], [Decimal.Pow], [Decimal.Exp], [Decimal.Log],
[Decimal.Log2], [Decimal.Log10], [Decimal.Expm1], [Decimal.Log1p]:
All digits in the integer part are significant, while digits in the
fractional part are considered insignificant.
# Rounding Methods
For all operations, the result is the one that would be obtained by computing
the exact result with infinite precision and then rounding it to 19 digits
using half-to-even rounding.
This method ensures that the result is as close as possible to the true
mathematical value and that rounding errors are evenly distributed between
rounding up and down.
In addition to implicit rounding, the package provides several methods for
explicit rounding:
- Half-to-even rounding:
[Decimal.Round], [Decimal.Quantize], [Decimal.Rescale].
- Rounding towards positive infinity:
[Decimal.Ceil].
- Rounding towards negative infinity:
[Decimal.Floor].
- Rounding towards zero:
[Decimal.Trunc].
See the documentation for each method for more details.
# Error Handling
All methods are panic-free and pure.
Errors are returned in the following cases:
- Division by Zero:
Unlike Go's standard library, [Decimal.Quo], [Decimal.QuoRem], [Decimal.Inv],
[Decimal.AddQuo], [Decimal.SubQuo], do not panic when dividing by 0.
Instead, they return an error.
- Invalid Operation:
[Sum], [Mean] and [Prod] return an error if no arguments are provided.
[Decimal.PowInt] returns an error if 0 is raised to a negative power.
[Decimal.Sqrt] returns an error if the square root of a negative decimal is requested.
[Decimal.Log], [Decimal.Log2], [Decimal.Log10] return an error when calculating a logarithm of a non-positive decimal.
[Decimal.Log1p] returns an error when calculating a logarithm of a decimal equal to or less than negative one.
[Decimal.Pow] returns an error if 0 is raised to a negative powere or a negative decimal is raised to a fractional power.
- Overflow:
Unlike standard integers, decimals do not "wrap around" when exceeding their maximum value.
For out-of-range values, methods return an error.
Errors are not returned in the following cases:
- Underflow:
Methods do not return an error for decimal underflow.
If the result is a decimal between -0.00000000000000000005 and
0.00000000000000000005 inclusive, it will be rounded to 0.
# Data Conversion
A. JSON
The package integrates with standard [encoding/json] through
the implementation of [json.Marshaler] and [json.Unmarshaler] interfaces.
Below is an example structure:
type Object struct {
Number decimal.Decimal `json:"some_number"`
// Other fields...
}
This package marshals decimals as quoted strings, ensuring the preservation of
the exact numerical value.
Below is an example OpenAPI schema:
Decimal:
type: string
format: decimal
pattern: '^(\-|\+)?((\d+(\.\d*)?)|(\.\d+))$'
B. BSON
The package integrates with [mongo-driver/bson] via the implementation of
[v2/bson.ValueMarshaler] and [v2/bson.ValueUnmarshaler] interfaces.
Below is an example structure:
type Record struct {
Number decimal.Decimal `bson:"some_number"`
// Other fields...
}
This package marshals decimals as [Decimal128], ensuring the preservation of
the exact numerical value.
C. XML
The package integrates with standard [encoding/xml] via the implementation of
[encoding.TextMarshaller] and [encoding.TextUnmarshaler] interfaces.
Below is an example structure:
type Entity struct {
Number decimal.Decimal `xml:"SomeNumber"`
// Other fields...
}
"xs:decimal" type can represent decimals in XML schema.
It is possible to impose restrictions on the length of the decimals
using the following type:
D. Protocol Buffers
Protocol Buffers provide two formats to represent decimals.
The first format represents decimals as [numerical strings].
The main advantage of this format is that it preserves trailing zeros.
To convert between this format and decimals, use [Parse] and [Decimal.String].
Below is an example of a proto definition:
message Decimal {
string value = 1;
}
The second format represents decimals as [a pair of integers]:
one for the integer part and another for the fractional part.
This format does not preserve trailing zeros and rounds decimals
with more than nine digits in the fractional part.
For conversion between this format and decimals, use [NewFromInt64] and
[Decimal.Int64] with a scale argument of "9".
Below is an example of a proto definition:
message Decimal {
int64 units = 1;
int32 nanos = 2;
}
E. SQL
The package integrates with the standard [database/sql] via the implementation
of [sql.Scanner] and [driver.Valuer] interfaces.
To ensure accurate preservation of decimal scales, it is essential to choose
appropriate column types:
| Database | Type |
| ---------- | ----------------------------- |
| PostgreSQL | DECIMAL |
| SQLite | TEXT |
| MySQL | DECIMAL(19, d) or VARCHAR(22) |
Below are the reasons for these preferences:
- PostgreSQL:
Always use DECIMAL without precision or scale specifications, that is,
avoid DECIMAL(p) or DECIMAL(p, s).
DECIMAL accurately preserves the scale of decimals.
- SQLite:
Prefer TEXT, since DECIMAL is just an alias for binary floating-point numbers.
TEXT accurately preserves the scale of decimals.
- MySQL:
Use DECIMAL(19, d), as DECIMAL is merely an alias for DECIMAL(10, 0).
The downside of this format is that MySQL automatically rescales all decimals:
it rounds values with more than d digits in the fractional part (using half
away from zero) and pads with trailing zeros those with fewer than d digits
in the fractional part.
To prevent automatic rescaling, consider using VARCHAR(22), which accurately
preserves the scale of decimals.
# Mathematical Context
Unlike many other decimal libraries, this package does not provide
an explicit mathematical [context].
Instead, the [context] is implicit and can be approximately equated to
the following settings:
| Attribute | Value |
| ----------------------- | ----------------------------------------------- |
| Precision | 19 |
| Maximum Exponent (Emax) | 18 |
| Minimum Exponent (Emin) | -19 |
| Tiny Exponent (Etiny) | -19 |
| Rounding Method | Half To Even |
| Enabled Traps | Division by Zero, Invalid Operation, Overflow |
| Disabled Traps | Inexact, Clamped, Rounded, Subnormal, Underflow |
The equality of Etiny and Emin implies that this package does not support
subnormal numbers.
[Infinity]: https://en.wikipedia.org/wiki/Infinity#Computing
[Subnormal numbers]: https://en.wikipedia.org/wiki/Subnormal_number
[NaN]: https://en.wikipedia.org/wiki/NaN
[ANSI X3.274-1996]: https://speleotrove.com/decimal/dax3274.html
[big.Int]: https://pkg.go.dev/math/big#Int
[sql.Scanner]: https://pkg.go.dev/database/sql#Scanner
[negative zeros]: https://en.wikipedia.org/wiki/Signed_zero
[context]: https://speleotrove.com/decimal/damodel.html
[numerical strings]: https://github.com/googleapis/googleapis/blob/master/google/type/decimal.proto
[a pair of integers]: https://github.com/googleapis/googleapis/blob/master/google/type/money.proto
[json.Marshaler]: https://pkg.go.dev/encoding/json#Marshaler
[json.Unmarshaler]: https://pkg.go.dev/encoding/json#Unmarshaler
[mongo-driver/bson]: https://pkg.go.dev/go.mongodb.org/mongo-driver/v2/bson
[Decimal128]: https://github.com/mongodb/specifications/blob/master/source/bson-decimal128/decimal128.md
[v2/bson.ValueMarshaler]: https://pkg.go.dev/go.mongodb.org/mongo-driver/v2/bson#ValueMarshaler
[v2/bson.ValueUnmarshaler]: https://pkg.go.dev/go.mongodb.org/mongo-driver/v2/bson#ValueUnmarshaler
*/
package decimal
================================================
FILE: doc_test.go
================================================
package decimal_test
import (
"bytes"
"encoding/gob"
"encoding/json"
"encoding/xml"
"fmt"
"slices"
"strings"
"github.com/govalues/decimal"
)
// This example implements a simple calculator that evaluates mathematical
// expressions written in [postfix notation].
// The calculator can handle basic arithmetic operations such as addition,
// subtraction, multiplication, and division.
//
// [postfix notation]: https://en.wikipedia.org/wiki/Reverse_Polish_notation
func Example_postfixCalculator() {
fmt.Println(evaluate("1.23 4.56 + 10 *"))
// Output:
// 57.90
}
func evaluate(input string) (decimal.Decimal, error) {
tokens := strings.Fields(input)
if len(tokens) == 0 {
return decimal.Decimal{}, fmt.Errorf("no tokens")
}
stack := make([]decimal.Decimal, 0, len(tokens))
for i, token := range tokens {
var err error
var result decimal.Decimal
if token == "+" || token == "-" || token == "*" || token == "/" {
if len(stack) < 2 {
return decimal.Decimal{}, fmt.Errorf("not enough operands")
}
left := stack[len(stack)-2]
right := stack[len(stack)-1]
stack = stack[:len(stack)-2]
switch token {
case "+":
result, err = left.Add(right)
case "-":
result, err = left.Sub(right)
case "*":
result, err = left.Mul(right)
case "/":
result, err = left.Quo(right)
}
} else {
result, err = decimal.Parse(token)
}
if err != nil {
return decimal.Decimal{}, fmt.Errorf("processing token %q at position %v: %w", token, i, err)
}
stack = append(stack, result)
}
if len(stack) != 1 {
return decimal.Decimal{}, fmt.Errorf("stack contains %v, expected exactly one item", stack)
}
return stack[0], nil
}
// This example calculates an approximate value of π using the [Leibniz formula].
// The Leibniz formula is an infinite series that converges to π/4, and is
// given by the equation: 1 - 1/3 + 1/5 - 1/7 + 1/9 - 1/11 + ... = π/4.
// This example computes the series up to the 500,000th term using decimal arithmetic
// and returns the approximate value of π.
//
// [Leibniz formula]: https://en.wikipedia.org/wiki/Leibniz_formula_for_%CF%80
func Example_piApproximation() {
fmt.Println(approximate(500_000))
fmt.Println(decimal.Pi)
// Output:
// 3.141590653589793192
// 3.141592653589793238
}
func approximate(terms int) (decimal.Decimal, error) {
pi := decimal.Zero
denominator := decimal.One
increment := decimal.Two
multiplier := decimal.MustParse("4")
var err error
for range terms {
pi, err = pi.AddQuo(multiplier, denominator)
if err != nil {
return decimal.Decimal{}, err
}
denominator, err = denominator.Add(increment)
if err != nil {
return decimal.Decimal{}, err
}
multiplier = multiplier.Neg()
}
return pi, nil
}
// This example demonstrates the advantage of decimals for financial calculations.
// It computes the sum 0.1 + 0.2 using both decimal and float64 arithmetic.
// In decimal arithmetic, the result is exactly 0.3, as expected.
// In float64 arithmetic, the result is 0.30000000000000004 due to floating-point inaccuracy.
func Example_floatInaccuracy() {
a := decimal.MustParse("0.1")
b := decimal.MustParse("0.2")
fmt.Println(a.Add(b))
x := 0.1
y := 0.2
fmt.Println(x + y)
// Output:
// 0.3
// 0.30000000000000004
}
func ExampleSum() {
d := decimal.MustParse("5.67")
e := decimal.MustParse("-8")
f := decimal.MustParse("23")
fmt.Println(decimal.Sum(d, e, f))
// Output: 20.67
}
func ExampleMean() {
d := decimal.MustParse("5.67")
e := decimal.MustParse("-8")
f := decimal.MustParse("23")
fmt.Println(decimal.Mean(d, e, f))
// Output: 6.89
}
func ExampleProd() {
d := decimal.MustParse("5.67")
e := decimal.MustParse("-8")
f := decimal.MustParse("23")
fmt.Println(decimal.Prod(d, e, f))
// Output: -1043.28
}
func ExampleMustNew() {
fmt.Println(decimal.MustNew(567, 0))
fmt.Println(decimal.MustNew(567, 1))
fmt.Println(decimal.MustNew(567, 2))
fmt.Println(decimal.MustNew(567, 3))
fmt.Println(decimal.MustNew(567, 4))
// Output:
// 567
// 56.7
// 5.67
// 0.567
// 0.0567
}
func ExampleNew() {
fmt.Println(decimal.New(567, 0))
fmt.Println(decimal.New(567, 1))
fmt.Println(decimal.New(567, 2))
fmt.Println(decimal.New(567, 3))
fmt.Println(decimal.New(567, 4))
// Output:
// 567
// 56.7
// 5.67
// 0.567
// 0.0567
}
func ExampleNewFromInt64() {
fmt.Println(decimal.NewFromInt64(5, 6, 1))
fmt.Println(decimal.NewFromInt64(5, 6, 2))
fmt.Println(decimal.NewFromInt64(5, 6, 3))
fmt.Println(decimal.NewFromInt64(5, 6, 4))
fmt.Println(decimal.NewFromInt64(5, 6, 5))
// Output:
// 5.6
// 5.06
// 5.006
// 5.0006
// 5.00006
}
func ExampleNewFromFloat64() {
fmt.Println(decimal.NewFromFloat64(5.67e-2))
fmt.Println(decimal.NewFromFloat64(5.67e-1))
fmt.Println(decimal.NewFromFloat64(5.67e0))
fmt.Println(decimal.NewFromFloat64(5.67e1))
fmt.Println(decimal.NewFromFloat64(5.67e2))
// Output:
// 0.0567
// 0.567
// 5.67
// 56.7
// 567
}
func ExampleDecimal_Zero() {
d := decimal.MustParse("5")
e := decimal.MustParse("5.6")
f := decimal.MustParse("5.67")
fmt.Println(d.Zero())
fmt.Println(e.Zero())
fmt.Println(f.Zero())
// Output:
// 0
// 0.0
// 0.00
}
func ExampleDecimal_One() {
d := decimal.MustParse("5")
e := decimal.MustParse("5.6")
f := decimal.MustParse("5.67")
fmt.Println(d.One())
fmt.Println(e.One())
fmt.Println(f.One())
// Output:
// 1
// 1.0
// 1.00
}
func ExampleDecimal_ULP() {
d := decimal.MustParse("5")
e := decimal.MustParse("5.6")
f := decimal.MustParse("5.67")
fmt.Println(d.ULP())
fmt.Println(e.ULP())
fmt.Println(f.ULP())
// Output:
// 1
// 0.1
// 0.01
}
func ExampleParse() {
fmt.Println(decimal.Parse("5.67"))
// Output: 5.67
}
func ExampleParseExact() {
fmt.Println(decimal.ParseExact("5.67", 0))
fmt.Println(decimal.ParseExact("5.67", 1))
fmt.Println(decimal.ParseExact("5.67", 2))
fmt.Println(decimal.ParseExact("5.67", 3))
fmt.Println(decimal.ParseExact("5.67", 4))
// Output:
// 5.67
// 5.67
// 5.67
// 5.670
// 5.6700
}
func ExampleMustParse() {
fmt.Println(decimal.MustParse("-1.23"))
// Output: -1.23
}
func ExampleDecimal_String() {
d := decimal.MustParse("1234567890.123456789")
fmt.Println(d.String())
// Output: 1234567890.123456789
}
func ExampleDecimal_UnmarshalBinary_gob() {
data := []byte{
0x12, 0x7f, 0x06, 0x01,
0x01, 0x07, 0x44, 0x65,
0x63, 0x69, 0x6d, 0x61,
0x6c, 0x01, 0xff, 0x80,
0x00, 0x00, 0x00, 0x08,
0xff, 0x80, 0x00, 0x04,
0x35, 0x2e, 0x36, 0x37,
}
fmt.Println(unmarshalGOB(data))
// Output:
// 5.67
}
func unmarshalGOB(data []byte) (decimal.Decimal, error) {
var d decimal.Decimal
dec := gob.NewDecoder(bytes.NewReader(data))
err := dec.Decode(&d)
if err != nil {
return decimal.Decimal{}, err
}
return d, nil
}
func ExampleDecimal_AppendBinary() {
d := decimal.MustParse("5.67")
var data []byte
data = append(data, 0x04)
data, err := d.AppendBinary(data)
data = append(data, 0x00)
fmt.Printf("% x %v\n", data, err)
// Output:
// 04 35 2e 36 37 00
}
func ExampleDecimal_MarshalBinary_gob() {
data, err := marshalGOB("5.67")
fmt.Printf("[% x] %v\n", data, err)
// Output:
// [12 7f 06 01 01 07 44 65 63 69 6d 61 6c 01 ff 80 00 00 00 08 ff 80 00 04 35 2e 36 37]
}
func marshalGOB(s string) ([]byte, error) {
d, err := decimal.Parse(s)
if err != nil {
return nil, err
}
var data bytes.Buffer
enc := gob.NewEncoder(&data)
err = enc.Encode(d)
if err != nil {
return nil, err
}
return data.Bytes(), nil
}
func ExampleDecimal_Float64() {
d := decimal.MustParse("0.1")
e := decimal.MustParse("123.456")
f := decimal.MustParse("1234567890.123456789")
fmt.Println(d.Float64())
fmt.Println(e.Float64())
fmt.Println(f.Float64())
// Output:
// 0.1 true
// 123.456 true
// 1.2345678901234567e+09 true
}
func ExampleDecimal_Int64() {
d := decimal.MustParse("5.67")
fmt.Println(d.Int64(0))
fmt.Println(d.Int64(1))
fmt.Println(d.Int64(2))
fmt.Println(d.Int64(3))
fmt.Println(d.Int64(4))
// Output:
// 6 0 true
// 5 7 true
// 5 67 true
// 5 670 true
// 5 6700 true
}
func ExampleDecimal_UnmarshalBSONValue_bson() {
data := []byte{
0x37, 0x02, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3c, 0x30,
}
var d decimal.Decimal
err := d.UnmarshalBSONValue(19, data)
fmt.Println(d, err)
// Output:
// 5.67
}
func ExampleDecimal_MarshalBSONValue_bson() {
d := decimal.MustParse("5.67")
t, data, err := d.MarshalBSONValue()
fmt.Printf("%v [% x] %v\n", t, data, err)
// Output:
// 19 [37 02 00 00 00 00 00 00 00 00 00 00 00 00 3c 30]
}
type Account struct {
Balance decimal.Decimal `json:"balance"`
}
func ExampleDecimal_UnmarshalJSON_json() {
fmt.Println(unmarshalJSON(`{"balance":"5.67"}`))
fmt.Println(unmarshalJSON(`{"balance":"-5.67"}`))
fmt.Println(unmarshalJSON(`{"balance":5.67e-5}`))
fmt.Println(unmarshalJSON(`{"balance":5.67e5}`))
// Output:
// {5.67}
// {-5.67}
// {0.0000567}
// {567000}
}
func unmarshalJSON(s string) (Account, error) {
var a Account
err := json.Unmarshal([]byte(s), &a)
if err != nil {
return Account{}, err
}
return a, nil
}
func ExampleDecimal_MarshalJSON_json() {
fmt.Println(marshalJSON("5.67"))
fmt.Println(marshalJSON("-5.67"))
// Output:
// {"balance":"5.67"}
// {"balance":"-5.67"}
}
func marshalJSON(s string) (string, error) {
d, err := decimal.Parse(s)
if err != nil {
return "", err
}
data, err := json.Marshal(Account{Balance: d})
if err != nil {
return "", err
}
return string(data), nil
}
type Transaction struct {
Amount decimal.Decimal `xml:"Amount"`
}
func ExampleDecimal_UnmarshalText_xml() {
fmt.Println(unmarshalXML(`5.67`))
fmt.Println(unmarshalXML(`-5.67`))
fmt.Println(unmarshalXML(`5.67e-5`))
fmt.Println(unmarshalXML(`5.67e5`))
// Output:
// {5.67}
// {-5.67}
// {0.0000567}
// {567000}
}
func unmarshalXML(s string) (Transaction, error) {
var t Transaction
err := xml.Unmarshal([]byte(s), &t)
return t, err
}
func ExampleDecimal_AppendText() {
var text []byte
d := decimal.MustParse("5.67")
text = append(text, ""...)
text, err := d.AppendText(text)
text = append(text, ""...)
fmt.Printf("%s %v\n", text, err)
// Output:
// 5.67
}
func ExampleDecimal_MarshalText_xml() {
fmt.Println(marshalXML("5.67"))
fmt.Println(marshalXML("-5.67"))
fmt.Println(marshalXML("5.67e-5"))
fmt.Println(marshalXML("5.67e5"))
// Output:
// 5.67
// -5.67
// 0.0000567
// 567000
}
func marshalXML(s string) (string, error) {
d, err := decimal.Parse(s)
if err != nil {
return "", err
}
data, err := xml.Marshal(Transaction{Amount: d})
if err != nil {
return "", err
}
return string(data), nil
}
func ExampleDecimal_Scan() {
var d decimal.Decimal
_ = d.Scan("5.67")
fmt.Println(d)
// Output: 5.67
}
func ExampleDecimal_Value() {
d := decimal.MustParse("5.67")
fmt.Println(d.Value())
// Output: 5.67
}
func ExampleDecimal_Format() {
d := decimal.MustParse("5.67")
fmt.Printf("%f\n", d)
fmt.Printf("%k\n", d)
// Output:
// 5.67
// 567%
}
func ExampleDecimal_Coef() {
d := decimal.MustParse("-123")
e := decimal.MustParse("5.7")
f := decimal.MustParse("0.4")
fmt.Println(d.Coef())
fmt.Println(e.Coef())
fmt.Println(f.Coef())
// Output:
// 123
// 57
// 4
}
func ExampleDecimal_Prec() {
d := decimal.MustParse("-123")
e := decimal.MustParse("5.7")
f := decimal.MustParse("0.4")
fmt.Println(d.Prec())
fmt.Println(e.Prec())
fmt.Println(f.Prec())
// Output:
// 3
// 2
// 1
}
func ExampleDecimal_Mul() {
d := decimal.MustParse("5.7")
e := decimal.MustParse("3")
fmt.Println(d.Mul(e))
// Output: 17.1
}
func ExampleDecimal_MulExact() {
d := decimal.MustParse("5.7")
e := decimal.MustParse("3")
fmt.Println(d.MulExact(e, 0))
fmt.Println(d.MulExact(e, 1))
fmt.Println(d.MulExact(e, 2))
fmt.Println(d.MulExact(e, 3))
fmt.Println(d.MulExact(e, 4))
// Output:
// 17.1
// 17.1
// 17.10
// 17.100
// 17.1000
}
func ExampleDecimal_SubMul() {
d := decimal.MustParse("2")
e := decimal.MustParse("3")
f := decimal.MustParse("4")
fmt.Println(d.SubMul(e, f))
// Output: -10
}
func ExampleDecimal_SubMulExact() {
d := decimal.MustParse("2")
e := decimal.MustParse("3")
f := decimal.MustParse("4")
fmt.Println(d.SubMulExact(e, f, 0))
fmt.Println(d.SubMulExact(e, f, 1))
fmt.Println(d.SubMulExact(e, f, 2))
fmt.Println(d.SubMulExact(e, f, 3))
fmt.Println(d.SubMulExact(e, f, 4))
// Output:
// -10
// -10.0
// -10.00
// -10.000
// -10.0000
}
func ExampleDecimal_AddMul() {
d := decimal.MustParse("2")
e := decimal.MustParse("3")
f := decimal.MustParse("4")
fmt.Println(d.AddMul(e, f))
// Output: 14
}
func ExampleDecimal_AddMulExact() {
d := decimal.MustParse("2")
e := decimal.MustParse("3")
f := decimal.MustParse("4")
fmt.Println(d.AddMulExact(e, f, 0))
fmt.Println(d.AddMulExact(e, f, 1))
fmt.Println(d.AddMulExact(e, f, 2))
fmt.Println(d.AddMulExact(e, f, 3))
fmt.Println(d.AddMulExact(e, f, 4))
// Output:
// 14
// 14.0
// 14.00
// 14.000
// 14.0000
}
func ExampleDecimal_SubQuo() {
d := decimal.MustParse("2")
e := decimal.MustParse("3")
f := decimal.MustParse("4")
fmt.Println(d.SubQuo(e, f))
// Output: 1.25
}
func ExampleDecimal_SubQuoExact() {
d := decimal.MustParse("2")
e := decimal.MustParse("3")
f := decimal.MustParse("4")
fmt.Println(d.SubQuoExact(e, f, 0))
fmt.Println(d.SubQuoExact(e, f, 1))
fmt.Println(d.SubQuoExact(e, f, 2))
fmt.Println(d.SubQuoExact(e, f, 3))
fmt.Println(d.SubQuoExact(e, f, 4))
// Output:
// 1.25
// 1.25
// 1.25
// 1.250
// 1.2500
}
func ExampleDecimal_AddQuo() {
d := decimal.MustParse("2")
e := decimal.MustParse("3")
f := decimal.MustParse("4")
fmt.Println(d.AddQuo(e, f))
// Output: 2.75
}
func ExampleDecimal_AddQuoExact() {
d := decimal.MustParse("2")
e := decimal.MustParse("3")
f := decimal.MustParse("4")
fmt.Println(d.AddQuoExact(e, f, 0))
fmt.Println(d.AddQuoExact(e, f, 1))
fmt.Println(d.AddQuoExact(e, f, 2))
fmt.Println(d.AddQuoExact(e, f, 3))
fmt.Println(d.AddQuoExact(e, f, 4))
// Output:
// 2.75
// 2.75
// 2.75
// 2.750
// 2.7500
}
func ExampleDecimal_Pow() {
d := decimal.MustParse("4")
e := decimal.MustParse("0.5")
f := decimal.MustParse("-0.5")
fmt.Println(d.Pow(e))
fmt.Println(d.Pow(f))
// Output:
// 2.000000000000000000
// 0.5000000000000000000
}
func ExampleDecimal_PowInt() {
d := decimal.MustParse("2")
fmt.Println(d.PowInt(-2))
fmt.Println(d.PowInt(-1))
fmt.Println(d.PowInt(0))
fmt.Println(d.PowInt(1))
fmt.Println(d.PowInt(2))
// Output:
// 0.25
// 0.5
// 1
// 2
// 4
}
func ExampleDecimal_Sqrt() {
d := decimal.MustParse("1")
e := decimal.MustParse("2")
f := decimal.MustParse("3")
g := decimal.MustParse("4")
fmt.Println(d.Sqrt())
fmt.Println(e.Sqrt())
fmt.Println(f.Sqrt())
fmt.Println(g.Sqrt())
// Output:
// 1
// 1.414213562373095049
// 1.732050807568877294
// 2
}
func ExampleDecimal_Exp() {
d := decimal.MustParse("-2.302585092994045684")
e := decimal.MustParse("0")
f := decimal.MustParse("2.302585092994045684")
fmt.Println(d.Exp())
fmt.Println(e.Exp())
fmt.Println(f.Exp())
// Output:
// 0.1000000000000000000
// 1
// 10.00000000000000000
}
func ExampleDecimal_Expm1() {
d := decimal.MustParse("-2.302585092994045684")
e := decimal.MustParse("0")
f := decimal.MustParse("2.302585092994045684")
fmt.Println(d.Expm1())
fmt.Println(e.Expm1())
fmt.Println(f.Expm1())
// Output:
// -0.9000000000000000000
// 0
// 9.000000000000000000
}
func ExampleDecimal_Log() {
d := decimal.MustParse("1")
e := decimal.MustParse("2")
f := decimal.MustParse("2.718281828459045236")
g := decimal.MustParse("10")
fmt.Println(d.Log())
fmt.Println(e.Log())
fmt.Println(f.Log())
fmt.Println(g.Log())
// Output:
// 0
// 0.6931471805599453094
// 1.000000000000000000
// 2.302585092994045684
}
func ExampleDecimal_Log1p() {
d := decimal.MustParse("1")
e := decimal.MustParse("2")
f := decimal.MustParse("2.718281828459045236")
g := decimal.MustParse("10")
fmt.Println(d.Log1p())
fmt.Println(e.Log1p())
fmt.Println(f.Log1p())
fmt.Println(g.Log1p())
// Output:
// 0.6931471805599453094
// 1.098612288668109691
// 1.313261687518222834
// 2.397895272798370544
}
func ExampleDecimal_Log2() {
d := decimal.MustParse("1")
e := decimal.MustParse("2")
f := decimal.MustParse("2.718281828459045236")
g := decimal.MustParse("10")
fmt.Println(d.Log2())
fmt.Println(e.Log2())
fmt.Println(f.Log2())
fmt.Println(g.Log2())
// Output:
// 0
// 1
// 1.442695040888963408
// 3.321928094887362348
}
func ExampleDecimal_Log10() {
d := decimal.MustParse("1")
e := decimal.MustParse("2")
f := decimal.MustParse("2.718281828459045236")
g := decimal.MustParse("10")
fmt.Println(d.Log10())
fmt.Println(e.Log10())
fmt.Println(f.Log10())
fmt.Println(g.Log10())
// Output:
// 0
// 0.3010299956639811952
// 0.4342944819032518278
// 1
}
func ExampleDecimal_Add() {
d := decimal.MustParse("5.67")
e := decimal.MustParse("8")
fmt.Println(d.Add(e))
// Output: 13.67
}
func ExampleDecimal_AddExact() {
d := decimal.MustParse("5.67")
e := decimal.MustParse("8")
fmt.Println(d.AddExact(e, 0))
fmt.Println(d.AddExact(e, 1))
fmt.Println(d.AddExact(e, 2))
fmt.Println(d.AddExact(e, 3))
fmt.Println(d.AddExact(e, 4))
// Output:
// 13.67
// 13.67
// 13.67
// 13.670
// 13.6700
}
func ExampleDecimal_Sub() {
d := decimal.MustParse("-5.67")
e := decimal.MustParse("8")
fmt.Println(d.Sub(e))
fmt.Println(e.Sub(d))
// Output:
// -13.67
// 13.67
}
func ExampleDecimal_SubAbs() {
d := decimal.MustParse("-5.67")
e := decimal.MustParse("8")
fmt.Println(d.SubAbs(e))
fmt.Println(e.SubAbs(d))
// Output:
// 13.67
// 13.67
}
func ExampleDecimal_SubExact() {
d := decimal.MustParse("8")
e := decimal.MustParse("5.67")
fmt.Println(d.SubExact(e, 0))
fmt.Println(d.SubExact(e, 1))
fmt.Println(d.SubExact(e, 2))
fmt.Println(d.SubExact(e, 3))
fmt.Println(d.SubExact(e, 4))
// Output:
// 2.33
// 2.33
// 2.33
// 2.330
// 2.3300
}
func ExampleDecimal_Quo() {
d := decimal.MustParse("5.67")
e := decimal.MustParse("2")
fmt.Println(d.Quo(e))
// Output: 2.835
}
func ExampleDecimal_QuoExact() {
d := decimal.MustParse("5.66")
e := decimal.MustParse("2")
fmt.Println(d.QuoExact(e, 0))
fmt.Println(d.QuoExact(e, 1))
fmt.Println(d.QuoExact(e, 2))
fmt.Println(d.QuoExact(e, 3))
fmt.Println(d.QuoExact(e, 4))
// Output:
// 2.83
// 2.83
// 2.83
// 2.830
// 2.8300
}
func ExampleDecimal_QuoRem() {
d := decimal.MustParse("5.67")
e := decimal.MustParse("2")
fmt.Println(d.QuoRem(e))
// Output: 2 1.67
}
func ExampleDecimal_Inv() {
d := decimal.MustParse("2")
fmt.Println(d.Inv())
// Output: 0.5
}
func ExampleDecimal_Less() {
d := decimal.MustParse("-23")
e := decimal.MustParse("5.67")
fmt.Println(d.Less(e))
fmt.Println(e.Less(d))
// Output:
// true
// false
}
func ExampleDecimal_Equal() {
d := decimal.MustParse("-23")
e := decimal.MustParse("5.67")
fmt.Println(d.Equal(e))
fmt.Println(d.Equal(d))
// Output:
// false
// true
}
func ExampleDecimal_Equal_slices() {
s := []decimal.Decimal{
decimal.MustParse("-5.67"),
decimal.MustParse("0"),
decimal.MustParse("0"),
}
fmt.Println(slices.EqualFunc(s, s, decimal.Decimal.Equal))
fmt.Println(slices.CompactFunc(s, decimal.Decimal.Equal))
// Output:
// true
// [-5.67 0]
}
func ExampleDecimal_Cmp() {
d := decimal.MustParse("-23")
e := decimal.MustParse("5.67")
fmt.Println(d.Cmp(e))
fmt.Println(d.Cmp(d))
fmt.Println(e.Cmp(d))
// Output:
// -1
// 0
// 1
}
func ExampleDecimal_Cmp_slices() {
s := []decimal.Decimal{
decimal.MustParse("-5.67"),
decimal.MustParse("23"),
decimal.MustParse("0"),
}
fmt.Println(slices.CompareFunc(s, s, decimal.Decimal.Cmp))
fmt.Println(slices.MaxFunc(s, decimal.Decimal.Cmp))
fmt.Println(slices.MinFunc(s, decimal.Decimal.Cmp))
fmt.Println(s, slices.IsSortedFunc(s, decimal.Decimal.Cmp))
slices.SortFunc(s, decimal.Decimal.Cmp)
fmt.Println(s, slices.IsSortedFunc(s, decimal.Decimal.Cmp))
fmt.Println(slices.BinarySearchFunc(s, decimal.MustParse("1"), decimal.Decimal.Cmp))
// Output:
// 0
// 23
// -5.67
// [-5.67 23 0] false
// [-5.67 0 23] true
// 2 false
}
func ExampleDecimal_CmpAbs() {
d := decimal.MustParse("-23")
e := decimal.MustParse("5.67")
fmt.Println(d.CmpAbs(e))
fmt.Println(d.CmpAbs(d))
fmt.Println(e.CmpAbs(d))
// Output:
// 1
// 0
// -1
}
func ExampleDecimal_CmpAbs_slices() {
s := []decimal.Decimal{
decimal.MustParse("-5.67"),
decimal.MustParse("23"),
decimal.MustParse("0"),
}
fmt.Println(slices.CompareFunc(s, s, decimal.Decimal.CmpAbs))
fmt.Println(slices.MaxFunc(s, decimal.Decimal.CmpAbs))
fmt.Println(slices.MinFunc(s, decimal.Decimal.CmpAbs))
fmt.Println(s, slices.IsSortedFunc(s, decimal.Decimal.CmpAbs))
slices.SortFunc(s, decimal.Decimal.CmpAbs)
fmt.Println(s, slices.IsSortedFunc(s, decimal.Decimal.CmpAbs))
fmt.Println(slices.BinarySearchFunc(s, decimal.MustParse("1"), decimal.Decimal.CmpAbs))
// Output:
// 0
// 23
// 0
// [-5.67 23 0] false
// [0 -5.67 23] true
// 1 false
}
func ExampleDecimal_CmpTotal() {
d := decimal.MustParse("2.0")
e := decimal.MustParse("2.00")
fmt.Println(d.CmpTotal(e))
fmt.Println(d.CmpTotal(d))
fmt.Println(e.CmpTotal(d))
// Output:
// 1
// 0
// -1
}
func ExampleDecimal_CmpTotal_slices() {
s := []decimal.Decimal{
decimal.MustParse("-5.67"),
decimal.MustParse("23"),
decimal.MustParse("0"),
}
fmt.Println(slices.CompareFunc(s, s, decimal.Decimal.CmpTotal))
fmt.Println(slices.MaxFunc(s, decimal.Decimal.CmpTotal))
fmt.Println(slices.MinFunc(s, decimal.Decimal.CmpTotal))
fmt.Println(s, slices.IsSortedFunc(s, decimal.Decimal.CmpTotal))
slices.SortFunc(s, decimal.Decimal.CmpTotal)
fmt.Println(s, slices.IsSortedFunc(s, decimal.Decimal.CmpTotal))
fmt.Println(slices.BinarySearchFunc(s, decimal.MustParse("10"), decimal.Decimal.CmpTotal))
// Output:
// 0
// 23
// -5.67
// [-5.67 23 0] false
// [-5.67 0 23] true
// 2 false
}
func ExampleDecimal_Max() {
d := decimal.MustParse("23")
e := decimal.MustParse("-5.67")
fmt.Println(d.Max(e))
// Output: 23
}
func ExampleDecimal_Min() {
d := decimal.MustParse("23")
e := decimal.MustParse("-5.67")
fmt.Println(d.Min(e))
// Output: -5.67
}
//nolint:revive
func ExampleDecimal_Clamp() {
min := decimal.MustParse("-20")
max := decimal.MustParse("20")
d := decimal.MustParse("-5.67")
e := decimal.MustParse("0")
f := decimal.MustParse("23")
fmt.Println(d.Clamp(min, max))
fmt.Println(e.Clamp(min, max))
fmt.Println(f.Clamp(min, max))
// Output:
// -5.67
// 0
// 20
}
func ExampleDecimal_Rescale() {
d := decimal.MustParse("5.678")
fmt.Println(d.Rescale(0))
fmt.Println(d.Rescale(1))
fmt.Println(d.Rescale(2))
fmt.Println(d.Rescale(3))
fmt.Println(d.Rescale(4))
// Output:
// 6
// 5.7
// 5.68
// 5.678
// 5.6780
}
func ExampleDecimal_Quantize() {
d := decimal.MustParse("5.678")
x := decimal.MustParse("1")
y := decimal.MustParse("0.1")
z := decimal.MustParse("0.01")
fmt.Println(d.Quantize(x))
fmt.Println(d.Quantize(y))
fmt.Println(d.Quantize(z))
// Output:
// 6
// 5.7
// 5.68
}
func ExampleDecimal_Pad() {
d := decimal.MustParse("5.67")
fmt.Println(d.Pad(0))
fmt.Println(d.Pad(1))
fmt.Println(d.Pad(2))
fmt.Println(d.Pad(3))
fmt.Println(d.Pad(4))
// Output:
// 5.67
// 5.67
// 5.67
// 5.670
// 5.6700
}
func ExampleDecimal_Round() {
d := decimal.MustParse("5.678")
fmt.Println(d.Round(0))
fmt.Println(d.Round(1))
fmt.Println(d.Round(2))
fmt.Println(d.Round(3))
fmt.Println(d.Round(4))
// Output:
// 6
// 5.7
// 5.68
// 5.678
// 5.678
}
func ExampleDecimal_Trunc() {
d := decimal.MustParse("5.678")
fmt.Println(d.Trunc(0))
fmt.Println(d.Trunc(1))
fmt.Println(d.Trunc(2))
fmt.Println(d.Trunc(3))
fmt.Println(d.Trunc(4))
// Output:
// 5
// 5.6
// 5.67
// 5.678
// 5.678
}
func ExampleDecimal_Ceil() {
d := decimal.MustParse("5.678")
fmt.Println(d.Ceil(0))
fmt.Println(d.Ceil(1))
fmt.Println(d.Ceil(2))
fmt.Println(d.Ceil(3))
fmt.Println(d.Ceil(4))
// Output:
// 6
// 5.7
// 5.68
// 5.678
// 5.678
}
func ExampleDecimal_Floor() {
d := decimal.MustParse("5.678")
fmt.Println(d.Floor(0))
fmt.Println(d.Floor(1))
fmt.Println(d.Floor(2))
fmt.Println(d.Floor(3))
fmt.Println(d.Floor(4))
// Output:
// 5
// 5.6
// 5.67
// 5.678
// 5.678
}
func ExampleDecimal_Scale() {
d := decimal.MustParse("23")
e := decimal.MustParse("5.67")
fmt.Println(d.Scale())
fmt.Println(e.Scale())
// Output:
// 0
// 2
}
func ExampleDecimal_SameScale() {
a := decimal.MustParse("23")
b := decimal.MustParse("5.67")
c := decimal.MustParse("1.23")
fmt.Println(a.SameScale(b))
fmt.Println(b.SameScale(c))
// Output:
// false
// true
}
func ExampleDecimal_MinScale() {
d := decimal.MustParse("23.0000")
e := decimal.MustParse("-5.6700")
fmt.Println(d.MinScale())
fmt.Println(e.MinScale())
// Output:
// 0
// 2
}
func ExampleDecimal_Trim() {
d := decimal.MustParse("23.400")
fmt.Println(d.Trim(0))
fmt.Println(d.Trim(1))
fmt.Println(d.Trim(2))
fmt.Println(d.Trim(3))
fmt.Println(d.Trim(4))
// Output:
// 23.4
// 23.4
// 23.40
// 23.400
// 23.400
}
func ExampleDecimal_Abs() {
d := decimal.MustParse("-5.67")
fmt.Println(d.Abs())
// Output: 5.67
}
func ExampleDecimal_CopySign() {
d := decimal.MustParse("23.00")
e := decimal.MustParse("-5.67")
fmt.Println(d.CopySign(e))
fmt.Println(e.CopySign(d))
// Output:
// -23.00
// 5.67
}
func ExampleDecimal_Neg() {
d := decimal.MustParse("5.67")
fmt.Println(d.Neg())
// Output: -5.67
}
func ExampleDecimal_Sign() {
d := decimal.MustParse("-5.67")
e := decimal.MustParse("23")
f := decimal.MustParse("0")
fmt.Println(d.Sign())
fmt.Println(e.Sign())
fmt.Println(f.Sign())
// Output:
// -1
// 1
// 0
}
func ExampleDecimal_IsNeg() {
d := decimal.MustParse("-5.67")
e := decimal.MustParse("23")
f := decimal.MustParse("0")
fmt.Println(d.IsNeg())
fmt.Println(e.IsNeg())
fmt.Println(f.IsNeg())
// Output:
// true
// false
// false
}
func ExampleDecimal_IsNeg_slices() {
s := []decimal.Decimal{
decimal.MustParse("-5.67"),
decimal.MustParse("23"),
decimal.MustParse("0"),
}
fmt.Println(slices.ContainsFunc(s, decimal.Decimal.IsNeg))
fmt.Println(slices.IndexFunc(s, decimal.Decimal.IsNeg))
fmt.Println(slices.DeleteFunc(s, decimal.Decimal.IsNeg))
// Output:
// true
// 0
// [23 0]
}
func ExampleDecimal_IsPos() {
d := decimal.MustParse("-5.67")
e := decimal.MustParse("23")
f := decimal.MustParse("0")
fmt.Println(d.IsPos())
fmt.Println(e.IsPos())
fmt.Println(f.IsPos())
// Output:
// false
// true
// false
}
func ExampleDecimal_IsPos_slices() {
s := []decimal.Decimal{
decimal.MustParse("-5.67"),
decimal.MustParse("23"),
decimal.MustParse("0"),
}
fmt.Println(slices.ContainsFunc(s, decimal.Decimal.IsPos))
fmt.Println(slices.IndexFunc(s, decimal.Decimal.IsPos))
fmt.Println(slices.DeleteFunc(s, decimal.Decimal.IsPos))
// Output:
// true
// 1
// [-5.67 0]
}
func ExampleDecimal_IsZero() {
d := decimal.MustParse("-5.67")
e := decimal.MustParse("23")
f := decimal.MustParse("0")
fmt.Println(d.IsZero())
fmt.Println(e.IsZero())
fmt.Println(f.IsZero())
// Output:
// false
// false
// true
}
func ExampleDecimal_IsZero_slices() {
s := []decimal.Decimal{
decimal.MustParse("-5.67"),
decimal.MustParse("23"),
decimal.MustParse("0"),
}
fmt.Println(slices.ContainsFunc(s, decimal.Decimal.IsZero))
fmt.Println(slices.IndexFunc(s, decimal.Decimal.IsZero))
fmt.Println(slices.DeleteFunc(s, decimal.Decimal.IsZero))
// Output:
// true
// 2
// [-5.67 23]
}
func ExampleDecimal_IsInt() {
d := decimal.MustParse("1.00")
e := decimal.MustParse("1.01")
fmt.Println(d.IsInt())
fmt.Println(e.IsInt())
// Output:
// true
// false
}
func ExampleDecimal_IsInt_slices() {
s := []decimal.Decimal{
decimal.MustParse("-5.67"),
decimal.MustParse("23"),
decimal.MustParse("0"),
}
fmt.Println(slices.ContainsFunc(s, decimal.Decimal.IsInt))
fmt.Println(slices.IndexFunc(s, decimal.Decimal.IsInt))
fmt.Println(slices.DeleteFunc(s, decimal.Decimal.IsInt))
// Output:
// true
// 1
// [-5.67]
}
func ExampleDecimal_IsOne() {
d := decimal.MustParse("1")
e := decimal.MustParse("2")
fmt.Println(d.IsOne())
fmt.Println(e.IsOne())
// Output:
// true
// false
}
func ExampleDecimal_IsOne_slices() {
s := []decimal.Decimal{
decimal.MustParse("-5.67"),
decimal.MustParse("23"),
decimal.MustParse("1"),
}
fmt.Println(slices.ContainsFunc(s, decimal.Decimal.IsOne))
fmt.Println(slices.IndexFunc(s, decimal.Decimal.IsOne))
fmt.Println(slices.DeleteFunc(s, decimal.Decimal.IsOne))
// Output:
// true
// 2
// [-5.67 23]
}
func ExampleDecimal_WithinOne() {
d := decimal.MustParse("1")
e := decimal.MustParse("0.9")
f := decimal.MustParse("-0.9")
g := decimal.MustParse("-1")
fmt.Println(d.WithinOne())
fmt.Println(e.WithinOne())
fmt.Println(f.WithinOne())
fmt.Println(g.WithinOne())
// Output:
// false
// true
// true
// false
}
func ExampleDecimal_WithinOne_slices() {
s := []decimal.Decimal{
decimal.MustParse("-5.67"),
decimal.MustParse("23"),
decimal.MustParse("0.1"),
}
fmt.Println(slices.ContainsFunc(s, decimal.Decimal.WithinOne))
fmt.Println(slices.IndexFunc(s, decimal.Decimal.WithinOne))
fmt.Println(slices.DeleteFunc(s, decimal.Decimal.WithinOne))
// Output:
// true
// 2
// [-5.67 23]
}
func ExampleNullDecimal_Scan() {
var n decimal.NullDecimal
_ = n.Scan(nil)
fmt.Println(n)
var m decimal.NullDecimal
_ = m.Scan("5.67")
fmt.Println(m)
// Output:
// {0 false}
// {5.67 true}
}
func ExampleNullDecimal_Value() {
n := decimal.NullDecimal{
Valid: false,
}
fmt.Println(n.Value())
m := decimal.NullDecimal{
Decimal: decimal.MustParse("5.67"),
Valid: true,
}
fmt.Println(m.Value())
// Output:
//
// 5.67
}
func ExampleNullDecimal_UnmarshalJSON_json() {
var n decimal.NullDecimal
_ = json.Unmarshal([]byte(`null`), &n)
fmt.Println(n)
var m decimal.NullDecimal
_ = json.Unmarshal([]byte(`"5.67"`), &m)
fmt.Println(m)
// Output:
// {0 false}
// {5.67 true}
}
func ExampleNullDecimal_MarshalJSON_json() {
n := decimal.NullDecimal{
Valid: false,
}
data, _ := json.Marshal(n)
fmt.Println(string(data))
m := decimal.NullDecimal{
Decimal: decimal.MustParse("5.67"),
Valid: true,
}
data, _ = json.Marshal(m)
fmt.Println(string(data))
// Output:
// null
// "5.67"
}
func ExampleNullDecimal_UnmarshalBSONValue_bson() {
var n decimal.NullDecimal
_ = n.UnmarshalBSONValue(10, nil)
fmt.Println(n)
data := []byte{
0x37, 0x02, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3c, 0x30,
}
var m decimal.NullDecimal
_ = m.UnmarshalBSONValue(19, data)
fmt.Println(m)
// Output:
// {0 false}
// {5.67 true}
}
func ExampleNullDecimal_MarshalBSONValue_bson() {
n := decimal.NullDecimal{
Valid: false,
}
t, data, _ := n.MarshalBSONValue()
fmt.Printf("%v [% x]\n", t, data)
m := decimal.NullDecimal{
Decimal: decimal.MustParse("5.67"),
Valid: true,
}
t, data, _ = m.MarshalBSONValue()
fmt.Printf("%v [% x]\n", t, data)
// Output:
// 10 []
// 19 [37 02 00 00 00 00 00 00 00 00 00 00 00 00 3c 30]
}
================================================
FILE: go.mod
================================================
module github.com/govalues/decimal
go 1.22
================================================
FILE: integer.go
================================================
package decimal
import (
"fmt"
"math/big"
"sync"
)
// fint (Fast INTeger) is a wrapper around uint64.
type fint uint64
// maxFint is a maximum value of fint.
const maxFint = 9_999_999_999_999_999_999
// pow10 is a cache of powers of 10, where pow10[x] = 10^x.
var pow10 = [...]fint{
1, // 10^0
10, // 10^1
100, // 10^2
1_000, // 10^3
10_000, // 10^4
100_000, // 10^5
1_000_000, // 10^6
10_000_000, // 10^7
100_000_000, // 10^8
1_000_000_000, // 10^9
10_000_000_000, // 10^10
100_000_000_000, // 10^11
1_000_000_000_000, // 10^12
10_000_000_000_000, // 10^13
100_000_000_000_000, // 10^14
1_000_000_000_000_000, // 10^15
10_000_000_000_000_000, // 10^16
100_000_000_000_000_000, // 10^17
1_000_000_000_000_000_000, // 10^18
10_000_000_000_000_000_000, // 10^19
}
// add calculates x + y and checks overflow.
func (x fint) add(y fint) (z fint, ok bool) {
if maxFint-x < y {
return 0, false
}
z = x + y
return z, true
}
// mul calculates x * y and checks overflow.
func (x fint) mul(y fint) (z fint, ok bool) {
if y == 0 {
return 0, true
}
z = x * y
if z/y != x {
return 0, false
}
if z > maxFint {
return 0, false
}
return z, true
}
// quo calculates x / y and checks division by zero and inexact division.
func (x fint) quo(y fint) (z fint, ok bool) {
if y == 0 {
return 0, false
}
z = x / y
if z*y != x {
return 0, false
}
return z, true
}
// quoRem calculates q = ⌊x / y⌋, r = x - y * q and checks division by zero.
func (x fint) quoRem(y fint) (q, r fint, ok bool) {
if y == 0 {
return 0, 0, false
}
q = x / y
r = x - q*y
return q, r, true
}
// subAbs calculates |x - y|.
func (x fint) subAbs(y fint) fint {
if x > y {
return x - y
}
return y - x
}
// lsh (Left Shift) calculates x * 10^shift and checks overflow.
func (x fint) lsh(shift int) (z fint, ok bool) {
// Special cases
switch {
case shift <= 0:
return x, true
case shift == 1 && x < maxFint/10: // to speed up common case
return x * 10, true
case shift >= len(pow10):
return 0, false
}
// General case
y := pow10[shift]
return x.mul(y)
}
// fsa (Fused Shift and Addition) calculates x * 10^shift + b and checks overflow.
func (x fint) fsa(shift int, b byte) (z fint, ok bool) {
z, ok = x.lsh(shift)
if !ok {
return 0, false
}
z, ok = z.add(fint(b))
if !ok {
return 0, false
}
return z, true
}
func (x fint) isOdd() bool {
return x&1 != 0
}
// rshHalfEven (Right Shift) calculates round(x / 10^shift) and rounds result
// using "half to even" rule.
func (x fint) rshHalfEven(shift int) fint {
// Special cases
switch {
case x == 0:
return 0
case shift <= 0:
return x
case shift >= len(pow10):
return 0
}
// General case
y := pow10[shift]
z := x / y
r := x - z*y // r = x % y
y = y >> 1 // y = y / 2, which is safe as y is a multiple of 10
if y < r || (y == r && z.isOdd()) { // half-to-even
z++
}
return z
}
// rshUp (Right Shift) calculates ⌈x / 10^shift⌉ and rounds result away from zero.
func (x fint) rshUp(shift int) fint {
// Special cases
switch {
case x == 0:
return 0
case shift <= 0:
return x
case shift >= len(pow10):
return 1
}
// General case
y := pow10[shift]
z := x / y
r := x - z*y // r = x % y
if r > 0 {
z++
}
return z
}
// rshDown (Right Shift) calculates ⌊x / 10^shift⌋ and rounds result towards zero.
func (x fint) rshDown(shift int) fint {
// Special cases
switch {
case x == 0:
return 0
case shift <= 0:
return x
case shift >= len(pow10):
return 0
}
// General case
y := pow10[shift]
return x / y
}
// prec returns length of x in decimal digits.
// prec assumes that 0 has no digits.
func (x fint) prec() int {
left, right := 0, len(pow10)
for left < right {
mid := (left + right) / 2
if x < pow10[mid] {
right = mid
} else {
left = mid + 1
}
}
return left
}
// ntz returns number of trailing zeros in x.
// ntz assumes that 0 has no trailing zeros.
func (x fint) ntz() int {
left, right := 1, x.prec()
for left < right {
mid := (left + right) / 2
if x%pow10[mid] == 0 {
left = mid + 1
} else {
right = mid
}
}
return left - 1
}
// hasPrec returns true if x has given number of digits or more.
// hasPrec assumes that 0 has no digits.
//
// x.hasPrec(p) is significantly faster than x.prec() >= p.
func (x fint) hasPrec(prec int) bool {
// Special cases
switch {
case prec < 1:
return true
case prec > len(pow10):
return false
}
// General case
return x >= pow10[prec-1]
}
// bint (Big INTeger) is a wrapper around big.Int.
type bint big.Int
// bpow10 is a cache of powers of 10, where bpow10[x] = 10^x.
var bpow10 = [...]*bint{
mustParseBint("1"),
mustParseBint("10"),
mustParseBint("100"),
mustParseBint("1000"),
mustParseBint("10000"),
mustParseBint("100000"),
mustParseBint("1000000"),
mustParseBint("10000000"),
mustParseBint("100000000"),
mustParseBint("1000000000"),
mustParseBint("10000000000"),
mustParseBint("100000000000"),
mustParseBint("1000000000000"),
mustParseBint("10000000000000"),
mustParseBint("100000000000000"),
mustParseBint("1000000000000000"),
mustParseBint("10000000000000000"),
mustParseBint("100000000000000000"),
mustParseBint("1000000000000000000"),
mustParseBint("10000000000000000000"),
mustParseBint("100000000000000000000"),
mustParseBint("1000000000000000000000"),
mustParseBint("10000000000000000000000"),
mustParseBint("100000000000000000000000"),
mustParseBint("1000000000000000000000000"),
mustParseBint("10000000000000000000000000"),
mustParseBint("100000000000000000000000000"),
mustParseBint("1000000000000000000000000000"),
mustParseBint("10000000000000000000000000000"),
mustParseBint("100000000000000000000000000000"),
mustParseBint("1000000000000000000000000000000"),
mustParseBint("10000000000000000000000000000000"),
mustParseBint("100000000000000000000000000000000"),
mustParseBint("1000000000000000000000000000000000"),
mustParseBint("10000000000000000000000000000000000"),
mustParseBint("100000000000000000000000000000000000"),
mustParseBint("1000000000000000000000000000000000000"),
mustParseBint("10000000000000000000000000000000000000"),
mustParseBint("100000000000000000000000000000000000000"),
mustParseBint("1000000000000000000000000000000000000000"),
mustParseBint("10000000000000000000000000000000000000000"),
mustParseBint("100000000000000000000000000000000000000000"),
mustParseBint("1000000000000000000000000000000000000000000"),
mustParseBint("10000000000000000000000000000000000000000000"),
mustParseBint("100000000000000000000000000000000000000000000"),
mustParseBint("1000000000000000000000000000000000000000000000"),
mustParseBint("10000000000000000000000000000000000000000000000"),
mustParseBint("100000000000000000000000000000000000000000000000"),
mustParseBint("1000000000000000000000000000000000000000000000000"),
mustParseBint("10000000000000000000000000000000000000000000000000"),
mustParseBint("100000000000000000000000000000000000000000000000000"),
mustParseBint("1000000000000000000000000000000000000000000000000000"),
mustParseBint("10000000000000000000000000000000000000000000000000000"),
mustParseBint("100000000000000000000000000000000000000000000000000000"),
mustParseBint("1000000000000000000000000000000000000000000000000000000"),
mustParseBint("10000000000000000000000000000000000000000000000000000000"),
mustParseBint("100000000000000000000000000000000000000000000000000000000"),
mustParseBint("1000000000000000000000000000000000000000000000000000000000"),
mustParseBint("10000000000000000000000000000000000000000000000000000000000"),
mustParseBint("100000000000000000000000000000000000000000000000000000000000"),
mustParseBint("1000000000000000000000000000000000000000000000000000000000000"),
mustParseBint("10000000000000000000000000000000000000000000000000000000000000"),
mustParseBint("100000000000000000000000000000000000000000000000000000000000000"),
mustParseBint("1000000000000000000000000000000000000000000000000000000000000000"),
mustParseBint("10000000000000000000000000000000000000000000000000000000000000000"),
mustParseBint("100000000000000000000000000000000000000000000000000000000000000000"),
mustParseBint("1000000000000000000000000000000000000000000000000000000000000000000"),
mustParseBint("10000000000000000000000000000000000000000000000000000000000000000000"),
mustParseBint("100000000000000000000000000000000000000000000000000000000000000000000"),
mustParseBint("1000000000000000000000000000000000000000000000000000000000000000000000"),
mustParseBint("10000000000000000000000000000000000000000000000000000000000000000000000"),
mustParseBint("100000000000000000000000000000000000000000000000000000000000000000000000"),
mustParseBint("1000000000000000000000000000000000000000000000000000000000000000000000000"),
mustParseBint("10000000000000000000000000000000000000000000000000000000000000000000000000"),
mustParseBint("100000000000000000000000000000000000000000000000000000000000000000000000000"),
mustParseBint("1000000000000000000000000000000000000000000000000000000000000000000000000000"),
mustParseBint("10000000000000000000000000000000000000000000000000000000000000000000000000000"),
mustParseBint("100000000000000000000000000000000000000000000000000000000000000000000000000000"),
mustParseBint("1000000000000000000000000000000000000000000000000000000000000000000000000000000"),
mustParseBint("10000000000000000000000000000000000000000000000000000000000000000000000000000000"),
mustParseBint("100000000000000000000000000000000000000000000000000000000000000000000000000000000"),
mustParseBint("1000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
mustParseBint("10000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
mustParseBint("100000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
mustParseBint("1000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
mustParseBint("10000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
mustParseBint("100000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
mustParseBint("1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
mustParseBint("10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
mustParseBint("100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
mustParseBint("1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
mustParseBint("10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
mustParseBint("100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
mustParseBint("1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
mustParseBint("10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
mustParseBint("100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
mustParseBint("1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
mustParseBint("10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
mustParseBint("100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
mustParseBint("1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
}
// bfact is a cache of factorials, where bfact[x] = x!.
var bfact = [...]*bint{
mustParseBint("1"),
mustParseBint("1"),
mustParseBint("2"),
mustParseBint("6"),
mustParseBint("24"),
mustParseBint("120"),
mustParseBint("720"),
mustParseBint("5040"),
mustParseBint("40320"),
mustParseBint("362880"),
mustParseBint("3628800"),
mustParseBint("39916800"),
mustParseBint("479001600"),
mustParseBint("6227020800"),
mustParseBint("87178291200"),
mustParseBint("1307674368000"),
mustParseBint("20922789888000"),
mustParseBint("355687428096000"),
mustParseBint("6402373705728000"),
mustParseBint("121645100408832000"),
mustParseBint("2432902008176640000"),
mustParseBint("51090942171709440000"),
mustParseBint("1124000727777607680000"),
mustParseBint("25852016738884976640000"),
mustParseBint("620448401733239439360000"),
mustParseBint("15511210043330985984000000"),
mustParseBint("403291461126605635584000000"),
mustParseBint("10888869450418352160768000000"),
mustParseBint("304888344611713860501504000000"),
mustParseBint("8841761993739701954543616000000"),
mustParseBint("265252859812191058636308480000000"),
mustParseBint("8222838654177922817725562880000000"),
mustParseBint("263130836933693530167218012160000000"),
mustParseBint("8683317618811886495518194401280000000"),
mustParseBint("295232799039604140847618609643520000000"),
mustParseBint("10333147966386144929666651337523200000000"),
mustParseBint("371993326789901217467999448150835200000000"),
mustParseBint("13763753091226345046315979581580902400000000"),
mustParseBint("523022617466601111760007224100074291200000000"),
mustParseBint("20397882081197443358640281739902897356800000000"),
mustParseBint("815915283247897734345611269596115894272000000000"),
mustParseBint("33452526613163807108170062053440751665152000000000"),
mustParseBint("1405006117752879898543142606244511569936384000000000"),
mustParseBint("60415263063373835637355132068513997507264512000000000"),
mustParseBint("2658271574788448768043625811014615890319638528000000000"),
mustParseBint("119622220865480194561963161495657715064383733760000000000"),
mustParseBint("5502622159812088949850305428800254892961651752960000000000"),
mustParseBint("258623241511168180642964355153611979969197632389120000000000"),
mustParseBint("12413915592536072670862289047373375038521486354677760000000000"),
mustParseBint("608281864034267560872252163321295376887552831379210240000000000"),
mustParseBint("30414093201713378043612608166064768844377641568960512000000000000"),
mustParseBint("1551118753287382280224243016469303211063259720016986112000000000000"),
mustParseBint("80658175170943878571660636856403766975289505440883277824000000000000"),
mustParseBint("4274883284060025564298013753389399649690343788366813724672000000000000"),
mustParseBint("230843697339241380472092742683027581083278564571807941132288000000000000"),
mustParseBint("12696403353658275925965100847566516959580321051449436762275840000000000000"),
mustParseBint("710998587804863451854045647463724949736497978881168458687447040000000000000"),
mustParseBint("40526919504877216755680601905432322134980384796226602145184481280000000000000"),
mustParseBint("2350561331282878571829474910515074683828862318181142924420699914240000000000000"),
mustParseBint("138683118545689835737939019720389406345902876772687432540821294940160000000000000"),
mustParseBint("8320987112741390144276341183223364380754172606361245952449277696409600000000000000"),
mustParseBint("507580213877224798800856812176625227226004528988036003099405939480985600000000000000"),
mustParseBint("31469973260387937525653122354950764088012280797258232192163168247821107200000000000000"),
mustParseBint("1982608315404440064116146708361898137544773690227268628106279599612729753600000000000000"),
mustParseBint("126886932185884164103433389335161480802865516174545192198801894375214704230400000000000000"),
mustParseBint("8247650592082470666723170306785496252186258551345437492922123134388955774976000000000000000"),
mustParseBint("544344939077443064003729240247842752644293064388798874532860126869671081148416000000000000000"),
mustParseBint("36471110918188685288249859096605464427167635314049524593701628500267962436943872000000000000000"),
mustParseBint("2480035542436830599600990418569171581047399201355367672371710738018221445712183296000000000000000"),
mustParseBint("171122452428141311372468338881272839092270544893520369393648040923257279754140647424000000000000000"),
mustParseBint("11978571669969891796072783721689098736458938142546425857555362864628009582789845319680000000000000000"),
mustParseBint("850478588567862317521167644239926010288584608120796235886430763388588680378079017697280000000000000000"),
mustParseBint("61234458376886086861524070385274672740778091784697328983823014963978384987221689274204160000000000000000"),
mustParseBint("4470115461512684340891257138125051110076800700282905015819080092370422104067183317016903680000000000000000"),
mustParseBint("330788544151938641225953028221253782145683251820934971170611926835411235700971565459250872320000000000000000"),
mustParseBint("24809140811395398091946477116594033660926243886570122837795894512655842677572867409443815424000000000000000000"),
mustParseBint("1885494701666050254987932260861146558230394535379329335672487982961844043495537923117729972224000000000000000000"),
mustParseBint("145183092028285869634070784086308284983740379224208358846781574688061991349156420080065207861248000000000000000000"),
mustParseBint("11324281178206297831457521158732046228731749579488251990048962825668835325234200766245086213177344000000000000000000"),
mustParseBint("894618213078297528685144171539831652069808216779571907213868063227837990693501860533361810841010176000000000000000000"),
mustParseBint("71569457046263802294811533723186532165584657342365752577109445058227039255480148842668944867280814080000000000000000000"),
mustParseBint("5797126020747367985879734231578109105412357244731625958745865049716390179693892056256184534249745940480000000000000000000"),
mustParseBint("475364333701284174842138206989404946643813294067993328617160934076743994734899148613007131808479167119360000000000000000000"),
mustParseBint("39455239697206586511897471180120610571436503407643446275224357528369751562996629334879591940103770870906880000000000000000000"),
mustParseBint("3314240134565353266999387579130131288000666286242049487118846032383059131291716864129885722968716753156177920000000000000000000"),
mustParseBint("281710411438055027694947944226061159480056634330574206405101912752560026159795933451040286452340924018275123200000000000000000000"),
mustParseBint("24227095383672732381765523203441259715284870552429381750838764496720162249742450276789464634901319465571660595200000000000000000000"),
mustParseBint("2107757298379527717213600518699389595229783738061356212322972511214654115727593174080683423236414793504734471782400000000000000000000"),
mustParseBint("185482642257398439114796845645546284380220968949399346684421580986889562184028199319100141244804501828416633516851200000000000000000000"),
mustParseBint("16507955160908461081216919262453619309839666236496541854913520707833171034378509739399912570787600662729080382999756800000000000000000000"),
mustParseBint("1485715964481761497309522733620825737885569961284688766942216863704985393094065876545992131370884059645617234469978112000000000000000000000"),
mustParseBint("135200152767840296255166568759495142147586866476906677791741734597153670771559994765685283954750449427751168336768008192000000000000000000000"),
mustParseBint("12438414054641307255475324325873553077577991715875414356840239582938137710983519518443046123837041347353107486982656753664000000000000000000000"),
mustParseBint("1156772507081641574759205162306240436214753229576413535186142281213246807121467315215203289516844845303838996289387078090752000000000000000000000"),
mustParseBint("108736615665674308027365285256786601004186803580182872307497374434045199869417927630229109214583415458560865651202385340530688000000000000000000000"),
mustParseBint("10329978488239059262599702099394727095397746340117372869212250571234293987594703124871765375385424468563282236864226607350415360000000000000000000000"),
mustParseBint("991677934870949689209571401541893801158183648651267795444376054838492222809091499987689476037000748982075094738965754305639874560000000000000000000000"),
mustParseBint("96192759682482119853328425949563698712343813919172976158104477319333745612481875498805879175589072651261284189679678167647067832320000000000000000000000"),
mustParseBint("9426890448883247745626185743057242473809693764078951663494238777294707070023223798882976159207729119823605850588608460429412647567360000000000000000000000"),
}
// bscale is a scale of precomputed values in bexp, blog and bnlog10.
const bscale = 41
// bexp is a cache of powers of e, where bexp[x] = round(exp(x) * 10^41).
var bexp = [...]*bint{
mustParseBint("100000000000000000000000000000000000000000"),
mustParseBint("271828182845904523536028747135266249775725"),
mustParseBint("738905609893065022723042746057500781318032"),
mustParseBint("2008553692318766774092852965458171789698791"),
mustParseBint("5459815003314423907811026120286087840279074"),
mustParseBint("14841315910257660342111558004055227962348767"),
mustParseBint("40342879349273512260838718054338827960589990"),
mustParseBint("109663315842845859926372023828812143244221913"),
mustParseBint("298095798704172827474359209945288867375596794"),
mustParseBint("810308392757538400770999668943275996501147609"),
mustParseBint("2202646579480671651695790064528424436635351262"),
mustParseBint("5987414171519781845532648579225778161426107970"),
mustParseBint("16275479141900392080800520489848678317020928448"),
mustParseBint("44241339200892050332610277594908828178439130606"),
mustParseBint("120260428416477677774923677076785944941248654338"),
mustParseBint("326901737247211063930185504609172131550573854382"),
mustParseBint("888611052050787263676302374078145035080271982186"),
mustParseBint("2415495275357529821477543518038582387986756735272"),
mustParseBint("6565996913733051113878650325906003356921635578619"),
mustParseBint("17848230096318726084491003378872270388361973316517"),
mustParseBint("48516519540979027796910683054154055868463898894485"),
mustParseBint("131881573448321469720999888374530278509144443738048"),
mustParseBint("358491284613159156168115994597842068922269306503727"),
mustParseBint("974480344624890260003463268482297527764938776403601"),
mustParseBint("2648912212984347229413916215281188234087019861924853"),
mustParseBint("7200489933738587252416135146612615791522353381339528"),
mustParseBint("19572960942883876426977639787609534279203610095069759"),
mustParseBint("53204824060179861668374730434117744165925580428368881"),
mustParseBint("144625706429147517367704742299692885690206232950992288"),
mustParseBint("393133429714404207438862058084352768579694233344390219"),
mustParseBint("1068647458152446214699046865074140165002449500547305499"),
mustParseBint("2904884966524742523108568211167982566676469509029698025"),
mustParseBint("7896296018268069516097802263510822421995619511535233066"),
mustParseBint("21464357978591606462429776153126088036922590605479789726"),
mustParseBint("58346174252745488140290273461039101900365923894110810578"),
mustParseBint("158601345231343072812964462577466012517620395013452615427"),
mustParseBint("431123154711519522711342229285692539078886361678034773077"),
mustParseBint("1171914237280261130877293979119019452167536369446182238348"),
mustParseBint("3185593175711375622032867170129864599954220990518100775324"),
mustParseBint("8659340042399374695360693271926493424970185470019598659152"),
mustParseBint("23538526683701998540789991074903480450887161725455546723665"),
mustParseBint("63984349353005494922266340351557081887933662139685527945496"),
mustParseBint("173927494152050104739468130361123522614798405772500840103706"),
mustParseBint("472783946822934656147445756274428037081975196238093817096720"),
mustParseBint("1285160011435930827580929963214309925780114322075882587192003"),
mustParseBint("3493427105748509534803479723340609953341165649751815426012609"),
mustParseBint("9496119420602448874513364911711832310181715892107998785043817"),
mustParseBint("25813128861900673962328580021527338043163708299304406081061397"),
mustParseBint("70167359120976317386547159988611740545593799872532198375454888"),
mustParseBint("190734657249509969052509984095384844738818973054378340247523471"),
mustParseBint("518470552858707246408745332293348538482746910058384640190405693"),
mustParseBint("1409349082426938796449214331237016878868476079006371401705261930"),
mustParseBint("3831008000716576849303569548786199389870559745511657759083460282"),
mustParseBint("10413759433029087797183472933493796439804671331549132480520877196"),
mustParseBint("28307533032746939004420635480140745408503258935359068407207313389"),
mustParseBint("76947852651420171381827455901293939920707675726508409192316811729"),
mustParseBint("209165949601299615390707115721467377815296684749926726566766760571"),
mustParseBint("568571999933593222264034882063325330337215833448821774348912207348"),
mustParseBint("1545538935590103930353076691117462006836371709693083024671167680619"),
mustParseBint("4201210403790514254956593430719161768411111973299096786464257294200"),
mustParseBint("11420073898156842836629571831447656301980459595563958395650279917582"),
mustParseBint("31042979357019199087073421411071003720629501767637088151075640107741"),
mustParseBint("84383566687414544890733294803731179600806926796674104046181781869882"),
mustParseBint("229378315946960987909935284026861360046327934090304823013811995111671"),
mustParseBint("623514908081161688290923870892846974483139184623579991438859169901398"),
mustParseBint("1694889244410333714141783611437197494892623622551650491315726964531624"),
mustParseBint("4607186634331291542677318442806008689334900303709604073064405455741671"),
mustParseBint("12523631708422137805135219607443657675348852740449748164080228572102416"),
mustParseBint("34042760499317405213769071870043505953738761399456516360515457366001246"),
mustParseBint("92537817255877876002423979166873458734765992072084131193538452395984132"),
mustParseBint("251543867091916700626578117425211296140741297338314051382184015698611046"),
mustParseBint("683767122976274386675589282667771095594583593128908772566867276581148527"),
mustParseBint("1858671745284127980340370181254541194694639669623280326839338508664990931"),
mustParseBint("5052393630276104194557038332185764648536724497561717707892131665519301059"),
mustParseBint("13733829795401761877841885298085389315799830792499374638225617048580357052"),
mustParseBint("37332419967990016402549083172647001434277836869160000233938286724489039463"),
mustParseBint("101480038811388872783246178413171697577666481516811788087636356532265354778"),
mustParseBint("275851345452317020628646981990266194334152017524870885909958836251105051085"),
mustParseBint("749841699699012043467563059122406045470465897778615881301712227912805589523"),
mustParseBint("2038281066512668766832313753717263237469736486152421023534282361781159646993"),
mustParseBint("5540622384393510052571173395831661292485672883268532287030018828204570044975"),
mustParseBint("15060973145850305483525941301676749818993964921282654216298674950430270913981"),
mustParseBint("40939969621274546966609142293278290432005379219385277776474289917001253733742"),
mustParseBint("111286375479175941208707147818394080573407692072049303419300322944399234801420"),
mustParseBint("302507732220114233826656639644342874246903222230408816021160842116018977688417"),
mustParseBint("822301271462291351030432801640777469548628618847627403952393384974416103487573"),
mustParseBint("2235246603734715047443065732332714739877539251320997394294418376804179728019707"),
mustParseBint("6076030225056872149522328938130276075261375325962121014840857614538080439681426"),
mustParseBint("16516362549940018555283297962648587670696288420000448138888115075308155590848548"),
mustParseBint("44896128191743452462842455796453162777659805863718515260493172176526871508945617"),
mustParseBint("122040329431784080200271003513636975397074642109976754624434382982431272735857720"),
mustParseBint("331740009833574262575551610785259190960301458118233082704880726006914701279896785"),
mustParseBint("901762840503429893140099598217090525912874611320072683317921490664655375792186090"),
mustParseBint("2451245542920085785552772943110915342348756414964690609545833883604150632588240812"),
mustParseBint("6663176216410895834244814050240873262687388754209656559399850257165488523386744387"),
mustParseBint("18112390828890232821937987580988159250478971745441286187030605794738143642445974469"),
mustParseBint("49234582860120583997548620591133044948377995712526602794095096218650199367793067780"),
mustParseBint("133833471920426950046173640870611502907671745721364460012055487319044738767664950934"),
mustParseBint("363797094760880457928774382676018572989310125586408296287549241498281217782703355658"),
mustParseBint("988903031934694677056003096713803710140508260719933517340199715371109444700740600601"),
}
// blog is a cache of natural logarithms, where blog[x] = round(ln(x) * 10^41).
var blog = [...]*bint{
nil,
mustParseBint("0"),
mustParseBint("69314718055994530941723212145817656807550"),
mustParseBint("109861228866810969139524523692252570464749"),
mustParseBint("138629436111989061883446424291635313615100"),
mustParseBint("160943791243410037460075933322618763952560"),
mustParseBint("179175946922805500081247735838070227272299"),
mustParseBint("194591014905531330510535274344317972963708"),
mustParseBint("207944154167983592825169636437452970422650"),
mustParseBint("219722457733621938279049047384505140929498"),
mustParseBint("230258509299404568401799145468436420760110"),
mustParseBint("239789527279837054406194357796512929982171"),
mustParseBint("248490664978800031022970947983887884079849"),
mustParseBint("256494935746153673605348744156531860480527"),
mustParseBint("263905732961525861452258486490135629771258"),
mustParseBint("270805020110221006599600457014871334417309"),
mustParseBint("277258872223978123766892848583270627230200"),
mustParseBint("283321334405621608024953461787312653558820"),
mustParseBint("289037175789616469220772259530322797737048"),
mustParseBint("294443897916644046000902743188785353723738"),
mustParseBint("299573227355399099343522357614254077567660"),
mustParseBint("304452243772342299650059798036570543428458"),
mustParseBint("309104245335831585347917569942330586789721"),
mustParseBint("313549421592914969080675283181019611844238"),
mustParseBint("317805383034794561964694160129705540887399"),
mustParseBint("321887582486820074920151866645237527905120"),
mustParseBint("325809653802148204547071956302349517288077"),
mustParseBint("329583686600432907418573571076757711394247"),
mustParseBint("333220451017520392393981698635953286578808"),
mustParseBint("336729582998647402718327203236191160549451"),
mustParseBint("340119738166215537541323669160688991224859"),
mustParseBint("343398720448514624592916432454235721044994"),
mustParseBint("346573590279972654708616060729088284037750"),
mustParseBint("349650756146648023545718881488765500446920"),
mustParseBint("352636052461616138966676673933130310366370"),
mustParseBint("355534806148941367970611207666936736916269"),
mustParseBint("358351893845611000162495471676140454544598"),
mustParseBint("361091791264422444436809567103144716390008"),
mustParseBint("363758615972638576942625955334603010531288"),
mustParseBint("366356164612964642744873267848784430945276"),
mustParseBint("368887945411393630285245569760071734375210"),
mustParseBint("371357206670430780386676337303740758837641"),
mustParseBint("373766961828336830591783010182388200236008"),
mustParseBint("376120011569356242347284251334584703555914"),
mustParseBint("378418963391826116289640782088148243597271"),
mustParseBint("380666248977031975739124980707123904882058"),
mustParseBint("382864139648909500022398495326837268651788"),
mustParseBint("385014760171005858682095066977217370889605"),
mustParseBint("387120101090789092906417372275523197694949"),
mustParseBint("389182029811062661021070548688635945927417"),
mustParseBint("391202300542814605861875078791055184712670"),
mustParseBint("393182563272432577164477985479565224023569"),
mustParseBint("395124371858142735488795168448167174095627"),
mustParseBint("397029191355212183414446913902905777035998"),
mustParseBint("398898404656427438360296783222575368201797"),
mustParseBint("400733318523247091866270291119131693934731"),
mustParseBint("402535169073514923335704910781770943386359"),
mustParseBint("404305126783455015140427266881037924188487"),
mustParseBint("406044301054641933660050415382008817357001"),
mustParseBint("407753744390571945061605037371969762406335"),
mustParseBint("409434456222210068483046881306506648032409"),
mustParseBint("411087386417331124875138910342561474631568"),
mustParseBint("412713438504509155534639644600053377852544"),
mustParseBint("414313472639153268789584321728823113893207"),
mustParseBint("415888308335967185650339272874905940845300"),
mustParseBint("417438726989563711065424677479150624433087"),
mustParseBint("418965474202642554487442093634583157254470"),
mustParseBint("420469261939096605967007199636372275056693"),
mustParseBint("421950770517610669908399886078947967173920"),
mustParseBint("423410650459725938220199806873272182308987"),
mustParseBint("424849524204935898912334419812754393723819"),
mustParseBint("426267987704131542132945453251303409675958"),
mustParseBint("427666611901605531104218683821958111352148"),
mustParseBint("429045944114839112909210885743854257090475"),
mustParseBint("430406509320416975378532779248962373197558"),
mustParseBint("431748811353631044059676390337490098369869"),
mustParseBint("433073334028633107884349167480420667338838"),
mustParseBint("434380542185368384916729632140830902945879"),
mustParseBint("435670882668959173686596479994602087752826"),
mustParseBint("436944785246702149417294554148141092217354"),
mustParseBint("438202663467388161226968781905889391182760"),
mustParseBint("439444915467243876558098094769010281858996"),
mustParseBint("440671924726425311328399549449558415645191"),
mustParseBint("441884060779659792347547222329137045302931"),
mustParseBint("443081679884331361533506222328205857043558"),
mustParseBint("444265125649031645485029395109931417511380"),
mustParseBint("445434729625350773289007463480402360363464"),
mustParseBint("446590811865458371857851726928443731014200"),
mustParseBint("447733681447820647231363994233965900404821"),
mustParseBint("448863636973213983831781554066984921940466"),
mustParseBint("449980967033026506680848192852941561689608"),
mustParseBint("451085950651685004115884018500849833444235"),
mustParseBint("452178857704904030964121707472654925459338"),
mustParseBint("453259949315325593732440956146488291509743"),
mustParseBint("454329478227000389623818279123035027697155"),
mustParseBint("455387689160054083460978676511404117676298"),
mustParseBint("456434819146783623848140584421340854502499"),
mustParseBint("457471097850338282211672162170396171380891"),
mustParseBint("458496747867057191962793760834453602734967"),
mustParseBint("459511985013458992685243405181018070911669"),
}
// bnlog10 is a cache of multiples of the natural logarithm of 10, where bnlog10[x] = round(x * ln(10) * 10^41).
var bnlog10 = [...]*bint{
mustParseBint("0"),
mustParseBint("230258509299404568401799145468436420760110"),
mustParseBint("460517018598809136803598290936872841520220"),
mustParseBint("690775527898213705205397436405309262280330"),
mustParseBint("921034037197618273607196581873745683040441"),
mustParseBint("1151292546497022842008995727342182103800551"),
mustParseBint("1381551055796427410410794872810618524560661"),
mustParseBint("1611809565095831978812594018279054945320771"),
mustParseBint("1842068074395236547214393163747491366080881"),
mustParseBint("2072326583694641115616192309215927786840991"),
mustParseBint("2302585092994045684017991454684364207601101"),
mustParseBint("2532843602293450252419790600152800628361212"),
mustParseBint("2763102111592854820821589745621237049121322"),
mustParseBint("2993360620892259389223388891089673469881432"),
mustParseBint("3223619130191663957625188036558109890641542"),
mustParseBint("3453877639491068526026987182026546311401652"),
mustParseBint("3684136148790473094428786327494982732161762"),
mustParseBint("3914394658089877662830585472963419152921873"),
mustParseBint("4144653167389282231232384618431855573681983"),
mustParseBint("4374911676688686799634183763900291994442093"),
mustParseBint("4605170185988091368035982909368728415202203"),
mustParseBint("4835428695287495936437782054837164835962313"),
mustParseBint("5065687204586900504839581200305601256722423"),
mustParseBint("5295945713886305073241380345774037677482533"),
mustParseBint("5526204223185709641643179491242474098242644"),
mustParseBint("5756462732485114210044978636710910519002754"),
mustParseBint("5986721241784518778446777782179346939762864"),
mustParseBint("6216979751083923346848576927647783360522974"),
mustParseBint("6447238260383327915250376073116219781283084"),
mustParseBint("6677496769682732483652175218584656202043194"),
mustParseBint("6907755278982137052053974364053092622803304"),
mustParseBint("7138013788281541620455773509521529043563415"),
mustParseBint("7368272297580946188857572654989965464323525"),
mustParseBint("7598530806880350757259371800458401885083635"),
mustParseBint("7828789316179755325661170945926838305843745"),
mustParseBint("8059047825479159894062970091395274726603855"),
mustParseBint("8289306334778564462464769236863711147363965"),
mustParseBint("8519564844077969030866568382332147568124076"),
mustParseBint("8749823353377373599268367527800583988884186"),
mustParseBint("8980081862676778167670166673269020409644296"),
mustParseBint("9210340371976182736071965818737456830404406"),
mustParseBint("9440598881275587304473764964205893251164516"),
mustParseBint("9670857390574991872875564109674329671924626"),
mustParseBint("9901115899874396441277363255142766092684736"),
mustParseBint("10131374409173801009679162400611202513444847"),
mustParseBint("10361632918473205578080961546079638934204957"),
mustParseBint("10591891427772610146482760691548075354965067"),
mustParseBint("10822149937072014714884559837016511775725177"),
mustParseBint("11052408446371419283286358982484948196485287"),
mustParseBint("11282666955670823851688158127953384617245397"),
mustParseBint("11512925464970228420089957273421821038005507"),
mustParseBint("11743183974269632988491756418890257458765618"),
mustParseBint("11973442483569037556893555564358693879525728"),
mustParseBint("12203700992868442125295354709827130300285838"),
mustParseBint("12433959502167846693697153855295566721045948"),
mustParseBint("12664218011467251262098953000764003141806058"),
mustParseBint("12894476520766655830500752146232439562566168"),
mustParseBint("13124735030066060398902551291700875983326278"),
mustParseBint("13354993539365464967304350437169312404086389"),
mustParseBint("13585252048664869535706149582637748824846499"),
mustParseBint("13815510557964274104107948728106185245606609"),
mustParseBint("14045769067263678672509747873574621666366719"),
mustParseBint("14276027576563083240911547019043058087126829"),
mustParseBint("14506286085862487809313346164511494507886939"),
mustParseBint("14736544595161892377715145309979930928647050"),
mustParseBint("14966803104461296946116944455448367349407160"),
mustParseBint("15197061613760701514518743600916803770167270"),
mustParseBint("15427320123060106082920542746385240190927380"),
mustParseBint("15657578632359510651322341891853676611687490"),
mustParseBint("15887837141658915219724141037322113032447600"),
mustParseBint("16118095650958319788125940182790549453207710"),
mustParseBint("16348354160257724356527739328258985873967821"),
mustParseBint("16578612669557128924929538473727422294727931"),
mustParseBint("16808871178856533493331337619195858715488041"),
mustParseBint("17039129688155938061733136764664295136248151"),
mustParseBint("17269388197455342630134935910132731557008261"),
mustParseBint("17499646706754747198536735055601167977768371"),
mustParseBint("17729905216054151766938534201069604398528481"),
mustParseBint("17960163725353556335340333346538040819288592"),
mustParseBint("18190422234652960903742132492006477240048702"),
mustParseBint("18420680743952365472143931637474913660808812"),
mustParseBint("18650939253251770040545730782943350081568922"),
mustParseBint("18881197762551174608947529928411786502329032"),
mustParseBint("19111456271850579177349329073880222923089142"),
mustParseBint("19341714781149983745751128219348659343849253"),
mustParseBint("19571973290449388314152927364817095764609363"),
mustParseBint("19802231799748792882554726510285532185369473"),
mustParseBint("20032490309048197450956525655753968606129583"),
mustParseBint("20262748818347602019358324801222405026889693"),
mustParseBint("20493007327647006587760123946690841447649803"),
mustParseBint("20723265836946411156161923092159277868409913"),
mustParseBint("20953524346245815724563722237627714289170024"),
mustParseBint("21183782855545220292965521383096150709930134"),
mustParseBint("21414041364844624861367320528564587130690244"),
mustParseBint("21644299874144029429769119674033023551450354"),
mustParseBint("21874558383443433998170918819501459972210464"),
mustParseBint("22104816892742838566572717964969896392970574"),
mustParseBint("22335075402042243134974517110438332813730684"),
mustParseBint("22565333911341647703376316255906769234490795"),
mustParseBint("22795592420641052271778115401375205655250905"),
}
// mustParseBint converts a string to *big.Int, panicking on error.
// Use only for package variable initialization and test code!
func mustParseBint(s string) *bint {
z, ok := new(big.Int).SetString(s, 10)
if !ok {
panic(fmt.Errorf("mustParseBint(%q) failed: parsing error", s))
}
if z.Sign() < 0 {
panic(fmt.Errorf("mustParseBint(%q) failed: negative number", s))
}
return (*bint)(z)
}
func (z *bint) sign() int {
return (*big.Int)(z).Sign()
}
func (z *bint) cmp(x *bint) int {
return (*big.Int)(z).Cmp((*big.Int)(x))
}
func (z *bint) string() string {
return (*big.Int)(z).String()
}
func (z *bint) setBint(x *bint) {
(*big.Int)(z).Set((*big.Int)(x))
}
func (z *bint) setInt64(x int64) {
(*big.Int)(z).SetInt64(x)
}
func (z *bint) setBytes(buf []byte) {
(*big.Int)(z).SetBytes(buf)
}
func (z *bint) setFint(x fint) {
(*big.Int)(z).SetUint64(uint64(x))
}
// fint converts *big.Int to uint64.
// If z cannot be represented as uint64, the result is undefined.
func (z *bint) fint() fint {
f := (*big.Int)(z).Uint64()
return fint(f)
}
// add calculates z = x + y.
func (z *bint) add(x, y *bint) {
(*big.Int)(z).Add((*big.Int)(x), (*big.Int)(y))
}
// inc calcualtes z = x + 1.
func (z *bint) inc(x *bint) {
y := bpow10[0]
z.add(x, y)
}
// sub calculates z = x - y.
func (z *bint) sub(x, y *bint) {
(*big.Int)(z).Sub((*big.Int)(x), (*big.Int)(y))
}
// subAbs calculates z = |x - y|.
func (z *bint) subAbs(x, y *bint) {
switch x.cmp(y) {
case 1:
z.sub(x, y)
default:
z.sub(y, x)
}
}
// dbl (Double) calculates z = x * 2.
func (z *bint) dbl(x *bint) {
(*big.Int)(z).Lsh((*big.Int)(x), 1)
}
// hlf (Half) calculates z = ⌊x / 2⌋.
func (z *bint) hlf(x *bint) {
(*big.Int)(z).Rsh((*big.Int)(x), 1)
}
// mul calculates z = x * y.
func (z *bint) mul(x, y *bint) {
// Copying x, y to prevent heap allocations.
if z == x {
b := getBint()
defer putBint(b)
b.setBint(x)
x = b
}
if z == y {
b := getBint()
defer putBint(b)
b.setBint(y)
y = b
}
(*big.Int)(z).Mul((*big.Int)(x), (*big.Int)(y))
}
// pow calculates z = x^y.
// If y is negative, the result is unpredictable.
func (z *bint) pow(x, y *bint) {
(*big.Int)(z).Exp((*big.Int)(x), (*big.Int)(y), nil)
}
// pow10 calculates z = 10^power.
// If power is negative, the result is unpredictable.
func (z *bint) pow10(power int) {
x := getBint()
defer putBint(x)
x.setInt64(10)
y := getBint()
defer putBint(y)
y.setInt64(int64(power))
z.pow(x, y)
}
// quo calculates z = ⌊x / y⌋.
func (z *bint) quo(x, y *bint) {
// Passing r to prevent heap allocations.
r := getBint()
defer putBint(r)
z.quoRem(x, y, r)
}
// quoRem calculates z = ⌊x / y⌋, r = x - y * z.
func (z *bint) quoRem(x, y, r *bint) {
(*big.Int)(z).QuoRem((*big.Int)(x), (*big.Int)(y), (*big.Int)(r))
}
func (z *bint) isOdd() bool {
return (*big.Int)(z).Bit(0) != 0
}
// lsh (Left Shift) calculates z = x * 10^shift.
func (z *bint) lsh(x *bint, shift int) {
var y *bint
if shift < len(bpow10) {
y = bpow10[shift]
} else {
y = getBint()
defer putBint(y)
y.pow10(shift)
}
z.mul(x, y)
}
// fsa (Fused Shift and Addition) calculates z = x * 10^shift + f.
func (z *bint) fsa(x *bint, shift int, f fint) {
y := getBint()
defer putBint(y)
y.setFint(f)
z.lsh(x, shift)
z.add(z, y)
}
// rshDown (Right Shift) calculates z = ⌊x / 10^shift⌋ and rounds
// result towards zero.
func (z *bint) rshDown(x *bint, shift int) {
// Special cases
switch {
case x.sign() == 0:
z.setFint(0)
return
case shift <= 0:
z.setBint(x)
return
}
// General case
var y *bint
if shift < len(bpow10) {
y = bpow10[shift]
} else {
y = getBint()
defer putBint(y)
y.pow10(shift)
}
z.quo(x, y)
}
// rshHalfEven (Right Shift) calculates z = round(x / 10^shift) and
// rounds result using "half to even" rule.
func (z *bint) rshHalfEven(x *bint, shift int) {
// Special cases
switch {
case x.sign() == 0:
z.setFint(0)
return
case shift <= 0:
z.setBint(x)
return
}
// General case
var y, r *bint
r = getBint()
defer putBint(r)
if shift < len(bpow10) {
y = bpow10[shift]
} else {
y = getBint()
defer putBint(y)
y.pow10(shift)
}
z.quoRem(x, y, r)
r.dbl(r) // r = r * 2
switch y.cmp(r) {
case -1:
z.inc(z) // z = z + 1
case 0:
// half-to-even
if z.isOdd() {
z.inc(z) // z = z + 1
}
}
}
// prec returns length of z in decimal digits.
// prec assumes that 0 has no digits.
// If z is negative, the result is unpredictable.
//
// z.prec() is significantly faster than len(z.string()),
// if z has less than len(bpow10) digits.
func (z *bint) prec() int {
// Special case
if z.cmp(bpow10[len(bpow10)-1]) > 0 {
return len(z.string())
}
// General case
left, right := 0, len(bpow10)
for left < right {
mid := (left + right) / 2
if z.cmp(bpow10[mid]) < 0 {
right = mid
} else {
left = mid + 1
}
}
return left
}
// hasPrec checks if z has a given number of digits or more.
// hasPrec assumes that 0 has no digits.
// If z is negative, the result is unpredictable.
//
// z.hasPrec(p) is significantly faster than z.prec() >= p,
// if z has no more than len(bpow10) digits.
func (z *bint) hasPrec(prec int) bool {
// Special cases
switch {
case prec < 1:
return true
case prec > len(bpow10):
return len(z.string()) >= prec
}
// General case
return z.cmp(bpow10[prec-1]) >= 0
}
// bpool is a cache of reusable *big.Int instances.
var bpool = sync.Pool{
New: func() any {
return (*bint)(new(big.Int))
},
}
// getBint obtains a *big.Int from the pool.
func getBint() *bint {
return bpool.Get().(*bint)
}
// putBint returns the *big.Int into the pool.
func putBint(b *bint) {
bpool.Put(b)
}
================================================
FILE: integer_test.go
================================================
package decimal
import (
"math"
"testing"
)
func TestFint_add(t *testing.T) {
cases := []struct {
x, y, wantCoef fint
wantOk bool
}{
{0, 0, 0, true},
{maxFint, 1, 0, false},
}
for _, tt := range cases {
x, y := tt.x, tt.y
gotCoef, gotOk := x.add(y)
if gotCoef != tt.wantCoef || gotOk != tt.wantOk {
t.Errorf("%v.add(%v) = %v, %v, want %v, %v", x, y, gotCoef, gotOk, tt.wantCoef, tt.wantOk)
}
}
}
func TestFint_mul(t *testing.T) {
cases := []struct {
x, y, wantCoef fint
wantOk bool
}{
{0, 0, 0, true},
{10, 10, 100, true},
{maxFint, 2, 0, false},
}
for _, tt := range cases {
x, y := tt.x, tt.y
gotCoef, gotOk := x.mul(y)
if gotCoef != tt.wantCoef || gotOk != tt.wantOk {
t.Errorf("%v.mul(%v) = %v, %v, want %v, %v", x, y, gotCoef, gotOk, tt.wantCoef, tt.wantOk)
}
}
}
func TestFint_quo(t *testing.T) {
cases := []struct {
x, y, wantCoef fint
wantOk bool
}{
{1, 0, 0, false},
{1, 1, 1, true},
{2, 4, 0, false},
{20, 4, 5, true},
{20, 3, 0, false},
{maxFint, 2, 0, false},
}
for _, tt := range cases {
x, y := tt.x, tt.y
gotCoef, gotOk := x.quo(y)
if gotCoef != tt.wantCoef || gotOk != tt.wantOk {
t.Errorf("%v.quo(%v) = %v, %v, want %v, %v", x, y, gotCoef, gotOk, tt.wantCoef, tt.wantOk)
}
}
}
func TestFint_quoRem(t *testing.T) {
cases := []struct {
x, y, wantQuo, wantRem fint
wantOk bool
}{
{1, 0, 0, 0, false},
{1, 1, 1, 0, true},
{2, 4, 0, 2, true},
{20, 4, 5, 0, true},
{20, 3, 6, 2, true},
{maxFint, 2, maxFint / 2, 1, true},
}
for _, tt := range cases {
x, y := tt.x, tt.y
gotQuo, gotRem, gotOk := x.quoRem(y)
if gotQuo != tt.wantQuo || gotRem != tt.wantRem || gotOk != tt.wantOk {
t.Errorf("%v.quoRem(%v) = %v, %v, %v, want %v, %v, %v", x, y, gotQuo, gotRem, gotOk, tt.wantQuo, tt.wantRem, tt.wantOk)
}
}
}
func TestFint_subAbs(t *testing.T) {
cases := []struct {
x, y, wantCoef fint
}{
{1, 0, 1},
{1, 1, 0},
{2, 4, 2},
{20, 4, 16},
{20, 3, 17},
{maxFint, 2, 9_999_999_999_999_999_997},
{maxFint, 1, 9_999_999_999_999_999_998},
{maxFint, 0, maxFint},
}
for _, tt := range cases {
x, y := tt.x, tt.y
gotCoef := x.subAbs(y)
if gotCoef != tt.wantCoef {
t.Errorf("%v.subAbs(%v) = %v, want %v", x, y, gotCoef, tt.wantCoef)
}
}
}
func TestFint_lsh(t *testing.T) {
cases := []struct {
x fint
shift int
wantCoef fint
wantOk bool
}{
{0, 0, 0, true},
{10, 0, 10, true},
{0, 1, 0, true},
{10, 1, 100, true},
{1, 20, 0, false},
}
for _, tt := range cases {
x := tt.x
gotCoef, gotOk := x.lsh(tt.shift)
if gotCoef != tt.wantCoef || gotOk != tt.wantOk {
t.Errorf("%v.lsh(%v) = %v, %v, want %v, %v", x, tt.shift, gotCoef, gotOk, tt.wantCoef, tt.wantOk)
}
}
}
func TestFint_fsa(t *testing.T) {
cases := []struct {
x fint
shift int
y byte
wantCoef fint
wantOk bool
}{
{0, 0, 0, 0, true},
{1, 1, 1, 11, true},
{2, 2, 2, 202, true},
{3, 3, 3, 3_003, true},
{1, 20, 0, 0, false},
{maxFint, 0, 1, 0, false},
}
for _, tt := range cases {
x, y, shift := tt.x, tt.y, tt.shift
gotCoef, gotOk := x.fsa(shift, y)
if gotCoef != tt.wantCoef || gotOk != tt.wantOk {
t.Errorf("%v.fsa(%v, %v) = %v, %v, want %v, %v", x, shift, y, gotCoef, gotOk, tt.wantCoef, tt.wantOk)
}
}
}
func TestFint_rshHalfEven(t *testing.T) {
cases := []struct {
x fint
shift int
want fint
}{
// Negative shift
{1, -1, 1},
// Rounding
{1, 0, 1},
{20, 1, 2},
{18, 1, 2},
{15, 1, 2},
{12, 1, 1},
{10, 1, 1},
{8, 1, 1},
{5, 1, 0},
{2, 1, 0},
{maxFint, 19, 1},
// Large shifts
{0, 17, 0},
{0, 18, 0},
{0, 19, 0},
{0, 20, 0},
{0, 21, 0},
{1, 17, 0},
{1, 18, 0},
{1, 19, 0},
{1, 20, 0},
{1, 21, 0},
{5_000_000_000_000_000_000, 17, 50},
{5_000_000_000_000_000_000, 18, 5},
{5_000_000_000_000_000_000, 19, 0},
{5_000_000_000_000_000_000, 20, 0},
{5_000_000_000_000_000_000, 21, 0},
{5_000_000_000_000_000_001, 17, 50},
{5_000_000_000_000_000_001, 18, 5},
{5_000_000_000_000_000_001, 19, 1},
{5_000_000_000_000_000_001, 20, 0},
{5_000_000_000_000_000_001, 21, 0},
{maxFint, 17, 100},
{maxFint, 18, 10},
{maxFint, 19, 1},
{maxFint, 20, 0},
{maxFint, 21, 0},
{10_000_000_000_000_000_000, 17, 100},
{10_000_000_000_000_000_000, 18, 10},
{10_000_000_000_000_000_000, 19, 1},
{10_000_000_000_000_000_000, 20, 0},
{10_000_000_000_000_000_000, 21, 0},
{14_999_999_999_999_999_999, 17, 150},
{14_999_999_999_999_999_999, 18, 15},
{14_999_999_999_999_999_999, 19, 1},
{14_999_999_999_999_999_999, 20, 0},
{14_999_999_999_999_999_999, 21, 0},
{15_000_000_000_000_000_000, 17, 150},
{15_000_000_000_000_000_000, 18, 15},
{15_000_000_000_000_000_000, 19, 2},
{15_000_000_000_000_000_000, 20, 0},
{15_000_000_000_000_000_000, 21, 0},
{math.MaxUint64, 17, 184},
{math.MaxUint64, 18, 18},
{math.MaxUint64, 19, 2},
{math.MaxUint64, 20, 0},
{math.MaxUint64, 21, 0},
}
for _, tt := range cases {
got := tt.x.rshHalfEven(tt.shift)
if got != tt.want {
t.Errorf("%v.rshHalfEven(%v) = %v, want %v", tt.x, tt.shift, got, tt.want)
}
}
}
func TestFint_rshUp(t *testing.T) {
cases := []struct {
x fint
shift int
want fint
}{
// Negative shift
{1, -1, 1},
// Rounding
{20, 1, 2},
{18, 1, 2},
{15, 1, 2},
{12, 1, 2},
{10, 1, 1},
{8, 1, 1},
{5, 1, 1},
{2, 1, 1},
// Large shifts
{0, 17, 0},
{0, 18, 0},
{0, 19, 0},
{0, 20, 0},
{0, 21, 0},
{1, 17, 1},
{1, 18, 1},
{1, 19, 1},
{1, 20, 1},
{1, 21, 1},
{maxFint, 17, 100},
{maxFint, 18, 10},
{maxFint, 19, 1},
{maxFint, 20, 1},
{maxFint, 21, 1},
{10_000_000_000_000_000_000, 17, 100},
{10_000_000_000_000_000_000, 18, 10},
{10_000_000_000_000_000_000, 19, 1},
{10_000_000_000_000_000_000, 20, 1},
{10_000_000_000_000_000_000, 21, 1},
{math.MaxUint64, 17, 185},
{math.MaxUint64, 18, 19},
{math.MaxUint64, 19, 2},
{math.MaxUint64, 20, 1},
{math.MaxUint64, 21, 1},
}
for _, tt := range cases {
got := tt.x.rshUp(tt.shift)
if got != tt.want {
t.Errorf("%v.rshUp(%v) = %v, want %v", tt.x, tt.shift, got, tt.want)
}
}
}
func TestFint_rshDown(t *testing.T) {
cases := []struct {
x fint
shift int
want fint
}{
// Negative shift
{1, -1, 1},
// Rounding
{1, 0, 1},
{20, 1, 2},
{18, 1, 1},
{15, 1, 1},
{12, 1, 1},
{10, 1, 1},
{8, 1, 0},
{5, 1, 0},
{2, 1, 0},
// Large shifts
{0, 17, 0},
{0, 18, 0},
{0, 19, 0},
{0, 20, 0},
{0, 21, 0},
{1, 17, 0},
{1, 18, 0},
{1, 19, 0},
{1, 20, 0},
{1, 21, 0},
{maxFint, 17, 99},
{maxFint, 18, 9},
{maxFint, 19, 0},
{maxFint, 20, 0},
{maxFint, 21, 0},
{10_000_000_000_000_000_000, 17, 100},
{10_000_000_000_000_000_000, 18, 10},
{10_000_000_000_000_000_000, 19, 1},
{10_000_000_000_000_000_000, 20, 0},
{10_000_000_000_000_000_000, 21, 0},
{math.MaxUint64, 17, 184},
{math.MaxUint64, 18, 18},
{math.MaxUint64, 19, 1},
{math.MaxUint64, 20, 0},
{math.MaxUint64, 21, 0},
}
for _, tt := range cases {
got := tt.x.rshDown(tt.shift)
if got != tt.want {
t.Errorf("%v.rshDown(%v) = %v, want %v", tt.x, tt.shift, got, tt.want)
}
}
}
func TestFint_prec(t *testing.T) {
cases := []struct {
x fint
want int
}{
{0, 0},
{1, 1},
{9, 1},
{10, 2},
{99, 2},
{100, 3},
{999, 3},
{1_000, 4},
{9_999, 4},
{10_000, 5},
{99_999, 5},
{100_000, 6},
{999_999, 6},
{1_000_000, 7},
{9_999_999, 7},
{10_000_000, 8},
{99_999_999, 8},
{100_000_000, 9},
{999_999_999, 9},
{1_000_000_000, 10},
{9_999_999_999, 10},
{10_000_000_000, 11},
{99_999_999_999, 11},
{100_000_000_000, 12},
{999_999_999_999, 12},
{1_000_000_000_000, 13},
{9_999_999_999_999, 13},
{10_000_000_000_000, 14},
{99_999_999_999_999, 14},
{100_000_000_000_000, 15},
{999_999_999_999_999, 15},
{1_000_000_000_000_000, 16},
{9_999_999_999_999_999, 16},
{10_000_000_000_000_000, 17},
{99_999_999_999_999_999, 17},
{100_000_000_000_000_000, 18},
{999_999_999_999_999_999, 18},
{1_000_000_000_000_000_000, 19},
{maxFint, 19},
{10_000_000_000_000_000_000, 20},
{math.MaxUint64, 20},
}
for _, tt := range cases {
got := tt.x.prec()
if got != tt.want {
t.Errorf("%v.prec() = %v, want %v", tt.x, got, tt.want)
}
}
}
func TestFint_ntz(t *testing.T) {
cases := []struct {
x fint
want int
}{
{0, 0},
{1, 0},
{9, 0},
{10, 1},
{99, 0},
{100, 2},
{999, 0},
{1_000, 3},
{9_999, 0},
{10_000, 4},
{99_999, 0},
{100_000, 5},
{999_999, 0},
{1_000_000, 6},
{9_999_999, 0},
{10_000_000, 7},
{99_999_999, 0},
{100_000_000, 8},
{999_999_999, 0},
{1_000_000_000, 9},
{9_999_999_999, 0},
{10_000_000_000, 10},
{99_999_999_999, 0},
{100_000_000_000, 11},
{999_999_999_999, 0},
{1_000_000_000_000, 12},
{9_999_999_999_999, 0},
{10_000_000_000_000, 13},
{99_999_999_999_999, 0},
{100_000_000_000_000, 14},
{999_999_999_999_999, 0},
{1_000_000_000_000_000, 15},
{9_999_999_999_999_999, 0},
{10_000_000_000_000_000, 16},
{99_999_999_999_999_999, 0},
{100_000_000_000_000_000, 17},
{999_999_999_999_999_999, 0},
{1_000_000_000_000_000_000, 18},
{1_000_000_000_000_000_001, 0},
{maxFint, 0},
{10_000_000_000_000_000_000, 19},
{math.MaxUint64, 0},
}
for _, tt := range cases {
got := tt.x.ntz()
if got != tt.want {
t.Errorf("%v.ntz() = %v, want %v", tt.x, got, tt.want)
}
}
}
func TestFint_hasPrec(t *testing.T) {
cases := []struct {
x fint
prec int
want bool
}{
{0, 0, true},
{0, 1, false},
{0, 2, false},
{1, 0, true},
{1, 1, true},
{1, 2, false},
{9, 0, true},
{9, 1, true},
{9, 2, false},
{10, 0, true},
{10, 1, true},
{10, 2, true},
{10, 3, false},
{99, 0, true},
{99, 1, true},
{99, 2, true},
{99, 3, false},
{100_000_000_000_000, 17, false},
{1_000_000_000_000_000, 17, false},
{10_000_000_000_000_000, 17, true},
{100_000_000_000_000_000, 17, true},
{1_000_000_000_000_000_000, 17, true},
{1_000_000_000_000_000_000, 17, true},
{1_000_000_000_000_000_000, 18, true},
{1_000_000_000_000_000_000, 19, true},
{1_000_000_000_000_000_000, 20, false},
{1_000_000_000_000_000_000, 21, false},
{maxFint, 17, true},
{maxFint, 18, true},
{maxFint, 19, true},
{maxFint, 20, false},
{maxFint, 21, false},
{10_000_000_000_000_000_000, 17, true},
{10_000_000_000_000_000_000, 18, true},
{10_000_000_000_000_000_000, 19, true},
{10_000_000_000_000_000_000, 20, true},
{10_000_000_000_000_000_000, 21, false},
{math.MaxUint64, 17, true},
{math.MaxUint64, 18, true},
{math.MaxUint64, 19, true},
{math.MaxUint64, 20, true},
{math.MaxUint64, 21, false},
}
for _, tt := range cases {
got := tt.x.hasPrec(tt.prec)
if got != tt.want {
t.Errorf("%v.hasPrec(%v) = %v, want %v", tt.x, tt.prec, got, tt.want)
}
}
}
func TestBint_rshDown(t *testing.T) {
cases := []struct {
z string
shift int
want string
}{
// Rounding
{"1", 0, "1"},
{"20", 1, "2"},
{"18", 1, "1"},
{"15", 1, "1"},
{"12", 1, "1"},
{"10", 1, "1"},
{"8", 1, "0"},
{"5", 1, "0"},
{"2", 1, "0"},
{"9999999999999999999", 19, "0"},
{"9999999999999999999", 100, "0"},
// Large shifts
{"0", 17, "0"},
{"0", 18, "0"},
{"0", 19, "0"},
{"0", 20, "0"},
{"0", 21, "0"},
{"1", 17, "0"},
{"1", 18, "0"},
{"1", 19, "0"},
{"1", 20, "0"},
{"1", 21, "0"},
{"5000000000000000000", 17, "50"},
{"5000000000000000000", 18, "5"},
{"5000000000000000000", 19, "0"},
{"5000000000000000000", 20, "0"},
{"5000000000000000000", 21, "0"},
{"5000000000000000001", 17, "50"},
{"5000000000000000001", 18, "5"},
{"5000000000000000001", 19, "0"},
{"5000000000000000001", 20, "0"},
{"5000000000000000001", 21, "0"},
{"9999999999999999999", 17, "99"},
{"9999999999999999999", 18, "9"},
{"9999999999999999999", 19, "0"},
{"9999999999999999999", 20, "0"},
{"9999999999999999999", 21, "0"},
{"10000000000000000000", 17, "100"},
{"10000000000000000000", 18, "10"},
{"10000000000000000000", 19, "1"},
{"10000000000000000000", 20, "0"},
{"10000000000000000000", 21, "0"},
{"14999999999999999999", 17, "149"},
{"14999999999999999999", 18, "14"},
{"14999999999999999999", 19, "1"},
{"14999999999999999999", 20, "0"},
{"14999999999999999999", 21, "0"},
{"15000000000000000000", 17, "150"},
{"15000000000000000000", 18, "15"},
{"15000000000000000000", 19, "1"},
{"15000000000000000000", 20, "0"},
{"15000000000000000000", 21, "0"},
{"18446744073709551615", 17, "184"},
{"18446744073709551615", 18, "18"},
{"18446744073709551615", 19, "1"},
{"18446744073709551615", 20, "0"},
{"18446744073709551615", 21, "0"},
}
for _, tt := range cases {
got := mustParseBint(tt.z)
got.rshDown(got, tt.shift)
want := mustParseBint(tt.want)
if got.cmp(want) != 0 {
t.Errorf("%v.rshDown(%v) = %v, want %v", tt.z, tt.shift, got, want)
}
}
}
func TestBint_rshHalfEven(t *testing.T) {
cases := []struct {
z string
shift int
want string
}{
// Rounding
{"1", 0, "1"},
{"20", 1, "2"},
{"18", 1, "2"},
{"15", 1, "2"},
{"12", 1, "1"},
{"10", 1, "1"},
{"8", 1, "1"},
{"5", 1, "0"},
{"2", 1, "0"},
{"9999999999999999999", 19, "1"},
{"9999999999999999999", 100, "0"},
// Large shifts
{"0", 17, "0"},
{"0", 18, "0"},
{"0", 19, "0"},
{"0", 20, "0"},
{"0", 21, "0"},
{"1", 17, "0"},
{"1", 18, "0"},
{"1", 19, "0"},
{"1", 20, "0"},
{"1", 21, "0"},
{"5000000000000000000", 17, "50"},
{"5000000000000000000", 18, "5"},
{"5000000000000000000", 19, "0"},
{"5000000000000000000", 20, "0"},
{"5000000000000000000", 21, "0"},
{"5000000000000000001", 17, "50"},
{"5000000000000000001", 18, "5"},
{"5000000000000000001", 19, "1"},
{"5000000000000000001", 20, "0"},
{"5000000000000000001", 21, "0"},
{"9999999999999999999", 17, "100"},
{"9999999999999999999", 18, "10"},
{"9999999999999999999", 19, "1"},
{"9999999999999999999", 20, "0"},
{"9999999999999999999", 21, "0"},
{"10000000000000000000", 17, "100"},
{"10000000000000000000", 18, "10"},
{"10000000000000000000", 19, "1"},
{"10000000000000000000", 20, "0"},
{"10000000000000000000", 21, "0"},
{"14999999999999999999", 17, "150"},
{"14999999999999999999", 18, "15"},
{"14999999999999999999", 19, "1"},
{"14999999999999999999", 20, "0"},
{"14999999999999999999", 21, "0"},
{"15000000000000000000", 17, "150"},
{"15000000000000000000", 18, "15"},
{"15000000000000000000", 19, "2"},
{"15000000000000000000", 20, "0"},
{"15000000000000000000", 21, "0"},
{"18446744073709551615", 17, "184"},
{"18446744073709551615", 18, "18"},
{"18446744073709551615", 19, "2"},
{"18446744073709551615", 20, "0"},
{"18446744073709551615", 21, "0"},
}
for _, tt := range cases {
got := mustParseBint(tt.z)
got.rshHalfEven(got, tt.shift)
want := mustParseBint(tt.want)
if got.cmp(want) != 0 {
t.Errorf("%v.rshHalfEven(%v) = %v, want %v", tt.z, tt.shift, got, want)
}
}
}
func TestBint_lsh(t *testing.T) {
cases := []struct {
z string
shift int
want string
}{
{"0", 1, "0"},
{"1", 1, "10"},
{"1", 20, "100000000000000000000"},
{"1", 100, "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},
}
for _, tt := range cases {
got := mustParseBint(tt.z)
got.lsh(got, tt.shift)
want := mustParseBint(tt.want)
if got.cmp(want) != 0 {
t.Errorf("%v.lsh(%v) = %v, want %v", tt.z, tt.shift, got, want)
}
}
}
func TestBint_prec(t *testing.T) {
cases := []struct {
z string
want int
}{
{"0", 0},
{"1", 1},
{"9", 1},
{"10", 2},
{"99", 2},
{"100", 3},
{"999", 3},
{"1000", 4},
{"9999", 4},
{"10000", 5},
{"99999", 5},
{"100000", 6},
{"999999", 6},
{"1000000", 7},
{"9999999", 7},
{"10000000", 8},
{"99999999", 8},
{"100000000", 9},
{"999999999", 9},
{"1000000000", 10},
{"9999999999", 10},
{"10000000000", 11},
{"99999999999", 11},
{"100000000000", 12},
{"999999999999", 12},
{"1000000000000", 13},
{"9999999999999", 13},
{"10000000000000", 14},
{"99999999999999", 14},
{"100000000000000", 15},
{"999999999999999", 15},
{"1000000000000000", 16},
{"9999999999999999", 16},
{"10000000000000000", 17},
{"99999999999999999", 17},
{"100000000000000000", 18},
{"999999999999999999", 18},
{"1000000000000000000", 19},
{"9999999999999999999", 19},
{"10000000000000000000", 20},
{"99999999999999999999", 20},
{"100000000000000000000", 21},
{"999999999999999999999", 21},
{"1000000000000000000000", 22},
{"9999999999999999999999", 22},
{"10000000000000000000000", 23},
{"99999999999999999999999", 23},
{"100000000000000000000000", 24},
{"999999999999999999999999", 24},
{"1000000000000000000000000", 25},
{"9999999999999999999999999", 25},
{"10000000000000000000000000", 26},
{"99999999999999999999999999", 26},
{"100000000000000000000000000", 27},
{"999999999999999999999999999", 27},
{"1000000000000000000000000000", 28},
{"9999999999999999999999999999", 28},
{"10000000000000000000000000000", 29},
{"99999999999999999999999999999", 29},
{"100000000000000000000000000000", 30},
{"999999999999999999999999999999", 30},
{"1000000000000000000000000000000", 31},
{"9999999999999999999999999999999", 31},
{"10000000000000000000000000000000", 32},
{"99999999999999999999999999999999", 32},
{"100000000000000000000000000000000", 33},
{"999999999999999999999999999999999", 33},
{"1000000000000000000000000000000000", 34},
{"9999999999999999999999999999999999", 34},
{"10000000000000000000000000000000000", 35},
{"99999999999999999999999999999999999", 35},
{"100000000000000000000000000000000000", 36},
{"999999999999999999999999999999999999", 36},
{"1000000000000000000000000000000000000", 37},
{"9999999999999999999999999999999999999", 37},
{"10000000000000000000000000000000000000", 38},
{"99999999999999999999999999999999999999", 38},
{"100000000000000000000000000000000000000", 39},
{"999999999999999999999999999999999999999", 39},
{"1000000000000000000000000000000000000000", 40},
{"9999999999999999999999999999999999999999", 40},
{"10000000000000000000000000000000000000000", 41},
{"99999999999999999999999999999999999999999", 41},
{"100000000000000000000000000000000000000000", 42},
{"999999999999999999999999999999999999999999", 42},
{"1000000000000000000000000000000000000000000", 43},
{"9999999999999999999999999999999999999999999", 43},
{"10000000000000000000000000000000000000000000", 44},
{"99999999999999999999999999999999999999999999", 44},
{"100000000000000000000000000000000000000000000", 45},
{"999999999999999999999999999999999999999999999", 45},
{"1000000000000000000000000000000000000000000000", 46},
{"9999999999999999999999999999999999999999999999", 46},
{"10000000000000000000000000000000000000000000000", 47},
{"99999999999999999999999999999999999999999999999", 47},
{"100000000000000000000000000000000000000000000000", 48},
{"999999999999999999999999999999999999999999999999", 48},
{"1000000000000000000000000000000000000000000000000", 49},
{"9999999999999999999999999999999999999999999999999", 49},
{"10000000000000000000000000000000000000000000000000", 50},
{"99999999999999999999999999999999999999999999999999", 50},
{"100000000000000000000000000000000000000000000000000", 51},
{"999999999999999999999999999999999999999999999999999", 51},
{"1000000000000000000000000000000000000000000000000000", 52},
{"9999999999999999999999999999999999999999999999999999", 52},
{"10000000000000000000000000000000000000000000000000000", 53},
{"99999999999999999999999999999999999999999999999999999", 53},
{"100000000000000000000000000000000000000000000000000000", 54},
{"999999999999999999999999999999999999999999999999999999", 54},
{"1000000000000000000000000000000000000000000000000000000", 55},
{"9999999999999999999999999999999999999999999999999999999", 55},
{"10000000000000000000000000000000000000000000000000000000", 56},
{"99999999999999999999999999999999999999999999999999999999", 56},
{"100000000000000000000000000000000000000000000000000000000", 57},
{"999999999999999999999999999999999999999999999999999999999", 57},
{"1000000000000000000000000000000000000000000000000000000000", 58},
{"9999999999999999999999999999999999999999999999999999999999", 58},
{"10000000000000000000000000000000000000000000000000000000000", 59},
{"99999999999999999999999999999999999999999999999999999999999", 59},
{"100000000000000000000000000000000000000000000000000000000000", 60},
{"999999999999999999999999999999999999999999999999999999999999", 60},
{"1000000000000000000000000000000000000000000000000000000000000", 61},
{"9999999999999999999999999999999999999999999999999999999999999", 61},
{"10000000000000000000000000000000000000000000000000000000000000", 62},
{"99999999999999999999999999999999999999999999999999999999999999", 62},
{"100000000000000000000000000000000000000000000000000000000000000", 63},
{"999999999999999999999999999999999999999999999999999999999999999", 63},
{"1000000000000000000000000000000000000000000000000000000000000000", 64},
{"9999999999999999999999999999999999999999999999999999999999999999", 64},
{"10000000000000000000000000000000000000000000000000000000000000000", 65},
{"99999999999999999999999999999999999999999999999999999999999999999", 65},
{"100000000000000000000000000000000000000000000000000000000000000000", 66},
{"999999999999999999999999999999999999999999999999999999999999999999", 66},
{"1000000000000000000000000000000000000000000000000000000000000000000", 67},
{"9999999999999999999999999999999999999999999999999999999999999999999", 67},
{"10000000000000000000000000000000000000000000000000000000000000000000", 68},
{"99999999999999999999999999999999999999999999999999999999999999999999", 68},
{"100000000000000000000000000000000000000000000000000000000000000000000", 69},
{"999999999999999999999999999999999999999999999999999999999999999999999", 69},
{"1000000000000000000000000000000000000000000000000000000000000000000000", 70},
{"9999999999999999999999999999999999999999999999999999999999999999999999", 70},
{"10000000000000000000000000000000000000000000000000000000000000000000000", 71},
{"99999999999999999999999999999999999999999999999999999999999999999999999", 71},
{"100000000000000000000000000000000000000000000000000000000000000000000000", 72},
{"999999999999999999999999999999999999999999999999999999999999999999999999", 72},
{"1000000000000000000000000000000000000000000000000000000000000000000000000", 73},
{"9999999999999999999999999999999999999999999999999999999999999999999999999", 73},
{"10000000000000000000000000000000000000000000000000000000000000000000000000", 74},
{"99999999999999999999999999999999999999999999999999999999999999999999999999", 74},
{"100000000000000000000000000000000000000000000000000000000000000000000000000", 75},
{"999999999999999999999999999999999999999999999999999999999999999999999999999", 75},
{"1000000000000000000000000000000000000000000000000000000000000000000000000000", 76},
{"9999999999999999999999999999999999999999999999999999999999999999999999999999", 76},
{"10000000000000000000000000000000000000000000000000000000000000000000000000000", 77},
{"99999999999999999999999999999999999999999999999999999999999999999999999999999", 77},
{"100000000000000000000000000000000000000000000000000000000000000000000000000000", 78},
{"999999999999999999999999999999999999999999999999999999999999999999999999999999", 78},
{"1000000000000000000000000000000000000000000000000000000000000000000000000000000", 79},
{"9999999999999999999999999999999999999999999999999999999999999999999999999999999", 79},
{"10000000000000000000000000000000000000000000000000000000000000000000000000000000", 80},
{"99999999999999999999999999999999999999999999999999999999999999999999999999999999", 80},
{"100000000000000000000000000000000000000000000000000000000000000000000000000000000", 81},
{"999999999999999999999999999999999999999999999999999999999999999999999999999999999", 81},
{"1000000000000000000000000000000000000000000000000000000000000000000000000000000000", 82},
{"9999999999999999999999999999999999999999999999999999999999999999999999999999999999", 82},
{"10000000000000000000000000000000000000000000000000000000000000000000000000000000000", 83},
{"99999999999999999999999999999999999999999999999999999999999999999999999999999999999", 83},
{"100000000000000000000000000000000000000000000000000000000000000000000000000000000000", 84},
{"999999999999999999999999999999999999999999999999999999999999999999999999999999999999", 84},
{"1000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 85},
{"9999999999999999999999999999999999999999999999999999999999999999999999999999999999999", 85},
{"10000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 86},
{"99999999999999999999999999999999999999999999999999999999999999999999999999999999999999", 86},
{"100000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 87},
{"999999999999999999999999999999999999999999999999999999999999999999999999999999999999999", 87},
{"1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 88},
{"9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999", 88},
{"10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 89},
{"99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999", 89},
{"100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 90},
{"999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999", 90},
{"1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 91},
{"9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999", 91},
{"10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 92},
{"99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999", 92},
{"100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 93},
{"999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999", 93},
{"1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 94},
{"9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999", 94},
{"10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 95},
{"99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999", 95},
{"100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 96},
{"999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999", 96},
{"1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 97},
{"9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999", 97},
{"10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 98},
{"99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999", 98},
{"100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 99},
{"999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999", 99},
{"1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 100},
{"9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999", 100},
{"10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 101},
}
for _, tt := range cases {
z := mustParseBint(tt.z)
got := z.prec()
if got != tt.want {
t.Errorf("%q.prec() = %v, want %v", tt.z, got, tt.want)
}
}
}
func TestBint_hasPrec(t *testing.T) {
cases := []struct {
z string
prec int
want bool
}{
{"0", -1, true},
{"0", 0, true},
{"0", 1, false},
{"1", 0, true},
{"1", 1, true},
{"1", 2, false},
{"10", 1, true},
{"10", 2, true},
{"10", 3, false},
{"100000000000000000", 19, false}, // 18 digits
{"1000000000000000000", 19, true}, // 19 digits
{"10000000000000000000", 19, true}, // 20 digits
{"1000000000000000000", 18, true}, // 19 digits
{"1000000000000000000", 19, true}, // 19 digits
{"1000000000000000000", 20, false}, // 19 digits
{"100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 100, false}, // 99 digits
{"1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 100, true}, // 100 digits
{"10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 100, true}, // 101 digits
{"1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 99, true}, // 100 digits
{"1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 100, true}, // 100 digits
{"1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 101, false}, // 100 digits
}
for _, tt := range cases {
z := mustParseBint(tt.z)
got := z.hasPrec(tt.prec)
if got != tt.want {
t.Errorf("%v.hasPrec(%v) = %v, want %v", tt.z, tt.prec, got, tt.want)
}
}
}