floatnum.scm 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  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. (implementation-restriction-violation
  45. 'string->float
  46. "not enough memory for STRING->FLOAT string buffer" string))))
  47. ; Call the VM to get a string
  48. (define (float->string float)
  49. (let* ((res (make-string 40 #\space))
  50. (len (floperate (enum flop float->string)
  51. float
  52. res)))
  53. (substring res 0 len)))
  54. ; Call back into the VM for a regular operation
  55. (define (extend-float&float->val op)
  56. (lambda (a b)
  57. (op (x->float a) (x->float b))))
  58. (define (x->float x)
  59. (cond ((double? x)
  60. x)
  61. ((integer? x)
  62. (exact-integer->float (if (exact? x)
  63. x
  64. (inexact->exact x))))
  65. ((rational? x)
  66. ;; This loses when num or den overflows flonum range
  67. ;; but x doesn't.
  68. (float/ (numerator x) (denominator x)))
  69. (else
  70. (assertion-violation 'x->float "cannot coerce to a float" x))))
  71. ; Conversion to/from exact integer
  72. (define (exact-integer->float k)
  73. (or (fixnum->float k)
  74. (float+ (float* (fixnum->float definitely-a-fixnum)
  75. (quotient k definitely-a-fixnum))
  76. (fixnum->float (remainder k definitely-a-fixnum)))))
  77. (define (fixnum->float k) ;Returns #f is k is a bignum
  78. (let ((res (make-double)))
  79. (if (floperate (enum flop fixnum->float) k res)
  80. res
  81. #f)))
  82. (define (float->exact-integer x)
  83. (or (float->fixnum x)
  84. (let ((d (fixnum->float definitely-a-fixnum)))
  85. (+ (* definitely-a-fixnum
  86. (float->exact-integer (float-quotient x d)))
  87. (float->fixnum (float-remainder x d))))))
  88. (define definitely-a-fixnum (expt 2 23)) ;Be conservative
  89. (define integral-floatnum? (float1 (enum flop integer?)))
  90. (define float->fixnum (float1 (enum flop float->fixnum)))
  91. (define float+ (extend-float&float->val +))
  92. (define float- (extend-float&float->val -))
  93. (define float* (extend-float&float->val *))
  94. (define float/ (extend-float&float->val /))
  95. (define float-quotient (float&float->float (enum flop quotient)))
  96. (define float-remainder (float&float->float (enum flop remainder)))
  97. (define float-atan1 (float->float (enum flop atan1)))
  98. (define float-atan2 (float&float->float (enum flop atan2)))
  99. (define float= (extend-float&float->val =))
  100. (define float< (extend-float&float->val <))
  101. (define float-exp (float->float (enum flop exp)))
  102. (define float-log (float->float (enum flop log)))
  103. (define float-sin (float->float (enum flop sin)))
  104. (define float-cos (float->float (enum flop cos)))
  105. (define float-tan (float->float (enum flop tan)))
  106. (define float-asin (float->float (enum flop asin)))
  107. (define float-acos (float->float (enum flop acos)))
  108. (define float-sqrt (float->float (enum flop sqrt)))
  109. (define float-floor (float->float (enum flop floor)))
  110. ; This lets you do ,open floatnum to get faster invocation
  111. ; (begin
  112. ; (define exp float-exp)
  113. ; (define log float-log)
  114. ; (define sin float-sin)
  115. ; (define cos float-cos)
  116. ; (define tan float-tan)
  117. ; (define asin float-asin)
  118. ; (define acos float-acos)
  119. ; (define (atan a . maybe-b)
  120. ; (cond ((null? maybe-b)
  121. ; (float-atan1 a))
  122. ; ((null? (cdr maybe-b))
  123. ; (float-atan2 a (car maybe-b)))
  124. ; (else
  125. ; (apply assertion-violation 'atan "too many arguments to ATAN" a maybe-b))))
  126. ; (define sqrt float-sqrt))
  127. (define (float-fraction-length x)
  128. (let ((two (exact-integer->float 2)))
  129. (do ((x x (float* x two))
  130. (i 0 (+ i 1)))
  131. ((integral-floatnum? x) i)
  132. (if (> i 3000) (assertion-violation 'float-fraction-length "I'm bored." x)))))
  133. (define (float-denominator x)
  134. (expt (exact-integer->float 2) (float-fraction-length x)))
  135. (define (float-numerator x)
  136. (float* x (float-denominator x)))
  137. (define float-precision
  138. (delay
  139. (do ((n 0 (+ n 1))
  140. (x (fixnum->float 1) (/ x 2)))
  141. ((= (fixnum->float 1) (+ (fixnum->float 1) x)) n))))
  142. (define infinity (delay (expt (exact->inexact 2) (exact->inexact 1500))))
  143. (define (nan? x)
  144. (not (= x x)))
  145. (define (float->exact x)
  146. (define (lose)
  147. (implementation-restriction-violation 'inexact->exact
  148. "no exact representation"
  149. x))
  150. (cond
  151. ((integral-floatnum? x)
  152. (float->exact-integer x)) ;+++
  153. ((not (rational? x))
  154. (lose))
  155. (else
  156. (let ((deliver
  157. (lambda (y d)
  158. (let ((q (expt 2 (float-fraction-length y))))
  159. (if (exact? q)
  160. (let ((e (/ (/ (float->exact-integer
  161. (float* y (exact-integer->float q)))
  162. q)
  163. d)))
  164. (if (exact? e)
  165. e
  166. (lose)))
  167. (lose))))))
  168. (if (and (< x (fixnum->float 1)) ; watch out for denormalized numbers
  169. (> x (fixnum->float -1)))
  170. (deliver (* x (expt (fixnum->float 2) (force float-precision)))
  171. (expt 2 (force float-precision)))
  172. (deliver x 1))))))
  173. ; Methods on floatnums
  174. (define-method &integer? ((x <double>))
  175. (integral-floatnum? x))
  176. (define-method &rational? ((n <double>))
  177. (and (not (nan? n))
  178. (not (= (force infinity) n))
  179. (not (= (- (force infinity)) n))))
  180. (define-method &exact? ((x <double>)) #f)
  181. (define-method &inexact->exact ((x <double>))
  182. (float->exact x))
  183. (define-method &exact->inexact ((x <rational>))
  184. (x->float x)) ;Should do this only if the number is within range.
  185. (define-method &floor ((x <double>)) (float-floor x))
  186. ; beware infinite regress
  187. (define-method &numerator ((x <double>)) (float-numerator x))
  188. (define-method &denominator ((x <double>)) (float-denominator x))
  189. (define (define-floatnum-method mtable proc)
  190. (define-method mtable ((m <rational>) (n <rational>)) (proc m n))
  191. ;; the horror
  192. (define-method mtable ((m <double>) (n <rational>)) (proc m n))
  193. (define-method mtable ((m <rational>) (n <double>)) (proc m n))
  194. (define-method mtable ((m <double>) (n <double>)) (proc m n)))
  195. ;; the numerical tower sucks
  196. (define (define-floatnum-comparison mtable proc float-proc)
  197. (define-method mtable ((m <double>) (n <double>)) (float-proc m n))
  198. (define-method mtable ((m <double>) (n <rational>))
  199. (cond
  200. ((nan? m) #f) ; #### not always correct, when < is used to implement >
  201. ((= m (force infinity)) #f)
  202. ((= m (- (force infinity))) #t)
  203. (proc (float->exact m) n))
  204. (define-method mtable ((m <rational>) (n <double>))
  205. (proc m (float->exact n)))))
  206. ; the numerical tower sucks big-time
  207. (define-method &= ((m <double>) (n <double>)) (float= m n))
  208. (define-method &= ((m <double>) (n <rational>))
  209. (and (rational? m)
  210. (float= (float->exact m) n)))
  211. (define-method &= ((m <rational>) (n <double>))
  212. (and (rational? n)
  213. (float= m (float->exact n))))
  214. (define-method &< ((m <double>) (n <double>)) (float< m n))
  215. (define-method &< ((m <double>) (n <rational>))
  216. (cond ((nan? m) #f)
  217. ((= (force infinity) m) #f)
  218. ((= (- (force infinity)) m) #t)
  219. (else
  220. (float< (float->exact m) n))))
  221. (define-method &< ((m <rational>) (n <double>))
  222. (cond ((nan? n) #f) ; #### not correct when < is used to implement >
  223. ((= (force infinity) n) #t)
  224. ((= (- (force infinity)) n) #f)
  225. (else
  226. (float< m (float->exact n)))))
  227. (define-floatnum-method &+ float+)
  228. (define-floatnum-method &- float-)
  229. (define-floatnum-method &* float*)
  230. (define-floatnum-method &/ float/)
  231. (define-floatnum-method &quotient float-quotient)
  232. (define-floatnum-method &remainder float-remainder)
  233. (define-floatnum-method &atan2 float-atan2)
  234. (define-method &exp ((x <rational>)) (float-exp x))
  235. (define-method &log ((x <rational>))
  236. (cond
  237. ((> x (exact->inexact 0)) ; avoid calling inexact->exact on X
  238. (float-log x))
  239. ((= x (exact->inexact 0))
  240. (if (exact? x)
  241. (assertion-violation 'log "log of exact 0 is undefined" x)
  242. (float-log x)))
  243. (else
  244. (next-method))))
  245. (define-method &sqrt ((x <rational>))
  246. (if (>= x (exact->inexact 0))
  247. (float-sqrt x)
  248. (next-method)))
  249. (define-method &sin ((x <rational>)) (float-sin x))
  250. (define-method &cos ((x <rational>)) (float-cos x))
  251. (define-method &tan ((x <rational>)) (float-tan x))
  252. (define-method &acos ((x <rational>)) (float-acos x))
  253. (define-method &asin ((x <rational>)) (float-asin x))
  254. (define-method &atan1 ((x <rational>)) (float-atan1 x))
  255. (define-method &number->string ((n <double>) radix)
  256. (cond
  257. ((= radix 10)
  258. (float->string n))
  259. ((zero? n)
  260. (string-copy "#i0"))
  261. ((not (= n n))
  262. (string-copy "+nan.0"))
  263. ;; awkward, so we don't get IEEE representations into the image
  264. ((= n (/ 1 (exact->inexact 0)))
  265. (string-copy "+inf.0"))
  266. ((= n (/ -1 (exact->inexact 0)))
  267. (string-copy "-inf.0"))
  268. (else
  269. (let* ((p (abs (inexact->exact (numerator n))))
  270. (q (inexact->exact (denominator n))))
  271. (string-append "#i"
  272. (if (negative? n) "-" "")
  273. (number->string p radix)
  274. (if (not (= q 1))
  275. (string-append "/"
  276. (number->string q radix))
  277. ""))))))
  278. ; Recognizing a floating point number. This doesn't know about `#'.
  279. (define (float-string? s)
  280. (let ((len (string-length s)))
  281. (define (start)
  282. (and (< 1 len)
  283. (let ((first (string-ref s 0))
  284. (second (string-ref s 1)))
  285. (if (char-numeric? first)
  286. (digits 1 #f #f)
  287. (case first
  288. ((#\+ #\-)
  289. (or (and (char-numeric? second)
  290. (digits 2 #f #f))
  291. (string=? s "+nan.0")
  292. (string=? s "-nan.0")
  293. (string=? s "+inf.0")
  294. (string=? s "-inf.0")))
  295. ((#\.)
  296. (and (char-numeric? second)
  297. (digits 2 #t #f)))
  298. (else #f))))))
  299. ; Read digits until the end or an `e' or a `.'. E-OR-DOT? is true if
  300. ; we have seen either, E? is true if we've seen an `e'.
  301. (define (digits i e-or-dot? e?)
  302. (if (= i len)
  303. e-or-dot?
  304. (let ((next (string-ref s i)))
  305. (if (char-numeric? next)
  306. (digits (+ i 1) e-or-dot? e?)
  307. (case next
  308. ((#\e #\E)
  309. (and (not e?)
  310. (exponent (+ i 1) #f)))
  311. ((#\.)
  312. (and (not e-or-dot?)
  313. (digits (+ i 1) #t #f)))
  314. (else #f))))))
  315. ; Read in an exponent. If SIGN? is true then we have already got the sign.
  316. (define (exponent i sign?)
  317. (and (< i len)
  318. (let ((next (string-ref s i)))
  319. (if (char-numeric? next)
  320. (digits (+ i 1) #t #t)
  321. (case next
  322. ((#\+ #\-)
  323. (and (not sign?)
  324. (exponent (+ i 1) #t)))
  325. (else #f))))))
  326. (start)))
  327. (define-simple-type <float-string> (<string>) float-string?)
  328. (define-method &really-string->number ((s <float-string>) radix exact?)
  329. (if (and (= radix 10)
  330. (not exact?))
  331. (string->float s)
  332. (next-method)))