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