/src/lib/numeric/mutable_big_integer.e
Specman e | 3242 lines | 2778 code | 118 blank | 346 comment | 173 complexity | 1607f00f3277ea7f98b3afbcb3c85bf5 MD5 | raw file
Large files files are truncated, but you can click here to view the full file
1-- This file is part of a Liberty Eiffel library. 2-- See the full copyright at the end. 3-- 4class MUTABLE_BIG_INTEGER 5 -- 6 -- A class used to represent multiprecision integers that makes efficient use of allocated space 7 -- by allowing a number to occupy only part of an array so that the arrays do not have to be 8 -- reallocated as often. When performing an operation with many iterations the array used to 9 -- hold a number is only reallocated when necessary and does not have to be the same size as 10 -- the number it represents. A mutable number allows calculations to occur on the same number 11 -- without having to create a new number for every step of the calculation as it occurs with 12 -- NUMBERs. 13 -- 14 15inherit 16 HASHABLE 17 redefine copy, fill_tagged_out_memory, out_in_tagged_out_memory 18 end 19 COMPARABLE 20 redefine copy, fill_tagged_out_memory, out_in_tagged_out_memory, is_equal 21 end 22 23insert 24 PLATFORM 25 redefine copy, fill_tagged_out_memory, out_in_tagged_out_memory, is_equal 26 end 27 28create {ANY} 29 from_integer, from_integer_64, from_string, copy 30 31feature {ANY} -- Creation / initialization from INTEGER_32 or INTEGER_64: 32 from_integer (value: INTEGER) 33 -- Create or initialize `Current' using `value' as an initializer. 34 do 35 if capacity = 0 then 36 storage := storage.calloc(4) 37 capacity := 4 38 end 39 offset := 0 40 if value > 0 then 41 negative := False 42 put(value, 0) 43 integer_length := 1 44 elseif value < 0 then 45 negative := True 46 put(#-value, 0) 47 integer_length := 1 48 else 49 check 50 value = 0 51 end 52 set_with_zero 53 end 54 ensure 55 to_integer_32 = value 56 end 57 58 is_integer_32: BOOLEAN 59 -- Does `Current' fit on an INTEGER_32? 60 do 61 if integer_length = 0 then 62 Result := True 63 elseif integer_length = 1 then 64 if item(offset) > 0 then 65 Result := True 66 elseif negative then 67 Result := item(offset) = 0x80000000 68 end 69 end 70 ensure 71 Result implies is_integer_64 72 Result implies integer_length <= 1 73 end 74 75 to_integer_32: INTEGER 76 -- Convert `Current' as a 32 bit INTEGER. 77 require 78 is_integer_32 79 do 80 if integer_length > 0 then 81 Result := item(offset) 82 if negative then 83 Result := #-Result 84 end 85 end 86 end 87 88 from_integer_64 (value: INTEGER_64) 89 -- Create or set `Current' using `value' as an initializer. 90 local 91 v32: INTEGER 92 do 93 if capacity < 2 then 94 storage := storage.calloc(4) 95 capacity := 4 96 end 97 if value > 0 then 98 negative := False 99 put(value.low_32, 0) 100 offset := 0 101 v32 := value.high_32 102 if v32 = 0 then 103 integer_length := 1 104 else 105 put(v32, 1) 106 integer_length := 2 107 end 108 elseif value < 0 then 109 negative := True 110 put((#-value).low_32, 0) 111 offset := 0 112 v32 := (#-value).high_32 113 if v32 = 0 then 114 integer_length := 1 115 else 116 put(v32, 1) 117 integer_length := 2 118 end 119 else 120 check 121 value = 0 122 end 123 set_with_zero 124 end 125 ensure 126 to_integer_64 = value 127 end 128 129 is_integer_64: BOOLEAN 130 -- Does `Current' fit on an INTEGER_64? 131 do 132 if integer_length <= 1 then 133 Result := True 134 elseif integer_length = 2 then 135 if negative then 136 if item(offset + 1) > 0 then 137 Result := True 138 elseif item(offset) = 0 then 139 Result := item(offset + 1) = 0x80000000 140 end 141 else 142 Result := item(offset + 1) > 0 143 end 144 end 145 ensure 146 not Result implies not is_integer_32 147 Result implies integer_length <= 2 148 end 149 150 to_integer_64: INTEGER_64 151 -- Convert `Current' as a INTEGER_64. 152 require 153 is_integer_64 154 local 155 v: INTEGER_64 156 do 157 inspect 158 integer_length 159 when 0 then 160 when 1 then 161 Result := unsigned_32_to_integer_64(item(offset)) 162 if negative then 163 Result := -Result 164 end 165 when 2 then 166 Result := unsigned_32_to_integer_64(item(offset)) 167 v := item(offset + 1) 168 v := v.bit_shift_left(32) 169 Result := Result.bit_xor(v) 170 if negative then 171 Result := #-Result 172 end 173 end 174 end 175 176feature {ANY} -- Creation / initialization from STRING: 177 from_string (str: STRING) 178 -- Create or initialize `Current' using `value' as an 179 -- initializer. (value = [-][0-9]^+) 180 local 181 i: INTEGER; cc: CHARACTER; neg: BOOLEAN; ten: like Current 182 do 183 --|*** This feature should be improved one day... (Vincent Croizier, 25/12/2004) 184 create ten.from_integer(10) 185 from 186 i := 1 187 variant 188 str.count - i 189 until 190 not str.item(i).is_separator 191 loop 192 i := i + 1 193 end 194 cc := str.item(i) 195 i := i + 1 196 if cc = '+' then 197 cc := str.item(i) 198 i := i + 1 199 elseif cc = '-' then 200 neg := True 201 cc := str.item(i) 202 i := i + 1 203 end 204 check 205 cc.is_digit 206 end 207 from_integer(cc.value) 208 from 209 variant 210 str.count - i 211 until 212 i > str.count 213 loop 214 cc := str.item(i) 215 if cc.is_digit then 216 multiply(ten) 217 add_integer(cc.value) 218 else 219 check 220 cc.is_separator 221 end 222 i := str.count -- terminate the loop 223 end 224 i := i + 1 225 end 226 if neg then 227 negate 228 end 229 end 230 231feature {ANY} -- Conversion tool 232 force_to_real_64: REAL_64 233 -- only a tool 234 -- unsigned conversion *** require ou changer export ? *** (Dom Oct 4th 2004) *** 235 local 236 i: INTEGER 237 do 238 from 239 i := offset + integer_length - 1 240 until 241 i < offset or else Result > Maximum_real_64 242 loop 243 Result := Result * Real_base + unsigned_32_to_integer_64(storage.item(i)).force_to_real_64 244 i := i - 1 245 end 246 if Result = Maximum_real_64 and then storage.item(offset) /= 0 then 247 Result := Maximum_real_64 * 2 248 end 249 if negative then 250 Result := -Result 251 end 252 end 253 254feature {NUMBER} 255 from_native_array (na: NATIVE_ARRAY[INTEGER]; cap: INTEGER; neg: BOOLEAN) 256 require 257 na.item(cap - 1) /= 0 258 do 259 negative := neg 260 offset := 0 261 integer_length := cap 262 if cap > capacity then 263 capacity := capacity_from_lower_bound(capacity, cap) 264 storage := storage.calloc(capacity) 265 end 266 storage.slice_copy(0, na, 0, cap - 1) 267 end 268 269 to_integer_general_number: INTEGER_GENERAL_NUMBER 270 local 271 na: like storage 272 do 273 if is_integer_64 then 274 create {INTEGER_64_NUMBER} Result.make(to_integer_64) 275 else 276 na := storage.calloc(integer_length) 277 na.slice_copy(0, storage, offset, offset + integer_length - 1) 278 create {BIG_INTEGER_NUMBER} Result.from_native_array(na, integer_length, negative) 279 end 280 end 281 282feature {ANY} -- Addition: 283 add (other: like Current) 284 -- Add `other' into `Current'. 285 -- 286 -- See also `add_integer', `add_integer_64', `add_natural'. 287 require 288 other /= Void 289 do 290 -- Choose the appropriate absolute operator depending on `Current' and `other' sign. 291 if other.integer_length = 0 then 292 -- Nothing to do, `Current' remains unchanged. 293 elseif integer_length = 0 then 294 -- `Current' is zero so simply copy the value of other 295 Current.copy(other) 296 elseif negative = other.negative then 297 -- same sign 298 add_magnitude(other) 299 else 300 -- different sign 301 subtract_magnitude(other) 302 end 303 end 304 305 add_to (other, res: like Current) 306 -- Add `other' and `Current', and put the result in `res'. 307 require 308 other /= Void 309 res /= Void 310 res /= Current 311 res /= other 312 do 313 --|*** Must be optimized later (Vincent Croizier, 15/07/04) *** 314 res.copy(Current) 315 res.add(other) 316 end 317 318 add_integer (other: INTEGER) 319 -- Add `other' into `Current'. 320 local 321 inc: BOOLEAN; v, i, n: INTEGER 322 do 323 if other = 0 then 324 -- Nothing to do, `Current' remains unchanged 325 elseif integer_length = 0 then 326 -- `Current' is null so simply copy the value of other 327 from_integer(other) 328 elseif negative = (other < 0) then 329 -- Same sign 330 if other < 0 then 331 v := #-other 332 else 333 v := other 334 end 335 -- Add `v' into `storage' 336 from 337 inc := mbi_add(item(offset), v, storage_at(storage, offset)) 338 i := offset + 1 339 n := offset + integer_length 340 until 341 not inc or else i >= n 342 loop 343 inc := mbi_inc(storage_at(storage, i)) 344 i := i + 1 345 end 346 if inc then 347 check 348 i = n 349 end 350 -- Extend the number length by 1 351 if n < capacity then 352 integer_length := integer_length + 1 353 put(1, n) 354 else 355 -- It's good only if the reallocation initialize 356 -- `storage' with 0. 357 v := item(offset) 358 capacity := capacity * 2 359 storage := storage.calloc(capacity) 360 offset := 0 361 put(v, 0) 362 put(1, integer_length) 363 integer_length := integer_length + 1 364 end 365 end 366 -- Different sign 367 elseif integer_length = 1 then 368 if other < 0 then 369 v := #-other 370 else 371 v := other 372 end 373 if mbi_subtract(item(offset), v, storage_at(storage, offset)) then 374 negative := not negative 375 put(-item(offset), offset) 376 end 377 if item(offset) = 0 then 378 integer_length := 0 379 negative := False 380 end 381 else 382 if other < 0 then 383 v := #-other 384 else 385 v := other 386 end 387 if mbi_subtract(item(offset), v, storage_at(storage, offset)) then 388 from 389 i := offset + 1 390 inc := mbi_dec(storage_at(storage, i)) 391 n := offset + integer_length - 1 392 until 393 not inc 394 loop 395 check 396 i < n 397 end 398 i := i + 1 399 inc := mbi_dec(storage_at(storage, i)) 400 end 401 if item(n) = 0 then 402 integer_length := integer_length - 1 403 end 404 end 405 end 406 end 407 408 add_integer_64 (other: INTEGER_64) 409 -- Add `other' into `Current'. 410 do 411 register1.from_integer_64(other) 412 add(register1) 413 end 414 415 add_natural (other: like Current) 416 -- Same behavior as `add', but this one works only when `Current' 417 -- and `other' are both positive numbers and are both greater than 418 -- zero. The only one advantage of using `add_natural' instead of the 419 -- general `add' is the gain of efficiency. 420 require 421 not is_zero and not is_negative 422 not other.is_zero and not other.is_negative 423 do 424 add_magnitude(other) 425 end 426 427feature {ANY} -- Subtract: 428 subtract (other: like Current) 429 -- Subtract `other' from `Current'. 430 require 431 other /= Void 432 do 433 if other = Current then 434 set_with_zero 435 elseif other.integer_length = 0 then 436 -- nothing to do, `Current' remains unchanged 437 elseif integer_length = 0 then 438 -- current is null so simply copy the value of other, the sign is also fixed 439 copy(other) 440 negative := not other.negative 441 elseif negative = other.negative then 442 -- same sign 443 subtract_magnitude(other) 444 else 445 -- different sign 446 add_magnitude(other) 447 end 448 end 449 450 subtract_to (other, res: like Current) 451 -- Subtract `other' from `Current' and put it in `res'. 452 require 453 other /= Void 454 res /= Void 455 res /= Current 456 res /= other 457 do 458 --|*** Must be optimized later (Vincent Croizier, 15/07/04) *** 459 res.copy(Current) 460 res.subtract(other) 461 end 462 463 subtract_integer (other: INTEGER) 464 do 465 if other = Minimum_integer then 466 add_integer(1) 467 add_integer(Maximum_integer) 468 else 469 add_integer(-other) 470 end 471 end 472 473feature {ANY} -- To divide: 474 divide (other: like Current) 475 -- Put the quotient of the Euclidian division of 476 -- `Current' by `other' in `Current'. 477 -- (The contents of `other' is not changed.) 478 require 479 not other.is_zero 480 other /= Current 481 do 482 -- `divide_with_remainder_to' already uses `register1'. 483 divide_with_remainder_to(other, register2) 484 end 485 486 mod (other: like Current) 487 -- Put the remainder of the Euclidian division of 488 -- `Current' by `other' in `Current'. 489 -- (The contents of `other' is not changed.) 490 require 491 not other.is_zero 492 other /= Current 493 local 494 quotient: like Current 495 do 496 --|*** Must be optimized (Vincent Croizier, 12/07/04) *** 497 create quotient.from_integer(0) 498 remainder_with_quotient_to(other, quotient) 499 ensure 500 not negative and abs_compare(other) = -1 501 end 502 503 divide_with_remainder_to (other, remainder: like Current) 504 -- Euclidian division. 505 -- Calculates the `quotient' and `remainder' of `Current' 506 -- divided by `other'. 507 -- Quotient is put in `Current'. 508 -- (The contents of `other' is not changed.) 509 require 510 not other.is_zero 511 remainder /= Void 512 remainder /= other 513 remainder /= Current 514 do 515 Current.remainder_with_quotient_to(other, remainder) 516 Current.swap_with(remainder) 517 ensure 518 not remainder.negative and remainder.abs_compare(other) = -1 519 end 520 521 remainder_with_quotient_to (other, quotient: like Current) 522 -- Euclidian division. 523 -- Calculates the `quotient' and `remainder' of `Current' 524 -- divided by `other'. 525 -- Remainder is put in `Current'. 526 -- (The contents of `other' is not changed.) 527 -- 528 -- Note: Uses Algorithm D in Knuth section 4.3.1. 529 require 530 not other.is_zero 531 quotient /= Void 532 quotient /= other 533 quotient /= Current 534 local 535 cmp, shift, dlen, qlen, j, k, v1, v2, u1, u2, rem: INTEGER; qhat, rhat, v2qhat_1, v2qhat_2, d_offset: INTEGER 536 q_storage, d_storage: like storage; q_capacity: like capacity; current_negative, borrow: BOOLEAN 537 do 538 if integer_length = 0 then 539 -- Dividend is zero: 540 quotient.set_with_zero 541 set_with_zero 542 else 543 current_negative := negative 544 cmp := Current.abs_compare(other) 545 if cmp < 0 then 546 -- Dividend less than divisor: 547 quotient.set_with_zero 548 -- Sign correction 549 set_negative(False) 550 divide_sign_correction_bis(other, quotient, current_negative) 551 elseif cmp = 0 then 552 -- Dividend equal to divisor: 553 if negative = other.negative then 554 quotient.from_integer(1) 555 else 556 quotient.from_integer(-1) 557 end 558 set_with_zero 559 elseif other.integer_length = 1 then 560 -- Special case one word divisor: 561 quotient.swap_with(Current) 562 --|*** replace by "from_unsigned_integer" ? (Vincent Croizier) 563 set_with_zero 564 rem := quotient.divide_one_word(other.item(other.offset)) 565 if rem /= 0 then 566 put(rem, 0) 567 set_integer_length(1) 568 else 569 check 570 is_zero 571 end 572 end 573 -- Sign correction 574 divide_sign_correction_bis(other, quotient, current_negative) 575 else 576 -- Copy divisor storage to protect divisor: 577 register1.copy(other) 578 -- D1 normalize the divisor: 579 shift := register1.normalize 580 if shift /= 0 then 581 shift_left(shift) 582 end 583 -- D2 Initialize j: 584 from 585 d_storage := register1.storage 586 d_offset := register1.offset 587 dlen := register1.integer_length 588 j := offset + integer_length - 1 589 u2 := storage.item(j) 590 k := register1.offset + dlen - 1 591 v1 := register1.item(k) 592 v2 := register1.item(k - 1) 593 if unsigned_greater_or_equal(u2, v1) then 594 k := integer_length - dlen 595 qlen := k + 1 596 else 597 qlen := integer_length - dlen 598 k := qlen - 1 599 j := j - 1 600 u1 := u2 601 u2 := storage.item(j) 602 end 603 -- Resize quotient if necessary 604 q_capacity := quotient.capacity 605 if q_capacity < qlen then 606 -- reallocation 607 q_capacity := capacity_from_lower_bound(q_capacity, qlen) 608 q_storage := storage.calloc(q_capacity) 609 else 610 q_storage := quotient.storage 611 end 612 -- To avoid invariant violation on `quotient' 613 quotient.set_with_zero 614 until 615 k < 0 616 loop 617 j := j - 1 -- D3 Calculate qhat - estimate qhat 618 if u1 = v1 then 619 qhat := ~0 620 else 621 qhat := mbi_divide(u1, u2, v1, $rhat) -- Correct qhat 622 if qhat = 0 then 623 else 624 v2qhat_1 := mbi_multiply(v2, qhat, $v2qhat_2) 625 if unsigned_greater_than(v2qhat_1, rhat) then 626 qhat := qhat - 1 627 if mbi_subtract(v2qhat_2, v2, $v2qhat_2) then 628 v2qhat_1 := v2qhat_1 - 1 629 end 630 if mbi_add(rhat, v1, $rhat) then 631 elseif unsigned_greater_than(v2qhat_1, rhat) then 632 qhat := qhat - 1 633 elseif j < 0 then 634 if v2qhat_1 = rhat and then v2qhat_2 /= 0 then 635 qhat := qhat - 1 636 end 637 elseif v2qhat_1 = rhat and then unsigned_greater_than(v2qhat_2, storage.item(j)) then 638 qhat := qhat - 1 639 end 640 elseif j < 0 then 641 if v2qhat_1 = rhat and then v2qhat_2 /= 0 then 642 qhat := qhat - 1 643 end 644 elseif v2qhat_1 = rhat and then unsigned_greater_than(v2qhat_2, storage.item(j)) then 645 qhat := qhat - 1 646 end 647 end 648 end 649 -- D4 Multiply and subtract: 650 if qhat = 0 then 651 q_storage.put(0, k) 652 else 653 borrow := multiply_and_subtract(u1, qhat, d_storage, d_offset, storage, j - dlen + 2, dlen) 654 -- D5 Test remainder: Result is negative ? 655 if borrow then 656 -- D6 Add back 657 borrow := add_back(u1, d_storage, d_offset, storage, j - dlen + 2, dlen) 658 check 659 borrow 660 end 661 q_storage.put(qhat - 1, k) 662 else 663 q_storage.put(qhat, k) 664 end 665 end 666 -- D7 loop on j 667 k := k - 1 668 u1 := storage.item(j + 1) 669 u2 := storage.item(j) 670 end 671 -- Remove leading zero of quotient 672 k := qlen - 1 673 if q_storage.item(k) = 0 then 674 qlen := k 675 end 676 quotient.set_all(q_storage, q_capacity, qlen, 0, False) 677 -- Remove leading zero of remainder 678 from 679 j := dlen - 1 680 until 681 j < 0 or else storage.item(j) /= 0 682 loop 683 j := j - 1 684 end 685 j := j + 1 686 check 687 j >= 0 688 end 689 if j = 0 then 690 set_with_zero 691 else 692 offset := 0 693 integer_length := j 694 negative := False 695 end 696 -- D8 Unnormalize: 697 if shift > 0 then 698 shift_right(shift) 699 end 700 -- Sign correction 701 divide_sign_correction_bis(other, quotient, current_negative) 702 end 703 end 704 ensure 705 not negative and abs_compare(other) = -1 706 end 707 708 divide_to (other, quotient, remainder: like Current) 709 -- Euclidian division. 710 -- Calculates the `quotient' and `remainder' of `Current' 711 -- divided by `other'. (The contents of `Current' and `other' are 712 -- not changed.) 713 -- 714 -- Note: Uses Algorithm D in Knuth section 4.3.1. 715 require 716 not other.is_zero 717 quotient /= Void 718 remainder /= Void 719 quotient /= other 720 quotient /= Current 721 remainder /= other 722 remainder /= Current 723 local 724 cmp, shift, nlen, dlen, qlen, j, k, v1, v2, u1, u2, rem: INTEGER 725 qhat, rhat, v2qhat_1, v2qhat_2, d_offset: INTEGER; q_storage, r_storage, d_storage: like storage 726 q_capacity, r_capacity: like capacity; borrow: BOOLEAN 727 do 728 if integer_length = 0 then 729 -- Dividend is zero: 730 quotient.set_with_zero 731 remainder.set_with_zero 732 else 733 cmp := Current.abs_compare(other) 734 if cmp < 0 then 735 -- Dividend less than divisor: 736 quotient.set_with_zero 737 remainder.copy(Current) 738 -- Sign correction 739 remainder.set_negative(False) 740 divide_sign_correction(other, quotient, remainder) 741 elseif cmp = 0 then 742 -- Dividend equal to divisor: 743 if negative = other.negative then 744 quotient.from_integer(1) 745 else 746 quotient.from_integer(-1) 747 end 748 remainder.set_with_zero 749 elseif other.integer_length = 1 then 750 -- Special case one word divisor: 751 quotient.copy(Current) 752 --|*** replace by "from_unsigned_integer" ? (Vincent Croizier) 753 remainder.set_with_zero 754 rem := quotient.divide_one_word(other.item(other.offset)) 755 if rem /= 0 then 756 remainder.put(rem, 0) 757 remainder.set_ilo(1, 0) 758 else 759 check 760 remainder.is_zero 761 end 762 end 763 -- Sign correction 764 divide_sign_correction(other, quotient, remainder) 765 else 766 -- Copy divisor storage to protect divisor: 767 register1.copy(other) 768 --|*** 769 remainder.copy(Current) 770 -- D1 normalize the divisor: 771 shift := register1.normalize 772 if shift /= 0 then 773 remainder.shift_left(shift) 774 end 775 -- D2 Initialize j: 776 from 777 r_storage := remainder.storage 778 r_capacity := remainder.capacity 779 check 780 remainder.offset = 0 781 end 782 nlen := remainder.integer_length -- To avoid invariant class violation 783 remainder.set_with_zero 784 d_storage := register1.storage 785 d_offset := register1.offset 786 dlen := register1.integer_length 787 j := nlen - 1 788 u2 := r_storage.item(j) 789 k := register1.offset + dlen - 1 790 v1 := register1.item(k) 791 v2 := register1.item(k - 1) 792 if unsigned_greater_or_equal(u2, v1) then 793 k := nlen - dlen 794 qlen := k + 1 795 else 796 qlen := nlen - dlen 797 k := qlen - 1 798 j := j - 1 799 u1 := u2 800 u2 := r_storage.item(j) 801 end 802 -- Resize quotient if necessary 803 q_capacity := quotient.capacity 804 if q_capacity < qlen then 805 -- reallocation 806 q_capacity := capacity_from_lower_bound(q_capacity, qlen) 807 q_storage := storage.calloc(q_capacity) 808 else 809 q_storage := quotient.storage 810 end 811 -- To avoid invariant violation on `quotient' 812 quotient.set_with_zero 813 until 814 k < 0 815 loop 816 j := j - 1 -- D3 Calculate qhat - estimate qhat 817 if u1 = v1 then 818 qhat := ~0 819 else 820 qhat := mbi_divide(u1, u2, v1, $rhat) -- Correct qhat 821 if qhat = 0 then 822 else 823 v2qhat_1 := mbi_multiply(v2, qhat, $v2qhat_2) 824 if unsigned_greater_than(v2qhat_1, rhat) then 825 qhat := qhat - 1 826 if mbi_subtract(v2qhat_2, v2, $v2qhat_2) then 827 v2qhat_1 := v2qhat_1 - 1 828 end 829 if mbi_add(rhat, v1, $rhat) then 830 elseif unsigned_greater_than(v2qhat_1, rhat) then 831 qhat := qhat - 1 832 elseif j < 0 then 833 if v2qhat_1 = rhat and then v2qhat_2 /= 0 then 834 qhat := qhat - 1 835 end 836 elseif v2qhat_1 = rhat and then unsigned_greater_than(v2qhat_2, r_storage.item(j)) then 837 qhat := qhat - 1 838 end 839 elseif j < 0 then 840 if v2qhat_1 = rhat and then v2qhat_2 /= 0 then 841 qhat := qhat - 1 842 end 843 elseif v2qhat_1 = rhat and then unsigned_greater_than(v2qhat_2, r_storage.item(j)) then 844 qhat := qhat - 1 845 end 846 end 847 end 848 -- D4 Multiply and subtract: 849 if qhat = 0 then 850 q_storage.put(0, k) 851 else 852 borrow := multiply_and_subtract(u1, qhat, d_storage, d_offset, r_storage, j - dlen + 2, dlen) 853 -- D5 Test remainder: Result is negative ? 854 if borrow then 855 -- D6 Add back 856 borrow := add_back(u1, d_storage, d_offset, r_storage, j - dlen + 2, dlen) 857 check 858 borrow 859 end 860 q_storage.put(qhat - 1, k) 861 else 862 q_storage.put(qhat, k) 863 end 864 end 865 -- D7 loop on j 866 k := k - 1 867 u1 := r_storage.item(j + 1) 868 u2 := r_storage.item(j) 869 end 870 -- Remove leading zero of quotient 871 k := qlen - 1 872 if q_storage.item(k) = 0 then 873 qlen := k 874 end 875 quotient.set_all(q_storage, q_capacity, qlen, 0, False) 876 -- Remove leading zero of remainder 877 from 878 j := dlen - 1 879 until 880 j < 0 or else r_storage.item(j) /= 0 881 loop 882 j := j - 1 883 end 884 j := j + 1 885 check 886 j >= 0 887 end 888 if j = 0 then 889 check 890 remainder.is_zero 891 end 892 else 893 remainder.set_all(r_storage, r_capacity, j, 0, False) 894 end 895 -- D8 Unnormalize: 896 if shift > 0 then 897 remainder.shift_right(shift) 898 end 899 -- Sign correction 900 divide_sign_correction(other, quotient, remainder) 901 end 902 end 903 ensure 904 is_a_good_divide(other, quotient, remainder) 905 not remainder.negative and remainder.abs_compare(other) = -1 906 end 907 908 shift_left (n: INTEGER) 909 -- Shift bits of magnitude by `n' position left. (Note that no bit can 910 -- be lost because the `storage' area is automatically extended when 911 -- it is necessary.) 912 require 913 n > 0 914 local 915 new_storage: like storage; left, right: INTEGER_8 916 new_capacity, new_integer_length, new_head, word_shift, i, j, k, val1, val2, val3: INTEGER 917 do 918 if integer_length > 0 then 919 word_shift := n |>>> 5 920 left := (n & 0x0000001F).to_integer_8 -- Optimistic prediction 921 new_integer_length := integer_length + word_shift 922 if left = 0 then 923 -- Just word shift 924 if offset >= word_shift then 925 -- no need to deplace the number in the storage 926 from 927 i := offset 928 offset := offset - word_shift 929 integer_length := new_integer_length 930 until 931 i = offset 932 loop 933 i := i - 1 934 put(0, i) 935 end 936 elseif capacity >= new_integer_length then 937 -- deplacing the number 938 from 939 i := offset + integer_length - 1 940 j := word_shift + integer_length - 1 941 until 942 i < offset 943 loop 944 put(item(i), j) 945 i := i - 1 946 j := j - 1 947 end 948 from 949 check 950 j = word_shift - 1 951 end 952 until 953 j < 0 954 loop 955 put(0, j) 956 j := j - 1 957 end 958 offset := 0 959 integer_length := new_integer_length 960 else 961 -- reallocation 962 new_capacity := capacity_from_lower_bound(capacity, new_integer_length) 963 new_storage := storage.calloc(new_capacity) 964 from 965 i := offset + integer_length 966 j := word_shift + integer_length 967 until 968 i = offset 969 loop 970 i := i - 1 971 j := j - 1 972 new_storage.put(item(i), j) 973 end 974 storage := new_storage 975 capacity := new_capacity 976 offset := 0 977 integer_length := new_integer_length 978 end 979 else 980 right := 32 - left -- Compute real `integer_length' 981 i := offset + integer_length - 1 982 val1 := item(i) 983 new_head := val1 |>>> right 984 if new_head = 0 then 985 -- new_integer_length is good 986 if capacity < new_integer_length then 987 -- reallocation 988 new_capacity := capacity_from_lower_bound(capacity, new_integer_length) 989 new_storage := storage.calloc(new_capacity) 990 from 991 j := new_integer_length - 1 992 check 993 i = offset + integer_length - 1 994 j = word_shift + integer_length - 1 995 val1 = item(i) 996 end 997 until 998 i = offset 999 loop 1000 i := i - 1 1001 val2 := item(i) 1002 new_storage.put(val1 |<< left | (val2 |>>> right), j) 1003 val1 := val2 1004 j := j - 1 1005 end 1006 new_storage.put(val1 |<< left, j) 1007 storage := new_storage 1008 capacity := new_capacity 1009 offset := 0 1010 integer_length := new_integer_length 1011 elseif offset > word_shift then 1012 from 1013 check 1014 j = 0 1015 end 1016 until 1017 j = word_shift 1018 loop 1019 put(0, j) 1020 j := j + 1 1021 end 1022 from 1023 k := offset 1024 check 1025 i = offset + integer_length - 1 1026 j = word_shift 1027 end 1028 until 1029 k = i 1030 loop 1031 val3 := item(k) 1032 put(val3 |<< left | (val2 |>>> right), j) 1033 val2 := val3 1034 k := k + 1 1035 j := j + 1 1036 end 1037 put(val1 |<< left | (val2 |>>> right), j) 1038 offset := 0 1039 integer_length := new_integer_length 1040 else 1041 from 1042 j := new_integer_length - 1 1043 check 1044 i = offset + integer_length - 1 1045 j = word_shift + integer_length - 1 1046 val1 = item(i) 1047 end 1048 until 1049 i = offset 1050 loop 1051 i := i - 1 1052 val2 := item(i) 1053 put(val1 |<< left | (val2 |>>> right), j) 1054 val1 := val2 1055 j := j - 1 1056 end 1057 put(val1 |<< left, j) 1058 from 1059 until 1060 j = 0 1061 loop 1062 j := j - 1 1063 put(0, j) 1064 end 1065 offset := 0 1066 integer_length := new_integer_length 1067 end 1068 else 1069 new_integer_length := new_integer_length + 1 1070 if capacity < new_integer_length then 1071 -- Reallocation 1072 new_capacity := capacity_from_lower_bound(capacity, new_integer_length) 1073 new_storage := storage.calloc(new_capacity) 1074 from 1075 j := new_integer_length - 2 1076 check 1077 i = offset + integer_length - 1 1078 j = word_shift + integer_length - 1 1079 val1 = item(i) 1080 end 1081 new_storage.put(new_head, j + 1) 1082 until 1083 i = offset 1084 loop 1085 i := i - 1 1086 val2 := item(i) 1087 new_storage.put(val1 |<< left | (val2 |>>> right), j) 1088 val1 := val2 1089 j := j - 1 1090 end 1091 new_storage.put(val1 |<< left, j) 1092 storage := new_storage 1093 capacity := new_capacity 1094 offset := 0 1095 integer_length := new_integer_length 1096 elseif offset > word_shift then 1097 from 1098 check 1099 j = 0 1100 end 1101 until 1102 j = word_shift 1103 loop 1104 put(0, j) 1105 j := j + 1 1106 end 1107 from 1108 k := offset 1109 check 1110 i = offset + integer_length - 1 1111 end 1112 until 1113 k = i 1114 loop 1115 val3 := item(k) 1116 put(val3 |<< left | (val2 |>>> right), j) 1117 val2 := val3 1118 k := k + 1 1119 j := j + 1 1120 end 1121 put(val1 |<< left | (val2 |>>> right), j) 1122 put(new_head, j + 1) 1123 offset := 0 1124 integer_length := new_integer_length 1125 else 1126 from 1127 j := new_integer_length - 2 1128 check 1129 i = offset + integer_length - 1 1130 j = word_shift + integer_length - 1 1131 val1 = item(i) 1132 end 1133 until 1134 i = offset 1135 loop 1136 i := i - 1 1137 val2 := item(i) 1138 put(val1 |<< left | (val2 |>>> right), j) 1139 val1 := val2 1140 j := j - 1 1141 end 1142 put(val1 |<< left, j) 1143 put(new_head, new_integer_length - 1) 1144 from 1145 until 1146 j = 0 1147 loop 1148 j := j - 1 1149 put(0, j) 1150 end 1151 offset := 0 1152 integer_length := new_integer_length 1153 end 1154 end 1155 end 1156 end 1157 end 1158 1159 shift_right (n: INTEGER) 1160 -- Right shift `Current' n bits. (`Current' is left in normal form.) 1161 require 1162 n > 0 1163 local 1164 n_ints, n_bits: INTEGER 1165 do 1166 if integer_length > 0 then 1167 n_ints := n |>>> 5 1168 n_bits := n & 0x0000001F 1169 integer_length := integer_length - n_ints 1170 offset := offset + n_ints 1171 if n_bits = 0 then 1172 else 1173 primitive_shift_right(n_bits.to_integer_8) 1174 end 1175 end 1176 end 1177 1178feature {ANY} -- GCD 1179 gcd (other: like Current) 1180 -- Compute GCD of `Current' and `other'. 1181 -- GCD is put in `Current' (`other' is not modified). 1182 require 1183 other /= Void 1184 do 1185 if other = Current then 1186 Current.abs 1187 elseif other.is_zero then 1188 Current.abs 1189 elseif Current.is_zero then 1190 Current.copy(other) 1191 Current.abs 1192 else 1193 from 1194 register2.copy(other) 1195 Current.mod(register2) 1196 if Current.is_zero then 1197 Current.swap_with(register2) 1198 Current.abs 1199 else 1200 register2.mod(Current) 1201 end 1202 until 1203 register2.is_zero 1204 loop 1205 Current.mod(register2) 1206 if Current.is_zero then 1207 Current.swap_with(register2) 1208 else 1209 register2.mod(Current) 1210 end 1211 end 1212 end 1213 ensure 1214 is_positive or is_zero and other.is_zero 1215 end 1216 1217feature {ANY} -- To multiply: 1218 multiply (other: like Current) 1219 -- Multiply `Current' by `other'. 1220 require 1221 other /= Void 1222 do 1223 if other = Current then 1224 multiply_to(other, register1) 1225 swap_with(register1) 1226 elseif is_zero or other.is_zero then 1227 set_with_zero 1228 elseif Current.is_one then 1229 copy(other) 1230 elseif other.is_one then 1231 elseif Current.is_one_negative then 1232 copy(other) 1233 set_negative(not negative) 1234 elseif other.is_one_negative then 1235 set_negative(not negative) 1236 else 1237 --|*** Must be replaced by an algorithm switch. (Vincent Croizier, 09/07/04) 1238 multiply_like_human(other) 1239 end 1240 end 1241 1242 multiply_to (other, res: like Current) 1243 -- Multiply the contents of `Current' and `other' and place the 1244 -- result in `res'. (`Current' and `other' are not modified.) 1245 require 1246 other /= Void 1247 res /= Void 1248 res /= Current 1249 do 1250 if is_zero or other.is_zero then 1251 res.set_with_zero 1252 elseif Current.is_one then 1253 res.copy(other) 1254 elseif other.is_one then 1255 res.copy(Current) 1256 elseif Current.is_one_negative then 1257 res.copy(other) 1258 res.set_negative(not res.negative) 1259 elseif other.is_one_negative then 1260 res.copy(Current) 1261 res.set_negative(not negative) 1262 else 1263 --|*** Must be replace by an algorithm switch. (Vincent Croizier, 01/05/04) 1264 multiply_to_like_human(other, res) 1265 end 1266 end 1267 1268 multiply_integer (other: INTEGER; res: like Current) 1269 -- Multiply the contents of `Current' and `other' and place the 1270 -- result in `res'. (`Current' is not modified.) 1271 require 1272 res /= Current 1273 res /= Void 1274 local 1275 overflow, res_integer_length, res_capacity, i, k, up_i, v: INTEGER; res_storage: like storage 1276 do 1277 if other = 0 or else is_zero then 1278 res.set_with_zero 1279 elseif other = Minimum_integer then 1280 res.set_negative(not negative) 1281 shift_left(31) 1282 else 1283 if other > 0 then 1284 res.set_negative(negative) 1285 v := other 1286 else 1287 res.set_negative(not negative) 1288 v := -other 1289 end 1290 -- Pessimistic estimation 1291 res_integer_length := integer_length + 1 -- Reallocation ? 1292 if res.capacity < res_integer_length then 1293 if capacity < res_integer_length then 1294 res_capacity := capacity * 2 1295 else 1296 res_capacity := capacity_from_upper_bound(capacity, res_integer_length) 1297 end 1298 set_capacity(res_capacity) 1299 res_storage := storage.calloc(res_capacity) 1300 res.set_storage(res_storage) 1301 else 1302 res_storage := res.storage 1303 end 1304 res.set_offset(0) 1305 -- Multiply 1306 from 1307 k := 0 1308 i := offset 1309 up_i := offset + integer_length - 1 1310 overflow := mbi_multiply(item(i), v, storage_at(res_storage, k)) 1311 until 1312 i = up_i 1313 loop 1314 i := i + 1 1315 k := k + 1 1316 overflow := mbi_multiply_with_add(item(i), v, overflow, storage_at(res_storage, k)) 1317 end 1318 if overflow = 0 then 1319 res.set_integer_length(res_integer_length - 1) 1320 else 1321 check 1322 k + 1 = integer_length 1323 end 1324 res.put(overflow, integer_length) 1325 end 1326 end 1327 end 1328 1329feature {MUTABLE_BIG_INTEGER} -- to multiply 1330 multiply_like_human (other: like Current) 1331 -- Simple multiply. 1332 -- Complexity = O(`integer_length'*`other.integer_length'). 1333 require 1334 not is_zero 1335 not other.is_zero 1336 local 1337 old_offset, new_integer_length: INTEGER 1338 do 1339 -- Pessimistique estimation 1340 new_integer_length := integer_length + other.integer_length -- Reallocation ? 1341 if capacity < new_integer_length then 1342 register1.swap_with(Current) 1343 register1.multiply_to_like_human(other, Current) 1344 -- Multiply in place 1345 elseif offset + new_integer_length <= capacity then 1346 multiply_like_human_aux_reverse(other) 1347 elseif offset >= other.integer_length then 1348 multiply_like_human_aux(other) 1349 else 1350 old_offset := offset 1351 offset := capacity - integer_length 1352 storage.slice_copy(offset, storage, old_offset, old_offset + integer_length - 1) 1353 multiply_like_human_aux(other) 1354 end 1355 end 1356 1357 multiply_like_human_aux (other: like Current) 1358 -- Only used by `multiply_to_like_human'. 1359 require 1360 not is_zero 1361 not other.is_zero 1362 offset >= other.integer_length 1363 local 1364 other_offset, other_integer_length, overflow, i, j, k, up_i, up_j, down_k, v: INTEGER 1365 other_storage: like storage 1366 do 1367 other_offset := other.offset 1368 other_integer_length := other.integer_length 1369 other_storage := other.storage -- First pass 1370 from 1371 k := 0 1372 i := other_offset 1373 up_i := other_offset + other_integer_length - 1 1374 j := offset 1375 up_j := offset + integer_length - 1 1376 v := storage.item(j) 1377 overflow := mbi_multiply(other_storage.item(i), v, storage_at(storage, k)) 1378 until 1379 i = up_i 1380 loop 1381 i := i + 1 1382 k := k + 1 1383 overflow := mbi_multiply_with_add(other_storage.item(i), v, overflow, storage_at(storage, k)) 1384 end 1385 k := k + 1 1386 check 1387 k <= j 1388 end 1389 storage.put(overflow, k) 1390 from 1391 down_k := 1 1392 until 1393 j = up_j 1394 loop 1395 j := j + 1 1396 from 1397 k := down_k 1398 i := other_offset 1399 v := storage.item(j) 1400 overflow := mbi_multiply_with_add(other_storage.item(i), v, storage.item(k), storage_at(storage, k)) 1401 until 1402 i = up_i 1403 loop 1404 i := i + 1 1405 k := k + 1 1406 overflow := mbi_multiply_with_2_add(other_storage.item(i), v, overflow, storage.item(k), storage_at(storage, k)) 1407 end 1408 k := k + 1 1409 check 1410 k <= j 1411 end 1412 storage.put(overflow, k) 1413 down_k := down_k + 1 1414 end 1415 -- Adjust `res.integer_length' 1416 if overflow = 0 then 1417 integer_length := integer_length + other_integer_length - 1 1418 else 1419 integer_length := integer_length + other_integer_length 1420 end 1421 negative := negative /= other.negative 1422 offset := 0 1423 end 1424 1425 multiply_like_human_aux_reverse (other: like Current) 1426 -- Only used by `multiply_to_like_human'. 1427 require 1428 not is_zero 1429 not other.is_zero 1430 offset + integer_length <= capacity - other.integer_length 1431 local 1432 other_offset, other_integer_length, overflow, i, j, k, up_i, down_j, down_k, v: INTEGER 1433 other_storage: like storage; inc: BOOLEAN 1434 do 1435 other_offset := other.offset 1436 other_integer_length := other.integer_length 1437 other_storage := other.storage -- First pass 1438 from 1439 …
Large files files are truncated, but you can click here to view the full file