/src/lib/numeric/integer_general.e

http://github.com/tybor/Liberty · Specman e · 740 lines · 585 code · 79 blank · 76 comment · 20 complexity · 544212cd34975c2a4d81eb829766b854 MD5 · raw file

  1. -- This file is part of a Liberty Eiffel library.
  2. -- See the full copyright at the end.
  3. --
  4. deferred class INTEGER_GENERAL
  5. --
  6. -- General integer abstraction to share common code for INTEGER_8, INTEGER_16, INTEGER_32 and
  7. -- INTEGER_64. (Keep in mind that, INTEGER is just a built_in short-hand for INTEGER_32.)
  8. --
  9. -- All implementations have a limited size (8, 16, 32 or 64 bits) and are supposed to use
  10. -- two's complement representation which is the most common one.
  11. -- Also keep in mind that INTEGER_8, INTEGER_16, INTEGER_32 and INTEGER_64 are expanded classes
  12. -- hence making polymorphism not possible (but keeping the very best execution speed).
  13. --
  14. -- If you need integers with bigger values, use NUMBER or MUTABLE_BIG_INTEGER.
  15. --
  16. -- See also NATURAL_8, NATURAL_16, NATURAL_32, NATURAL_64, NUMBER or MUTABLE_BIG_INTEGER.
  17. --
  18. inherit
  19. INTEGRAL
  20. redefine fill_tagged_out_memory, out_in_tagged_out_memory, is_equal
  21. end
  22. feature {ANY}
  23. infix "+" (other: like Current): like Current
  24. external "built_in"
  25. end
  26. infix "-" (other: like Current): like Current
  27. external "built_in"
  28. end
  29. infix "*" (other: like Current): like Current
  30. external "built_in"
  31. end
  32. infix "/" (other: like Current): REAL
  33. external "built_in"
  34. end
  35. infix "//" (other: like Current): like Current
  36. do
  37. if Current >= 0 then
  38. Result := Current #// other
  39. elseif other > 0 then
  40. Result := (Current + 1) #// other - 1
  41. else
  42. Result := (Current + 1) #// other + 1
  43. end
  44. end
  45. infix "\\" (other: like Current): like Current
  46. do
  47. Result := Current #\\ other
  48. if Result < 0 then
  49. if other > 0 then
  50. Result := Result + other
  51. else
  52. Result := Result - other
  53. end
  54. check
  55. Result > 0
  56. end
  57. end
  58. end
  59. infix "^" (exp: like Current): INTEGER_64
  60. local
  61. i: like Current; k: INTEGER_64
  62. do
  63. i := exp
  64. if i = 0 then
  65. Result := 1
  66. else
  67. Result := Current
  68. from
  69. k := 1
  70. until
  71. i <= 1
  72. loop
  73. if i.is_odd then
  74. k := k * Result
  75. end
  76. Result := Result * Result
  77. i := i #// 2
  78. end
  79. Result := Result * k
  80. end
  81. end
  82. abs: like Current
  83. do
  84. if Current < 0 then
  85. Result := -Current
  86. else
  87. Result := Current
  88. end
  89. end
  90. infix "<" (other: like Current): BOOLEAN
  91. external "built_in"
  92. end
  93. infix "<=" (other: like Current): BOOLEAN
  94. external "built_in"
  95. end
  96. infix ">" (other: like Current): BOOLEAN
  97. external "built_in"
  98. end
  99. infix ">=" (other: like Current): BOOLEAN
  100. external "built_in"
  101. end
  102. prefix "+": like Current
  103. do
  104. Result := Current
  105. end
  106. prefix "-": like Current
  107. external "built_in"
  108. end
  109. is_odd: BOOLEAN
  110. do
  111. Result := Current & 1 /= 0
  112. end
  113. is_even: BOOLEAN
  114. do
  115. Result := Current & 1 = 0
  116. end
  117. is_prime: BOOLEAN
  118. -- Is prime?
  119. local
  120. index, limit: like Current
  121. do
  122. if Current > 3 then
  123. if (is_even) or ((Current #\\ 3) = 0) then
  124. Result := False
  125. else
  126. limit ::= sqrt.force_to_integer_64 + 1
  127. Result := True
  128. from
  129. index := 5
  130. until
  131. index >= limit
  132. loop
  133. if (Current #\\ index = 0) or (Current #\\ (index+2) = 0) then
  134. Result := False
  135. index := limit
  136. end
  137. index := index + 6
  138. end
  139. end
  140. elseif Current < 2 then
  141. Result := False
  142. else
  143. Result := True
  144. end
  145. end
  146. is_fibonacci: BOOLEAN
  147. -- Is Fibonacci number?
  148. local
  149. n: like Current
  150. do
  151. n := Current * Current * 5
  152. Result := ( is_perfect_square(n+4) or is_perfect_square(n-4) )
  153. end
  154. sqrt: REAL
  155. deferred
  156. end
  157. log: REAL
  158. deferred
  159. end
  160. log10: REAL
  161. deferred
  162. end
  163. gcd (other: like Current): like Current
  164. do
  165. if other = 0 then
  166. Result := Current.abs
  167. else
  168. Result := other.gcd(Current \\ other)
  169. end
  170. end
  171. feature {}
  172. --| class-local helper, hence local access only
  173. is_perfect_square(other: like Current): BOOLEAN
  174. local
  175. s: like Current
  176. do
  177. s ::= other.sqrt.force_to_integer_64
  178. Result := ((s*s) = other)
  179. end
  180. feature {ANY} -- Conversions:
  181. to_string: STRING
  182. do
  183. string_buffer.clear_count
  184. append_in(string_buffer)
  185. Result := string_buffer.twin
  186. end
  187. to_unicode_string: UNICODE_STRING
  188. do
  189. unicode_string_buffer.clear_count
  190. append_in_unicode(unicode_string_buffer)
  191. Result := unicode_string_buffer.twin
  192. end
  193. to_boolean: BOOLEAN
  194. do
  195. Result := Current /= 0
  196. end
  197. to_number: NUMBER
  198. deferred
  199. end
  200. append_in (buffer: STRING)
  201. local
  202. val: like Current; i, idx: INTEGER
  203. do
  204. if Current = 0 then
  205. buffer.extend('0')
  206. else
  207. from
  208. if Current > 0 then
  209. val := Current
  210. -- Save the position of first character in the buffer.
  211. i := buffer.count + 1
  212. else
  213. buffer.extend('-')
  214. -- Save the position of first character in the buffer.
  215. i := buffer.count + 1
  216. -- First (last) digit
  217. val := Current #\\ 10
  218. if val <= 0 then
  219. buffer.extend((-val).decimal_digit)
  220. val := -(Current #// 10)
  221. else
  222. buffer.extend((-val + 10).decimal_digit)
  223. val := -(Current #// 10) - 1
  224. end
  225. check
  226. val >= 0
  227. end
  228. end
  229. until
  230. val = 0
  231. loop
  232. buffer.extend((val #\\ 10).decimal_digit)
  233. val := val #// 10
  234. end
  235. -- Change character order.
  236. from
  237. idx := buffer.count
  238. until
  239. i >= idx
  240. loop
  241. buffer.swap(i, idx)
  242. idx := idx - 1
  243. i := i + 1
  244. end
  245. end
  246. end
  247. append_in_unicode (buffer: UNICODE_STRING)
  248. local
  249. val: like Current; i, idx: INTEGER
  250. do
  251. if Current = 0 then
  252. buffer.extend('0'.code)
  253. else
  254. from
  255. if Current > 0 then
  256. val := Current
  257. -- Save the position of first character in the buffer.
  258. i := buffer.count + 1
  259. else
  260. buffer.extend('-'.code)
  261. -- Save the position of first character in the buffer.
  262. i := buffer.count + 1
  263. -- First (last) digit
  264. val := Current #\\ 10
  265. if val <= 0 then
  266. buffer.extend((-val).decimal_digit.code)
  267. val := -(Current #// 10)
  268. else
  269. buffer.extend((- val + 10).decimal_digit.code)
  270. val := -(Current #// 10) - 1
  271. end
  272. check
  273. val >= 0
  274. end
  275. end
  276. until
  277. val = 0
  278. loop
  279. buffer.extend((val #\\ 10).decimal_digit.code)
  280. val := val #// 10
  281. end
  282. -- Change character order.
  283. from
  284. idx := buffer.count
  285. until
  286. i >= idx
  287. loop
  288. buffer.swap(i, idx)
  289. idx := idx - 1
  290. i := i + 1
  291. end
  292. end
  293. end
  294. to_string_format (s: INTEGER): STRING
  295. local
  296. i: INTEGER
  297. do
  298. string_buffer.clear_count
  299. append_in(string_buffer)
  300. from
  301. create Result.make(string_buffer.count.max(s))
  302. i := s - string_buffer.count
  303. until
  304. i <= 0
  305. loop
  306. Result.extend(' ')
  307. i := i - 1
  308. end
  309. Result.append(string_buffer)
  310. end
  311. to_unicode_string_format (s: INTEGER): UNICODE_STRING
  312. local
  313. i: INTEGER
  314. do
  315. unicode_string_buffer.clear_count
  316. append_in_unicode(unicode_string_buffer)
  317. from
  318. create Result.make(unicode_string_buffer.count.max(s))
  319. i := s - unicode_string_buffer.count
  320. until
  321. i <= 0
  322. loop
  323. Result.extend(' '.code)
  324. i := i - 1
  325. end
  326. Result.append(unicode_string_buffer)
  327. end
  328. append_in_format (buffer: STRING; s: INTEGER)
  329. local
  330. i: INTEGER
  331. do
  332. string_buffer.clear_count
  333. append_in(string_buffer)
  334. from
  335. i := s - string_buffer.count
  336. until
  337. i <= 0
  338. loop
  339. buffer.extend(' ')
  340. i := i - 1
  341. end
  342. buffer.append(string_buffer)
  343. end
  344. append_in_unicode_format (buffer: UNICODE_STRING; s: INTEGER)
  345. local
  346. i: INTEGER
  347. do
  348. unicode_string_buffer.clear_count
  349. append_in_unicode(unicode_string_buffer)
  350. from
  351. i := s - unicode_string_buffer.count
  352. until
  353. i <= 0
  354. loop
  355. buffer.extend(' '.code)
  356. i := i - 1
  357. end
  358. buffer.append(unicode_string_buffer)
  359. end
  360. digit: CHARACTER
  361. do
  362. Result := decimal_digit
  363. end
  364. is_decimal_digit: BOOLEAN
  365. do
  366. Result := in_range(0, 9)
  367. end
  368. decimal_digit: CHARACTER
  369. deferred
  370. end
  371. is_hexadecimal_digit: BOOLEAN
  372. do
  373. Result := in_range(0, 15)
  374. end
  375. hexadecimal_digit: CHARACTER
  376. deferred
  377. end
  378. to_character: CHARACTER
  379. external "built_in"
  380. end
  381. to_octal_in (buffer: STRING)
  382. local
  383. index, timez: INTEGER; value: like Current
  384. do
  385. from
  386. value := Current
  387. timez := bit_count #// 3 + 1
  388. index := buffer.count + timez
  389. buffer.extend_multiple(' ', timez)
  390. until
  391. timez = 0
  392. loop
  393. buffer.put((value & 0x07).decimal_digit, index)
  394. index := index - 1
  395. value := value |>>> 3
  396. timez := timez - 1
  397. end
  398. end
  399. to_octal: STRING
  400. do
  401. string_buffer.clear_count
  402. to_octal_in(string_buffer)
  403. Result := string_buffer.twin
  404. end
  405. to_hexadecimal: STRING
  406. do
  407. string_buffer.clear_count
  408. to_hexadecimal_in(string_buffer)
  409. Result := string_buffer.twin
  410. end
  411. to_hexadecimal_in (buffer: STRING)
  412. local
  413. index, timez: INTEGER; value: like Current
  414. do
  415. from
  416. value := Current
  417. timez := object_size * 2
  418. index := buffer.count + timez
  419. buffer.extend_multiple(' ', timez)
  420. until
  421. timez = 0
  422. loop
  423. buffer.put((value & 0x0F).hexadecimal_digit, index)
  424. index := index - 1
  425. value := value |>> 4
  426. timez := timez - 1
  427. end
  428. end
  429. feature {ANY} -- Bitwise Logical Operators:
  430. bit_test (idx: INTEGER_8): BOOLEAN
  431. do
  432. Result := Current.bit_shift_right(idx) & 1 /= 0
  433. end
  434. bit_set (idx: INTEGER_8): like Current
  435. local
  436. mask: like Current
  437. do
  438. mask := 1
  439. Result := Current.bit_or(mask.bit_shift_left(idx))
  440. end
  441. bit_reset (idx: INTEGER_8): like Current
  442. local
  443. mask: like Current
  444. do
  445. mask := 1
  446. Result := Current.bit_and(mask.bit_shift_left(idx).bit_not)
  447. end
  448. infix "|>>", bit_shift_right (s: INTEGER_8): like Current
  449. -- Shift by `s' positions right (sign bit copied) bits falling off the end are lost.
  450. external "built_in"
  451. end
  452. infix "|>>>", bit_shift_right_unsigned (s: INTEGER_8): like Current
  453. -- Shift by `s' positions right (sign bit not copied) bits falling off the end are lost.
  454. external "built_in"
  455. end
  456. infix "|<<", bit_shift_left (s: INTEGER_8): like Current
  457. -- Shift by `s' positions left bits falling off the end are lost.
  458. external "built_in"
  459. end
  460. infix "#>>", bit_rotate_right (s: INTEGER_8): like Current
  461. external "built_in"
  462. end
  463. infix "#<<", bit_rotate_left (s: INTEGER_8): like Current
  464. external "built_in"
  465. end
  466. bit_rotate (s: INTEGER_8): like Current
  467. external "built_in"
  468. end
  469. prefix "~", bit_not: like Current
  470. external "built_in"
  471. end
  472. infix "&", bit_and (other: like Current): like Current
  473. external "built_in"
  474. end
  475. infix "|", bit_or (other: like Current): like Current
  476. external "built_in"
  477. end
  478. bit_xor (other: like Current): like Current
  479. external "built_in"
  480. end
  481. bit_shift (s: INTEGER_8): like Current
  482. do
  483. if s > 0 then
  484. Result := Current |>> s
  485. else
  486. Result := Current |<< -s
  487. end
  488. end
  489. bit_shift_unsigned (s: INTEGER_8): like Current
  490. do
  491. if s > 0 then
  492. Result := Current |>>> s
  493. else
  494. Result := Current |<< -s
  495. end
  496. end
  497. feature {ANY} -- Object Printing:
  498. out_in_tagged_out_memory, fill_tagged_out_memory
  499. do
  500. Current.append_in(tagged_out_memory)
  501. end
  502. feature {ANY} -- Miscellaneous:
  503. sign: INTEGER_8
  504. do
  505. if Current < 0 then
  506. Result := -1
  507. elseif Current > 0 then
  508. Result := 1
  509. end
  510. end
  511. divisible (other: like Current): BOOLEAN
  512. do
  513. Result := other /= zero
  514. end
  515. is_equal (other: like Current): BOOLEAN
  516. do
  517. Result := Current = other
  518. end
  519. is_a_power_of_2: BOOLEAN
  520. -- Is `Current' a power of 2?
  521. do
  522. Result := (Current - 1) & Current = 0
  523. end
  524. feature {ANY} -- Looping:
  525. times (repeat: PROCEDURE[TUPLE[like Current]])
  526. -- Repeats the procedure from 1 to Current. As for any Liberty Eiffel agent the open argument may be
  527. -- safely ignored. You may also build your agent with closed arguments.
  528. --
  529. -- See also `loop_to', `loop_from'
  530. require
  531. meaningful: Current >= zero
  532. local
  533. i: like Current
  534. do
  535. -- Note:
  536. -- should really be loop_from(1, repeat) but for the type of 1 (INTEGER_8) not being the type of Current
  537. from
  538. i := 1
  539. until
  540. i > Current
  541. loop
  542. repeat.call([i])
  543. i := i + 1
  544. end
  545. end
  546. loop_to (bound: like Current; repeat: PROCEDURE[TUPLE[like Current]])
  547. -- Repeats the procedure from Current to `bound'. As for any Liberty Eiffel agent the open argument may
  548. -- be safely ignored. You may also build your agent with closed arguments.
  549. --
  550. -- See also `times', `loop_from'
  551. --
  552. -- See also the simpler `loop_up_to', `loop_down_to'
  553. local
  554. i: like Current
  555. do
  556. if bound > Current then
  557. loop_up_to(bound, repeat)
  558. elseif bound < Current then
  559. loop_down_to(bound, repeat)
  560. else
  561. repeat.call([Current])
  562. end
  563. end
  564. loop_from (bound: like Current; repeat: PROCEDURE[TUPLE[like Current]])
  565. -- Repeats the procedure from `bound' to Current. As for any Liberty Eiffel agent the open argument may
  566. -- be safely ignored. You may also build your agent with closed arguments.
  567. --
  568. -- See also `times', `loop_to'
  569. require
  570. useful: bound /= Current
  571. do
  572. bound.loop_to(Current, repeat)
  573. end
  574. loop_up_to (bound: like Current; repeat: PROCEDURE[TUPLE[like Current]])
  575. -- Repeats the procedure from Current to a greater `bound'. As for any Liberty Eiffel agent the open
  576. -- argument may be safely ignored. You may also build your agent with closed arguments.
  577. --
  578. -- See also `loop_to', `loop_down_to'
  579. local
  580. i: like Current
  581. do
  582. from
  583. i := Current
  584. until
  585. i > bound
  586. loop
  587. repeat.call([i])
  588. i := i + 1
  589. end
  590. end
  591. loop_down_to (bound: like Current; repeat: PROCEDURE[TUPLE[like Current]])
  592. -- Repeats the procedure from Current to a lower `bound'. As for any Liberty Eiffel agent the open
  593. -- argument may be safely ignored. You may also build your agent with closed arguments.
  594. --
  595. -- See also `loop_to', `loop_down_to'
  596. local
  597. i: like Current
  598. do
  599. from
  600. i := Current
  601. until
  602. i < bound
  603. loop
  604. repeat.call([i])
  605. i := i - 1
  606. end
  607. end
  608. feature {ANY} -- Modular arithmetic (these wrap around on overflow)
  609. infix "#+" (other: like Current): like Current
  610. external "built_in"
  611. end
  612. prefix "#-": like Current
  613. external "built_in"
  614. end
  615. infix "#-" (other: like Current): like Current
  616. external "built_in"
  617. end
  618. infix "#*" (other: like Current): like Current
  619. external "built_in"
  620. end
  621. infix "#//" (other: like Current): like Current
  622. external "built_in"
  623. end
  624. infix "#\\" (other: like Current): like Current
  625. external "built_in"
  626. end
  627. feature {ANY} -- Size query
  628. bit_count: INTEGER_8
  629. -- The number of bits used to store the value of Current
  630. deferred
  631. end
  632. feature {}
  633. string_buffer: STRING
  634. once
  635. create Result.make(128)
  636. end
  637. unicode_string_buffer: UNICODE_STRING
  638. once
  639. create Result.make(128)
  640. end
  641. end -- class INTEGER_GENERAL
  642. --
  643. -- Copyright (C) 2009-2017: by all the people cited in the AUTHORS file.
  644. --
  645. -- Permission is hereby granted, free of charge, to any person obtaining a copy
  646. -- of this software and associated documentation files (the "Software"), to deal
  647. -- in the Software without restriction, including without limitation the rights
  648. -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  649. -- copies of the Software, and to permit persons to whom the Software is
  650. -- furnished to do so, subject to the following conditions:
  651. --
  652. -- The above copyright notice and this permission notice shall be included in
  653. -- all copies or substantial portions of the Software.
  654. --
  655. -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  656. -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  657. -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  658. -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  659. -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  660. -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  661. -- THE SOFTWARE.