PageRenderTime 13ms CodeModel.GetById 8ms app.highlight 2ms RepoModel.GetById 1ms app.codeStats 0ms

/src/lib/numeric/internal/big_integer_number.e

http://github.com/tybor/Liberty
Specman e | 529 lines | 429 code | 58 blank | 42 comment | 26 complexity | b2fc3fb04d1270ef74960287a3cd2ff5 MD5 | raw file
  1-- This file is part of a Liberty Eiffel library.
  2-- See the full copyright at the end.
  3--
  4class BIG_INTEGER_NUMBER
  5   --
  6   -- To implement NUMBER (do not use this class, see NUMBER).
  7   --
  8
  9inherit
 10   INTEGER_GENERAL_NUMBER
 11
 12create {ANY}
 13   from_native_array
 14
 15feature {ANY}
 16   is_positive: BOOLEAN
 17      do
 18         Result := not negative
 19      end
 20
 21   is_negative: BOOLEAN
 22      do
 23         Result := negative
 24      end
 25
 26   infix "\\" (other: NUMBER): NUMBER
 27      local
 28         oth: INTEGER_GENERAL_NUMBER
 29      do
 30         oth ::= other
 31         Result := oth.remainder_of_divide_big_integer_number(Current)
 32      end
 33
 34   infix "@\\" (other: INTEGER_64): NUMBER
 35      do
 36         put_into_mutable_big_integer(mutable_register1)
 37         mutable_register2.from_integer_64(other)
 38         mutable_register1.divide_to(mutable_register2, mutable_register3, mutable_register4)
 39         Result := mutable_register4.to_integer_general_number
 40      end
 41
 42feature {ANY} -- Misc:
 43   hash_code: INTEGER
 44      local
 45         i, c, v: INTEGER
 46      do
 47         from
 48            c := 2
 49         until
 50            c = 0 or else i = capacity
 51         loop
 52            v := storage.item(i)
 53            if v /= 0 then
 54               Result := Result #+ v
 55               c := c - 1
 56            end
 57            i := i + 1
 58         end
 59         Result := capacity #* Result
 60         if negative then
 61            Result := Result #+ 1
 62         end
 63         if Result < 0 then
 64            Result := ~Result
 65         end
 66      end
 67
 68   gcd (other: NUMBER): INTEGER_GENERAL_NUMBER
 69      do
 70         Result := other.gcd_with_big_integer_number(Current)
 71      end
 72
 73   is_integer_value: BOOLEAN False
 74
 75   force_to_real_64: REAL_64
 76      do
 77         put_into_mutable_big_integer(mutable_register1)
 78         Result := mutable_register1.force_to_real_64
 79      end
 80
 81   prefix "-": NUMBER
 82      do
 83         if is_positive and then capacity = 2 and then storage.item(0) = 0 and then storage.item(1) = Minimum_integer then
 84            create {INTEGER_64_NUMBER} Result.make(Minimum_integer_64)
 85         else
 86            create {BIG_INTEGER_NUMBER} Result.from_native_array(storage, capacity, not negative)
 87         end
 88      end
 89
 90   infix "+" (other: NUMBER): NUMBER
 91      do
 92         Result := other.add_with_big_integer_number(Current)
 93      end
 94
 95   infix "//" (other: NUMBER): NUMBER
 96      local
 97         oth: INTEGER_GENERAL_NUMBER
 98      do
 99         oth ::= other
