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