calc-frac.el 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. ;;; calc-frac.el --- fraction functions for Calc
  2. ;; Copyright (C) 1990-1993, 2001-2017 Free Software Foundation, Inc.
  3. ;; Author: David Gillespie <daveg@synaptics.com>
  4. ;; This file is part of GNU Emacs.
  5. ;; GNU Emacs is free software: you can redistribute it and/or modify
  6. ;; it under the terms of the GNU General Public License as published by
  7. ;; the Free Software Foundation, either version 3 of the License, or
  8. ;; (at your option) any later version.
  9. ;; GNU Emacs is distributed in the hope that it will be useful,
  10. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. ;; GNU General Public License for more details.
  13. ;; You should have received a copy of the GNU General Public License
  14. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  15. ;;; Commentary:
  16. ;;; Code:
  17. ;; This file is autoloaded from calc-ext.el.
  18. (require 'calc-ext)
  19. (require 'calc-macs)
  20. (defun calc-fdiv (arg)
  21. (interactive "P")
  22. (calc-slow-wrapper
  23. (calc-binary-op ":" 'calcFunc-fdiv arg 1)))
  24. (defun calc-fraction (arg)
  25. (interactive "P")
  26. (calc-slow-wrapper
  27. (let ((func (if (calc-is-hyperbolic) 'calcFunc-frac 'calcFunc-pfrac)))
  28. (if (eq arg 0)
  29. (calc-enter-result 2 "frac" (list func
  30. (calc-top-n 2)
  31. (calc-top-n 1)))
  32. (calc-enter-result 1 "frac" (list func
  33. (calc-top-n 1)
  34. (prefix-numeric-value (or arg 0))))))))
  35. (defun calc-over-notation (fmt)
  36. (interactive "sFraction separator: ")
  37. (calc-wrapper
  38. (if (string-match "\\`\\([^ 0-9][^ 0-9]?\\)[0-9]*\\'" fmt)
  39. (let ((n nil))
  40. (if (/= (match-end 0) (match-end 1))
  41. (setq n (string-to-number (substring fmt (match-end 1)))
  42. fmt (math-match-substring fmt 1)))
  43. (if (eq n 0) (error "Bad denominator"))
  44. (calc-change-mode 'calc-frac-format (list fmt n) t))
  45. (error "Bad fraction separator format"))))
  46. (defun calc-slash-notation (n)
  47. (interactive "P")
  48. (calc-wrapper
  49. (calc-change-mode 'calc-frac-format (if n '("//" nil) '("/" nil)) t)))
  50. (defun calc-frac-mode (n)
  51. (interactive "P")
  52. (calc-wrapper
  53. (calc-change-mode 'calc-prefer-frac n nil t)
  54. (message (if calc-prefer-frac
  55. "Integer division will now generate fractions"
  56. "Integer division will now generate floating-point results"))))
  57. ;;;; Fractions.
  58. ;;; Build a normalized fraction. [R I I]
  59. ;;; (This could probably be implemented more efficiently than using
  60. ;;; the plain gcd algorithm.)
  61. (defun math-make-frac (num den)
  62. (if (Math-integer-negp den)
  63. (setq num (math-neg num)
  64. den (math-neg den)))
  65. (let ((gcd (math-gcd num den)))
  66. (if (eq gcd 1)
  67. (if (eq den 1)
  68. num
  69. (list 'frac num den))
  70. (if (equal gcd den)
  71. (math-quotient num gcd)
  72. (list 'frac (math-quotient num gcd) (math-quotient den gcd))))))
  73. (defun calc-add-fractions (a b)
  74. (if (eq (car-safe a) 'frac)
  75. (if (eq (car-safe b) 'frac)
  76. (math-make-frac (math-add (math-mul (nth 1 a) (nth 2 b))
  77. (math-mul (nth 2 a) (nth 1 b)))
  78. (math-mul (nth 2 a) (nth 2 b)))
  79. (math-make-frac (math-add (nth 1 a)
  80. (math-mul (nth 2 a) b))
  81. (nth 2 a)))
  82. (math-make-frac (math-add (math-mul a (nth 2 b))
  83. (nth 1 b))
  84. (nth 2 b))))
  85. (defun calc-mul-fractions (a b)
  86. (if (eq (car-safe a) 'frac)
  87. (if (eq (car-safe b) 'frac)
  88. (math-make-frac (math-mul (nth 1 a) (nth 1 b))
  89. (math-mul (nth 2 a) (nth 2 b)))
  90. (math-make-frac (math-mul (nth 1 a) b)
  91. (nth 2 a)))
  92. (math-make-frac (math-mul a (nth 1 b))
  93. (nth 2 b))))
  94. (defun calc-div-fractions (a b)
  95. (if (eq (car-safe a) 'frac)
  96. (if (eq (car-safe b) 'frac)
  97. (math-make-frac (math-mul (nth 1 a) (nth 2 b))
  98. (math-mul (nth 2 a) (nth 1 b)))
  99. (math-make-frac (nth 1 a)
  100. (math-mul (nth 2 a) b)))
  101. (math-make-frac (math-mul a (nth 2 b))
  102. (nth 1 b))))
  103. ;;; Convert a real value to fractional form. [T R I; T R F] [Public]
  104. (defun calcFunc-frac (a &optional tol)
  105. (or tol (setq tol 0))
  106. (cond ((Math-ratp a)
  107. a)
  108. ((memq (car a) '(cplx polar vec hms date sdev intv mod))
  109. (cons (car a) (mapcar (function
  110. (lambda (x)
  111. (calcFunc-frac x tol)))
  112. (cdr a))))
  113. ((Math-messy-integerp a)
  114. (math-trunc a))
  115. ((Math-negp a)
  116. (math-neg (calcFunc-frac (math-neg a) tol)))
  117. ((not (eq (car a) 'float))
  118. (if (math-infinitep a)
  119. a
  120. (if (math-provably-integerp a)
  121. a
  122. (math-reject-arg a 'numberp))))
  123. ((integerp tol)
  124. (if (<= tol 0)
  125. (setq tol (+ tol calc-internal-prec)))
  126. (calcFunc-frac a (list 'float 5
  127. (- (+ (math-numdigs (nth 1 a))
  128. (nth 2 a))
  129. (1+ tol)))))
  130. ((not (eq (car tol) 'float))
  131. (if (Math-realp tol)
  132. (calcFunc-frac a (math-float tol))
  133. (math-reject-arg tol 'realp)))
  134. ((Math-negp tol)
  135. (calcFunc-frac a (math-neg tol)))
  136. ((Math-zerop tol)
  137. (calcFunc-frac a 0))
  138. ((not (math-lessp-float tol '(float 1 0)))
  139. (math-trunc a))
  140. ((Math-zerop a)
  141. 0)
  142. (t
  143. (let ((cfrac (math-continued-fraction a tol))
  144. (calc-prefer-frac t))
  145. (math-eval-continued-fraction cfrac)))))
  146. (defun math-continued-fraction (a tol)
  147. (let ((calc-internal-prec (+ calc-internal-prec 2)))
  148. (let ((cfrac nil)
  149. (aa a)
  150. (calc-prefer-frac nil)
  151. int)
  152. (while (or (null cfrac)
  153. (and (not (Math-zerop aa))
  154. (not (math-lessp-float
  155. (math-abs
  156. (math-sub a
  157. (let ((f (math-eval-continued-fraction
  158. cfrac)))
  159. (math-working "Fractionalize" f)
  160. f)))
  161. tol))))
  162. (setq int (math-trunc aa)
  163. aa (math-sub aa int)
  164. cfrac (cons int cfrac))
  165. (or (Math-zerop aa)
  166. (setq aa (math-div 1 aa))))
  167. cfrac)))
  168. (defun math-eval-continued-fraction (cf)
  169. (let ((n (car cf))
  170. (d 1)
  171. temp)
  172. (while (setq cf (cdr cf))
  173. (setq temp (math-add (math-mul (car cf) n) d)
  174. d n
  175. n temp))
  176. (math-div n d)))
  177. (defun calcFunc-fdiv (a b) ; [R I I] [Public]
  178. (cond
  179. ((Math-num-integerp a)
  180. (cond
  181. ((Math-num-integerp b)
  182. (if (Math-zerop b)
  183. (math-reject-arg a "*Division by zero")
  184. (math-make-frac (math-trunc a) (math-trunc b))))
  185. ((eq (car-safe b) 'frac)
  186. (if (Math-zerop (nth 1 b))
  187. (math-reject-arg a "*Division by zero")
  188. (math-make-frac (math-mul (math-trunc a) (nth 2 b)) (nth 1 b))))
  189. (t (math-reject-arg b 'integerp))))
  190. ((eq (car-safe a) 'frac)
  191. (cond
  192. ((Math-num-integerp b)
  193. (if (Math-zerop b)
  194. (math-reject-arg a "*Division by zero")
  195. (math-make-frac (cadr a) (math-mul (nth 2 a) (math-trunc b)))))
  196. ((eq (car-safe b) 'frac)
  197. (if (Math-zerop (nth 1 b))
  198. (math-reject-arg a "*Division by zero")
  199. (math-make-frac (math-mul (nth 1 a) (nth 2 b)) (math-mul (nth 2 a) (nth 1 b)))))
  200. (t (math-reject-arg b 'integerp))))
  201. (t
  202. (math-reject-arg a 'integerp))))
  203. (provide 'calc-frac)
  204. ;;; calc-frac.el ends here