github.com/richardwilkes/toolbox@v1.121.0/xmath/num/int128.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 num 11 12 import ( 13 "fmt" 14 "math" 15 "math/big" 16 "math/bits" 17 "strconv" 18 19 "github.com/richardwilkes/toolbox/errs" 20 ) 21 22 const ( 23 signBit = 0x8000000000000000 24 minInt128Float = float64(-170141183460469231731687303715884105728) 25 maxInt128Float = float64(170141183460469231731687303715884105727) 26 ) 27 28 var ( 29 // MaxInt128 is the maximum value representable by an Int128. 30 MaxInt128 = Int128{hi: 0x7FFFFFFFFFFFFFFF, lo: 0xFFFFFFFFFFFFFFFF} 31 // MinInt128 is the minimum value representable by an Int128. 32 MinInt128 = Int128{hi: signBit, lo: 0} 33 ) 34 35 var ( 36 minInt128AsAbsUint128 = Uint128{hi: signBit, lo: 0} 37 maxInt128AsUint128 = Uint128{hi: 0x7FFFFFFFFFFFFFFF, lo: 0xFFFFFFFFFFFFFFFF} 38 maxBigUint128, _ = new(big.Int).SetString("340282366920938463463374607431768211455", 10) 39 big1 = new(big.Int).SetInt64(1) 40 ) 41 42 // Int128 represents a signed 128-bit integer. 43 type Int128 struct { 44 hi uint64 45 lo uint64 46 } 47 48 // Int128From64 creates an Int128 from an int64 value. 49 func Int128From64(v int64) Int128 { 50 var hi uint64 51 if v < 0 { 52 hi = math.MaxUint64 53 } 54 return Int128{hi: hi, lo: uint64(v)} 55 } 56 57 // Int128FromUint64 creates an Int128 from a uint64 value. 58 func Int128FromUint64(v uint64) Int128 { 59 return Int128{lo: v} 60 } 61 62 // Int128FromFloat64 creates an Int128 from a float64 value. 63 func Int128FromFloat64(f float64) Int128 { 64 switch { 65 case f == 0 || f != f: // 0 or NaN 66 return Int128{} 67 case f < 0: 68 switch { 69 case f >= -float64(math.MaxUint64)-1: 70 return Int128{ 71 hi: math.MaxUint64, 72 lo: uint64(f), 73 } 74 case f >= minInt128Float: 75 f = -f 76 lo := math.Mod(f, wrapUint64Float) 77 return Int128{ 78 hi: ^uint64(f / wrapUint64Float), 79 lo: ^uint64(lo), 80 } 81 default: 82 return MinInt128 83 } 84 default: 85 switch { 86 case f <= float64(math.MaxUint64): 87 return Int128{lo: uint64(f)} 88 case f <= maxInt128Float: 89 return Int128{ 90 hi: uint64(f / wrapUint64Float), 91 lo: uint64(math.Mod(f, wrapUint64Float)), 92 } 93 default: 94 return MaxInt128 95 } 96 } 97 } 98 99 // Int128FromBigInt creates an Int128 from a big.Int. 100 func Int128FromBigInt(v *big.Int) Int128 { 101 var i Uint128 102 words := v.Bits() 103 switch len(words) { 104 case 0: 105 case 1: 106 i.lo = uint64(words[0]) 107 case 2: 108 if intSize == 64 { 109 i.hi = uint64(words[1]) 110 i.lo = uint64(words[0]) 111 } else { 112 i.lo = (uint64(words[1]) << 32) | (uint64(words[0])) 113 } 114 case 3: 115 if intSize == 64 { 116 i = MaxUint128 117 } else { 118 i.hi = uint64(words[2]) 119 i.lo = (uint64(words[1]) << 32) | (uint64(words[0])) 120 } 121 case 4: 122 if intSize == 64 { 123 i = MaxUint128 124 } else { 125 i.hi = (uint64(words[3]) << 32) | (uint64(words[2])) 126 i.lo = (uint64(words[1]) << 32) | (uint64(words[0])) 127 } 128 default: 129 i = MaxUint128 130 } 131 if v.Sign() >= 0 { 132 if i.LessThan(maxInt128AsUint128) { 133 return i.AsInt128() 134 } 135 return MaxInt128 136 } 137 if i.LessThan(minInt128AsAbsUint128) { 138 return i.AsInt128().Neg() 139 } 140 return MinInt128 141 } 142 143 // Int128FromString creates an Int128 from a string. 144 func Int128FromString(s string) (Int128, error) { 145 b, err := parseToBigInt(s) 146 if err != nil { 147 return Int128{}, err 148 } 149 return Int128FromBigInt(b), nil 150 } 151 152 // Int128FromStringNoCheck creates an Int128 from a string. Unlike Int128FromString, this allows any string as input. 153 func Int128FromStringNoCheck(s string) Int128 { 154 i, _ := Int128FromString(s) //nolint:errcheck // Failure results in 0 155 return i 156 } 157 158 // Int128FromComponents creates an Int128 from two uint64 values representing the high and low bits. 159 func Int128FromComponents(high, low uint64) Int128 { 160 return Int128{hi: high, lo: low} 161 } 162 163 // Int128FromRand generates a signed 128-bit random integer. 164 func Int128FromRand(source RandomSource) Int128 { 165 return Int128{hi: source.Uint64(), lo: source.Uint64()} 166 } 167 168 // Components returns the two uint64 values representing the high and low bits. 169 func (i Int128) Components() (high, low uint64) { 170 return i.hi, i.lo 171 } 172 173 // IsZero returns true if the value is 0. 174 func (i Int128) IsZero() bool { 175 return i.hi|i.lo == 0 176 } 177 178 // ToBigInt stores the Int128's value into the specified big.Int. 179 func (i Int128) ToBigInt(b *big.Int) { 180 Uint128(i).ToBigInt(b) 181 if !i.IsUint128() { 182 b.Xor(b, maxBigUint128).Add(b, big1).Neg(b) 183 } 184 } 185 186 // AsBigInt returns the Int128 as a big.Int. 187 func (i Int128) AsBigInt() *big.Int { 188 var b big.Int 189 i.ToBigInt(&b) 190 return &b 191 } 192 193 // AsBigFloat returns the Int128 as a big.Float. 194 func (i Int128) AsBigFloat() (b *big.Float) { 195 return new(big.Float).SetInt(i.AsBigInt()) 196 } 197 198 // AsFloat64 returns the Int128 as a float64. 199 func (i Int128) AsFloat64() float64 { 200 switch { 201 case i.hi == 0: 202 if i.lo == 0 { 203 return 0 204 } 205 return float64(i.lo) 206 case i.hi == math.MaxUint64: 207 return -float64((^i.lo) + 1) 208 case i.hi&signBit == 0: 209 return (float64(i.hi) * maxUint64Float) + float64(i.lo) 210 default: 211 return (-float64(^i.hi) * maxUint64Float) + -float64(^i.lo) 212 } 213 } 214 215 // IsUint128 returns true if this value can be represented as an Uint128 without any loss. 216 func (i Int128) IsUint128() bool { 217 return i.hi&signBit == 0 218 } 219 220 // AsUint128 returns the Int128 as a Uint128. 221 func (i Int128) AsUint128() Uint128 { 222 return Uint128(i) 223 } 224 225 // IsInt64 returns true if this value can be represented as an int64 without any loss. 226 func (i Int128) IsInt64() bool { 227 if i.hi&signBit != 0 { 228 return i.hi == math.MaxUint64 && i.lo >= signBit 229 } 230 return i.hi == 0 && i.lo <= math.MaxInt64 231 } 232 233 // AsInt64 returns the Int128 as an int64. 234 func (i Int128) AsInt64() int64 { 235 if i.hi&signBit != 0 { 236 return -int64(^(i.lo - 1)) 237 } 238 return int64(i.lo) 239 } 240 241 // IsUint64 returns true if this value can be represented as a uint64 without any loss. 242 func (i Int128) IsUint64() bool { 243 return i.hi == 0 244 } 245 246 // AsUint64 returns the Int128 as a uint64. 247 func (i Int128) AsUint64() uint64 { 248 return i.lo 249 } 250 251 // Add returns i + n. 252 func (i Int128) Add(n Int128) Int128 { 253 lo, carry := bits.Add64(i.lo, n.lo, 0) 254 hi, _ := bits.Add64(i.hi, n.hi, carry) 255 return Int128{ 256 hi: hi, 257 lo: lo, 258 } 259 } 260 261 // Add64 returns i + n. 262 func (i Int128) Add64(n int64) Int128 { 263 lo, carry := bits.Add64(i.lo, uint64(n), 0) 264 if n < 0 { 265 carry += math.MaxUint64 266 } 267 return Int128{ 268 hi: i.hi + carry, 269 lo: lo, 270 } 271 } 272 273 // Sub returns i - n. 274 func (i Int128) Sub(n Int128) Int128 { 275 lo, borrow := bits.Sub64(i.lo, n.lo, 0) 276 hi, _ := bits.Sub64(i.hi, n.hi, borrow) 277 return Int128{ 278 hi: hi, 279 lo: lo, 280 } 281 } 282 283 // Sub64 returns i - n. 284 func (i Int128) Sub64(n int64) Int128 { 285 lo, borrow := bits.Sub64(i.lo, uint64(n), 0) 286 hi := i.hi - borrow 287 if n < 0 { 288 hi -= math.MaxUint64 289 } 290 return Int128{ 291 hi: hi, 292 lo: lo, 293 } 294 } 295 296 // Inc returns i + 1. 297 func (i Int128) Inc() Int128 { 298 return Int128(Uint128(i).Inc()) 299 } 300 301 // Dec returns i - 1. 302 func (i Int128) Dec() Int128 { 303 return Int128(Uint128(i).Dec()) 304 } 305 306 // Sign returns 1 if i > 0, 0 if i == 0, and -1 if i < 0. 307 func (i Int128) Sign() int { 308 switch { 309 case i.hi|i.lo == 0: 310 return 0 311 case i.hi&signBit == 0: 312 return 1 313 default: 314 return -1 315 } 316 } 317 318 // Neg returns -i. 319 func (i Int128) Neg() Int128 { 320 switch { 321 case i.hi|i.lo == 0 || i == MinInt128: 322 return i 323 case i.hi&signBit != 0: 324 hi := ^i.hi 325 lo := ^(i.lo - 1) 326 if lo == 0 { 327 hi++ 328 } 329 return Int128{hi: hi, lo: lo} 330 default: 331 hi := ^i.hi 332 lo := (^i.lo) + 1 333 if lo == 0 { 334 hi++ 335 } 336 return Int128{hi: hi, lo: lo} 337 } 338 } 339 340 // Abs returns the absolute value of i as an Int128. 341 func (i Int128) Abs() Int128 { 342 if i.hi&signBit != 0 { 343 i.hi = ^i.hi 344 i.lo = ^(i.lo - 1) 345 if i.lo == 0 { 346 i.hi++ 347 } 348 } 349 return i 350 } 351 352 // AbsUint128 returns the absolute value of i as a Uint128. 353 func (i Int128) AbsUint128() Uint128 { 354 v := Uint128(i) 355 if i == MinInt128 { 356 return v 357 } 358 if i.hi&signBit != 0 { 359 v.hi = ^i.hi 360 v.lo = ^(i.lo - 1) 361 if v.lo == 0 { 362 v.hi++ 363 } 364 } 365 return v 366 } 367 368 // Cmp returns 1 if i > n, 0 if i == n, and -1 if i < n. 369 func (i Int128) Cmp(n Int128) int { 370 switch { 371 case i.hi == n.hi && i.lo == n.lo: 372 return 0 373 case i.hi&signBit == n.hi&signBit: 374 if i.hi > n.hi || (i.hi == n.hi && i.lo > n.lo) { 375 return 1 376 } 377 case i.hi&signBit == 0: 378 return 1 379 } 380 return -1 381 } 382 383 // Cmp64 returns 1 if i > n, 0 if i == n, and -1 if i < n. 384 func (i Int128) Cmp64(n int64) int { 385 var nhi uint64 386 nlo := uint64(n) 387 if n < 0 { 388 nhi = math.MaxUint64 389 } 390 switch { 391 case i.hi == nhi && i.lo == nlo: 392 return 0 393 case i.hi&signBit == nhi&signBit: 394 if i.hi > nhi || (i.hi == nhi && i.lo > nlo) { 395 return 1 396 } 397 case i.hi&signBit == 0: 398 return 1 399 } 400 return -1 401 } 402 403 // GreaterThan returns true if i > n. 404 func (i Int128) GreaterThan(n Int128) bool { 405 switch { 406 case i.hi&signBit == n.hi&signBit: 407 return i.hi > n.hi || (i.hi == n.hi && i.lo > n.lo) 408 case i.hi&signBit == 0: 409 return true 410 default: 411 return false 412 } 413 } 414 415 // GreaterThan64 returns true if i > n. 416 func (i Int128) GreaterThan64(n int64) bool { 417 var nhi uint64 418 nlo := uint64(n) 419 if n < 0 { 420 nhi = math.MaxUint64 421 } 422 switch { 423 case i.hi&signBit == nhi&signBit: 424 return i.hi > nhi || (i.hi == nhi && i.lo > nlo) 425 case i.hi&signBit == 0: 426 return true 427 default: 428 return false 429 } 430 } 431 432 // GreaterThanOrEqual returns true if i >= n. 433 func (i Int128) GreaterThanOrEqual(n Int128) bool { 434 switch { 435 case i.hi == n.hi && i.lo == n.lo: 436 return true 437 case i.hi&signBit == n.hi&signBit: 438 return i.hi > n.hi || (i.hi == n.hi && i.lo > n.lo) 439 case i.hi&signBit == 0: 440 return true 441 default: 442 return false 443 } 444 } 445 446 // GreaterThanOrEqual64 returns true if i >= n. 447 func (i Int128) GreaterThanOrEqual64(n int64) bool { 448 var nhi uint64 449 nlo := uint64(n) 450 if n < 0 { 451 nhi = math.MaxUint64 452 } 453 switch { 454 case i.hi == nhi && i.lo == nlo: 455 return true 456 case i.hi&signBit == nhi&signBit: 457 return i.hi > nhi || (i.hi == nhi && i.lo > nlo) 458 case i.hi&signBit == 0: 459 return true 460 default: 461 return false 462 } 463 } 464 465 // Equal returns true if i == n. 466 func (i Int128) Equal(n Int128) bool { 467 return i.hi == n.hi && i.lo == n.lo 468 } 469 470 // Equal64 returns true if i == n. 471 func (i Int128) Equal64(n int64) bool { 472 var nhi uint64 473 nlo := uint64(n) 474 if n < 0 { 475 nhi = math.MaxUint64 476 } 477 return i.hi == nhi && i.lo == nlo 478 } 479 480 // LessThan returns true if i < n. 481 func (i Int128) LessThan(n Int128) bool { 482 switch { 483 case i.hi&signBit == n.hi&signBit: 484 return i.hi < n.hi || (i.hi == n.hi && i.lo < n.lo) 485 case i.hi&signBit != 0: 486 return true 487 default: 488 return false 489 } 490 } 491 492 // LessThan64 returns true if i < n. 493 func (i Int128) LessThan64(n int64) bool { 494 var nhi uint64 495 nlo := uint64(n) 496 if n < 0 { 497 nhi = math.MaxUint64 498 } 499 switch { 500 case i.hi&signBit == nhi&signBit: 501 return i.hi < nhi || (i.hi == nhi && i.lo < nlo) 502 case i.hi&signBit != 0: 503 return true 504 default: 505 return false 506 } 507 } 508 509 // LessThanOrEqual returns true if i <= n. 510 func (i Int128) LessThanOrEqual(n Int128) bool { 511 switch { 512 case i.hi == n.hi && i.lo == n.lo: 513 return true 514 case i.hi&signBit == n.hi&signBit: 515 return i.hi < n.hi || (i.hi == n.hi && i.lo < n.lo) 516 case i.hi&signBit != 0: 517 return true 518 default: 519 return false 520 } 521 } 522 523 // LessThanOrEqual64 returns true if i <= n. 524 func (i Int128) LessThanOrEqual64(n int64) bool { 525 var nhi uint64 526 nlo := uint64(n) 527 if n < 0 { 528 nhi = math.MaxUint64 529 } 530 switch { 531 case i.hi == nhi && i.lo == nlo: 532 return true 533 case i.hi&signBit == nhi&signBit: 534 return i.hi < nhi || (i.hi == nhi && i.lo < nlo) 535 case i.hi&signBit != 0: 536 return true 537 default: 538 return false 539 } 540 } 541 542 // Mul returns i * n. 543 func (i Int128) Mul(n Int128) Int128 { 544 hi, lo := bits.Mul64(i.lo, n.lo) 545 return Int128{ 546 hi: hi + i.hi*n.lo + i.lo*n.hi, 547 lo: lo, 548 } 549 } 550 551 // Mul64 returns i * n. 552 func (i Int128) Mul64(n int64) Int128 { 553 return i.Mul(Int128From64(n)) 554 } 555 556 // Div returns i / n. If n == 0, a divide by zero panic will occur. 557 func (i Int128) Div(n Int128) Int128 { 558 qSign := 1 559 if i.LessThan(Int128{}) { 560 qSign = -1 561 //goland:noinspection GoAssignmentToReceiver 562 i = i.Neg() 563 } 564 if n.LessThan(Int128{}) { 565 qSign = -qSign 566 n = n.Neg() 567 } 568 q := Int128(Uint128(i).Div(Uint128(n))) 569 if qSign < 0 { 570 q = q.Neg() 571 } 572 return q 573 } 574 575 // Div64 returns i / n. If n == 0, a divide by zero panic will occur. 576 func (i Int128) Div64(n int64) Int128 { 577 qSign := 1 578 if i.LessThan(Int128{}) { 579 qSign = -1 580 //goland:noinspection GoAssignmentToReceiver 581 i = i.Neg() 582 } 583 if n < 0 { 584 qSign = -qSign 585 n = -n 586 } 587 q := Int128(Uint128(i).Div64(uint64(n))) 588 if qSign < 0 { 589 q = q.Neg() 590 } 591 return q 592 } 593 594 // DivMod returns both the result of i / n as well i % n. If n == 0, a divide by zero panic will occur. 595 func (i Int128) DivMod(n Int128) (q, r Int128) { 596 qSign := 1 597 rSign := 1 598 if i.LessThan(Int128{}) { 599 qSign = -1 600 rSign = -1 601 //goland:noinspection GoAssignmentToReceiver 602 i = i.Neg() 603 } 604 if n.LessThan(Int128{}) { 605 qSign = -qSign 606 n = n.Neg() 607 } 608 qu, ru := Uint128(i).DivMod(Uint128(n)) 609 q = Int128(qu) 610 r = Int128(ru) 611 if qSign < 0 { 612 q = q.Neg() 613 } 614 if rSign < 0 { 615 r = r.Neg() 616 } 617 return q, r 618 } 619 620 // DivMod64 returns both the result of i / n as well i % n. If n == 0, a divide by zero panic will occur. 621 func (i Int128) DivMod64(n int64) (q, r Int128) { 622 var hi uint64 623 if n < 0 { 624 hi = math.MaxUint64 625 } 626 return i.DivMod(Int128{hi: hi, lo: uint64(n)}) 627 } 628 629 // Mod returns i % n. If n == 0, a divide by zero panic will occur. 630 func (i Int128) Mod(n Int128) (r Int128) { 631 _, r = i.DivMod(n) 632 return r 633 } 634 635 // Mod64 returns i % n. If n == 0, a divide by zero panic will occur. 636 func (i Int128) Mod64(n int64) (r Int128) { 637 _, r = i.DivMod64(n) 638 return r 639 } 640 641 // String implements fmt.Stringer. 642 func (i Int128) String() string { 643 if i.hi == 0 { 644 if i.lo == 0 { 645 return "0" 646 } 647 return strconv.FormatUint(i.lo, 10) 648 } 649 return i.AsBigInt().String() 650 } 651 652 // Format implements fmt.Formatter. 653 func (i Int128) Format(s fmt.State, c rune) { 654 i.AsBigInt().Format(s, c) 655 } 656 657 // Scan implements fmt.Scanner. 658 func (i *Int128) Scan(state fmt.ScanState, _ rune) error { 659 t, err := state.Token(true, nil) 660 if err != nil { 661 return errs.Wrap(err) 662 } 663 var v Int128 664 if v, err = Int128FromString(string(t)); err != nil { 665 return errs.Wrap(err) 666 } 667 *i = v 668 return nil 669 } 670 671 // MarshalText implements encoding.TextMarshaler. 672 func (i Int128) MarshalText() ([]byte, error) { 673 return []byte(i.String()), nil 674 } 675 676 // UnmarshalText implements encoding.TextUnmarshaler. 677 func (i *Int128) UnmarshalText(text []byte) error { 678 v, err := Int128FromString(string(text)) 679 if err != nil { 680 return err 681 } 682 *i = v 683 return nil 684 } 685 686 // Float64 implements json.Number. Intentionally always returns an error, as we never want to emit floating point values 687 // into json for Int128. 688 func (i Int128) Float64() (float64, error) { 689 return 0, errNoFloat64 690 } 691 692 // Int64 implements json.Number. 693 func (i Int128) Int64() (int64, error) { 694 if !i.IsInt64() { 695 return 0, errDoesNotFitInInt64 696 } 697 return i.AsInt64(), nil 698 } 699 700 // MarshalJSON implements json.Marshaler. 701 func (i Int128) MarshalJSON() ([]byte, error) { 702 return []byte(i.String()), nil 703 } 704 705 // UnmarshalJSON implements json.Unmarshaler. 706 func (i *Int128) UnmarshalJSON(in []byte) error { 707 v, err := Int128FromString(string(in)) 708 if err != nil { 709 return err 710 } 711 *i = v 712 return nil 713 } 714 715 // MarshalYAML implements yaml.Marshaler. 716 func (i Int128) MarshalYAML() (any, error) { 717 return i.String(), nil 718 } 719 720 // UnmarshalYAML implements yaml.Unmarshaler. 721 func (i *Int128) UnmarshalYAML(unmarshal func(any) error) error { 722 var str string 723 if err := unmarshal(&str); err != nil { 724 return err 725 } 726 v, err := Int128FromString(str) 727 if err != nil { 728 return err 729 } 730 *i = v 731 return nil 732 }