100         Result := oth.integer_divide_big_integer_number(Current)
101      end
102
103   infix "@//" (other: INTEGER_64): NUMBER
104      do
105         put_into_mutable_big_integer(mutable_register1)
106         mutable_register2.from_integer_64(other)
107         mutable_register1.divide_to(mutable_register2, mutable_register3, mutable_register4)
108         Result := mutable_register3.to_integer_general_number
109      end
110
111   infix "*" (other: NUMBER): NUMBER
112      do
113         Result := other.multiply_with_big_integer_number(Current)
114      end
115
116   infix "@/" (other: INTEGER_64): NUMBER
117      do
118         Result := from_integer_general_number_and_integer(Current, other)
119      end
120
121   infix "@+" (other: INTEGER_64): NUMBER
122      do
123         put_into_mutable_big_integer(mutable_register1)
124         mutable_register1.add_integer_64(other)
125         Result := mutable_register1.to_integer_general_number
126      end
127
128   infix "@*" (other: INTEGER_64): NUMBER
129      do
130         if other = 0 then
131            create {INTEGER_64_NUMBER} Result.make(0)
132         elseif other = 1 then
133            Result := Current
134         elseif other = -1 then
135            Result := -Current
136         else
137            put_into_mutable_big_integer(mutable_register1)
138            mutable_register2.from_integer_64(other)
139            mutable_register1.multiply_to(mutable_register2, mutable_register3)
140            Result := mutable_register3.to_integer_general_number
141         end
142      end
143
144feature {NUMBER}
145   add_with_big_integer_number (other: BIG_INTEGER_NUMBER): NUMBER
146      do
147         put_into_mutable_big_integer(mutable_register1)
148         other.put_into_mutable_big_integer(mutable_register2)
149         mutable_register1.add(mutable_register2)
150         Result := mutable_register1.to_integer_general_number
151      end
152
153   add_with_fraction_with_big_integer_number (other: FRACTION_WITH_BIG_INTEGER_NUMBER): NUMBER
154      do
155         Result := other.add_with_big_integer_number(Current)
156      end
157
158feature {NUMBER} -- Multiplication
159   multiply_with_big_integer_number (other: BIG_INTEGER_NUMBER): NUMBER
160      do
161         put_into_mutable_big_integer(mutable_register1)
162         other.put_into_mutable_big_integer(mutable_register2)
163         mutable_register1.multiply_to(mutable_register2, mutable_register3)
164         Result := mutable_register3.to_integer_general_number
165      end
166
167   multiply_with_fraction_with_big_integer_number (other: FRACTION_WITH_BIG_INTEGER_NUMBER): NUMBER
168      do
169         Result := other.multiply_with_big_integer_number(Current)
170      end
171
172feature {NUMBER} -- division
173   integer_divide_integer_64_number (other: INTEGER_64_NUMBER): INTEGER_GENERAL_NUMBER
174      do
175         if other @= Minimum_integer_64 and then is_positive and then capacity = 2 and then storage.item(0) = 0 and then storage.item(1) = Minimum_integer then
176            Result := integer_general_number_one_negative
177         else
178            Result := integer_general_number_zero
179         end
180      end
181
182   remainder_of_divide_integer_64_number (other: INTEGER_64_NUMBER): INTEGER_GENERAL_NUMBER
183      do
184         if other @= Minimum_integer_64 and then is_positive and then capacity = 2 and then storage.item(0) = 0 and then storage.item(1) = Minimum_integer then
185            Result := integer_general_number_zero
186         else
187            Result := other
188         end
189      end
190
191   integer_divide_big_integer_number (other: BIG_INTEGER_NUMBER): INTEGER_GENERAL_NUMBER
192      do
193         put_into_mutable_big_integer(mutable_register2)
194         other.put_into_mutable_big_integer(mutable_register1)
195         mutable_register1.divide_to(mutable_register2, mutable_register3, mutable_register4)
196         Result := mutable_register3.to_integer_general_number
197      end
198
199   remainder_of_divide_big_integer_number (other: BIG_INTEGER_NUMBER): INTEGER_GENERAL_NUMBER
200      do
201         put_into_mutable_big_integer(mutable_register2)
202         other.put_into_mutable_big_integer(mutable_register1)
203         mutable_register1.divide_to(mutable_register2, mutable_register3, mutable_register4)
204         Result := mutable_register4.to_integer_general_number
205      end
206
207feature {NUMBER} -- Implementation:
208   gcd_with_integer_64_number (other: INTEGER_64_NUMBER): INTEGER_GENERAL_NUMBER
209      do
210         put_into_mutable_big_integer(mutable_register1)
211         other.put_into_mutable_big_integer(mutable_register2)
212         mutable_register1.gcd(mutable_register2)
213         Result := mutable_register1.to_integer_general_number
214      end
215
216feature {ANY}
217   inverse: NUMBER
218      local
219         tmp: INTEGER_GENERAL_NUMBER
220      do
221         if is_negative then
222            tmp ::= -Current
223            create {FRACTION_WITH_BIG_INTEGER_NUMBER} Result.make(integer_general_number_one_negative, tmp)
224         else
225            create {FRACTION_WITH_BIG_INTEGER_NUMBER} Result.make(integer_general_number_one, Current)
226         end
227      end
228
229   infix "@=" (other: INTEGER_64): BOOLEAN
230      do
231      end
232
233   infix "@<" (other: INTEGER_64): BOOLEAN
234      do
235         Result := negative
236      end
237
238   infix "@>" (other: INTEGER_64): BOOLEAN
239      do
240         Result := not negative
241      end
242
243   infix "@>=" (other: INTEGER_64): BOOLEAN
244      do
245         Result := not negative
246      end
247
248   infix "@<=" (other: INTEGER_64): BOOLEAN
249      do
250         Result := negative
251      end
252
253feature {ANY} -- comparisons with NUMBER
254   infix "<" (other: NUMBER): BOOLEAN
255      do
256         Result := other.greater_with_big_integer_number(Current)
257      end
258
259feature {ANY} -- comparisons with REAL_64
260   infix "#=" (other: REAL_64): BOOLEAN
261      do
262         if is_negative then
263            if other >= 0 then
264            elseif other >= Minimum_integer_64.force_to_real_64 then
265               --|*** Vincent, can you check ? *** (Dom Oct 2004) ***
266            elseif Current < min_double then
267            else
268               Result := force_to_real_64 = other
269            end
270         elseif other < 0 then
271         elseif other <= Maximum_integer_64.force_to_real_64 then
272            --|*** Vincent, can you check ? *** (Dom Oct 2004) ***
273         elseif Current > max_double then
274         else
275            Result := force_to_real_64 = other
276         end
277      end
278
279   infix "#<" (other: REAL_64): BOOLEAN
280      do
281         if is_negative then
282            if other >= 0 then
283               Result := True
284            elseif other >= Minimum_integer_64.force_to_real_64 then
285               --|*** Vincent, can you check ? *** (Dom Oct 2004) ***
286               Result := True
287            elseif Current < min_double then
288               Result := True
289            else
290               Result := force_to_real_64 < other
291            end
292         elseif other < 0 then
293         elseif other <= Maximum_integer_64.force_to_real_64 then
294            --|*** Vincent, can you check ? *** (Dom Oct 2004) ***
295         elseif Current > max_double then
296         else
297            Result := force_to_real_64 < other
298         end
299      end
300
301   infix "#<=" (other: REAL_64): BOOLEAN
302      do
303         if is_negative then
304            if other >= 0 then
305               Result := True
306            elseif other >= Minimum_integer_64.force_to_real_64 then
307               --|*** Vincent, can you check ? *** (Dom Oct 2004) ***
308               Result := True
309            elseif Current <= min_double then
310               Result := True
311            else
312               Result := force_to_real_64 <= other
313            end
314         elseif other <= 0 then
315         elseif other <= Maximum_integer_64.force_to_real_64 then
316            --|*** Vincent, can you check ? *** (Dom Oct 2004) ***
317         elseif Current >= max_double then
318         else
319            Result := force_to_real_64 <= other
320         end
321      end
322
323   infix "#>" (other: REAL_64): BOOLEAN
324      do
325         if is_negative then
326            if other >= 0 then
327            elseif other >= Minimum_integer_64.force_to_real_64 then
328               --|*** Vincent, can you check ? *** (Dom Oct 2004) ***
329            elseif Current < min_double then
330            else
331               Result := force_to_real_64 > other
332            end
333         elseif other < 0 then
334            Result := True
335         elseif other <= Maximum_integer_64.force_to_real_64 then
336            --|*** Vincent, can you check ? *** (Dom Oct 2004) ***
337            Result := True
338         elseif Current > max_double then
339            Result := True
340         else
341            Result := force_to_real_64 > other
342         end
343      end
344
345   infix "#>=" (other: REAL_64): BOOLEAN
346      do
347         if is_negative then
348            if other >= 0 then
349            elseif other >= Minimum_integer_64.force_to_real_64 then
350               --|*** Vincent, can you check ? *** (Dom Oct 2004) ***
351            elseif Current <= min_double then
352            else
353               Result := force_to_real_64 >= other
354            end
355         elseif other <= 0 then
356            Result := True
357         elseif other <= Maximum_integer_64.force_to_real_64 then
358            --|*** Vincent, can you check ? *** (Dom Oct 2004) ***
359            Result := True
360         elseif Current >= max_double then
361            Result := True
362         else
363            Result := force_to_real_64 >= other
364         end
365      end
366
367feature {NUMBER, NUMBER_TOOLS}
368   greater_with_big_integer_number (other: BIG_INTEGER_NUMBER): BOOLEAN
369      local
370         i, other_capacity: INTEGER; other_storage: like storage
371      do
372         if is_negative /= other.is_negative then
373            Result := is_positive
374         else
375            other_capacity := other.value_length
376            if capacity = other_capacity then
377               from
378                  other_storage := other.value
379                  i := capacity - 1
380               variant
381                  i
382               until
383                  i < 0 or else storage.item(i) /= other_storage.item(i)
384               loop
385                  i := i - 1
386               end
387               Result := i >= 0 and then (storage.item(i) > other_storage.item(i) xor is_negative)
388            else
389               Result := capacity > other_capacity xor is_negative
390            end
391         end
392      end
393
394   greater_with_fraction_with_big_integer_number (other: FRACTION_WITH_BIG_INTEGER_NUMBER): BOOLEAN
395      do
396         Result := not other.greater_with_big_integer_number(Current)
397      end
398
399feature {ANY}
400   is_zero: BOOLEAN False
401
402   is_one: BOOLEAN False
403
404   is_equal (other: NUMBER): BOOLEAN
405         -- Compares two LARGE_INTEGERs. As they both have same sign
406         -- comparison is done with absolute values.
407      local
408         i: INTEGER; n2: like Current; n2_storage: like storage
409      do
410         if n2 ?:= other then
411            n2 ::= other
412            if is_negative = n2.is_negative then
413               if capacity = n2.value_length then
414                  from
415                     n2_storage := n2.value
416                     i := capacity - 1
417                     Result := True
418                  until
419                     not Result or else i < 0
420                  loop
421                     Result := storage.item(i) = n2_storage.item(i)
422                     i := i - 1
423                  end
424               end
425            end
426         end
427      end
428
429   append_in (buffer: STRING)
430      do
431         put_into_mutable_big_integer(mutable_register1)
432         mutable_register1.append_in(buffer)
433      end
434
435   append_in_unicode (buffer: UNICODE_STRING)
436      do
437         put_into_mutable_big_integer(mutable_register1)
438         mutable_register1.append_in_unicode(buffer)
439      end
440
441feature {NUMBER}
442   value: NATIVE_ARRAY[INTEGER]
443      do
444         Result := storage
445      ensure
446         Result = storage
447      end
448
449   value_length: INTEGER
450      do
451         Result := capacity
452      ensure
453         Result = capacity
454      end
455
456feature {MUTABLE_BIG_INTEGER}
457   from_native_array (na: NATIVE_ARRAY[INTEGER]; cap: INTEGER; neg: BOOLEAN)
458      require
459      --na.item(cap - 1) /= 0 --|*** To be completed (class invariant) (Vincent Croizier, 02/07/04) ***
460      do
461         capacity := cap
462         storage := na
463         negative := neg
464      ensure
465         capacity = cap
466         storage = na
467         negative = neg
468      end
469
470feature {NUMBER}
471   put_into_mutable_big_integer (mut: MUTABLE_BIG_INTEGER)
472      do
473         mut.from_native_array(storage, capacity, negative)
474      end
475
476   is_natural_64_: BOOLEAN
477      do
478         Result := capacity = 2
479      end
480
481   to_natural_64_: NATURAL_64
482      do
483         Result := signed_32_to_unsigned_64(storage.item(1))
484         --|*** Replace the following by a 32 left-shift:
485         Result := Result * 4294967296.to_natural_64
486         --|*** as soon as shift are available in NATURALs!
487         --|*** (Dom. sept. 14th 2007).
488         Result := Result + signed_32_to_unsigned_64(storage.item(0))
489      end
490
491feature {}
492   signed_32_to_unsigned_64 (integer_32: INTEGER): NATURAL_64
493      external "C inline"
494      alias "((uint64_t)(((uint32_t)($integer_32))))"
495      end
496
497   negative: BOOLEAN
498
499   capacity: INTEGER
500
501   storage: NATIVE_ARRAY[INTEGER_32]
502
503invariant
504   capacity >= 2
505   storage.item(capacity - 1) /= 0
506   not negative implies Current @> Maximum_integer_64
507   negative implies Current @< Minimum_integer_64
508
509end -- class BIG_INTEGER_NUMBER
510--
511-- Copyright (C) 2009-2017: by all the people cited in the AUTHORS file.
512--
513-- Permission is hereby granted, free of charge, to any person obtaining a copy
514-- of this software and associated documentation files (the "Software"), to deal
515-- in the Software without restriction, including without limitation the rights
516-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
517-- copies of the Software, and to permit persons to whom the Software is
518-- furnished to do so, subject to the following conditions:
519--
520-- The above copyright notice and this permission notice shall be included in
521-- all copies or substantial portions of the Software.
522--
523-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
524-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
525-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
526-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
527-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
528-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
529-- THE SOFTWARE.