github.com/richardwilkes/toolbox@v1.121.0/xmath/fixed/f128/f128_test.go (about) 1 // Copyright (c) 2016-2024 by Richard A. Wilkes. All rights reserved. 2 // 3 // This Source Code Form is subject to the terms of the Mozilla Public 4 // License, version 2.0. If a copy of the MPL was not distributed with 5 // this file, You can obtain one at http://mozilla.org/MPL/2.0/. 6 // 7 // This Source Code Form is "Incompatible With Secondary Licenses", as 8 // defined by the Mozilla Public License, version 2.0. 9 10 package f128_test 11 12 import ( 13 "encoding/json" 14 "strings" 15 "testing" 16 17 "github.com/richardwilkes/toolbox/check" 18 "github.com/richardwilkes/toolbox/xmath/fixed" 19 "github.com/richardwilkes/toolbox/xmath/fixed/f128" 20 "gopkg.in/yaml.v3" 21 ) 22 23 func TestConversion(t *testing.T) { 24 testConversion[fixed.D1](t) 25 testConversion[fixed.D2](t) 26 testConversion[fixed.D3](t) 27 testConversion[fixed.D4](t) 28 testConversion[fixed.D5](t) 29 testConversion[fixed.D6](t) 30 } 31 32 //nolint:goconst // Not helpful 33 func testConversion[T fixed.Dx](t *testing.T) { 34 check.Equal(t, "0.1", f128.From[T, float64](0.1).String()) 35 check.Equal(t, "0.2", f128.From[T, float64](0.2).String()) 36 check.Equal(t, "0.3", f128.FromStringForced[T]("0.3").String()) 37 check.Equal(t, "-0.1", f128.From[T, float64](-0.1).String()) 38 check.Equal(t, "-0.2", f128.From[T, float64](-0.2).String()) 39 check.Equal(t, "-0.3", f128.FromStringForced[T]("-0.3").String()) 40 threeFill := strings.Repeat("3", f128.MaxDecimalDigits[T]()) 41 check.Equal(t, "0."+threeFill, f128.FromStringForced[T]("0.33333333").String()) 42 check.Equal(t, "-0."+threeFill, f128.FromStringForced[T]("-0.33333333").String()) 43 sixFill := strings.Repeat("6", f128.MaxDecimalDigits[T]()) 44 check.Equal(t, "0."+sixFill, f128.FromStringForced[T]("0.66666666").String()) 45 check.Equal(t, "-0."+sixFill, f128.FromStringForced[T]("-0.66666666").String()) 46 check.Equal(t, "1", f128.From[T, float64](1.0000004).String()) 47 check.Equal(t, "1", f128.From[T, float64](1.00000049).String()) 48 check.Equal(t, "1", f128.From[T, float64](1.0000005).String()) 49 check.Equal(t, "1", f128.From[T, float64](1.0000009).String()) 50 check.Equal(t, "-1", f128.From[T, float64](-1.0000004).String()) 51 check.Equal(t, "-1", f128.From[T, float64](-1.00000049).String()) 52 check.Equal(t, "-1", f128.From[T, float64](-1.0000005).String()) 53 check.Equal(t, "-1", f128.From[T, float64](-1.0000009).String()) 54 zeroFill := strings.Repeat("0", f128.MaxDecimalDigits[T]()-1) 55 check.Equal(t, "0."+zeroFill+"4", f128.FromStringForced[T]("0."+zeroFill+"405").String()) 56 check.Equal(t, "-0."+zeroFill+"4", f128.FromStringForced[T]("-0."+zeroFill+"405").String()) 57 58 v, err := f128.FromString[T]("33.0") 59 check.NoError(t, err) 60 check.Equal(t, v, f128.From[T, int](33)) 61 62 v, err = f128.FromString[T]("33.00000000000000000000") 63 check.NoError(t, err) 64 check.Equal(t, v, f128.From[T, int](33)) 65 } 66 67 func TestAddSub(t *testing.T) { 68 testAddSub[fixed.D1](t) 69 testAddSub[fixed.D2](t) 70 testAddSub[fixed.D3](t) 71 testAddSub[fixed.D4](t) 72 testAddSub[fixed.D5](t) 73 testAddSub[fixed.D6](t) 74 } 75 76 func testAddSub[T fixed.Dx](t *testing.T) { 77 oneThird := f128.FromStringForced[T]("0.333333") 78 negTwoThirds := f128.FromStringForced[T]("-0.666666") 79 one := f128.From[T, int](1) 80 oneAndTwoThirds := f128.FromStringForced[T]("1.666666") 81 nineThousandSix := f128.From[T, int](9006) 82 two := f128.From[T, int](2) 83 check.Equal(t, "0."+strings.Repeat("9", f128.MaxDecimalDigits[T]()), oneThird.Add(oneThird).Add(oneThird).String()) 84 check.Equal(t, "0."+strings.Repeat("6", f128.MaxDecimalDigits[T]()-1)+"7", one.Sub(oneThird).String()) 85 check.Equal(t, "-1."+strings.Repeat("6", f128.MaxDecimalDigits[T]()), negTwoThirds.Sub(one).String()) 86 check.Equal(t, "0", negTwoThirds.Sub(one).Add(oneAndTwoThirds).String()) 87 check.Equal(t, f128.From[T, int](10240), f128.From[T, int](1234).Add(nineThousandSix)) 88 check.Equal(t, "10240", f128.From[T, int](1234).Add(nineThousandSix).String()) 89 check.Equal(t, "-1.5", f128.From[T, float64](0.5).Sub(two).String()) 90 ninetyPointZeroSix := f128.FromStringForced[T]("90.06") 91 twelvePointThirtyFour := f128.FromStringForced[T]("12.34") 92 var answer string 93 if f128.MaxDecimalDigits[T]() > 1 { 94 answer = "102.4" 95 } else { 96 answer = "102.3" 97 } 98 check.Equal(t, f128.FromStringForced[T](answer), twelvePointThirtyFour.Add(ninetyPointZeroSix)) 99 check.Equal(t, answer, twelvePointThirtyFour.Add(ninetyPointZeroSix).String()) 100 } 101 102 func TestMulDiv(t *testing.T) { 103 testMulDiv[fixed.D1](t) 104 testMulDiv[fixed.D2](t) 105 testMulDiv[fixed.D3](t) 106 testMulDiv[fixed.D4](t) 107 testMulDiv[fixed.D5](t) 108 testMulDiv[fixed.D6](t) 109 } 110 111 func testMulDiv[T fixed.Dx](t *testing.T) { 112 pointThree := f128.FromStringForced[T]("0.3") 113 negativePointThree := f128.FromStringForced[T]("-0.3") 114 threeFill := strings.Repeat("3", f128.MaxDecimalDigits[T]()) 115 check.Equal(t, "0."+threeFill, f128.From[T, int](1).Div(f128.From[T, int](3)).String()) 116 check.Equal(t, "-0."+threeFill, f128.From[T, int](1).Div(f128.From[T, int](-3)).String()) 117 check.Equal(t, "0.1", pointThree.Div(f128.From[T, int](3)).String()) 118 check.Equal(t, "0.9", pointThree.Mul(f128.From[T, int](3)).String()) 119 check.Equal(t, "-0.9", negativePointThree.Mul(f128.From[T, int](3)).String()) 120 } 121 122 func TestMod(t *testing.T) { 123 testMod[fixed.D1](t) 124 testMod[fixed.D2](t) 125 testMod[fixed.D3](t) 126 testMod[fixed.D4](t) 127 testMod[fixed.D5](t) 128 testMod[fixed.D6](t) 129 } 130 131 func testMod[T fixed.Dx](t *testing.T) { 132 check.Equal(t, f128.From[T, int](1), f128.From[T, int](3).Mod(f128.From[T, int](2))) 133 check.Equal(t, f128.FromStringForced[T]("0.3"), f128.FromStringForced[T]("9.3").Mod(f128.From[T, int](3))) 134 check.Equal(t, f128.FromStringForced[T]("0.1"), f128.FromStringForced[T]("3.1").Mod(f128.FromStringForced[T]("0.2"))) 135 } 136 137 func TestTrunc(t *testing.T) { 138 testTrunc[fixed.D1](t) 139 testTrunc[fixed.D2](t) 140 testTrunc[fixed.D3](t) 141 testTrunc[fixed.D4](t) 142 testTrunc[fixed.D5](t) 143 testTrunc[fixed.D6](t) 144 } 145 146 func testTrunc[T fixed.Dx](t *testing.T) { 147 check.Equal(t, f128.From[T, int](0), f128.FromStringForced[T]("0.3333").Trunc()) 148 check.Equal(t, f128.From[T, int](2), f128.FromStringForced[T]("2.6789").Trunc()) 149 check.Equal(t, f128.From[T, int](3), f128.From[T, int](3).Trunc()) 150 check.Equal(t, f128.From[T, int](0), f128.FromStringForced[T]("-0.3333").Trunc()) 151 check.Equal(t, f128.From[T, int](-2), f128.FromStringForced[T]("-2.6789").Trunc()) 152 check.Equal(t, f128.From[T, int](-3), f128.From[T, int](-3).Trunc()) 153 } 154 155 func TestCeil(t *testing.T) { 156 testCeil[fixed.D1](t) 157 testCeil[fixed.D2](t) 158 testCeil[fixed.D3](t) 159 testCeil[fixed.D4](t) 160 testCeil[fixed.D5](t) 161 testCeil[fixed.D6](t) 162 } 163 164 func testCeil[T fixed.Dx](t *testing.T) { 165 check.Equal(t, f128.From[T, int](1), f128.FromStringForced[T]("0.3333").Ceil()) 166 check.Equal(t, f128.From[T, int](3), f128.FromStringForced[T]("2.6789").Ceil()) 167 check.Equal(t, f128.From[T, int](3), f128.From[T, int](3).Ceil()) 168 check.Equal(t, f128.From[T, int](0), f128.FromStringForced[T]("-0.3333").Ceil()) 169 check.Equal(t, f128.From[T, int](-2), f128.FromStringForced[T]("-2.6789").Ceil()) 170 check.Equal(t, f128.From[T, int](-3), f128.From[T, int](-3).Ceil()) 171 } 172 173 func TestRound(t *testing.T) { 174 testRound[fixed.D1](t) 175 testRound[fixed.D2](t) 176 testRound[fixed.D3](t) 177 testRound[fixed.D4](t) 178 testRound[fixed.D5](t) 179 testRound[fixed.D6](t) 180 } 181 182 func testRound[T fixed.Dx](t *testing.T) { 183 check.Equal(t, f128.From[T, int](0), f128.FromStringForced[T]("0.3333").Round()) 184 check.Equal(t, f128.From[T, int](3), f128.FromStringForced[T]("2.6789").Round()) 185 check.Equal(t, f128.From[T, int](3), f128.From[T, int](3).Round()) 186 check.Equal(t, f128.From[T, int](0), f128.FromStringForced[T]("-0.3333").Round()) 187 check.Equal(t, f128.From[T, int](-3), f128.FromStringForced[T]("-2.6789").Round()) 188 check.Equal(t, f128.From[T, int](-3), f128.From[T, int](-3).Round()) 189 } 190 191 func TestAbs(t *testing.T) { 192 testAbs[fixed.D1](t) 193 testAbs[fixed.D2](t) 194 testAbs[fixed.D3](t) 195 testAbs[fixed.D4](t) 196 testAbs[fixed.D5](t) 197 testAbs[fixed.D6](t) 198 } 199 200 func testAbs[T fixed.Dx](t *testing.T) { 201 check.Equal(t, f128.FromStringForced[T]("0.3333"), f128.FromStringForced[T]("0.3333").Abs()) 202 check.Equal(t, f128.FromStringForced[T]("2.6789"), f128.FromStringForced[T]("2.6789").Abs()) 203 check.Equal(t, f128.From[T, int](3), f128.From[T, int](3).Abs()) 204 check.Equal(t, f128.FromStringForced[T]("0.3333"), f128.FromStringForced[T]("-0.3333").Abs()) 205 check.Equal(t, f128.FromStringForced[T]("2.6789"), f128.FromStringForced[T]("-2.6789").Abs()) 206 check.Equal(t, f128.From[T, int](3), f128.From[T, int](-3).Abs()) 207 } 208 209 func TestNeg(t *testing.T) { 210 testNeg[fixed.D1](t) 211 testNeg[fixed.D2](t) 212 testNeg[fixed.D3](t) 213 testNeg[fixed.D4](t) 214 testNeg[fixed.D5](t) 215 testNeg[fixed.D6](t) 216 } 217 218 func testNeg[T fixed.Dx](t *testing.T) { 219 check.Equal(t, f128.FromStringForced[T]("-0.3333"), f128.FromStringForced[T]("0.3333").Neg()) 220 check.Equal(t, f128.FromStringForced[T]("-2.6789"), f128.FromStringForced[T]("2.6789").Neg()) 221 check.Equal(t, f128.From[T](-3), f128.From[T](3).Neg()) 222 check.Equal(t, f128.FromStringForced[T]("0.3333"), f128.FromStringForced[T]("-0.3333").Neg()) 223 check.Equal(t, f128.FromStringForced[T]("2.6789"), f128.FromStringForced[T]("-2.6789").Neg()) 224 check.Equal(t, f128.From[T](3), f128.From[T](-3).Neg()) 225 } 226 227 func TestCmp(t *testing.T) { 228 testCmp[fixed.D1](t) 229 testCmp[fixed.D2](t) 230 testCmp[fixed.D3](t) 231 testCmp[fixed.D4](t) 232 testCmp[fixed.D5](t) 233 testCmp[fixed.D6](t) 234 } 235 236 func testCmp[T fixed.Dx](t *testing.T) { 237 check.Equal(t, 1, f128.FromStringForced[T]("0.3333").Cmp(f128.From[T](-3))) 238 check.Equal(t, -1, f128.FromStringForced[T]("2.6789").Cmp(f128.From[T](3))) 239 check.Equal(t, 0, f128.From[T](3).Cmp(f128.From[T](3))) 240 } 241 242 func TestEqual(t *testing.T) { 243 testEqual[fixed.D1](t) 244 testEqual[fixed.D2](t) 245 testEqual[fixed.D3](t) 246 testEqual[fixed.D4](t) 247 testEqual[fixed.D5](t) 248 testEqual[fixed.D6](t) 249 } 250 251 func testEqual[T fixed.Dx](t *testing.T) { 252 check.Equal(t, false, f128.FromStringForced[T]("0.3333").Equal(f128.From[T](-3))) 253 check.Equal(t, false, f128.FromStringForced[T]("2.6789").Equal(f128.From[T](3))) 254 check.Equal(t, true, f128.From[T](3).Equal(f128.From[T](3))) 255 } 256 257 func TestGreaterThan(t *testing.T) { 258 testGreaterThan[fixed.D1](t) 259 testGreaterThan[fixed.D2](t) 260 testGreaterThan[fixed.D3](t) 261 testGreaterThan[fixed.D4](t) 262 testGreaterThan[fixed.D5](t) 263 testGreaterThan[fixed.D6](t) 264 } 265 266 func testGreaterThan[T fixed.Dx](t *testing.T) { 267 check.Equal(t, true, f128.FromStringForced[T]("0.3333").GreaterThan(f128.From[T](-3))) 268 check.Equal(t, false, f128.FromStringForced[T]("2.6789").GreaterThan(f128.From[T](3))) 269 check.Equal(t, false, f128.From[T](3).GreaterThan(f128.From[T](3))) 270 check.Equal(t, true, f128.From[T](4).GreaterThan(f128.From[T](3))) 271 check.Equal(t, true, f128.FromStringForced[T]("2.6789").GreaterThan(f128.From[T](-1))) 272 } 273 274 func TestGreaterThanOrEqual(t *testing.T) { 275 testGreaterThanOrEqual[fixed.D1](t) 276 testGreaterThanOrEqual[fixed.D2](t) 277 testGreaterThanOrEqual[fixed.D3](t) 278 testGreaterThanOrEqual[fixed.D4](t) 279 testGreaterThanOrEqual[fixed.D5](t) 280 testGreaterThanOrEqual[fixed.D6](t) 281 } 282 283 func testGreaterThanOrEqual[T fixed.Dx](t *testing.T) { 284 check.Equal(t, true, f128.FromStringForced[T]("0.3333").GreaterThanOrEqual(f128.From[T](-3))) 285 check.Equal(t, false, f128.FromStringForced[T]("2.6789").GreaterThanOrEqual(f128.From[T](3))) 286 check.Equal(t, true, f128.From[T](3).GreaterThanOrEqual(f128.From[T](3))) 287 check.Equal(t, true, f128.From[T](4).GreaterThanOrEqual(f128.From[T](3))) 288 check.Equal(t, true, f128.FromStringForced[T]("2.6789").GreaterThanOrEqual(f128.From[T](-1))) 289 } 290 291 func TestLessThan(t *testing.T) { 292 testLessThan[fixed.D1](t) 293 testLessThan[fixed.D2](t) 294 testLessThan[fixed.D3](t) 295 testLessThan[fixed.D4](t) 296 testLessThan[fixed.D5](t) 297 testLessThan[fixed.D6](t) 298 } 299 300 func testLessThan[T fixed.Dx](t *testing.T) { 301 check.Equal(t, false, f128.FromStringForced[T]("0.3333").LessThan(f128.From[T](-3))) 302 check.Equal(t, true, f128.FromStringForced[T]("2.6789").LessThan(f128.From[T](3))) 303 check.Equal(t, false, f128.From[T](3).LessThan(f128.From[T](3))) 304 check.Equal(t, false, f128.From[T](4).LessThan(f128.From[T](3))) 305 check.Equal(t, false, f128.FromStringForced[T]("2.6789").LessThan(f128.From[T](-1))) 306 } 307 308 func TestLessThanOrEqual(t *testing.T) { 309 testLessThanOrEqual[fixed.D1](t) 310 testLessThanOrEqual[fixed.D2](t) 311 testLessThanOrEqual[fixed.D3](t) 312 testLessThanOrEqual[fixed.D4](t) 313 testLessThanOrEqual[fixed.D5](t) 314 testLessThanOrEqual[fixed.D6](t) 315 } 316 317 func testLessThanOrEqual[T fixed.Dx](t *testing.T) { 318 check.Equal(t, false, f128.FromStringForced[T]("0.3333").LessThanOrEqual(f128.From[T](-3))) 319 check.Equal(t, true, f128.FromStringForced[T]("2.6789").LessThanOrEqual(f128.From[T](3))) 320 check.Equal(t, true, f128.From[T](3).LessThanOrEqual(f128.From[T](3))) 321 check.Equal(t, false, f128.From[T](4).LessThanOrEqual(f128.From[T](3))) 322 check.Equal(t, false, f128.FromStringForced[T]("2.6789").LessThanOrEqual(f128.From[T](-1))) 323 } 324 325 func TestComma(t *testing.T) { 326 check.Equal(t, "0.12", f128.FromStringForced[fixed.D2]("0.12").Comma()) 327 check.Equal(t, "1,234,567,890.12", f128.FromStringForced[fixed.D2]("1234567890.12").Comma()) 328 check.Equal(t, "91,234,567,890.12", f128.FromStringForced[fixed.D2]("91234567890.12").Comma()) 329 check.Equal(t, "891,234,567,890.12", f128.FromStringForced[fixed.D2]("891234567890.12").Comma()) 330 } 331 332 func TestJSON(t *testing.T) { 333 testJSON[fixed.D1](t) 334 testJSON[fixed.D2](t) 335 testJSON[fixed.D3](t) 336 testJSON[fixed.D4](t) 337 testJSON[fixed.D5](t) 338 testJSON[fixed.D6](t) 339 } 340 341 func testJSON[T fixed.Dx](t *testing.T) { 342 for i := -25000; i < 25001; i += 13 { 343 testJSONActual(t, f128.From[T](i)) 344 } 345 testJSONActual(t, f128.From[T, int64](1844674407371259000)) 346 } 347 348 type embedded[T fixed.Dx] struct { 349 Field f128.Int[T] 350 } 351 352 func testJSONActual[T fixed.Dx](t *testing.T, v f128.Int[T]) { 353 t.Helper() 354 e1 := embedded[T]{Field: v} 355 data, err := json.Marshal(&e1) 356 check.NoError(t, err) 357 var e2 embedded[T] 358 err = json.Unmarshal(data, &e2) 359 check.NoError(t, err) 360 check.Equal(t, e1, e2) 361 } 362 363 func TestYAML(t *testing.T) { 364 testYAML[fixed.D1](t) 365 testYAML[fixed.D2](t) 366 testYAML[fixed.D3](t) 367 testYAML[fixed.D4](t) 368 testYAML[fixed.D5](t) 369 testYAML[fixed.D6](t) 370 } 371 372 func testYAML[T fixed.Dx](t *testing.T) { 373 for i := -25000; i < 25001; i += 13 { 374 testYAMLActual(t, f128.From[T](i)) 375 } 376 testYAMLActual(t, f128.From[T, int64](1844674407371259000)) 377 } 378 379 func testYAMLActual[T fixed.Dx](t *testing.T, v f128.Int[T]) { 380 t.Helper() 381 e1 := embedded[T]{Field: v} 382 data, err := yaml.Marshal(&e1) 383 check.NoError(t, err) 384 var e2 embedded[T] 385 err = yaml.Unmarshal(data, &e2) 386 check.NoError(t, err) 387 check.Equal(t, e1, e2) 388 }