99 lines
2.0 KiB
Go
99 lines
2.0 KiB
Go
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))
|
|
}
|