floatnum.scm 11 KB

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