diff --git a/fixed.go b/fixed.go index ff26b03..2cafc5b 100644 --- a/fixed.go +++ b/fixed.go @@ -8,6 +8,7 @@ import ( "fmt" "io" "math" + "math/bits" "strconv" "strings" ) @@ -231,10 +232,29 @@ func (f Fixed) Mul(f0 Fixed) Fixed { // Div divides f by f0 returning a Fixed. If either operand is NaN, NaN is returned func (f Fixed) Div(f0 Fixed) Fixed { - if f.IsNaN() || f0.IsNaN() { + if f.IsNaN() || f0.IsNaN() || f0.fp == 0 { return NaN } - return NewF(f.Float() / f0.Float()) + + sign, fp, fp0 := int64(1), f.fp, f0.fp + + if fp < 0 { + fp, sign = -fp, -sign + } + if fp0 < 0 { + fp0, sign = -fp0, -sign + } + + // Use 128-bit math to calculate fp * scale / fp0. + hi, lo := bits.Mul64(uint64(fp), uint64(scale)) + quo, rem := bits.Div64(hi, lo, uint64(fp0)) + + // Round if remainder >= divisor/2 + if rem >= uint64(fp0)/2 { + quo++ + } + + return Fixed{fp: int64(quo) * sign} } func sign(fp int64) int64 { diff --git a/readme.md b/readme.md index 07716e5..ea0dae0 100644 --- a/readme.md +++ b/readme.md @@ -28,33 +28,33 @@ The fixed.Fixed API uses NaN for reporting errors in the common case, since ofte and this would be a huge pain with error handling. Since all operations involving a NaN result in a NaN, any errors quickly surface anyway. -**Performance** +**Performance**
-using Go 1.21.5 -cpu: Intel(R) Core(TM) i7-6700K CPU @ 4.00GHz -BenchmarkAddFixed-8 1000000000 0.9627 ns/op 0 B/op 0 allocs/op -BenchmarkAddDecimal-8 17871763 66.52 ns/op 80 B/op 2 allocs/op -BenchmarkAddBigInt-8 125826048 9.562 ns/op 0 B/op 0 allocs/op -BenchmarkAddBigFloat-8 18763552 63.51 ns/op 48 B/op 1 allocs/op -BenchmarkMulFixed-8 335886367 3.538 ns/op 0 B/op 0 allocs/op -BenchmarkMulDecimal-8 18164803 66.12 ns/op 80 B/op 2 allocs/op -BenchmarkMulBigInt-8 100000000 10.41 ns/op 0 B/op 0 allocs/op -BenchmarkMulBigFloat-8 50151100 23.93 ns/op 0 B/op 0 allocs/op -BenchmarkDivFixed-8 328157694 3.722 ns/op 0 B/op 0 allocs/op -BenchmarkDivDecimal-8 2558497 461.7 ns/op 384 B/op 12 allocs/op -BenchmarkDivBigInt-8 33726384 34.68 ns/op 8 B/op 1 allocs/op -BenchmarkDivBigFloat-8 10757650 110.1 ns/op 24 B/op 2 allocs/op -BenchmarkCmpFixed-8 1000000000 0.2519 ns/op 0 B/op 0 allocs/op -BenchmarkCmpDecimal-8 171236422 6.926 ns/op 0 B/op 0 allocs/op -BenchmarkCmpBigInt-8 250970304 4.791 ns/op 0 B/op 0 allocs/op -BenchmarkCmpBigFloat-8 271898336 4.428 ns/op 0 B/op 0 allocs/op -BenchmarkStringFixed-8 23637406 50.30 ns/op 24 B/op 1 allocs/op -BenchmarkStringNFixed-8 23457960 51.85 ns/op 24 B/op 1 allocs/op -BenchmarkStringDecimal-8 5763308 210.2 ns/op 56 B/op 4 allocs/op -BenchmarkStringBigInt-8 11742596 114.0 ns/op 16 B/op 1 allocs/op -BenchmarkStringBigFloat-8 3003280 395.3 ns/op 176 B/op 7 allocs/op -BenchmarkWriteTo-8 38573978 43.13 ns/op 27 B/op 0 allocs/op +using Go 1.25.3 +cpu: Intel(R) Core(TM) i9-10850K CPU @ 3.60GHz +BenchmarkAddFixed-20 1000000000 0.7317 ns/op 0 B/op 0 allocs/op +BenchmarkAddDecimal-20 23494767 50.49 ns/op 80 B/op 2 allocs/op +BenchmarkAddBigInt-20 146968544 8.481 ns/op 0 B/op 0 allocs/op +BenchmarkAddBigFloat-20 19393024 59.52 ns/op 48 B/op 1 allocs/op +BenchmarkMulFixed-20 233557537 4.824 ns/op 0 B/op 0 allocs/op +BenchmarkMulDecimal-20 22572376 51.77 ns/op 80 B/op 2 allocs/op +BenchmarkMulBigInt-20 100000000 10.03 ns/op 0 B/op 0 allocs/op +BenchmarkMulBigFloat-20 56131700 21.59 ns/op 0 B/op 0 allocs/op +BenchmarkDivFixed-20 57347422 20.90 ns/op 0 B/op 0 allocs/op +BenchmarkDivDecimal-20 2935522 408.3 ns/op 384 B/op 12 allocs/op +BenchmarkDivBigInt-20 42439080 27.72 ns/op 8 B/op 1 allocs/op +BenchmarkDivBigFloat-20 14065242 84.40 ns/op 8 B/op 1 allocs/op +BenchmarkCmpFixed-20 1000000000 0.2113 ns/op 0 B/op 0 allocs/op +BenchmarkCmpDecimal-20 203959459 5.651 ns/op 0 B/op 0 allocs/op +BenchmarkCmpBigInt-20 311228709 3.796 ns/op 0 B/op 0 allocs/op +BenchmarkCmpBigFloat-20 319646821 3.756 ns/op 0 B/op 0 allocs/op +BenchmarkStringFixed-20 29299454 40.59 ns/op 24 B/op 1 allocs/op +BenchmarkStringNFixed-20 29791072 39.66 ns/op 24 B/op 1 allocs/op +BenchmarkStringDecimal-20 6768283 178.1 ns/op 56 B/op 4 allocs/op +BenchmarkStringBigInt-20 12304304 93.86 ns/op 16 B/op 1 allocs/op +BenchmarkStringBigFloat-20 3670106 325.5 ns/op 152 B/op 6 allocs/op +BenchmarkWriteTo-20 46491169 27.41 ns/op 23 B/op 0 allocs/opThe "decimal" above is the common [shopspring decimal](https://github.com/shopspring/decimal) library