/src/lib/numeric/internal/fraction_with_big_integer_number.e
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.