From 4bc9b9e3e6ee8a672db777939104a05fc12de9c5 Mon Sep 17 00:00:00 2001 From: Ethan Reesor Date: Sun, 30 Nov 2025 16:16:48 -0600 Subject: [PATCH] Don't use float for div --- fixed.go | 24 ++++++++++++++++++++++-- readme.md | 50 +++++++++++++++++++++++++------------------------- 2 files changed, 47 insertions(+), 27 deletions(-) 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/op
 
The "decimal" above is the common [shopspring decimal](https://github.com/shopspring/decimal) library