PageRenderTime 34ms CodeModel.GetById 19ms app.highlight 6ms RepoModel.GetById 1ms app.codeStats 1ms

/src/lib/numeric/mutable_big_integer.e

http://github.com/tybor/Liberty
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