calc-frac.el 6.7 KB

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