go.charczuk.com@v0.0.0-20240327042549-bc490516bd1a/sdk/decimal/decimal.go (about) 1 /* 2 3 Copyright (c) 2023 - Present. Will Charczuk. All rights reserved. 4 Use of this source code is governed by a MIT license that can be found in the LICENSE file at the root of the repository. 5 6 */ 7 8 package decimal 9 10 import ( 11 "encoding/json" 12 "fmt" 13 ) 14 15 const _exp = 1e3 16 17 var ( 18 _ json.Marshaler = (*Decimal)(nil) 19 ) 20 21 // New returns a new decimal. 22 func New(v any) Decimal { 23 d := new(Decimal) 24 switch typed := v.(type) { 25 case float64: 26 d.Set(typed) 27 case float32: 28 d.Set(float64(typed)) 29 case int32: 30 d.Set(float64(typed)) 31 case int64: 32 d.Set(float64(typed)) 33 case uint32: 34 d.Set(float64(typed)) 35 case uint64: 36 d.Set(float64(typed)) 37 case int: 38 d.Set(float64(typed)) 39 case Decimal: 40 *d = typed 41 default: 42 panic("invalid origin type for decimal") 43 } 44 return *d 45 } 46 47 // Decimal is a fixed precision number with (4) digits of precision. 48 // 49 // It blends the benefits of an arbitrary precision type (e.g. math.big) 50 // with the performance of register types for common operations. 51 // 52 // Addition and subtraction can be done directly on values with the 53 // builtin operators. For everything else, there are helper 54 // functions on the type itself. 55 type Decimal int64 56 57 // Float64 returns a float64 for the given decimal value. 58 func (d Decimal) Float64() float64 { 59 return float64(d) / float64(_exp) 60 } 61 62 // Set sets the decimal value. 63 func (d *Decimal) Set(v float64) { 64 *d = Decimal(int64(v * _exp)) 65 } 66 67 // Add adds this decimal to a given decimal. 68 // 69 // It is equivalent to d + v. 70 func (d Decimal) Add(v Decimal) Decimal { 71 return Decimal(d + v) 72 } 73 74 // Sub subtracts this decimal from a given decimal. 75 // 76 // It is equivalent to d - v. 77 func (d Decimal) Sub(v Decimal) Decimal { 78 return Decimal(d - v) 79 } 80 81 // Div divides this decimal by a given decimal. 82 // 83 // It is equivalent to d / v. 84 func (d Decimal) Div(v Decimal) Decimal { 85 if d < v { 86 d0 := d * _exp 87 return (d0 / v) 88 } 89 return (d / v) * _exp 90 } 91 92 // Mul multiplies this decimal by a given decimal. 93 // 94 // It is equivalent to d * v. 95 func (d Decimal) Mul(v Decimal) Decimal { 96 return Decimal((d * v) / _exp) 97 } 98 99 // Abs returnst the absolute value of the decimal. 100 // 101 // It is equivalent to -d if d < 0. 102 func (d Decimal) Abs() Decimal { 103 if d < 0 { 104 return Decimal(-d) 105 } 106 return d 107 } 108 109 // Neg inverts the sign of this decimal. 110 // 111 // It is equivalent to -d. 112 func (d Decimal) Neg() Decimal { 113 return Decimal(-d) 114 } 115 116 // Invert inverts the value of this decimal. 117 // 118 // It is equivalent to 1/d. 119 func (d Decimal) Invert() Decimal { 120 return ((_exp * _exp) / d * _exp) / _exp 121 } 122 123 // String returns a string representation of the decimal. 124 func (d *Decimal) String() string { 125 return fmt.Sprintf("%.4f", d.Float64()) 126 } 127 128 // MarshalJSON marshals the decimal as a json. 129 func (d Decimal) MarshalJSON() ([]byte, error) { 130 return []byte(d.String()), nil 131 }