168 lines
5.3 KiB
Racket
168 lines
5.3 KiB
Racket
#lang racket/base
|
||
|
||
;; Extra math functions and constants.
|
||
|
||
(require racket/math racket/flonum racket/match racket/list racket/contract
|
||
"contract.rkt" "contract-doc.rkt")
|
||
|
||
(provide (all-defined-out))
|
||
|
||
(define-struct ivl (min max) #:transparent
|
||
#:guard (λ (a b _)
|
||
(cond [(and (regular? a) (regular? b)) (values (min* a b) (max* a b))]
|
||
[else (values a b)])))
|
||
|
||
(defproc (bounds->intervals [xs (listof real?)]) (listof ivl?)
|
||
(cond [((length xs) . < . 2) (raise-type-error 'bounds->intervals "list with length >= 2" xs)]
|
||
[else
|
||
(for/list ([x1 (in-list xs)]
|
||
[x2 (in-list (rest xs))])
|
||
(ivl x1 x2))]))
|
||
|
||
(define -pi (- pi))
|
||
(define 2pi (* 2 pi))
|
||
(define -1/2pi (* -1/2 pi))
|
||
(define 1/2pi (* 1/2 pi))
|
||
|
||
(define 180/pi (fl/ 180.0 pi))
|
||
(define pi/180 (fl/ pi 180.0))
|
||
|
||
(defproc (degrees->radians [d real?]) real?
|
||
(fl* (exact->inexact d) pi/180))
|
||
|
||
(defproc (radians->degrees [r real?]) real?
|
||
(fl* (exact->inexact r) 180/pi))
|
||
|
||
(define (atan2 y x)
|
||
(if (and (zero? y) (zero? x)) 0 (atan y x)))
|
||
|
||
(define (real-modulo x y) (- x (* y (floor (/ x y)))))
|
||
|
||
(define (sum f xs) (apply + (map f xs)))
|
||
|
||
(define (flmodulo x y) (fl- x (fl* y (flfloor (fl/ x y)))))
|
||
(define (fldist2 x y) (flsqrt (fl+ (fl* x x) (fl* y y))))
|
||
(define (fldist3 x y z) (flsqrt (fl+ (fl* x x) (fl+ (fl* y y) (fl* z z)))))
|
||
|
||
(define (flsum ps)
|
||
(for/fold ([sum 0.0]) ([p (in-list ps)])
|
||
(fl+ sum p)))
|
||
|
||
(define (factorial n)
|
||
(if (zero? n) 1 (* n (factorial (sub1 n)))))
|
||
|
||
(define (alpha-blend x1 x2 a)
|
||
(+ (* a x1) (* (- 1 a) x2)))
|
||
|
||
(define (build-linear-seq start step num)
|
||
(for/list ([n (in-range num)])
|
||
(+ start (* n step))))
|
||
|
||
(defproc (linear-seq [start real?] [end real?] [num (integer>=/c 0)]
|
||
[#:start? start? boolean? #t]
|
||
[#:end? end? boolean? #t]) (listof real?)
|
||
(cond
|
||
[(zero? num) empty]
|
||
; ambiguous request: arbitrarily return start
|
||
[(and start? end? (= 1 num)) (list start)]
|
||
[else
|
||
(define size (- end start))
|
||
(define step (/ size (cond [(and start? end?) (- num 1)]
|
||
[(or start? end?) (- num 1/2)]
|
||
[else num])))
|
||
(define real-start
|
||
(cond [start? start]
|
||
[else (+ start (* 1/2 step))]))
|
||
|
||
(build-linear-seq real-start step num)]))
|
||
|
||
(defproc (linear-seq* [points (listof real?)] [num (integer>=/c 0)]
|
||
[#:start? start? boolean? #t]
|
||
[#:end? end? boolean? #t]) (listof real?)
|
||
(let/ec return
|
||
(when (empty? points) (raise-type-error 'linear-seq* "nonempty (listof real?)" points))
|
||
|
||
(define pts (list->vector points))
|
||
(define len (vector-length pts))
|
||
|
||
(define indexes (linear-seq 0 (sub1 len) num #:start? start? #:end? end?))
|
||
(define int-parts (map floor indexes))
|
||
(define frac-parts (map - indexes int-parts))
|
||
(map (λ (i f)
|
||
(if (= i (sub1 len))
|
||
(vector-ref pts i)
|
||
(alpha-blend (vector-ref pts (add1 i)) (vector-ref pts i) f)))
|
||
int-parts frac-parts)))
|
||
|
||
(define (nan? x) (eqv? x +nan.0))
|
||
(define (infinite? x) (or (eqv? x +inf.0) (eqv? x -inf.0)))
|
||
(define (regular? x) (and (real? x) (not (nan? x)) (not (infinite? x))))
|
||
|
||
(define (min2 x y)
|
||
(cond [(x . < . y) x]
|
||
[(y . < . x) y]
|
||
[(exact? x) x]
|
||
[else y]))
|
||
|
||
(define (max2 x y)
|
||
(cond [(x . > . y) x]
|
||
[(y . > . x) y]
|
||
[(exact? x) x]
|
||
[else y]))
|
||
|
||
(define (clamp x mn mx) (min (max x mn) mx))
|
||
(define (clamp* x mn mx) (min2 (max2 x mn) mx))
|
||
|
||
(define (min* x . xs) (foldl min2 x xs))
|
||
(define (max* x . xs) (foldl max2 x xs))
|
||
|
||
(define (maybe-min x . xs)
|
||
(for/fold ([x x]) ([y (in-list xs)])
|
||
(if x (if y (min* x y) x)
|
||
(if y y #f))))
|
||
|
||
(define (maybe-max x . xs)
|
||
(for/fold ([x x]) ([y (in-list xs)])
|
||
(if x (if y (max* x y) x)
|
||
(if y y #f))))
|
||
|
||
(define (floor-log10 x)
|
||
(inexact->exact (floor (/ (log (abs x)) (log 10)))))
|
||
|
||
(define (ceiling-log10 x)
|
||
(inexact->exact (ceiling (/ (log (abs x)) (log 10)))))
|
||
|
||
(define (bin-samples bin-bounds xs)
|
||
(let* ([bin-bounds (filter (compose not nan?) (remove-duplicates bin-bounds))]
|
||
[bin-bounds (sort bin-bounds <)]
|
||
[x-min (first bin-bounds)]
|
||
[x-max (last bin-bounds)]
|
||
[xs (filter (λ (x) (<= x-min x x-max)) xs)]
|
||
[xs (sort xs <)])
|
||
(define-values (res rest-xs)
|
||
(for/fold ([res empty] [xs xs]) ([x1 (in-list bin-bounds)]
|
||
[x2 (in-list (rest bin-bounds))])
|
||
(define-values (lst rest-xs)
|
||
(let loop ([lst empty] [xs xs])
|
||
(if (and (not (empty? xs)) (<= x1 (first xs) x2))
|
||
(loop (cons (first xs) lst) (rest xs))
|
||
(values lst xs))))
|
||
(values (cons (reverse lst) res)
|
||
rest-xs)))
|
||
(reverse res)))
|
||
|
||
(define (polar->cartesian θ r)
|
||
(let ([θ (exact->inexact θ)]
|
||
[r (exact->inexact r)])
|
||
(vector (fl* r (flcos θ))
|
||
(fl* r (flsin θ)))))
|
||
|
||
(define (3d-polar->3d-cartesian θ ρ r)
|
||
(let* ([θ (exact->inexact θ)]
|
||
[ρ (exact->inexact ρ)]
|
||
[r (exact->inexact r)]
|
||
[cos-ρ (flcos ρ)])
|
||
(vector (fl* r (fl* (flcos θ) cos-ρ))
|
||
(fl* r (fl* (flsin θ) cos-ρ))
|
||
(fl* r (flsin ρ)))))
|