PageRenderTime 20ms CodeModel.GetById 10ms app.highlight 6ms RepoModel.GetById 1ms app.codeStats 0ms

/src/lib/numeric/integer_general.e

http://github.com/tybor/Liberty
Specman e | 740 lines | 585 code | 79 blank | 76 comment | 20 complexity | 544212cd34975c2a4d81eb829766b854 MD5 | raw file
  1-- This file is part of a Liberty Eiffel library.
  2-- See the full copyright at the end.
  3--
  4deferred class INTEGER_GENERAL
  5   --
  6   -- General integer abstraction to share common code for INTEGER_8, INTEGER_16, INTEGER_32 and
  7   -- INTEGER_64. (Keep in mind that, INTEGER is just a built_in short-hand for INTEGER_32.)
  8   --
  9   -- All implementations have a limited size (8, 16, 32 or 64 bits) and are supposed to use
 10   -- two's complement representation which is the most common one.
 11   -- Also keep in mind that INTEGER_8, INTEGER_16, INTEGER_32 and INTEGER_64 are expanded classes
 12   -- hence making polymorphism not possible (but keeping the very best execution speed).
 13   --
 14   -- If you need integers with bigger values, use NUMBER or MUTABLE_BIG_INTEGER.
 15   --
 16   -- See also NATURAL_8, NATURAL_16, NATURAL_32, NATURAL_64, NUMBER or MUTABLE_BIG_INTEGER.
 17   --
 18
 19inherit
 20   INTEGRAL
 21      redefine fill_tagged_out_memory, out_in_tagged_out_memory, is_equal
 22      end
 23
 24feature {ANY}
 25   infix "+" (other: like Current): like Current
 26      external "built_in"
 27      end
 28
 29   infix "-" (other: like Current): like Current
 30      external "built_in"
 31      end
 32
 33   infix "*" (other: like Current): like Current
 34      external "built_in"
 35      end
 36
 37   infix "/" (other: like Current): REAL
 38      external "built_in"
 39      end
 40
 41   infix "//" (other: like Current): like Current
 42      do
 43         if Current >= 0 then
 44            Result := Current #// other
 45         elseif other > 0 then
 46            Result := (Current + 1) #// other - 1
 47         else
 48            Result := (Current + 1) #// other + 1
 49         end
 50      end
 51
 52   infix "\\" (other: like Current): like Current
 53      do
 54         Result := Current #\\ other
 55         if Result < 0 then
 56            if other > 0 then
 57               Result := Result + other
 58            else
 59               Result := Result - other
 60            end
 61            check
 62               Result > 0
 63            end
 64         end
 65      end
 66
 67   infix "^" (exp: like Current): INTEGER_64
 68      local
 69         i: like Current; k: INTEGER_64
 70      do
 71         i := exp
 72         if i = 0 then
 73            Result := 1
 74         else
 75            Result := Current
 76            from
 77               k := 1
 78            until
 79               i <= 1
 80            loop
 81               if i.is_odd then
 82                  k := k * Result
 83               end
 84               Result := Result * Result
 85               i := i #// 2
 86            end
 87            Result := Result * k
 88         end
 89      end
 90
 91   abs: like Current
 92      do
 93         if Current < 0 then
 94            Result := -Current
 95         else
 96            Result := Current
 97         end
 98      end
 99
