github.com/godaddy-x/freego@v1.0.156/utils/decimal/decimal.go (about) 1 // Package decimal implements an arbitrary precision fixed-point decimal. 2 // 3 // To use as part of a struct: 4 // 5 // type Struct struct { 6 // Number Decimal 7 // } 8 // 9 // The zero-value of a Decimal is 0, as you would expect. 10 // 11 // The best way to create a new Decimal is to use decimal.NewFromString, ex: 12 // 13 // n, err := decimal.NewFromString("-123.4567") 14 // n.String() // output: "-123.4567" 15 // 16 // NOTE: This can "only" represent numbers with a maximum of 2^31 digits 17 // after the decimal point. 18 package decimal 19 20 import ( 21 "database/sql/driver" 22 "encoding/binary" 23 "fmt" 24 "math" 25 "math/big" 26 "strconv" 27 "strings" 28 ) 29 30 // DivisionPrecision is the number of decimal places in the result when it 31 // doesn't divide exactly. 32 // 33 // Example: 34 // 35 // d1 := decimal.NewFromFloat(2).Div(decimal.NewFromFloat(3) 36 // d1.String() // output: "0.6666666666666667" 37 // d2 := decimal.NewFromFloat(2).Div(decimal.NewFromFloat(30000) 38 // d2.String() // output: "0.0000666666666667" 39 // d3 := decimal.NewFromFloat(20000).Div(decimal.NewFromFloat(3) 40 // d3.String() // output: "6666.6666666666666667" 41 // decimal.DivisionPrecision = 3 42 // d4 := decimal.NewFromFloat(2).Div(decimal.NewFromFloat(3) 43 // d4.String() // output: "0.667" 44 // 45 var DivisionPrecision = 16 46 47 // MarshalJSONWithoutQuotes should be set to true if you want the decimal to 48 // be JSON marshaled as a number, instead of as a string. 49 // WARNING: this is dangerous for decimals with many digits, since many JSON 50 // unmarshallers (ex: Javascript's) will unmarshal JSON numbers to IEEE 754 51 // double-precision floating point numbers, which means you can potentially 52 // silently lose precision. 53 var MarshalJSONWithoutQuotes = false 54 55 // Zero constant, to make computations faster. 56 var Zero = New(0, 1) 57 58 // fiveDec used in Cash Rounding 59 var fiveDec = New(5, 0) 60 61 var zeroInt = big.NewInt(0) 62 var oneInt = big.NewInt(1) 63 var twoInt = big.NewInt(2) 64 var fourInt = big.NewInt(4) 65 var fiveInt = big.NewInt(5) 66 var tenInt = big.NewInt(10) 67 var twentyInt = big.NewInt(20) 68 69 // Decimal represents a fixed-point decimal. It is immutable. 70 // number = value * 10 ^ exp 71 type Decimal struct { 72 value *big.Int 73 74 // NOTE(vadim): this must be an int32, because we cast it to float64 during 75 // calculations. If exp is 64 bit, we might lose precision. 76 // If we cared about being able to represent every possible decimal, we 77 // could make exp a *big.Int but it would hurt performance and numbers 78 // like that are unrealistic. 79 exp int32 80 } 81 82 // New returns a new fixed-point decimal, value * 10 ^ exp. 83 func New(value int64, exp int32) Decimal { 84 return Decimal{ 85 value: big.NewInt(value), 86 exp: exp, 87 } 88 } 89 90 // NewFromBigInt returns a new Decimal from a big.Int, value * 10 ^ exp 91 func NewFromBigInt(value *big.Int, exp int32) Decimal { 92 return Decimal{ 93 value: big.NewInt(0).Set(value), 94 exp: exp, 95 } 96 } 97 98 // NewFromString returns a new Decimal from a string representation. 99 // 100 // Example: 101 // 102 // d, err := NewFromString("-123.45") 103 // d2, err := NewFromString(".0001") 104 // 105 func NewFromString(value string) (Decimal, error) { 106 originalInput := value 107 var intString string 108 var exp int64 109 110 // Check if number is using scientific notation 111 eIndex := strings.IndexAny(value, "Ee") 112 if eIndex != -1 { 113 expInt, err := strconv.ParseInt(value[eIndex+1:], 10, 32) 114 if err != nil { 115 if e, ok := err.(*strconv.NumError); ok && e.Err == strconv.ErrRange { 116 return Decimal{}, fmt.Errorf("can't convert %s to decimal: fractional part too long", value) 117 } 118 return Decimal{}, fmt.Errorf("can't convert %s to decimal: exponent is not numeric", value) 119 } 120 value = value[:eIndex] 121 exp = expInt 122 } 123 124 parts := strings.Split(value, ".") 125 if len(parts) == 1 { 126 // There is no decimal point, we can just parse the original string as 127 // an int 128 intString = value 129 } else if len(parts) == 2 { 130 // strip the insignificant digits for more accurate comparisons. 131 decimalPart := strings.TrimRight(parts[1], "0") 132 intString = parts[0] + decimalPart 133 expInt := -len(decimalPart) 134 exp += int64(expInt) 135 } else { 136 return Decimal{}, fmt.Errorf("can't convert %s to decimal: too many .s", value) 137 } 138 139 dValue := new(big.Int) 140 _, ok := dValue.SetString(intString, 10) 141 if !ok { 142 return Decimal{}, fmt.Errorf("can't convert %s to decimal", value) 143 } 144 145 if exp < math.MinInt32 || exp > math.MaxInt32 { 146 // NOTE(vadim): I doubt a string could realistically be this long 147 return Decimal{}, fmt.Errorf("can't convert %s to decimal: fractional part too long", originalInput) 148 } 149 150 return Decimal{ 151 value: dValue, 152 exp: int32(exp), 153 }, nil 154 } 155 156 // RequireFromString returns a new Decimal from a string representation 157 // or panics if NewFromString would have returned an error. 158 // 159 // Example: 160 // 161 // d := RequireFromString("-123.45") 162 // d2 := RequireFromString(".0001") 163 // 164 func RequireFromString(value string) Decimal { 165 dec, err := NewFromString(value) 166 if err != nil { 167 panic(err) 168 } 169 return dec 170 } 171 172 // NewFromFloat converts a float64 to Decimal. 173 // 174 // The converted number will contain the number of significant digits that can be 175 // represented in a float with reliable roundtrip. 176 // This is typically 15 digits, but may be more in some cases. 177 // See https://www.exploringbinary.com/decimal-precision-of-binary-floating-point-numbers/ for more information. 178 // 179 // For slightly faster conversion, use NewFromFloatWithExponent where you can specify the precision in absolute terms. 180 // 181 // NOTE: this will panic on NaN, +/-inf 182 func NewFromFloat(value float64) Decimal { 183 if value == 0 { 184 return New(0, 0) 185 } 186 return newFromFloat(value, math.Float64bits(value), &float64info) 187 } 188 189 // NewFromFloat converts a float32 to Decimal. 190 // 191 // The converted number will contain the number of significant digits that can be 192 // represented in a float with reliable roundtrip. 193 // This is typically 6-8 digits depending on the input. 194 // See https://www.exploringbinary.com/decimal-precision-of-binary-floating-point-numbers/ for more information. 195 // 196 // For slightly faster conversion, use NewFromFloatWithExponent where you can specify the precision in absolute terms. 197 // 198 // NOTE: this will panic on NaN, +/-inf 199 func NewFromFloat32(value float32) Decimal { 200 if value == 0 { 201 return New(0, 0) 202 } 203 // XOR is workaround for https://github.com/golang/go/issues/26285 204 a := math.Float32bits(value) ^ 0x80808080 205 return newFromFloat(float64(value), uint64(a)^0x80808080, &float32info) 206 } 207 208 func newFromFloat(val float64, bits uint64, flt *floatInfo) Decimal { 209 if math.IsNaN(val) || math.IsInf(val, 0) { 210 panic(fmt.Sprintf("Cannot create a Decimal from %v", val)) 211 } 212 exp := int(bits>>flt.mantbits) & (1<<flt.expbits - 1) 213 mant := bits & (uint64(1)<<flt.mantbits - 1) 214 215 switch exp { 216 case 0: 217 // denormalized 218 exp++ 219 220 default: 221 // add implicit top bit 222 mant |= uint64(1) << flt.mantbits 223 } 224 exp += flt.bias 225 226 var d decimal 227 d.Assign(mant) 228 d.Shift(exp - int(flt.mantbits)) 229 d.neg = bits>>(flt.expbits+flt.mantbits) != 0 230 231 roundShortest(&d, mant, exp, flt) 232 // If less than 19 digits, we can do calculation in an int64. 233 if d.nd < 19 { 234 tmp := int64(0) 235 m := int64(1) 236 for i := d.nd - 1; i >= 0; i-- { 237 tmp += m * int64(d.d[i]-'0') 238 m *= 10 239 } 240 if d.neg { 241 tmp *= -1 242 } 243 return Decimal{value: big.NewInt(tmp), exp: int32(d.dp) - int32(d.nd)} 244 } 245 dValue := new(big.Int) 246 dValue, ok := dValue.SetString(string(d.d[:d.nd]), 10) 247 if ok { 248 return Decimal{value: dValue, exp: int32(d.dp) - int32(d.nd)} 249 } 250 251 return NewFromFloatWithExponent(val, int32(d.dp)-int32(d.nd)) 252 } 253 254 // NewFromFloatWithExponent converts a float64 to Decimal, with an arbitrary 255 // number of fractional digits. 256 // 257 // Example: 258 // 259 // NewFromFloatWithExponent(123.456, -2).String() // output: "123.46" 260 // 261 func NewFromFloatWithExponent(value float64, exp int32) Decimal { 262 if math.IsNaN(value) || math.IsInf(value, 0) { 263 panic(fmt.Sprintf("Cannot create a Decimal from %v", value)) 264 } 265 266 bits := math.Float64bits(value) 267 mant := bits & (1<<52 - 1) 268 exp2 := int32((bits >> 52) & (1<<11 - 1)) 269 sign := bits >> 63 270 271 if exp2 == 0 { 272 // specials 273 if mant == 0 { 274 return Decimal{} 275 } else { 276 // subnormal 277 exp2++ 278 } 279 } else { 280 // normal 281 mant |= 1 << 52 282 } 283 284 exp2 -= 1023 + 52 285 286 // normalizing base-2 values 287 for mant&1 == 0 { 288 mant = mant >> 1 289 exp2++ 290 } 291 292 // maximum number of fractional base-10 digits to represent 2^N exactly cannot be more than -N if N<0 293 if exp < 0 && exp < exp2 { 294 if exp2 < 0 { 295 exp = exp2 296 } else { 297 exp = 0 298 } 299 } 300 301 // representing 10^M * 2^N as 5^M * 2^(M+N) 302 exp2 -= exp 303 304 temp := big.NewInt(1) 305 dMant := big.NewInt(int64(mant)) 306 307 // applying 5^M 308 if exp > 0 { 309 temp = temp.SetInt64(int64(exp)) 310 temp = temp.Exp(fiveInt, temp, nil) 311 } else if exp < 0 { 312 temp = temp.SetInt64(-int64(exp)) 313 temp = temp.Exp(fiveInt, temp, nil) 314 dMant = dMant.Mul(dMant, temp) 315 temp = temp.SetUint64(1) 316 } 317 318 // applying 2^(M+N) 319 if exp2 > 0 { 320 dMant = dMant.Lsh(dMant, uint(exp2)) 321 } else if exp2 < 0 { 322 temp = temp.Lsh(temp, uint(-exp2)) 323 } 324 325 // rounding and downscaling 326 if exp > 0 || exp2 < 0 { 327 halfDown := new(big.Int).Rsh(temp, 1) 328 dMant = dMant.Add(dMant, halfDown) 329 dMant = dMant.Quo(dMant, temp) 330 } 331 332 if sign == 1 { 333 dMant = dMant.Neg(dMant) 334 } 335 336 return Decimal{ 337 value: dMant, 338 exp: exp, 339 } 340 } 341 342 // rescale returns a rescaled version of the decimal. Returned 343 // decimal may be less precise if the given exponent is bigger 344 // than the initial exponent of the Decimal. 345 // NOTE: this will truncate, NOT round 346 // 347 // Example: 348 // 349 // d := New(12345, -4) 350 // d2 := d.rescale(-1) 351 // d3 := d2.rescale(-4) 352 // println(d1) 353 // println(d2) 354 // println(d3) 355 // 356 // Output: 357 // 358 // 1.2345 359 // 1.2 360 // 1.2000 361 // 362 func (d Decimal) rescale(exp int32) Decimal { 363 d.ensureInitialized() 364 // NOTE(vadim): must convert exps to float64 before - to prevent overflow 365 diff := math.Abs(float64(exp) - float64(d.exp)) 366 value := new(big.Int).Set(d.value) 367 368 expScale := new(big.Int).Exp(tenInt, big.NewInt(int64(diff)), nil) 369 if exp > d.exp { 370 value = value.Quo(value, expScale) 371 } else if exp < d.exp { 372 value = value.Mul(value, expScale) 373 } 374 375 return Decimal{ 376 value: value, 377 exp: exp, 378 } 379 } 380 381 // Abs returns the absolute value of the decimal. 382 func (d Decimal) Abs() Decimal { 383 d.ensureInitialized() 384 d2Value := new(big.Int).Abs(d.value) 385 return Decimal{ 386 value: d2Value, 387 exp: d.exp, 388 } 389 } 390 391 // Add returns d + d2. 392 func (d Decimal) Add(d2 Decimal) Decimal { 393 baseScale := min(d.exp, d2.exp) 394 rd := d.rescale(baseScale) 395 rd2 := d2.rescale(baseScale) 396 397 d3Value := new(big.Int).Add(rd.value, rd2.value) 398 return Decimal{ 399 value: d3Value, 400 exp: baseScale, 401 } 402 } 403 404 // Sub returns d - d2. 405 func (d Decimal) Sub(d2 Decimal) Decimal { 406 baseScale := min(d.exp, d2.exp) 407 rd := d.rescale(baseScale) 408 rd2 := d2.rescale(baseScale) 409 410 d3Value := new(big.Int).Sub(rd.value, rd2.value) 411 return Decimal{ 412 value: d3Value, 413 exp: baseScale, 414 } 415 } 416 417 // Neg returns -d. 418 func (d Decimal) Neg() Decimal { 419 d.ensureInitialized() 420 val := new(big.Int).Neg(d.value) 421 return Decimal{ 422 value: val, 423 exp: d.exp, 424 } 425 } 426 427 // Mul returns d * d2. 428 func (d Decimal) Mul(d2 Decimal) Decimal { 429 d.ensureInitialized() 430 d2.ensureInitialized() 431 432 expInt64 := int64(d.exp) + int64(d2.exp) 433 if expInt64 > math.MaxInt32 || expInt64 < math.MinInt32 { 434 // NOTE(vadim): better to panic than give incorrect results, as 435 // Decimals are usually used for money 436 panic(fmt.Sprintf("exponent %v overflows an int32!", expInt64)) 437 } 438 439 d3Value := new(big.Int).Mul(d.value, d2.value) 440 return Decimal{ 441 value: d3Value, 442 exp: int32(expInt64), 443 } 444 } 445 446 // Shift shifts the decimal in base 10. 447 // It shifts left when shift is positive and right if shift is negative. 448 // In simpler terms, the given value for shift is added to the exponent 449 // of the decimal. 450 func (d Decimal) Shift(shift int32) Decimal { 451 d.ensureInitialized() 452 return Decimal{ 453 value: new(big.Int).Set(d.value), 454 exp: d.exp + shift, 455 } 456 } 457 458 // Div returns d / d2. If it doesn't divide exactly, the result will have 459 // DivisionPrecision digits after the decimal point. 460 func (d Decimal) Div(d2 Decimal) Decimal { 461 return d.DivRound(d2, int32(DivisionPrecision)) 462 } 463 464 // QuoRem does divsion with remainder 465 // d.QuoRem(d2,precision) returns quotient q and remainder r such that 466 // d = d2 * q + r, q an integer multiple of 10^(-precision) 467 // 0 <= r < abs(d2) * 10 ^(-precision) if d>=0 468 // 0 >= r > -abs(d2) * 10 ^(-precision) if d<0 469 // Note that precision<0 is allowed as input. 470 func (d Decimal) QuoRem(d2 Decimal, precision int32) (Decimal, Decimal) { 471 d.ensureInitialized() 472 d2.ensureInitialized() 473 if d2.value.Sign() == 0 { 474 panic("decimal division by 0") 475 } 476 scale := -precision 477 e := int64(d.exp - d2.exp - scale) 478 if e > math.MaxInt32 || e < math.MinInt32 { 479 panic("overflow in decimal QuoRem") 480 } 481 var aa, bb, expo big.Int 482 var scalerest int32 483 // d = a 10^ea 484 // d2 = b 10^eb 485 if e < 0 { 486 aa = *d.value 487 expo.SetInt64(-e) 488 bb.Exp(tenInt, &expo, nil) 489 bb.Mul(d2.value, &bb) 490 scalerest = d.exp 491 // now aa = a 492 // bb = b 10^(scale + eb - ea) 493 } else { 494 expo.SetInt64(e) 495 aa.Exp(tenInt, &expo, nil) 496 aa.Mul(d.value, &aa) 497 bb = *d2.value 498 scalerest = scale + d2.exp 499 // now aa = a ^ (ea - eb - scale) 500 // bb = b 501 } 502 var q, r big.Int 503 q.QuoRem(&aa, &bb, &r) 504 dq := Decimal{value: &q, exp: scale} 505 dr := Decimal{value: &r, exp: scalerest} 506 return dq, dr 507 } 508 509 // DivRound divides and rounds to a given precision 510 // i.e. to an integer multiple of 10^(-precision) 511 // for a positive quotient digit 5 is rounded up, away from 0 512 // if the quotient is negative then digit 5 is rounded down, away from 0 513 // Note that precision<0 is allowed as input. 514 func (d Decimal) DivRound(d2 Decimal, precision int32) Decimal { 515 // QuoRem already checks initialization 516 q, r := d.QuoRem(d2, precision) 517 // the actual rounding decision is based on comparing r*10^precision and d2/2 518 // instead compare 2 r 10 ^precision and d2 519 var rv2 big.Int 520 rv2.Abs(r.value) 521 rv2.Lsh(&rv2, 1) 522 // now rv2 = abs(r.value) * 2 523 r2 := Decimal{value: &rv2, exp: r.exp + precision} 524 // r2 is now 2 * r * 10 ^ precision 525 var c = r2.Cmp(d2.Abs()) 526 527 if c < 0 { 528 return q 529 } 530 531 if d.value.Sign()*d2.value.Sign() < 0 { 532 return q.Sub(New(1, -precision)) 533 } 534 535 return q.Add(New(1, -precision)) 536 } 537 538 // Mod returns d % d2. 539 func (d Decimal) Mod(d2 Decimal) Decimal { 540 quo := d.Div(d2).Truncate(0) 541 return d.Sub(d2.Mul(quo)) 542 } 543 544 // Pow returns d to the power d2 545 func (d Decimal) Pow(d2 Decimal) Decimal { 546 var temp Decimal 547 if d2.IntPart() == 0 { 548 return NewFromFloat(1) 549 } 550 temp = d.Pow(d2.Div(NewFromFloat(2))) 551 if d2.IntPart()%2 == 0 { 552 return temp.Mul(temp) 553 } 554 if d2.IntPart() > 0 { 555 return temp.Mul(temp).Mul(d) 556 } 557 return temp.Mul(temp).Div(d) 558 } 559 560 // Cmp compares the numbers represented by d and d2 and returns: 561 // 562 // -1 if d < d2 563 // 0 if d == d2 564 // +1 if d > d2 565 // 566 func (d Decimal) Cmp(d2 Decimal) int { 567 d.ensureInitialized() 568 d2.ensureInitialized() 569 570 if d.exp == d2.exp { 571 return d.value.Cmp(d2.value) 572 } 573 574 baseExp := min(d.exp, d2.exp) 575 rd := d.rescale(baseExp) 576 rd2 := d2.rescale(baseExp) 577 578 return rd.value.Cmp(rd2.value) 579 } 580 581 // Equal returns whether the numbers represented by d and d2 are equal. 582 func (d Decimal) Equal(d2 Decimal) bool { 583 return d.Cmp(d2) == 0 584 } 585 586 // Equals is deprecated, please use Equal method instead 587 func (d Decimal) Equals(d2 Decimal) bool { 588 return d.Equal(d2) 589 } 590 591 // GreaterThan (GT) returns true when d is greater than d2. 592 func (d Decimal) GreaterThan(d2 Decimal) bool { 593 return d.Cmp(d2) == 1 594 } 595 596 // GreaterThanOrEqual (GTE) returns true when d is greater than or equal to d2. 597 func (d Decimal) GreaterThanOrEqual(d2 Decimal) bool { 598 cmp := d.Cmp(d2) 599 return cmp == 1 || cmp == 0 600 } 601 602 // LessThan (LT) returns true when d is less than d2. 603 func (d Decimal) LessThan(d2 Decimal) bool { 604 return d.Cmp(d2) == -1 605 } 606 607 // LessThanOrEqual (LTE) returns true when d is less than or equal to d2. 608 func (d Decimal) LessThanOrEqual(d2 Decimal) bool { 609 cmp := d.Cmp(d2) 610 return cmp == -1 || cmp == 0 611 } 612 613 // Sign returns: 614 // 615 // -1 if d < 0 616 // 0 if d == 0 617 // +1 if d > 0 618 // 619 func (d Decimal) Sign() int { 620 if d.value == nil { 621 return 0 622 } 623 return d.value.Sign() 624 } 625 626 // IsPositive return 627 // 628 // true if d > 0 629 // false if d == 0 630 // false if d < 0 631 func (d Decimal) IsPositive() bool { 632 return d.Sign() == 1 633 } 634 635 // IsNegative return 636 // 637 // true if d < 0 638 // false if d == 0 639 // false if d > 0 640 func (d Decimal) IsNegative() bool { 641 return d.Sign() == -1 642 } 643 644 // IsZero return 645 // 646 // true if d == 0 647 // false if d > 0 648 // false if d < 0 649 func (d Decimal) IsZero() bool { 650 return d.Sign() == 0 651 } 652 653 // Exponent returns the exponent, or scale component of the decimal. 654 func (d Decimal) Exponent() int32 { 655 return d.exp 656 } 657 658 // Coefficient returns the coefficient of the decimal. It is scaled by 10^Exponent() 659 func (d Decimal) Coefficient() *big.Int { 660 // we copy the coefficient so that mutating the result does not mutate the 661 // Decimal. 662 return big.NewInt(0).Set(d.value) 663 } 664 665 // IntPart returns the integer component of the decimal. 666 func (d Decimal) IntPart() int64 { 667 scaledD := d.rescale(0) 668 return scaledD.value.Int64() 669 } 670 671 // Rat returns a rational number representation of the decimal. 672 func (d Decimal) Rat() *big.Rat { 673 d.ensureInitialized() 674 if d.exp <= 0 { 675 // NOTE(vadim): must negate after casting to prevent int32 overflow 676 denom := new(big.Int).Exp(tenInt, big.NewInt(-int64(d.exp)), nil) 677 return new(big.Rat).SetFrac(d.value, denom) 678 } 679 680 mul := new(big.Int).Exp(tenInt, big.NewInt(int64(d.exp)), nil) 681 num := new(big.Int).Mul(d.value, mul) 682 return new(big.Rat).SetFrac(num, oneInt) 683 } 684 685 // Float64 returns the nearest float64 value for d and a bool indicating 686 // whether f represents d exactly. 687 // For more details, see the documentation for big.Rat.Float64 688 func (d Decimal) Float64() (f float64, exact bool) { 689 return d.Rat().Float64() 690 } 691 692 // String returns the string representation of the decimal 693 // with the fixed point. 694 // 695 // Example: 696 // 697 // d := New(-12345, -3) 698 // println(d.String()) 699 // 700 // Output: 701 // 702 // -12.345 703 // 704 func (d Decimal) String() string { 705 return d.string(true) 706 } 707 708 // StringFixed returns a rounded fixed-point string with places digits after 709 // the decimal point. 710 // 711 // Example: 712 // 713 // NewFromFloat(0).StringFixed(2) // output: "0.00" 714 // NewFromFloat(0).StringFixed(0) // output: "0" 715 // NewFromFloat(5.45).StringFixed(0) // output: "5" 716 // NewFromFloat(5.45).StringFixed(1) // output: "5.5" 717 // NewFromFloat(5.45).StringFixed(2) // output: "5.45" 718 // NewFromFloat(5.45).StringFixed(3) // output: "5.450" 719 // NewFromFloat(545).StringFixed(-1) // output: "550" 720 // 721 func (d Decimal) StringFixed(places int32) string { 722 rounded := d.Round(places) 723 return rounded.string(false) 724 } 725 726 // StringFixedBank returns a banker rounded fixed-point string with places digits 727 // after the decimal point. 728 // 729 // Example: 730 // 731 // NewFromFloat(0).StringFixed(2) // output: "0.00" 732 // NewFromFloat(0).StringFixed(0) // output: "0" 733 // NewFromFloat(5.45).StringFixed(0) // output: "5" 734 // NewFromFloat(5.45).StringFixed(1) // output: "5.4" 735 // NewFromFloat(5.45).StringFixed(2) // output: "5.45" 736 // NewFromFloat(5.45).StringFixed(3) // output: "5.450" 737 // NewFromFloat(545).StringFixed(-1) // output: "550" 738 // 739 func (d Decimal) StringFixedBank(places int32) string { 740 rounded := d.RoundBank(places) 741 return rounded.string(false) 742 } 743 744 // StringFixedCash returns a Swedish/Cash rounded fixed-point string. For 745 // more details see the documentation at function RoundCash. 746 func (d Decimal) StringFixedCash(interval uint8) string { 747 rounded := d.RoundCash(interval) 748 return rounded.string(false) 749 } 750 751 // Round rounds the decimal to places decimal places. 752 // If places < 0, it will round the integer part to the nearest 10^(-places). 753 // 754 // Example: 755 // 756 // NewFromFloat(5.45).Round(1).String() // output: "5.5" 757 // NewFromFloat(545).Round(-1).String() // output: "550" 758 // 759 func (d Decimal) Round(places int32) Decimal { 760 // truncate to places + 1 761 ret := d.rescale(-places - 1) 762 763 // add sign(d) * 0.5 764 if ret.value.Sign() < 0 { 765 ret.value.Sub(ret.value, fiveInt) 766 } else { 767 ret.value.Add(ret.value, fiveInt) 768 } 769 770 // floor for positive numbers, ceil for negative numbers 771 _, m := ret.value.DivMod(ret.value, tenInt, new(big.Int)) 772 ret.exp++ 773 if ret.value.Sign() < 0 && m.Cmp(zeroInt) != 0 { 774 ret.value.Add(ret.value, oneInt) 775 } 776 777 return ret 778 } 779 780 // RoundBank rounds the decimal to places decimal places. 781 // If the final digit to round is equidistant from the nearest two integers the 782 // rounded value is taken as the even number 783 // 784 // If places < 0, it will round the integer part to the nearest 10^(-places). 785 // 786 // Examples: 787 // 788 // NewFromFloat(5.45).Round(1).String() // output: "5.4" 789 // NewFromFloat(545).Round(-1).String() // output: "540" 790 // NewFromFloat(5.46).Round(1).String() // output: "5.5" 791 // NewFromFloat(546).Round(-1).String() // output: "550" 792 // NewFromFloat(5.55).Round(1).String() // output: "5.6" 793 // NewFromFloat(555).Round(-1).String() // output: "560" 794 // 795 func (d Decimal) RoundBank(places int32) Decimal { 796 797 round := d.Round(places) 798 remainder := d.Sub(round).Abs() 799 800 half := New(5, -places-1) 801 if remainder.Cmp(half) == 0 && round.value.Bit(0) != 0 { 802 if round.value.Sign() < 0 { 803 round.value.Add(round.value, oneInt) 804 } else { 805 round.value.Sub(round.value, oneInt) 806 } 807 } 808 809 return round 810 } 811 812 // RoundCash aka Cash/Penny/öre rounding rounds decimal to a specific 813 // interval. The amount payable for a cash transaction is rounded to the nearest 814 // multiple of the minimum currency unit available. The following intervals are 815 // available: 5, 10, 15, 25, 50 and 100; any other number throws a panic. 816 // 5: 5 cent rounding 3.43 => 3.45 817 // 10: 10 cent rounding 3.45 => 3.50 (5 gets rounded up) 818 // 15: 10 cent rounding 3.45 => 3.40 (5 gets rounded down) 819 // 25: 25 cent rounding 3.41 => 3.50 820 // 50: 50 cent rounding 3.75 => 4.00 821 // 100: 100 cent rounding 3.50 => 4.00 822 // For more details: https://en.wikipedia.org/wiki/Cash_rounding 823 func (d Decimal) RoundCash(interval uint8) Decimal { 824 var iVal *big.Int 825 switch interval { 826 case 5: 827 iVal = twentyInt 828 case 10: 829 iVal = tenInt 830 case 15: 831 if d.exp < 0 { 832 // TODO: optimize and reduce allocations 833 orgExp := d.exp 834 dOne := New(10^-int64(orgExp), orgExp) 835 d2 := d 836 d2.exp = 0 837 if d2.Mod(fiveDec).Equal(Zero) { 838 d2.exp = orgExp 839 d2 = d2.Sub(dOne) 840 d = d2 841 } 842 } 843 iVal = tenInt 844 case 25: 845 iVal = fourInt 846 case 50: 847 iVal = twoInt 848 case 100: 849 iVal = oneInt 850 default: 851 panic(fmt.Sprintf("Decimal does not support this Cash rounding interval `%d`. Supported: 5, 10, 15, 25, 50, 100", interval)) 852 } 853 dVal := Decimal{ 854 value: iVal, 855 } 856 // TODO: optimize those calculations to reduce the high allocations (~29 allocs). 857 return d.Mul(dVal).Round(0).Div(dVal).Truncate(2) 858 } 859 860 // Floor returns the nearest integer value less than or equal to d. 861 func (d Decimal) Floor() Decimal { 862 d.ensureInitialized() 863 864 if d.exp >= 0 { 865 return d 866 } 867 868 exp := big.NewInt(10) 869 870 // NOTE(vadim): must negate after casting to prevent int32 overflow 871 exp.Exp(exp, big.NewInt(-int64(d.exp)), nil) 872 873 z := new(big.Int).Div(d.value, exp) 874 return Decimal{value: z, exp: 0} 875 } 876 877 // Ceil returns the nearest integer value greater than or equal to d. 878 func (d Decimal) Ceil() Decimal { 879 d.ensureInitialized() 880 881 if d.exp >= 0 { 882 return d 883 } 884 885 exp := big.NewInt(10) 886 887 // NOTE(vadim): must negate after casting to prevent int32 overflow 888 exp.Exp(exp, big.NewInt(-int64(d.exp)), nil) 889 890 z, m := new(big.Int).DivMod(d.value, exp, new(big.Int)) 891 if m.Cmp(zeroInt) != 0 { 892 z.Add(z, oneInt) 893 } 894 return Decimal{value: z, exp: 0} 895 } 896 897 // Truncate truncates off digits from the number, without rounding. 898 // 899 // NOTE: precision is the last digit that will not be truncated (must be >= 0). 900 // 901 // Example: 902 // 903 // decimal.NewFromString("123.456").Truncate(2).String() // "123.45" 904 // 905 func (d Decimal) Truncate(precision int32) Decimal { 906 d.ensureInitialized() 907 if precision >= 0 && -precision > d.exp { 908 return d.rescale(-precision) 909 } 910 return d 911 } 912 913 // UnmarshalJSON implements the json.Unmarshaler interface. 914 func (d *Decimal) UnmarshalJSON(decimalBytes []byte) error { 915 if string(decimalBytes) == "null" { 916 return nil 917 } 918 919 str, err := unquoteIfQuoted(decimalBytes) 920 if err != nil { 921 return fmt.Errorf("Error decoding string '%s': %s", decimalBytes, err) 922 } 923 924 decimal, err := NewFromString(str) 925 *d = decimal 926 if err != nil { 927 return fmt.Errorf("Error decoding string '%s': %s", str, err) 928 } 929 return nil 930 } 931 932 // MarshalJSON implements the json.Marshaler interface. 933 func (d Decimal) MarshalJSON() ([]byte, error) { 934 var str string 935 if MarshalJSONWithoutQuotes { 936 str = d.String() 937 } else { 938 str = "\"" + d.String() + "\"" 939 } 940 return []byte(str), nil 941 } 942 943 // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface. As a string representation 944 // is already used when encoding to text, this method stores that string as []byte 945 func (d *Decimal) UnmarshalBinary(data []byte) error { 946 // Extract the exponent 947 d.exp = int32(binary.BigEndian.Uint32(data[:4])) 948 949 // Extract the value 950 d.value = new(big.Int) 951 return d.value.GobDecode(data[4:]) 952 } 953 954 // MarshalBinary implements the encoding.BinaryMarshaler interface. 955 func (d Decimal) MarshalBinary() (data []byte, err error) { 956 // Write the exponent first since it's a fixed size 957 v1 := make([]byte, 4) 958 binary.BigEndian.PutUint32(v1, uint32(d.exp)) 959 960 // Add the value 961 var v2 []byte 962 if v2, err = d.value.GobEncode(); err != nil { 963 return 964 } 965 966 // Return the byte array 967 data = append(v1, v2...) 968 return 969 } 970 971 // Scan implements the sql.Scanner interface for database deserialization. 972 func (d *Decimal) Scan(value interface{}) error { 973 // first try to see if the data is stored in database as a Numeric datatype 974 switch v := value.(type) { 975 976 case float32: 977 *d = NewFromFloat(float64(v)) 978 return nil 979 980 case float64: 981 // numeric in sqlite3 sends us float64 982 *d = NewFromFloat(v) 983 return nil 984 985 case int64: 986 // at least in sqlite3 when the value is 0 in db, the data is sent 987 // to us as an int64 instead of a float64 ... 988 *d = New(v, 0) 989 return nil 990 991 default: 992 // default is trying to interpret value stored as string 993 str, err := unquoteIfQuoted(v) 994 if err != nil { 995 return err 996 } 997 *d, err = NewFromString(str) 998 return err 999 } 1000 } 1001 1002 // Value implements the driver.Valuer interface for database serialization. 1003 func (d Decimal) Value() (driver.Value, error) { 1004 return d.String(), nil 1005 } 1006 1007 // UnmarshalText implements the encoding.TextUnmarshaler interface for XML 1008 // deserialization. 1009 func (d *Decimal) UnmarshalText(text []byte) error { 1010 str := string(text) 1011 1012 dec, err := NewFromString(str) 1013 *d = dec 1014 if err != nil { 1015 return fmt.Errorf("Error decoding string '%s': %s", str, err) 1016 } 1017 1018 return nil 1019 } 1020 1021 // MarshalText implements the encoding.TextMarshaler interface for XML 1022 // serialization. 1023 func (d Decimal) MarshalText() (text []byte, err error) { 1024 return []byte(d.String()), nil 1025 } 1026 1027 // GobEncode implements the gob.GobEncoder interface for gob serialization. 1028 func (d Decimal) GobEncode() ([]byte, error) { 1029 return d.MarshalBinary() 1030 } 1031 1032 // GobDecode implements the gob.GobDecoder interface for gob serialization. 1033 func (d *Decimal) GobDecode(data []byte) error { 1034 return d.UnmarshalBinary(data) 1035 } 1036 1037 // StringScaled first scales the decimal then calls .String() on it. 1038 // NOTE: buggy, unintuitive, and DEPRECATED! Use StringFixed instead. 1039 func (d Decimal) StringScaled(exp int32) string { 1040 return d.rescale(exp).String() 1041 } 1042 1043 func (d Decimal) string(trimTrailingZeros bool) string { 1044 if d.exp >= 0 { 1045 return d.rescale(0).value.String() 1046 } 1047 1048 abs := new(big.Int).Abs(d.value) 1049 str := abs.String() 1050 1051 var intPart, fractionalPart string 1052 1053 // NOTE(vadim): this cast to int will cause bugs if d.exp == INT_MIN 1054 // and you are on a 32-bit machine. Won't fix this super-edge case. 1055 dExpInt := int(d.exp) 1056 if len(str) > -dExpInt { 1057 intPart = str[:len(str)+dExpInt] 1058 fractionalPart = str[len(str)+dExpInt:] 1059 } else { 1060 intPart = "0" 1061 1062 num0s := -dExpInt - len(str) 1063 fractionalPart = strings.Repeat("0", num0s) + str 1064 } 1065 1066 if trimTrailingZeros { 1067 i := len(fractionalPart) - 1 1068 for ; i >= 0; i-- { 1069 if fractionalPart[i] != '0' { 1070 break 1071 } 1072 } 1073 fractionalPart = fractionalPart[:i+1] 1074 } 1075 1076 number := intPart 1077 if len(fractionalPart) > 0 { 1078 number += "." + fractionalPart 1079 } 1080 1081 if d.value.Sign() < 0 { 1082 return "-" + number 1083 } 1084 1085 return number 1086 } 1087 1088 func (d *Decimal) ensureInitialized() { 1089 if d.value == nil { 1090 d.value = new(big.Int) 1091 } 1092 } 1093 1094 // Min returns the smallest Decimal that was passed in the arguments. 1095 // 1096 // To call this function with an array, you must do: 1097 // 1098 // Min(arr[0], arr[1:]...) 1099 // 1100 // This makes it harder to accidentally call Min with 0 arguments. 1101 func Min(first Decimal, rest ...Decimal) Decimal { 1102 ans := first 1103 for _, item := range rest { 1104 if item.Cmp(ans) < 0 { 1105 ans = item 1106 } 1107 } 1108 return ans 1109 } 1110 1111 // Max returns the largest Decimal that was passed in the arguments. 1112 // 1113 // To call this function with an array, you must do: 1114 // 1115 // Max(arr[0], arr[1:]...) 1116 // 1117 // This makes it harder to accidentally call Max with 0 arguments. 1118 func Max(first Decimal, rest ...Decimal) Decimal { 1119 ans := first 1120 for _, item := range rest { 1121 if item.Cmp(ans) > 0 { 1122 ans = item 1123 } 1124 } 1125 return ans 1126 } 1127 1128 // Sum returns the combined total of the provided first and rest Decimals 1129 func Sum(first Decimal, rest ...Decimal) Decimal { 1130 total := first 1131 for _, item := range rest { 1132 total = total.Add(item) 1133 } 1134 1135 return total 1136 } 1137 1138 // Avg returns the average value of the provided first and rest Decimals 1139 func Avg(first Decimal, rest ...Decimal) Decimal { 1140 count := New(int64(len(rest)+1), 0) 1141 sum := Sum(first, rest...) 1142 return sum.Div(count) 1143 } 1144 1145 func min(x, y int32) int32 { 1146 if x >= y { 1147 return y 1148 } 1149 return x 1150 } 1151 1152 func unquoteIfQuoted(value interface{}) (string, error) { 1153 var bytes []byte 1154 1155 switch v := value.(type) { 1156 case string: 1157 bytes = []byte(v) 1158 case []byte: 1159 bytes = v 1160 default: 1161 return "", fmt.Errorf("Could not convert value '%+v' to byte array of type '%T'", 1162 value, value) 1163 } 1164 1165 // If the amount is quoted, strip the quotes 1166 if len(bytes) > 2 && bytes[0] == '"' && bytes[len(bytes)-1] == '"' { 1167 bytes = bytes[1 : len(bytes)-1] 1168 } 1169 return string(bytes), nil 1170 } 1171 1172 // NullDecimal represents a nullable decimal with compatibility for 1173 // scanning null values from the database. 1174 type NullDecimal struct { 1175 Decimal Decimal 1176 Valid bool 1177 } 1178 1179 // Scan implements the sql.Scanner interface for database deserialization. 1180 func (d *NullDecimal) Scan(value interface{}) error { 1181 if value == nil { 1182 d.Valid = false 1183 return nil 1184 } 1185 d.Valid = true 1186 return d.Decimal.Scan(value) 1187 } 1188 1189 // Value implements the driver.Valuer interface for database serialization. 1190 func (d NullDecimal) Value() (driver.Value, error) { 1191 if !d.Valid { 1192 return nil, nil 1193 } 1194 return d.Decimal.Value() 1195 } 1196 1197 // UnmarshalJSON implements the json.Unmarshaler interface. 1198 func (d *NullDecimal) UnmarshalJSON(decimalBytes []byte) error { 1199 if string(decimalBytes) == "null" { 1200 d.Valid = false 1201 return nil 1202 } 1203 d.Valid = true 1204 return d.Decimal.UnmarshalJSON(decimalBytes) 1205 } 1206 1207 // MarshalJSON implements the json.Marshaler interface. 1208 func (d NullDecimal) MarshalJSON() ([]byte, error) { 1209 if !d.Valid { 1210 return []byte("null"), nil 1211 } 1212 return d.Decimal.MarshalJSON() 1213 } 1214 1215 // Trig functions 1216 1217 // Atan returns the arctangent, in radians, of x. 1218 func (x Decimal) Atan() Decimal { 1219 if x.Equal(NewFromFloat(0.0)) { 1220 return x 1221 } 1222 if x.GreaterThan(NewFromFloat(0.0)) { 1223 return x.satan() 1224 } 1225 return x.Neg().satan().Neg() 1226 } 1227 1228 func (d Decimal) xatan() Decimal { 1229 P0 := NewFromFloat(-8.750608600031904122785e-01) 1230 P1 := NewFromFloat(-1.615753718733365076637e+01) 1231 P2 := NewFromFloat(-7.500855792314704667340e+01) 1232 P3 := NewFromFloat(-1.228866684490136173410e+02) 1233 P4 := NewFromFloat(-6.485021904942025371773e+01) 1234 Q0 := NewFromFloat(2.485846490142306297962e+01) 1235 Q1 := NewFromFloat(1.650270098316988542046e+02) 1236 Q2 := NewFromFloat(4.328810604912902668951e+02) 1237 Q3 := NewFromFloat(4.853903996359136964868e+02) 1238 Q4 := NewFromFloat(1.945506571482613964425e+02) 1239 z := d.Mul(d) 1240 b1 := P0.Mul(z).Add(P1).Mul(z).Add(P2).Mul(z).Add(P3).Mul(z).Add(P4).Mul(z) 1241 b2 := z.Add(Q0).Mul(z).Add(Q1).Mul(z).Add(Q2).Mul(z).Add(Q3).Mul(z).Add(Q4) 1242 z = b1.Div(b2) 1243 z = d.Mul(z).Add(d) 1244 return z 1245 } 1246 1247 // satan reduces its argument (known to be positive) 1248 // to the range [0, 0.66] and calls xatan. 1249 func (d Decimal) satan() Decimal { 1250 Morebits := NewFromFloat(6.123233995736765886130e-17) // pi/2 = PIO2 + Morebits 1251 Tan3pio8 := NewFromFloat(2.41421356237309504880) // tan(3*pi/8) 1252 pi := NewFromFloat(3.14159265358979323846264338327950288419716939937510582097494459) 1253 1254 if d.LessThanOrEqual(NewFromFloat(0.66)) { 1255 return d.xatan() 1256 } 1257 if d.GreaterThan(Tan3pio8) { 1258 return pi.Div(NewFromFloat(2.0)).Sub(NewFromFloat(1.0).Div(d).xatan()).Add(Morebits) 1259 } 1260 return pi.Div(NewFromFloat(4.0)).Add((d.Sub(NewFromFloat(1.0)).Div(d.Add(NewFromFloat(1.0)))).xatan()).Add(NewFromFloat(0.5).Mul(Morebits)) 1261 } 1262 1263 // sin coefficients 1264 var _sin = [...]Decimal{ 1265 NewFromFloat(1.58962301576546568060E-10), // 0x3de5d8fd1fd19ccd 1266 NewFromFloat(-2.50507477628578072866E-8), // 0xbe5ae5e5a9291f5d 1267 NewFromFloat(2.75573136213857245213E-6), // 0x3ec71de3567d48a1 1268 NewFromFloat(-1.98412698295895385996E-4), // 0xbf2a01a019bfdf03 1269 NewFromFloat(8.33333333332211858878E-3), // 0x3f8111111110f7d0 1270 NewFromFloat(-1.66666666666666307295E-1), // 0xbfc5555555555548 1271 } 1272 1273 // Sin returns the sine of the radian argument x. 1274 func (d Decimal) Sin() Decimal { 1275 PI4A := NewFromFloat(7.85398125648498535156E-1) // 0x3fe921fb40000000, Pi/4 split into three parts 1276 PI4B := NewFromFloat(3.77489470793079817668E-8) // 0x3e64442d00000000, 1277 PI4C := NewFromFloat(2.69515142907905952645E-15) // 0x3ce8469898cc5170, 1278 M4PI := NewFromFloat(1.273239544735162542821171882678754627704620361328125) // 4/pi 1279 1280 if d.Equal(NewFromFloat(0.0)) { 1281 return d 1282 } 1283 // make argument positive but save the sign 1284 sign := false 1285 if d.LessThan(NewFromFloat(0.0)) { 1286 d = d.Neg() 1287 sign = true 1288 } 1289 1290 j := d.Mul(M4PI).IntPart() // integer part of x/(Pi/4), as integer for tests on the phase angle 1291 y := NewFromFloat(float64(j)) // integer part of x/(Pi/4), as float 1292 1293 // map zeros to origin 1294 if j&1 == 1 { 1295 j++ 1296 y = y.Add(NewFromFloat(1.0)) 1297 } 1298 j &= 7 // octant modulo 2Pi radians (360 degrees) 1299 // reflect in x axis 1300 if j > 3 { 1301 sign = !sign 1302 j -= 4 1303 } 1304 z := d.Sub(y.Mul(PI4A)).Sub(y.Mul(PI4B)).Sub(y.Mul(PI4C)) // Extended precision modular arithmetic 1305 zz := z.Mul(z) 1306 1307 if j == 1 || j == 2 { 1308 w := zz.Mul(zz).Mul(_cos[0].Mul(zz).Add(_cos[1]).Mul(zz).Add(_cos[2]).Mul(zz).Add(_cos[3]).Mul(zz).Add(_cos[4]).Mul(zz).Add(_cos[5])) 1309 y = NewFromFloat(1.0).Sub(NewFromFloat(0.5).Mul(zz)).Add(w) 1310 } else { 1311 y = z.Add(z.Mul(zz).Mul(_sin[0].Mul(zz).Add(_sin[1]).Mul(zz).Add(_sin[2]).Mul(zz).Add(_sin[3]).Mul(zz).Add(_sin[4]).Mul(zz).Add(_sin[5]))) 1312 } 1313 if sign { 1314 y = y.Neg() 1315 } 1316 return y 1317 } 1318 1319 // cos coefficients 1320 var _cos = [...]Decimal{ 1321 NewFromFloat(-1.13585365213876817300E-11), // 0xbda8fa49a0861a9b 1322 NewFromFloat(2.08757008419747316778E-9), // 0x3e21ee9d7b4e3f05 1323 NewFromFloat(-2.75573141792967388112E-7), // 0xbe927e4f7eac4bc6 1324 NewFromFloat(2.48015872888517045348E-5), // 0x3efa01a019c844f5 1325 NewFromFloat(-1.38888888888730564116E-3), // 0xbf56c16c16c14f91 1326 NewFromFloat(4.16666666666665929218E-2), // 0x3fa555555555554b 1327 } 1328 1329 // Cos returns the cosine of the radian argument x. 1330 func (d Decimal) Cos() Decimal { 1331 1332 PI4A := NewFromFloat(7.85398125648498535156E-1) // 0x3fe921fb40000000, Pi/4 split into three parts 1333 PI4B := NewFromFloat(3.77489470793079817668E-8) // 0x3e64442d00000000, 1334 PI4C := NewFromFloat(2.69515142907905952645E-15) // 0x3ce8469898cc5170, 1335 M4PI := NewFromFloat(1.273239544735162542821171882678754627704620361328125) // 4/pi 1336 1337 // make argument positive 1338 sign := false 1339 if d.LessThan(NewFromFloat(0.0)) { 1340 d = d.Neg() 1341 } 1342 1343 j := d.Mul(M4PI).IntPart() // integer part of x/(Pi/4), as integer for tests on the phase angle 1344 y := NewFromFloat(float64(j)) // integer part of x/(Pi/4), as float 1345 1346 // map zeros to origin 1347 if j&1 == 1 { 1348 j++ 1349 y = y.Add(NewFromFloat(1.0)) 1350 } 1351 j &= 7 // octant modulo 2Pi radians (360 degrees) 1352 // reflect in x axis 1353 if j > 3 { 1354 sign = !sign 1355 j -= 4 1356 } 1357 if j > 1 { 1358 sign = !sign 1359 } 1360 1361 z := d.Sub(y.Mul(PI4A)).Sub(y.Mul(PI4B)).Sub(y.Mul(PI4C)) // Extended precision modular arithmetic 1362 zz := z.Mul(z) 1363 1364 if j == 1 || j == 2 { 1365 y = z.Add(z.Mul(zz).Mul(_sin[0].Mul(zz).Add(_sin[1]).Mul(zz).Add(_sin[2]).Mul(zz).Add(_sin[3]).Mul(zz).Add(_sin[4]).Mul(zz).Add(_sin[5]))) 1366 } else { 1367 w := zz.Mul(zz).Mul(_cos[0].Mul(zz).Add(_cos[1]).Mul(zz).Add(_cos[2]).Mul(zz).Add(_cos[3]).Mul(zz).Add(_cos[4]).Mul(zz).Add(_cos[5])) 1368 y = NewFromFloat(1.0).Sub(NewFromFloat(0.5).Mul(zz)).Add(w) 1369 } 1370 if sign { 1371 y = y.Neg() 1372 } 1373 return y 1374 } 1375 1376 var _tanP = [...]Decimal{ 1377 NewFromFloat(-1.30936939181383777646E+4), // 0xc0c992d8d24f3f38 1378 NewFromFloat(1.15351664838587416140E+6), // 0x413199eca5fc9ddd 1379 NewFromFloat(-1.79565251976484877988E+7), // 0xc1711fead3299176 1380 } 1381 var _tanQ = [...]Decimal{ 1382 NewFromFloat(1.00000000000000000000E+0), 1383 NewFromFloat(1.36812963470692954678E+4), //0x40cab8a5eeb36572 1384 NewFromFloat(-1.32089234440210967447E+6), //0xc13427bc582abc96 1385 NewFromFloat(2.50083801823357915839E+7), //0x4177d98fc2ead8ef 1386 NewFromFloat(-5.38695755929454629881E+7), //0xc189afe03cbe5a31 1387 } 1388 1389 // Tan returns the tangent of the radian argument x. 1390 func (d Decimal) Tan() Decimal { 1391 1392 PI4A := NewFromFloat(7.85398125648498535156E-1) // 0x3fe921fb40000000, Pi/4 split into three parts 1393 PI4B := NewFromFloat(3.77489470793079817668E-8) // 0x3e64442d00000000, 1394 PI4C := NewFromFloat(2.69515142907905952645E-15) // 0x3ce8469898cc5170, 1395 M4PI := NewFromFloat(1.273239544735162542821171882678754627704620361328125) // 4/pi 1396 1397 if d.Equal(NewFromFloat(0.0)) { 1398 return d 1399 } 1400 1401 // make argument positive but save the sign 1402 sign := false 1403 if d.LessThan(NewFromFloat(0.0)) { 1404 d = d.Neg() 1405 sign = true 1406 } 1407 1408 j := d.Mul(M4PI).IntPart() // integer part of x/(Pi/4), as integer for tests on the phase angle 1409 y := NewFromFloat(float64(j)) // integer part of x/(Pi/4), as float 1410 1411 // map zeros to origin 1412 if j&1 == 1 { 1413 j++ 1414 y = y.Add(NewFromFloat(1.0)) 1415 } 1416 1417 z := d.Sub(y.Mul(PI4A)).Sub(y.Mul(PI4B)).Sub(y.Mul(PI4C)) // Extended precision modular arithmetic 1418 zz := z.Mul(z) 1419 1420 if zz.GreaterThan(NewFromFloat(1e-14)) { 1421 w := zz.Mul(_tanP[0].Mul(zz).Add(_tanP[1]).Mul(zz).Add(_tanP[2])) 1422 x := zz.Add(_tanQ[1]).Mul(zz).Add(_tanQ[2]).Mul(zz).Add(_tanQ[3]).Mul(zz).Add(_tanQ[4]) 1423 y = z.Add(z.Mul(w.Div(x))) 1424 } else { 1425 y = z 1426 } 1427 if j&2 == 2 { 1428 y = NewFromFloat(-1.0).Div(y) 1429 } 1430 if sign { 1431 y = y.Neg() 1432 } 1433 return y 1434 }