2 files changed,
103 insertions(+),
0 deletions(-)
Author:
Oleksandr Smirnov
olexsmir@gmail.com
Committed at:
2026-06-09 15:33:31 +0300
Authored at:
2026-06-09 15:25:32 +0300
Change ID:
nvnywlzvuqltyrwsmpwwmxpuqzlknyxo
Parent:
4c27ef1
M
internal/decimal/decimal.go
··· 189 189 } 190 190 } 191 191 192 +func (d Decimal) Abs() Decimal { 193 + if d.coeff == nil || d.coeff.Sign() == 0 { 194 + return Decimal{} 195 + } 196 + if d.coeff.Sign() > 0 { 197 + return Decimal{coeff: new(big.Int).Set(d.coeff), scale: d.scale} 198 + } 199 + return Decimal{coeff: new(big.Int).Neg(d.coeff), scale: d.scale} 200 +} 201 + 192 202 func (d Decimal) Neg() Decimal { 193 203 if d.coeff == nil || d.coeff.Sign() == 0 { 194 204 return Decimal{} ··· 209 219 } 210 220 product := new(big.Int).Mul(d.coeffOrZero(), other.coeffOrZero()) 211 221 return Decimal{coeff: product, scale: d.scale + other.scale}.normalized() 222 +} 223 + 224 +func (d Decimal) Div(other Decimal) Decimal { 225 + if other.IsZero() { 226 + panic("decimal: division by zero") 227 + } 228 + if d.IsZero() { 229 + return Decimal{} 230 + } 231 + 232 + scale := max(d.scale, other.scale) + 10 233 + 234 + dCoeff := d.coeffOrZero() 235 + oCoeff := other.coeffOrZero() 236 + 237 + shift := scale + other.scale - d.scale 238 + if shift > 0 { 239 + dCoeff = new(big.Int).Mul(dCoeff, pow10(shift)) 240 + } else if shift < 0 { 241 + oCoeff = new(big.Int).Mul(oCoeff, pow10(-shift)) 242 + } 243 + 244 + quo := new(big.Int).Quo(dCoeff, oCoeff) 245 + return Decimal{coeff: quo, scale: scale}.normalized() 212 246 } 213 247 214 248 func (d Decimal) Cmp(other Decimal) int {
M
internal/decimal/decimal_test.go
··· 104 104 } 105 105 } 106 106 107 +func TestAbs(t *testing.T) { 108 + tests := []struct { 109 + in, want string 110 + }{ 111 + {"0", "0"}, 112 + {"-0", "0"}, 113 + {"0.00", "0"}, 114 + {"1.5", "1.5"}, 115 + {"-1.5", "1.5"}, 116 + {"100", "100"}, 117 + {"-100", "100"}, 118 + {"0.001", "0.001"}, 119 + {"-0.001", "0.001"}, 120 + {"123.456", "123.456"}, 121 + {"-123.456", "123.456"}, 122 + } 123 + for _, tt := range tests { 124 + d, err := FromString(tt.in) 125 + if err != nil { 126 + t.Fatalf("FromString(%q) unexpected error: %v", tt.in, err) 127 + } 128 + if got := d.Abs().String(); got != tt.want { 129 + t.Fatalf("Abs(%q) = %q, want %q", tt.in, got, tt.want) 130 + } 131 + } 132 +} 133 + 134 +func TestDiv(t *testing.T) { 135 + tests := []struct { 136 + a, b, want string 137 + }{ 138 + {"1", "2", "0.5"}, 139 + {"10", "3", "3.3333333333"}, 140 + {"1.50", "3.00", "0.5"}, 141 + {"0.1", "0.3", "0.33333333333"}, 142 + {"100", "10", "10"}, 143 + {"-1", "2", "-0.5"}, 144 + {"1", "-2", "-0.5"}, 145 + {"-1", "-2", "0.5"}, 146 + {"0", "5", "0"}, 147 + {"5.50", "5", "1.1"}, 148 + {"1000", "3", "333.3333333333"}, 149 + } 150 + for _, tt := range tests { 151 + a, err := FromString(tt.a) 152 + if err != nil { 153 + t.Fatalf("FromString(%q) unexpected error: %v", tt.a, err) 154 + } 155 + b, err := FromString(tt.b) 156 + if err != nil { 157 + t.Fatalf("FromString(%q) unexpected error: %v", tt.b, err) 158 + } 159 + got := a.Div(b).String() 160 + if got != tt.want { 161 + t.Fatalf("Div(%q, %q) = %q, want %q", tt.a, tt.b, got, tt.want) 162 + } 163 + } 164 +} 165 + 166 +func TestDivByZero(t *testing.T) { 167 + defer func() { 168 + if r := recover(); r == nil { 169 + t.Fatal("expected panic on division by zero") 170 + } 171 + }() 172 + d, _ := FromString("1") 173 + d.Div(Decimal{}) 174 +} 175 + 107 176 func TestCmpAndNeg(t *testing.T) { 108 177 a, _ := FromString("1.0") 109 178 b, _ := FromString("1")