Clojure 中的梯形积分不够准确

Trapezoidal Integration is not accurate enough in Clojure

所以目前,我写了一个 Clojure 代码来对 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)

然而,我的输出是:

107.38602491666647
45611.95754801859

虽然应该是:

101.4
41193.0

我的代码通过了前两个测试用例,但未能通过其余测试用例。我假设是因为准确性问题。我多次查看我的代码,但似乎无法让它变得更好。我在这里做错了什么?谢谢。

您的 exp 函数不太正确 -- 它不能正确处理负指数。可能最好只使用 Math/pow.

您可以做的另一件事是调整 volumeIntegral 中的 h 值,但为避免堆栈问题,请使用 recur(这会为您提供尾递归),例如这是一个稍微修改过的版本:

(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))

(我做了与 integral 类似的事情。)总而言之,我没能完全达到第二个数字,但这应该让你走上正轨:

101.33517384995224
41119.11576557253