PageRenderTime 14ms CodeModel.GetById 9ms app.highlight 2ms RepoModel.GetById 1ms app.codeStats 0ms

/src/lib/numeric/internal/fraction_with_big_integer_number.e

http://github.com/tybor/Liberty
Specman e | 430 lines | 364 code | 35 blank | 31 comment | 28 complexity | 541afcf089c923eef0b4ff1f69ecd87b MD5 | raw file
  1-- This file is part of a Liberty Eiffel library.
  2-- See the full copyright at the end.
  3--
  4class FRACTION_WITH_BIG_INTEGER_NUMBER
  5   --
  6   -- To implement NUMBER (do not use this class, see NUMBER).
  7   --
  8
  9inherit
 10   FRACTION_GENERAL_NUMBER
 11
 12create {ANY}
 13   make, make_simply
 14
 15feature {ANY}
 16   numerator: INTEGER_GENERAL_NUMBER
 17
 18   denominator: INTEGER_GENERAL_NUMBER
 19
 20feature {NUMBER}
 21   make (n, d: INTEGER_GENERAL_NUMBER)
 22         -- Create a simplified large_fraction
 23      require
 24         not ((n \\ d) @= 0)
 25      local
 26         gcd_frac, num, den: INTEGER_GENERAL_NUMBER
 27      do
 28         gcd_frac := n.gcd(d)
 29         num ::= n // gcd_frac
 30         den ::= d // gcd_frac
 31         if den.is_negative then
 32            numerator ::= -num
 33            denominator ::= -den
 34         else
 35            numerator := num
 36            denominator := den
 37         end
 38      end
 39
 40   make_simply (n, d: INTEGER_GENERAL_NUMBER)
 41         -- create a large_fraction without simplify it
 42      require
 43         d.is_positive
 44         n.gcd(d).is_one
 45         d @>= 2
 46      do
 47         numerator := n
 48         denominator := d
 49      ensure
 50         numerator = n
 51         denominator = d
 52      end
 53
 54feature {ANY}
 55   inverse: NUMBER
 56      local
 57         tmp1, tmp2: INTEGER_GENERAL_NUMBER
 58      do
 59         if numerator @= 1 then
 60            Result := denominator
 61         elseif numerator @= -1 then
 62            Result := -denominator
 63         elseif is_negative then
 64            tmp1 ::= -denominator
 65            tmp2 ::= -numerator
 66            create {FRACTION_WITH_BIG_INTEGER_NUMBER} Result.make_simply(tmp1, tmp2)
 67         else
 68            create {FRACTION_WITH_BIG_INTEGER_NUMBER} Result.make_simply(denominator, numerator)
 69         end
 70      end
 71
 72   prefix "-": NUMBER
 73      local
 74         tmp: INTEGER_GENERAL_NUMBER
 75      do
 76         tmp ::= -numerator
 77         create {FRACTION_WITH_BIG_INTEGER_NUMBER} Result.make_simply(tmp, denominator)
 78      end
 79
 80   infix "+" (other: NUMBER): NUMBER
 81      do
 82         Result := other.add_with_fraction_with_big_integer_number(Current)
 83      end
 84
 85   append_in (buffer: STRING)
 86      do
 87         numerator.append_in(buffer)
 88         buffer.extend('/')
 89         denominator.append_in(buffer)
 90      end
 91
 92   append_in_unicode (buffer: UNICODE_STRING)
 93      do
 94         numerator.append_in_unicode(buffer)
 95         buffer.extend('/'.code)
 96         denominator.append_in_unicode(buffer)
 97      end
 98
 99   append_decimal_in (buffer: STRING; digits: INTEGER; all_digits: BOOLEAN)
