atmosphere506
atmosphere506

Reputation: 343

Trapezoidal Integration is not accurate enough in Clojure

So currently, I wrote a Clojure code to do Trapezoidal integration of a polynomial function in HackerRank.com: https://www.hackerrank.com/challenges/area-under-curves-and-volume-of-revolving-a-curv

(defn abs[x]
  (max x (- 0 x))
  )

(defn exp[x n]
  (if (> n 0)
    (* x (exp x (- n 1)))
    1
    )
  )

(defn fact[x]
  (if (> x 0)
    (* x (fact (- x 1)))
    1)
  )

(defn func[x lst1 lst2]
  ((fn step [sum lst1 lst2]
     (if (> (.size lst1) 0)
        (step (+ sum (* (last lst1) (exp x (last lst2)))) (drop-last lst1) (drop-last lst2))
        sum
       )
     )
   0 lst1 lst2
   )
  )


(defn integrate[f a b]
  (def h 0.001)
  (def n (/ (abs (- b a)) h))
  ((fn step[i sum]
    (if (< i n)
      (step (+ i 1) (+ sum (f (+ (* i h) a))))
      (* h (+ (/(+ (f a) (f b)) 2) sum))
      )
    ) 0 0)
  )


(defn volumeIntegral[f a b]
  (defn area[r]
    (* 3.14159265359 (* r r)))

  (def h 0.001)
  (def n (/ (abs (- b a)) h))
  ((fn step[i sum]
     (if (< i n)
       (step (+ i 1) (+ sum (area (f (+ (* i h) a)))))
       (* h (+ (/ (+ (f a) (f b)) 2) sum))
       )
     ) 0 0)
   )

(defn lineToVec[line_str] (clojure.string/split line_str #"\s+"))
(defn strToDouble [x] (Double/parseDouble (apply str (filter #(Character/isDigit %) x))))

(defn readline[vec]
  ((fn step[list vec]
    (if (> (.size vec) 0)
      (step (conj list (last vec)) (drop-last vec))
      list
      )
    ) '() vec)
  )


(integrate (fn [x] (func x '(1 2 3 4 5 6 7 8) '(-1 -2 -3 -4 1 2 3 4))) 1 2)
(volumeIntegral (fn [x] (func x '(1 2 3 4 5 6 7 8) '(-1 -2 -3 -4 1 2 3 4))) 1 2)

However, the output I have is:

107.38602491666647
45611.95754801859

While is supposed to be around:

101.4
41193.0

My code passed the first two test cases, but didn't manage to pass the rest. I assume is because of the issue accuracy. I looked through my code several times but couldn't seem to make it better. What am I doing wrong here ? Thank you.

Upvotes: 2

Views: 147

Answers (1)

user2524973
user2524973

Reputation: 1117

Your exp function isn't quite right -- it doesn't handle negative exponents correctly. Probably best just to use Math/pow.

The other thing you could do is adjust your h value in volumeIntegral but to avoid stack issues, use recur (which gives you tail recursion), e.g. here's a slightly modified version:

(defn volume-integral [f a b]
  (defn area[r]
    (* Math/PI (* r r)))
  (def h 0.000001)
  (def n (/ (abs (- b a)) h))
  ((fn [i sum]
     (if (not (< i n))
       (* h (+ (/ (+ (f a) (f b)) 2) sum))
       (recur (+ i 1) (+ sum (area (f (+ (* i h) a)))))))
     0 0))

(I did the something similar with integral.) All in all, I wasn't able to quite hit the second figure, but this should get you on the right track:

101.33517384995224
41119.11576557253

Upvotes: 3

Related Questions