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