UNB/ CS/ David Bremner/ teaching/ cs4613/ tutorials/ tutorial3/ calculus.rkt
#lang racket
(require racket/math)
(provide deriv 2pi -2pi integrate)

(module+ test
  (require rackunit)
  (define epsilon .001))

(define dx 0.001)
(define -2pi (* -2 pi))
(define 2pi (* 2 pi))

;; compute the derivative of `f' at the given point `x'
(define (deriv f x)
  (/ (- (f (+ x dx)) (f x)) dx))

;; Integrate a function from 0 to x (using tail recursion)
(define (integrate f x)
  (define (loop y acc)
    (if (> y x)
        (* acc dx)
        (loop (+ y dx) (+ acc (f y)))))
  (loop 0 0))

(module+ test
  (check-= (integrate cos (/ pi 4)) (sin (/ pi 4)) epsilon))
;; Generate a bunch of numerical tests
;; use a for loop (generalizes let)
(module+ test
  (define test-points (build-list 20 (lambda (x) (* 2 pi (random)))))
  (define (sin2 x) (integrate cos x))
  (define (cos2 x) (deriv sin x))
  (for ([x test-points])
    (check-= (sin x) (sin2 x) epsilon)
    (check-= (cos x) (cos2 x) epsilon)))

(define (integrate2 f x)
  (* dx
   (for/fold
       ([acc 0])
       ([y (in-range 0 x dx)])
     (+ acc (f y)))))

(module+ test
  (for ([x test-points])
    (check-= (integrate cos x) (integrate2 cos x) epsilon)))