100   infix "<" (other: like Current): BOOLEAN
101      external "built_in"
102      end
103
104   infix "<=" (other: like Current): BOOLEAN
105      external "built_in"
106      end
107
108   infix ">" (other: like Current): BOOLEAN
109      external "built_in"
110      end
111
112   infix ">=" (other: like Current): BOOLEAN
113      external "built_in"
114      end
115
116   prefix "+": like Current
117      do
118         Result := Current
119      end
120
121   prefix "-": like Current
122      external "built_in"
123      end
124
125   is_odd: BOOLEAN
126      do
127         Result := Current & 1 /= 0
128      end
129
130   is_even: BOOLEAN
131      do
132         Result := Current & 1 = 0
133      end
134
135   is_prime: BOOLEAN
136         -- Is prime?
137      local
138         index, limit: like Current
139      do
140         if Current > 3 then
141            if (is_even) or ((Current #\\ 3) = 0) then
142               Result := False
143            else
144               limit ::= sqrt.force_to_integer_64 + 1
145               Result := True
146               from
147                  index := 5
148               until
149                  index >= limit
150               loop
151                  if (Current #\\ index = 0) or (Current #\\ (index+2) = 0)  then
152                     Result := False
153                     index := limit
154                  end
155                  index := index + 6
156               end
157            end
158         elseif  Current < 2 then
159            Result := False
160         else
161            Result := True
162         end
163      end
164
165   is_fibonacci: BOOLEAN
166         -- Is Fibonacci number?
167      local
168         n: like Current
169      do
170         n := Current * Current * 5
171         Result := ( is_perfect_square(n+4) or is_perfect_square(n-4) )
172      end      
173
174   sqrt: REAL
175      deferred
176      end
177
178   log: REAL
179      deferred
180      end
181
182   log10: REAL
183      deferred
184      end
185
186   gcd (other: like Current): like Current
187      do
188         if other = 0 then
189            Result := Current.abs
190         else
191            Result := other.gcd(Current \\ other)
192         end
193      end
194
195feature {}
196      --| class-local helper, hence local access only
197   is_perfect_square(other: like Current): BOOLEAN
198      local
199         s: like Current
200      do
201         s ::= other.sqrt.force_to_integer_64
202         Result := ((s*s) = other)
203      end
204
205feature {ANY} -- Conversions:
206   to_string: STRING
207      do
208         string_buffer.clear_count
209         append_in(string_buffer)
210         Result := string_buffer.twin
211      end
212
213   to_unicode_string: UNICODE_STRING
214      do
215         unicode_string_buffer.clear_count
216         append_in_unicode(unicode_string_buffer)
217         Result := unicode_string_buffer.twin
218      end
219
220   to_boolean: BOOLEAN
221      do
222         Result := Current /= 0
223      end
224
225   to_number: NUMBER
226      deferred
227      end
228
229   append_in (buffer: STRING)
230      local
231         val: like Current; i, idx: INTEGER
232      do
233         if Current = 0 then
234            buffer.extend('0')
235         else
236            from
237               if Current > 0 then
238                  val := Current
239                  -- Save the position of first character in the buffer.
240                  i := buffer.count + 1
241               else
242                  buffer.extend('-')
243                  -- Save the position of first character in the buffer.
244                  i := buffer.count + 1
245                  -- First (last) digit
246                  val := Current #\\ 10
247                  if val <= 0 then
248                     buffer.extend((-val).decimal_digit)
249                     val := -(Current #// 10)
250                  else
251                     buffer.extend((-val + 10).decimal_digit)
252                     val := -(Current #// 10) - 1
253                  end
254                  check
255                     val >= 0
256                  end
257               end
258            until
259               val = 0
260            loop
261               buffer.extend((val #\\ 10).decimal_digit)
262               val := val #// 10
263            end
264            -- Change character order.
265            from
266               idx := buffer.count
267            until
268               i >= idx
269            loop
270               buffer.swap(i, idx)
271               idx := idx - 1
272               i := i + 1
273            end
274         end
275      end
276
277   append_in_unicode (buffer: UNICODE_STRING)
278      local
279         val: like Current; i, idx: INTEGER
280      do
281         if Current = 0 then
282            buffer.extend('0'.code)
283         else
284            from
285               if Current > 0 then
286                  val := Current
287                  -- Save the position of first character in the buffer.
288                  i := buffer.count + 1
289               else
290                  buffer.extend('-'.code)
291                  -- Save the position of first character in the buffer.
292                  i := buffer.count + 1
293                  -- First (last) digit
294                  val := Current #\\ 10
295                  if val <= 0 then
296                     buffer.extend((-val).decimal_digit.code)
297                     val := -(Current #// 10)
298                  else
299                     buffer.extend((- val + 10).decimal_digit.code)
300                     val := -(Current #// 10) - 1
301                  end
302                  check
303                     val >= 0
304                  end
305               end
306            until
307               val = 0
308            loop
309               buffer.extend((val #\\ 10).decimal_digit.code)
310               val := val #// 10
311            end
312            -- Change character order.
313            from
314               idx := buffer.count
315            until
316               i >= idx
317            loop
318               buffer.swap(i, idx)
319               idx := idx - 1
320               i := i + 1
321            end
322         end
323      end
324
325   to_string_format (s: INTEGER): STRING
326      local
327         i: INTEGER
328      do
329         string_buffer.clear_count
330         append_in(string_buffer)
331         from
332            create Result.make(string_buffer.count.max(s))
333            i := s - string_buffer.count
334         until
335            i <= 0
336         loop
337            Result.extend(' ')
338            i := i - 1
339         end
340         Result.append(string_buffer)
341      end
342
343   to_unicode_string_format (s: INTEGER): UNICODE_STRING
344      local
345         i: INTEGER
346      do
347         unicode_string_buffer.clear_count
348         append_in_unicode(unicode_string_buffer)
349         from
350            create Result.make(unicode_string_buffer.count.max(s))
351            i := s - unicode_string_buffer.count
352         until
353            i <= 0
354         loop
355            Result.extend(' '.code)
356            i := i - 1
357         end
358         Result.append(unicode_string_buffer)
359      end
360
361   append_in_format (buffer: STRING; s: INTEGER)
362      local
363         i: INTEGER
364      do
365         string_buffer.clear_count
366         append_in(string_buffer)
367         from
368            i := s - string_buffer.count
369         until
370            i <= 0
371         loop
372            buffer.extend(' ')
373            i := i - 1
374         end
375         buffer.append(string_buffer)
376      end
377
378   append_in_unicode_format (buffer: UNICODE_STRING; s: INTEGER)
379      local
380         i: INTEGER
381      do
382         unicode_string_buffer.clear_count
383         append_in_unicode(unicode_string_buffer)
384         from
385            i := s - unicode_string_buffer.count
386         until
387            i <= 0
388         loop
389            buffer.extend(' '.code)
390            i := i - 1
391         end
392         buffer.append(unicode_string_buffer)
393      end
394
395   digit: CHARACTER
396      do
397         Result := decimal_digit
398      end
399
400   is_decimal_digit: BOOLEAN
401      do
402         Result := in_range(0, 9)
403      end
404
405   decimal_digit: CHARACTER
406      deferred
407      end
408
409   is_hexadecimal_digit: BOOLEAN
410      do
411         Result := in_range(0, 15)
412      end
413
414   hexadecimal_digit: CHARACTER
415      deferred
416      end
417
418   to_character: CHARACTER
419      external "built_in"
420      end
421
422   to_octal_in (buffer: STRING)
423      local
424         index, timez: INTEGER; value: like Current
425      do
426         from
427            value := Current
428            timez := bit_count #// 3 + 1
429            index := buffer.count + timez
430            buffer.extend_multiple(' ', timez)
431         until
432            timez = 0
433         loop
434            buffer.put((value & 0x07).decimal_digit, index)
435            index := index - 1
436            value := value |>>> 3
437            timez := timez - 1
438         end
439      end
440
441   to_octal: STRING
442      do
443         string_buffer.clear_count
444         to_octal_in(string_buffer)
445         Result := string_buffer.twin
446      end
447
448   to_hexadecimal: STRING
449      do
450         string_buffer.clear_count
451         to_hexadecimal_in(string_buffer)
452         Result := string_buffer.twin
453      end
454
455   to_hexadecimal_in (buffer: STRING)
456      local
457         index, timez: INTEGER; value: like Current
458      do
459         from
460            value := Current
461            timez := object_size * 2
462            index := buffer.count + timez
463            buffer.extend_multiple(' ', timez)
464         until
465            timez = 0
466         loop
467            buffer.put((value & 0x0F).hexadecimal_digit, index)
468            index := index - 1
469            value := value |>> 4
470            timez := timez - 1
471         end
472      end
473
474feature {ANY} -- Bitwise Logical Operators:
475   bit_test (idx: INTEGER_8): BOOLEAN
476      do
477         Result := Current.bit_shift_right(idx) & 1 /= 0
478      end
479
480   bit_set (idx: INTEGER_8): like Current
481      local
482         mask: like Current
483      do
484         mask := 1
485         Result := Current.bit_or(mask.bit_shift_left(idx))
486      end
487
488   bit_reset (idx: INTEGER_8): like Current
489      local
490         mask: like Current
491      do
492         mask := 1
493         Result := Current.bit_and(mask.bit_shift_left(idx).bit_not)
494      end
495
496   infix "|>>", bit_shift_right (s: INTEGER_8): like Current
497         -- Shift by `s' positions right (sign bit copied) bits falling off the end are lost.
498      external "built_in"
499      end
500
501   infix "|>>>", bit_shift_right_unsigned (s: INTEGER_8): like Current
502         -- Shift by `s' positions right (sign bit not copied) bits falling off the end are lost.
503      external "built_in"
504      end
505
506   infix "|<<", bit_shift_left (s: INTEGER_8): like Current
507         -- Shift by `s' positions left bits falling off the end are lost.
508      external "built_in"
509      end
510
511   infix "#>>", bit_rotate_right (s: INTEGER_8): like Current
512      external "built_in"
513      end
514
515   infix "#<<", bit_rotate_left (s: INTEGER_8): like Current
516      external "built_in"
517      end
518
519   bit_rotate (s: INTEGER_8): like Current
520      external "built_in"
521      end
522
523   prefix "~", bit_not: like Current
524      external "built_in"
525      end
526
527   infix "&", bit_and (other: like Current): like Current
528      external "built_in"
529      end
530
531   infix "|", bit_or (other: like Current): like Current
532      external "built_in"
533      end
534
535   bit_xor (other: like Current): like Current
536      external "built_in"
537      end
538
539   bit_shift (s: INTEGER_8): like Current
540      do
541         if s > 0 then
542            Result := Current |>> s
543         else
544            Result := Current |<< -s
545         end
546      end
547
548   bit_shift_unsigned (s: INTEGER_8): like Current
549      do
550         if s > 0 then
551            Result := Current |>>> s
552         else
553            Result := Current |<< -s
554         end
555      end
556
557feature {ANY} -- Object Printing:
558   out_in_tagged_out_memory, fill_tagged_out_memory
559      do
560         Current.append_in(tagged_out_memory)
561      end
562
563feature {ANY} -- Miscellaneous:
564   sign: INTEGER_8
565      do
566         if Current < 0 then
567            Result := -1
568         elseif Current > 0 then
569            Result := 1
570         end
571      end
572
573   divisible (other: like Current): BOOLEAN
574      do
575         Result := other /= zero
576      end
577
578   is_equal (other: like Current): BOOLEAN
579      do
580         Result := Current = other
581      end
582
583   is_a_power_of_2: BOOLEAN
584         -- Is `Current' a power of 2?
585      do
586         Result := (Current - 1) & Current = 0
587      end
588
589feature {ANY} -- Looping:
590   times (repeat: PROCEDURE[TUPLE[like Current]])
591         -- Repeats the procedure from 1 to Current. As for any Liberty Eiffel agent the open argument may be
592         -- safely ignored. You may also build your agent with closed arguments.
593         --
594         -- See also `loop_to', `loop_from'
595      require
596         meaningful: Current >= zero
597      local
598         i: like Current
599      do
600         -- Note:
601         -- should really be loop_from(1, repeat) but for the type of 1 (INTEGER_8) not being the type of Current
602         from
603            i := 1
604         until
605            i > Current
606         loop
607            repeat.call([i])
608            i := i + 1
609         end
610      end
611
612   loop_to (bound: like Current; repeat: PROCEDURE[TUPLE[like Current]])
613         -- Repeats the procedure from Current to `bound'. As for any Liberty Eiffel agent the open argument may
614         -- be safely ignored. You may also build your agent with closed arguments.
615         --
616         -- See also `times', `loop_from'
617         --
618         -- See also the simpler `loop_up_to', `loop_down_to'
619      local
620         i: like Current
621      do
622         if bound > Current then
623            loop_up_to(bound, repeat)
624         elseif bound < Current then
625            loop_down_to(bound, repeat)
626         else
627            repeat.call([Current])
628         end
629      end
630
631   loop_from (bound: like Current; repeat: PROCEDURE[TUPLE[like Current]])
632         -- Repeats the procedure from `bound' to Current. As for any Liberty Eiffel agent the open argument may
633         -- be safely ignored. You may also build your agent with closed arguments.
634         --
635         -- See also `times', `loop_to'
636      require
637         useful: bound /= Current
638      do
639         bound.loop_to(Current, repeat)
640      end
641
642   loop_up_to (bound: like Current; repeat: PROCEDURE[TUPLE[like Current]])
643         -- Repeats the procedure from Current to a greater `bound'. As for any Liberty Eiffel agent the open
644         -- argument may be safely ignored. You may also build your agent with closed arguments.
645         --
646         -- See also `loop_to', `loop_down_to'
647      local
648         i: like Current
649      do
650         from
651            i := Current
652         until
653            i > bound
654         loop
655            repeat.call([i])
656            i := i + 1
657         end
658      end
659
660   loop_down_to (bound: like Current; repeat: PROCEDURE[TUPLE[like Current]])
661         -- Repeats the procedure from Current to a lower `bound'. As for any Liberty Eiffel agent the open
662         -- argument may be safely ignored. You may also build your agent with closed arguments.
663         --
664         -- See also `loop_to', `loop_down_to'
665      local
666         i: like Current
667      do
668         from
669            i := Current
670         until
671            i < bound
672         loop
673            repeat.call([i])
674            i := i - 1
675         end
676      end
677
678feature {ANY} -- Modular arithmetic (these wrap around on overflow)
679   infix "#+" (other: like Current): like Current
680      external "built_in"
681      end
682
683   prefix "#-": like Current
684      external "built_in"
685      end
686
687   infix "#-" (other: like Current): like Current
688      external "built_in"
689      end
690
691   infix "#*" (other: like Current): like Current
692      external "built_in"
693      end
694
695   infix "#//" (other: like Current): like Current
696      external "built_in"
697      end
698
699   infix "#\\" (other: like Current): like Current
700      external "built_in"
701      end
702
703feature {ANY} -- Size query
704   bit_count: INTEGER_8
705      -- The number of bits used to store the value of Current
706      deferred
707      end
708
709feature {}
710   string_buffer: STRING
711      once
712         create Result.make(128)
713      end
714
715   unicode_string_buffer: UNICODE_STRING
716      once
717         create Result.make(128)
718      end
719
720end -- class INTEGER_GENERAL
721--
722-- Copyright (C) 2009-2017: by all the people cited in the AUTHORS file.
723--
724-- Permission is hereby granted, free of charge, to any person obtaining a copy
725-- of this software and associated documentation files (the "Software"), to deal
726-- in the Software without restriction, including without limitation the rights
727-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
728-- copies of the Software, and to permit persons to whom the Software is
729-- furnished to do so, subject to the following conditions:
730--
731-- The above copyright notice and this permission notice shall be included in
732-- all copies or substantial portions of the Software.
733--
734-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
735-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
736-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
737-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
738-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
739-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
740-- THE SOFTWARE.