/collects/racket/math.rkt

https://bitbucket.org/agocke/racket · Racket · 181 lines · 141 code · 26 blank · 14 comment · 50 complexity · 19fb72b4efe952b5a202be247d8fe070 MD5 · raw file

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;
  3. ;; math.rkt: some extra math routines
  4. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  5. #lang racket/base
  6. (require "unsafe/ops.rkt"
  7. "performance-hint.rkt")
  8. (provide pi pi.f
  9. nan? infinite?
  10. sqr
  11. sgn conjugate
  12. sinh cosh tanh
  13. degrees->radians radians->degrees
  14. exact-round exact-floor exact-ceiling exact-truncate
  15. order-of-magnitude)
  16. (define pi (atan 0 -1))
  17. (define pi.f (atan 0.0f0 -1.0f0))
  18. (begin-encourage-inline
  19. ;; real predicates
  20. (define (nan? x)
  21. (unless (real? x) (raise-argument-error 'nan? "real?" x))
  22. (or (eqv? x +nan.0) (eqv? x +nan.f)))
  23. (define (infinite? x)
  24. (unless (real? x) (raise-argument-error 'infinite? "real?" x))
  25. (or (= x +inf.0) (= x -inf.0)))
  26. ;; z^2
  27. (define (sqr z)
  28. (unless (number? z) (raise-argument-error 'sqr "number?" z))
  29. (* z z))
  30. ;; sgn function
  31. (define (sgn x)
  32. (unless (real? x) (raise-argument-error 'sgn "real?" x))
  33. (cond [(= 0 x) x] ; preserve 0, 0.0 and 0.0f0
  34. [(double-flonum? x) (cond [(unsafe-fl> x 0.0) 1.0]
  35. [(unsafe-fl< x 0.0) -1.0]
  36. [else +nan.0])]
  37. [(single-flonum? x) (cond [(> x 0.0f0) 1.0f0]
  38. [(< x 0.0f0) -1.0f0]
  39. [else +nan.f])]
  40. [else (if (> x 0) 1 -1)]))
  41. ;; complex conjugate
  42. (define (conjugate z)
  43. (unless (number? z) (raise-argument-error 'conjugate "number?" z))
  44. (make-rectangular (real-part z) (- (imag-part z))))
  45. ;; complex hyperbolic functions
  46. (define (sinh z)
  47. (unless (number? z) (raise-argument-error 'sinh "number?" z))
  48. (cond [(= z 0) z] ; preserve 0, 0.0, -0.0, 0.0f0, 0.0+0.0i, etc.
  49. [(real? z)
  50. (let loop ([z z])
  51. (cond [(z . < . 0) (- (loop (- z)))]
  52. [else (/ (- (exp z) (exp (- z))) 2)]))]
  53. [else (/ (- (exp z) (exp (- z))) 2)]))
  54. (define (cosh z)
  55. (unless (number? z) (raise-argument-error 'cosh "number?" z))
  56. (cond [(and (real? z) (= z 0)) (if (single-flonum? z) 1.0f0 1.0)]
  57. [else (/ (+ (exp z) (exp (- z))) 2)]))
  58. (define (tanh z)
  59. (unless (number? z) (raise-argument-error 'tanh "number?" z))
  60. (cond [(= z 0) z] ; preserve 0, 0.0, -0.0, 0.0f0, 0.0+0.0i, etc.
  61. [(real? z)
  62. (let loop ([z z])
  63. (cond [(z . < . 0) (- (loop (- z)))]
  64. [(z . < . 20) (define exp2z (exp (* 2 z)))
  65. (/ (- exp2z 1) (+ exp2z 1))]
  66. [(z . >= . 20) (if (single-flonum? z) 1.0f0 1.0)]
  67. [else z]))] ; +nan.0 or +nan.f
  68. [else
  69. (define exp2z (exp (* 2 z)))
  70. (/ (- exp2z 1) (+ exp2z 1))]))
  71. ;; angle conversion
  72. (define (degrees->radians x)
  73. (unless (real? x) (raise-argument-error 'degrees->radians "real?" x))
  74. (cond [(single-flonum? x) (* x (/ pi.f 180f0))]
  75. [else (* x (/ pi 180.0))]))
  76. (define (radians->degrees x)
  77. (unless (real? x) (raise-argument-error 'radians->degrees "real?" x))
  78. (cond [(single-flonum? x) (* x (/ 180f0 pi.f))]
  79. [else (* x (/ 180.0 pi))]))
  80. ;; inexact->exact composed with round, floor, ceiling, truncate
  81. (define-syntax-rule (define-integer-conversion name convert)
  82. (define (name x)
  83. (unless (rational? x) (raise-argument-error 'name "rational?" x))
  84. (inexact->exact (convert x))))
  85. (define-integer-conversion exact-round round)
  86. (define-integer-conversion exact-floor floor)
  87. (define-integer-conversion exact-ceiling ceiling)
  88. (define-integer-conversion exact-truncate truncate)
  89. )
  90. (define order-of-magnitude
  91. (let* ([exact-log (Îť (x) (inexact->exact (log x)))]
  92. [inverse-exact-log10 (/ (exact-log 10))])
  93. (Îť (r)
  94. (unless (and (real? r) (positive? r) (not (= r +inf.0)))
  95. (raise-argument-error 'order-of-magnitude "(and/c (>/c 0.0) (not/c +inf.0))" r))
  96. (define q (inexact->exact r))
  97. (define m
  98. (floor (* (- (exact-log (numerator q)) (exact-log (denominator q)))
  99. inverse-exact-log10)))
  100. (let loop ([m m] [p (expt 10 m)])
  101. (if (< q p)
  102. (loop (sub1 m) (* p 1/10))
  103. (let ([u (* p 10)])
  104. (if (>= q u) (loop (add1 m) u) m)))))))
  105. #|
  106. ;; Timing tests below provided by Jos Koot for the order-of-magnitude function
  107. #lang racket
  108. ;;; Tests and timings of order-of-magnitude
  109. (require "order-of-magnitude.rkt")
  110. (require (planet joskoot/planet-fmt:1:1/fmt))
  111. (define-syntax timer
  112. (syntax-rules ()
  113. ((_ type iter k expr)
  114. (let* ([output-string (open-output-string)]
  115. [result expr]
  116. [dummy (parameterize ([current-output-port output-string])
  117. (time (for ([k (in-range iter)]) expr)))]
  118. [input-string (open-input-string (get-output-string output-string))])
  119. (parameterize ([current-input-port input-string])
  120. (let ([cpu (begin (read) (read) (read))]
  121. [real (begin (read) (read) (read))]
  122. [gc (begin (read) (read) (read))]
  123. [micro (/ iter 1000)])
  124. (if (and (>= cpu 0) (>= real 0) (>= gc 0))
  125. ((fmt
  126. "'test type : ' d/
  127. 'exponent : ' i6/
  128. 'n-obs : ' i6/
  129. 'mean cpu : ' i6 x 'microseconds'/
  130. 'mean real : ' i6 x 'microseconds'/
  131. 'mean gc : ' i6 x 'microseconds'/
  132. 'real - gc : ' i6 x 'microseconds'//" 'current)
  133. type
  134. k
  135. iter
  136. (/ cpu micro)
  137. (/ real micro)
  138. (/ gc micro)
  139. (/ (- cpu gc) micro))
  140. ((fmt "'incorrect times for k='i//" 'current) k))))
  141. result))))
  142. (let* ([max-expt 10000] [small (expt 10 (- (* 2 max-expt)))] [iter 1000])
  143. (for ([k (in-range (- max-expt) (add1 max-expt) (/ max-expt 10))])
  144. (let* ([q (expt 10 k)] [qq (- q small)] [qqq (+ q small)])
  145. (unless (= k (timer "exact power of 10" iter k (order-of-magnitude q)))
  146. (error 'test-1 "~s" k))
  147. (unless (= (sub1 k)
  148. (timer "slightly less than power of 10"
  149. iter k (order-of-magnitude qq)))
  150. (error 'test-2 "~s" k))
  151. (unless (= k
  152. (timer "slightly more than power of 10"
  153. iter k (order-of-magnitude qqq)))
  154. (error 'test-3 "~s" k)))))
  155. |#