floatnum.scm 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. ; Copyright (c) 1993-2008 by Richard Kelsey and Jonathan Rees. See file COPYING.
  2. ; Inexact rational arithmetic using hacked-in floating point numbers.
  3. (define floatnum? double?)
  4. (define-enumeration flop
  5. (fixnum->float
  6. string->float
  7. float->string
  8. exp log sin cos tan asin acos atan1 atan2 sqrt
  9. floor
  10. integer?
  11. float->fixnum
  12. quotient
  13. remainder))
  14. (define-syntax floperate
  15. (syntax-rules ()
  16. ((floperate ?which ?x)
  17. (vm-extension (+ ?which 100) ?x))
  18. ((floperate ?which ?x ?y)
  19. (vm-extension (+ ?which 100) (cons ?x ?y)))
  20. ((floperate ?which ?x ?y ?z)
  21. (vm-extension (+ ?which 100) (vector ?x ?y ?z)))))
  22. (define (float&float->float op)
  23. (lambda (a b)
  24. (let ((res (make-double)))
  25. (floperate op (x->float a) (x->float b) res)
  26. res)))
  27. (define (float&float->boolean op)
  28. (lambda (a b)
  29. (floperate op (x->float a) (x->float b))))
  30. (define (float1 op)
  31. (lambda (float)
  32. (floperate op float)))
  33. (define (float2 op)
  34. (lambda (a b)
  35. (floperate op a b)))
  36. (define (float->float op)
  37. (lambda (a)
  38. (let ((res (make-double)))
  39. (floperate op (x->float a) res)
  40. res)))
  41. (define (string->float string)
  42. (let ((res (make-double)))
  43. (or (floperate (enum flop string->float) string res)
  44. (error "not enough memory for STRING->FLOAT string buffer" string))))
  45. ; Call the VM to get a string
  46. (define (float->string float)
  47. (let* ((res (make-string 40 #\space))
  48. (len (floperate (enum flop float->string)
  49. float
  50. res)))
  51. (substring res 0 len)))
  52. ; Call back into the VM for a regular operation
  53. (define (extend-float&float->val op)
  54. (lambda (a b)
  55. (op (x->float a) (x->float b))))
  56. (define (x->float x)
  57. (cond ((double? x)
  58. x)
  59. ((integer? x)
  60. (exact-integer->float (if (exact? x)
  61. x
  62. (inexact->exact x))))
  63. ((rational? x)
  64. ;; This loses when num or den overflows flonum range
  65. ;; but x doesn't.
  66. (float/ (numerator x) (denominator x)))
  67. (else
  68. (error "cannot coerce to a float" x))))
  69. ; Conversion to/from exact integer
  70. (define (exact-integer->float k)
  71. (or (fixnum->float k)
  72. (float+ (float* (fixnum->float definitely-a-fixnum)
  73. (quotient k definitely-a-fixnum))
  74. (fixnum->float (remainder k definitely-a-fixnum)))))
  75. (define (fixnum->float k) ;Returns #f is k is a bignum
  76. (let ((res (make-double)))
  77. (if (floperate (enum flop fixnum->float) k res)
  78. res
  79. #f)))
  80. (define (float->exact-integer x)
  81. (or (float->fixnum x)
  82. (let ((d (fixnum->float definitely-a-fixnum)))
  83. (+ (* definitely-a-fixnum
  84. (float->exact-integer (float-quotient x d)))
  85. (float->fixnum (loophole :double ; outsmarted ourselves
  86. (float-remainder x d)))))))
  87. (define definitely-a-fixnum (expt 2 23)) ;Be conservative
  88. (define integral-floatnum? (float1 (enum flop integer?)))
  89. (define float->fixnum (float1 (enum flop float->fixnum)))
  90. (define float+ (extend-float&float->val +))
  91. (define float- (extend-float&float->val -))
  92. (define float* (extend-float&float->val *))
  93. (define float/ (extend-float&float->val /))
  94. (define float-quotient (float&float->float (enum flop quotient)))
  95. (define float-remainder (float&float->float (enum flop remainder)))
  96. (define float-atan1 (float->float (enum flop atan1)))
  97. (define float-atan2 (float&float->float (enum flop atan2)))
  98. (define float= (extend-float&float->val =))
  99. (define float< (extend-float&float->val <))
  100. (define float-exp (float->float (enum flop exp)))
  101. (define float-log (float->float (enum flop log)))
  102. (define float-sin (float->float (enum flop sin)))
  103. (define float-cos (float->float (enum flop cos)))
  104. (define float-tan (float->float (enum flop tan)))
  105. (define float-asin (float->float (enum flop asin)))
  106. (define float-acos (float->float (enum flop acos)))
  107. (define float-sqrt (float->float (enum flop sqrt)))
  108. (define float-floor (float->float (enum flop floor)))
  109. ; This lets you do ,open floatnum to get faster invocation
  110. ; (begin
  111. ; (define exp float-exp)
  112. ; (define log float-log)
  113. ; (define sin float-sin)
  114. ; (define cos float-cos)
  115. ; (define tan float-tan)
  116. ; (define asin float-asin)
  117. ; (define acos float-acos)
  118. ; (define (atan a . maybe-b)
  119. ; (cond ((null? maybe-b)
  120. ; (float-atan1 a))
  121. ; ((null? (cdr maybe-b))
  122. ; (float-atan2 a (car maybe-b)))
  123. ; (else
  124. ; (error "too many arguments to ATAN" (cons a maybe-b)))))
  125. ; (define sqrt float-sqrt))
  126. (define (float-fraction-length x)
  127. (let ((two (exact-integer->float 2)))
  128. (do ((x x (float* x two))
  129. (i 0 (+ i 1)))
  130. ((integral-floatnum? x) i)
  131. (if (> i 3000) (error "I'm bored." x)))))
  132. (define (float-denominator x)
  133. (expt (exact-integer->float 2) (float-fraction-length x)))
  134. (define (float-numerator x)
  135. (float* x (float-denominator x)))
  136. (define float-precision
  137. (delay
  138. (do ((n 0 (+ n 1))
  139. (x (fixnum->float 1) (/ x 2)))
  140. ((= (fixnum->float 1) (+ (fixnum->float 1) x)) n))))
  141. (define infinity (delay (expt (exact->inexact 2) (exact->inexact 1500))))
  142. (define (float->exact x)
  143. (define (lose)
  144. (call-error "no exact representation"
  145. inexact->exact x))
  146. (cond
  147. ((integral-floatnum? x)
  148. (float->exact-integer x)) ;+++
  149. ((or (not (= x x)) ; NaN
  150. (= x (force infinity))
  151. (= (- x) (force infinity)))
  152. (lose))
  153. (else
  154. (let ((deliver
  155. (lambda (y d)
  156. (let ((q (expt 2 (float-fraction-length y))))
  157. (if (exact? q)
  158. (let ((e (/ (/ (float->exact-integer
  159. (float* y (exact-integer->float q)))
  160. q)
  161. d)))
  162. (if (exact? e)
  163. e
  164. (lose)))
  165. (lose))))))
  166. (if (and (< x (fixnum->float 1)) ; watch out for denormalized numbers
  167. (> x (fixnum->float -1)))
  168. (deliver (* x (expt (fixnum->float 2) (force float-precision)))
  169. (expt 2 (force float-precision)))
  170. (deliver x 1))))))
  171. ; Methods on floatnums
  172. (define-method &integer? ((x :double))
  173. (integral-floatnum? x))
  174. (define-method &rational? ((n :double)) #t)
  175. (define-method &exact? ((x :double)) #f)
  176. (define-method &inexact->exact ((x :double))
  177. (float->exact x))
  178. (define-method &exact->inexact ((x :rational))
  179. (x->float x)) ;Should do this only if the number is within range.
  180. (define-method &floor ((x :double)) (float-floor x))
  181. ; beware infinite regress
  182. (define-method &numerator ((x :double)) (float-numerator x))
  183. (define-method &denominator ((x :double)) (float-denominator x))
  184. (define (define-floatnum-method mtable proc)
  185. (define-method mtable ((m :rational) (n :rational)) (proc m n)))
  186. ;; the numerical tower sucks
  187. (define (define-floatnum-comparison mtable proc float-proc)
  188. (define-method mtable ((m :double) (n :double)) (float-proc m n))
  189. (define-method mtable ((m :double) (n :rational))
  190. (proc (float->exact m) n))
  191. (define-method mtable ((m :rational) (n :double))
  192. (proc m (float->exact n))))
  193. (define-floatnum-method &+ float+)
  194. (define-floatnum-method &- float-)
  195. (define-floatnum-method &* float*)
  196. (define-floatnum-method &/ float/)
  197. (define-floatnum-method &quotient float-quotient)
  198. (define-floatnum-method &remainder float-remainder)
  199. (define-floatnum-comparison &= = float=)
  200. (define-floatnum-comparison &< < float<)
  201. (define-floatnum-method &atan2 float-atan2)
  202. (define-method &exp ((x :rational)) (float-exp x))
  203. (define-method &log ((x :rational))
  204. (cond
  205. ((> x (exact->inexact 0)) ; avoid calling inexact->exact on X
  206. (float-log x))
  207. ((= x (exact->inexact 0))
  208. (if (exact? x)
  209. (call-error "log of exact 0 is undefined" log x)
  210. (float-log x)))
  211. (else
  212. (next-method))))
  213. (define-method &sqrt ((x :rational))
  214. (if (>= x (exact->inexact 0))
  215. (float-sqrt x)
  216. (next-method)))
  217. (define-method &sin ((x :rational)) (float-sin x))
  218. (define-method &cos ((x :rational)) (float-cos x))
  219. (define-method &tan ((x :rational)) (float-tan x))
  220. (define-method &acos ((x :rational)) (float-acos x))
  221. (define-method &asin ((x :rational)) (float-asin x))
  222. (define-method &atan1 ((x :rational)) (float-atan1 x))
  223. (define-method &number->string ((n :double) radix)
  224. (cond
  225. ((= radix 10)
  226. (float->string n))
  227. ((zero? n)
  228. (string-copy "#i0"))
  229. (else
  230. (let* ((p (abs (inexact->exact (numerator n))))
  231. (q (inexact->exact (denominator n))))
  232. (string-append "#i"
  233. (if (negative? n) "-" "")
  234. (number->string p radix)
  235. (if (not (= q 1))
  236. (string-append "/"
  237. (number->string q radix))
  238. ""))))))
  239. ; Recognizing a floating point number. This doesn't know about `#'.
  240. (define (float-string? s)
  241. (let ((len (string-length s)))
  242. (define (start)
  243. (and (< 1 len)
  244. (let ((first (string-ref s 0))
  245. (second (string-ref s 1)))
  246. (if (char-numeric? first)
  247. (digits 1 #f #f)
  248. (case first
  249. ((#\+ #\-)
  250. (and (char-numeric? second)
  251. (digits 2 #f #f)))
  252. ((#\.)
  253. (and (char-numeric? second)
  254. (digits 2 #t #f)))
  255. (else #f))))))
  256. ; Read digits until the end or an `e' or a `.'. E-OR-DOT? is true if
  257. ; we have seen either, E? is true if we've seen an `e'.
  258. (define (digits i e-or-dot? e?)
  259. (if (= i len)
  260. e-or-dot?
  261. (let ((next (string-ref s i)))
  262. (if (char-numeric? next)
  263. (digits (+ i 1) e-or-dot? e?)
  264. (case next
  265. ((#\e #\E)
  266. (and (not e?)
  267. (exponent (+ i 1) #f)))
  268. ((#\.)
  269. (and (not e-or-dot?)
  270. (digits (+ i 1) #t #f)))
  271. (else #f))))))
  272. ; Read in an exponent. If SIGN? is true then we have already got the sign.
  273. (define (exponent i sign?)
  274. (and (< i len)
  275. (let ((next (string-ref s i)))
  276. (if (char-numeric? next)
  277. (digits (+ i 1) #t #t)
  278. (case next
  279. ((#\+ #\-)
  280. (and (not sign?)
  281. (exponent (+ i 1) #t)))
  282. (else #f))))))
  283. (start)))
  284. (define-simple-type :float-string (:string) float-string?)
  285. (define-method &really-string->number ((s :float-string) radix exact?)
  286. (if (and (= radix 10)
  287. (not exact?))
  288. (string->float s)
  289. (next-method)))