File: float64.go

package info (click to toggle)
golang-github-savsgio-gotils 0.0~git20250408.196191e-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 176 kB
  • sloc: makefile: 2
file content (98 lines) | stat: -rw-r--r-- 2,030 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
package math

import (
	"bytes"
	"math"
	"strconv"

	"github.com/valyala/bytebufferpool"
)

// NewFloat64Calculator returns a float64 calculator
// for basic operations without losing precision in decimals.
func NewFloat64Calculator() *Float64Calculator {
	return &Float64Calculator{}
}

// DecimalPlaces returns the number of decimal places.
func (fc *Float64Calculator) DecimalPlaces(x float64) int {
	buf := bytebufferpool.Get()
	defer bytebufferpool.Put(buf)

	buf.B = strconv.AppendFloat(buf.B, x, 'f', -1, 64)
	i := bytes.IndexByte(buf.B, '.')

	if i > -1 {
		return len(buf.B) - i - 1
	}

	return 0
}

// Max returns the larger of x or y.
func (fc *Float64Calculator) Max(x, y int) int {
	if x > y {
		return x
	}

	return y
}

// Add returns a + b.
func (fc *Float64Calculator) Add(a, b float64) float64 {
	exp := math.Pow10(fc.Max(fc.DecimalPlaces(a), fc.DecimalPlaces(b)))

	intA := math.Round(a * exp)
	intB := math.Round(b * exp)

	return (intA + intB) / exp
}

// Sub returns a - b.
func (fc *Float64Calculator) Sub(a, b float64) float64 {
	exp := math.Pow10(fc.Max(fc.DecimalPlaces(a), fc.DecimalPlaces(b)))

	intA := math.Round(a * exp)
	intB := math.Round(b * exp)

	return (intA - intB) / exp
}

// Mul returns a * b.
func (fc *Float64Calculator) Mul(a, b float64) float64 {
	placesA := fc.DecimalPlaces(a)
	placesB := fc.DecimalPlaces(b)

	expA := math.Pow10(placesA)
	expB := math.Pow10(placesB)

	intA := math.Round(a * expA)
	intB := math.Round(b * expB)

	exp := math.Pow10(placesA + placesB)

	return (intA * intB) / exp
}

// Div returns a / b.
func (fc *Float64Calculator) Div(a, b float64) float64 {
	placesA := fc.DecimalPlaces(a)
	placesB := fc.DecimalPlaces(b)

	expA := math.Pow10(placesA)
	expB := math.Pow10(placesB)

	intA := math.Round(a * expA)
	intB := math.Round(b * expB)

	exp := math.Pow10(placesA - placesB)

	return (intA / intB) / exp
}

// Mod returns a % b.
func (fc *Float64Calculator) Mod(a, b float64) float64 {
	quo := math.Round(fc.Div(a, b))

	return fc.Sub(a, fc.Mul(b, quo))
}