100      do
101         decimal_in(buffer, numerator, denominator, is_negative, digits, all_digits)
102      end
103
104   is_equal (other: NUMBER): BOOLEAN
105      local
106         n2: like Current
107      do
108         if n2 ?:= other then
109            n2 ::= other
110            Result := denominator.is_equal(n2.denominator) and then numerator.is_equal(n2.numerator)
111         end
112      end
113
114   force_to_real_64: REAL_64
115         --|*** This is not very good, bad precision on big numbers
116         --| (Vincent Croizier, 05/07/04) ***
117      do
118         Result := numerator.force_to_real_64 / denominator.force_to_real_64
119      end
120
121   infix "*" (other: NUMBER): NUMBER
122      do
123         Result := other.multiply_with_fraction_with_big_integer_number(Current)
124      end
125
126   infix "@+" (other: INTEGER_64): NUMBER
127         -- Sum of 'Current' and 'other'.
128      local
129         tmp: INTEGER_GENERAL_NUMBER
130      do
131         tmp ::= denominator @* other + numerator
132         create {FRACTION_WITH_BIG_INTEGER_NUMBER} Result.make_simply(tmp, denominator)
133      end
134
135feature {NUMBER, NUMBER_TOOLS}
136   add_with_big_integer_number (other: BIG_INTEGER_NUMBER): NUMBER
137      local
138         tmp: INTEGER_GENERAL_NUMBER
139      do
140         tmp ::= other * denominator + numerator
141         Result := from_two_integer_general_number(tmp, denominator)
142      end
143
144   add_with_fraction_with_big_integer_number (other: FRACTION_WITH_BIG_INTEGER_NUMBER): NUMBER
145      local
146         new_num, new_den, dg, d1, d2, g: INTEGER_GENERAL_NUMBER
147      do
148         if denominator.is_equal(other.denominator) then
149            new_num ::= numerator + other.numerator
150            if new_num.is_zero then
151               Result := zero
152            else
153               g := new_num.gcd(denominator)
154               if denominator.is_equal(g) then
155                  Result := new_num // g
156               else
157                  new_num ::= new_num // g
158                  new_den ::= denominator // g
159                  create {FRACTION_WITH_BIG_INTEGER_NUMBER} Result.make_simply(new_num, new_den)
160               end
161            end
162         else
163            dg := denominator.gcd(other.denominator)
164            check
165               dg.is_positive
166            end
167            d1 ::= denominator // dg
168            d2 ::= other.denominator // dg
169            check
170               denominator.is_equal(dg * d1)
171               other.denominator.is_equal(dg * d2)
172            end
173            new_num ::= numerator * d2 + other.numerator * d1
174            if new_num.is_zero then
175               Result := new_num
176            else
177               new_den ::= denominator * d2
178               g := new_num.gcd(dg)
179               if g.is_one then
180                  create {FRACTION_WITH_BIG_INTEGER_NUMBER} Result.make_simply(new_num, new_den)
181               else
182                  new_num ::= new_num // g
183                  new_den ::= new_den // g
184                  check
185                     not new_den.is_one
186                  end
187                  create {FRACTION_WITH_BIG_INTEGER_NUMBER} Result.make_simply(new_num, new_den)
188               end
189            end
190         end
191      end
192
193   multiply_with_big_integer_number (other: BIG_INTEGER_NUMBER): NUMBER
194      local
195         g, n, d: INTEGER_GENERAL_NUMBER
196      do
197         g := other.gcd(denominator)
198         d ::= denominator // g
199         n ::= numerator * (other // g)
200         if d.is_one then
201            Result := n
202         else
203            create {FRACTION_WITH_BIG_INTEGER_NUMBER} Result.make_simply(n, d)
204         end
205      end
206
207   multiply_with_fraction_with_big_integer_number (other: FRACTION_WITH_BIG_INTEGER_NUMBER): NUMBER
208      local
209         g1, g2, n, d: INTEGER_GENERAL_NUMBER
210      do
211         g1 := numerator.gcd(other.denominator)
212         g2 := denominator.gcd(other.numerator)
213         n ::= numerator // g1 * (other.numerator // g2)
214         d ::= denominator // g2 * (other.denominator // g1)
215         if d.is_one then
216            Result := n
217         else
218            create {FRACTION_WITH_BIG_INTEGER_NUMBER} Result.make_simply(n, d)
219         end
220      end
221
222feature {ANY}
223   infix "@*" (other: INTEGER_64): NUMBER
224      local
225         tmp1, tmp2, g: INTEGER_GENERAL_NUMBER
226      do
227         g := denominator.gcd(other.to_number)
228         check
229            g.is_integer_64
230         end
231         if g.is_one then
232            tmp1 ::= numerator @* other
233            create {FRACTION_WITH_BIG_INTEGER_NUMBER} Result.make_simply(tmp1, denominator)
234         elseif denominator.is_equal(g) then
235            Result := numerator @* (other // g.to_integer_64)
236         else
237            tmp1 ::= numerator @* (other // g.to_integer_64)
238            tmp2 ::= denominator // g
239            create {FRACTION_WITH_BIG_INTEGER_NUMBER} Result.make_simply(tmp1, tmp2)
240         end
241      end
242
243   infix "@/" (other: INTEGER_64): NUMBER
244      local
245         tmp1, tmp2, g: INTEGER_GENERAL_NUMBER
246      do
247         if other = 1 then
248            Result := Current
249         elseif other = -1 then
250            Result := -Current
251         else
252            g := numerator.gcd(other.to_number)
253            check
254               g.is_integer_64
255            end
256            if g.is_one then
257               if other < 0 then
258                  tmp1 ::= -numerator
259                  tmp2 ::= -(denominator @* other)
260                  create {FRACTION_WITH_BIG_INTEGER_NUMBER} Result.make_simply(tmp1, tmp2)
261               else
262                  tmp2 ::= denominator @* other
263                  create {FRACTION_WITH_BIG_INTEGER_NUMBER} Result.make_simply(numerator, tmp2)
264               end
265            elseif other < 0 then
266               tmp1 ::= -(numerator // g)
267               tmp2 ::= -denominator @* (other // g.to_integer_64)
268               create {FRACTION_WITH_BIG_INTEGER_NUMBER} Result.make_simply(tmp1, tmp2)
269            else
270               tmp1 ::= numerator // g
271               tmp2 ::= denominator @* (other // g.to_integer_64)
272               create {FRACTION_WITH_BIG_INTEGER_NUMBER} Result.make_simply(tmp1, tmp2)
273            end
274         end
275      end
276
277   infix "@<" (other: INTEGER_64): BOOLEAN
278      do
279         if is_negative then
280            if other < 0 then
281               Result := numerator < denominator @* other
282            else
283               Result := True
284            end
285         else
286            if other >= 0 then
287               Result := numerator < denominator @* other
288            end
289         end
290      end
291
292   infix "@>" (other: INTEGER_64): BOOLEAN
293      do
294         Result := not (Current @< other)
295      end
296
297   infix "@<=" (other: INTEGER_64): BOOLEAN
298      do
299         Result := Current @< other
300      end
301
302   infix "@>=" (other: INTEGER_64): BOOLEAN
303      do
304         Result := not (Current @< other)
305      end
306
307   infix "<" (other: NUMBER): BOOLEAN
308      do
309         Result := other.greater_with_fraction_with_big_integer_number(Current)
310      end
311
312   infix "#=" (other: REAL_64): BOOLEAN
313      do
314         if is_negative then
315            if other >= 0 then
316            elseif Current < min_double then
317            else
318               Result := force_to_real_64 = other
319            end
320         elseif other < 0 then
321         elseif Current > max_double then
322         else
323            Result := force_to_real_64 = other
324         end
325      end
326
327   infix "#<" (other: REAL_64): BOOLEAN
328      do
329         if is_negative then
330            if other >= 0 then
331               Result := True
332            elseif Current < min_double then
333               Result := True
334            else
335               Result := force_to_real_64 < other
336            end
337         elseif other < 0 then
338         elseif Current > max_double then
339         else
340            Result := force_to_real_64 < other
341         end
342      end
343
344   infix "#<=" (other: REAL_64): BOOLEAN
345      do
346         if is_negative then
347            if other >= 0 then
348               Result := True
349            elseif Current <= -max_double then
350               Result := True
351            else
352               Result := force_to_real_64 <= other
353            end
354         elseif other <= 0 then
355         elseif Current >= max_double then
356         else
357            Result := force_to_real_64 <= other
358         end
359      end
360
361   infix "#>=" (other: REAL_64): BOOLEAN
362      do
363         if is_negative then
364            if other >= 0 then
365            elseif Current <= min_double then
366            else
367               Result := force_to_real_64 >= other
368            end
369         elseif other <= 0 then
370            Result := True
371         elseif Current >= max_double then
372            Result := True
373         else
374            Result := force_to_real_64 >= other
375         end
376      end
377
378   infix "#>" (other: REAL_64): BOOLEAN
379      do
380         if is_negative then
381            if other >= 0 then
382            elseif Current < min_double then
383            else
384               Result := force_to_real_64 > other
385            end
386         elseif other < 0 then
387            Result := True
388         elseif Current > max_double then
389            Result := True
390         else
391            Result := force_to_real_64 > other
392         end
393      end
394
395feature {NUMBER, NUMBER_TOOLS}
396   greater_with_big_integer_number (other: BIG_INTEGER_NUMBER): BOOLEAN
397      do
398         Result := denominator.multiply_with_big_integer_number(other) < numerator
399      end
400
401   greater_with_fraction_with_big_integer_number (other: FRACTION_WITH_BIG_INTEGER_NUMBER): BOOLEAN
402      do
403         if is_negative = other.is_negative then
404            Result := numerator * other.denominator > other.numerator * denominator
405         elseif other.is_negative then
406            Result := True
407         end
408      end
409
410end -- class FRACTION_WITH_BIG_INTEGER_NUMBER
411--
412-- Copyright (C) 2009-2017: by all the people cited in the AUTHORS file.
413--
414-- Permission is hereby granted, free of charge, to any person obtaining a copy
415-- of this software and associated documentation files (the "Software"), to deal
416-- in the Software without restriction, including without limitation the rights
417-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
418-- copies of the Software, and to permit persons to whom the Software is
419-- furnished to do so, subject to the following conditions:
420--
421-- The above copyright notice and this permission notice shall be included in
422-- all copies or substantial portions of the Software.
423--
424-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
425-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
426-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
427-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
428-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
429-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
430-- THE SOFTWARE.