ক্লোজারে স্কয়ার রুট
আমরা এখন ক্লোজারে একটি ফাংশন লিখবো যেটি একটি সঙ্খ্যার স্কয়ার রুট বা বর্গমূল বের করবে।
আমার লেখা পুরো ফাংশনটি এরকম:
(defn sqrt
([x] (sqrt x 0.001))
([x precision]
(letfn [(abs [x]
(if (< x 0)
(- x)
x))
(square [x]
(* x x))
(average [& args]
(/ (apply + args) (count args)))
(good-enough? [guess]
(< (abs (- (square guess) x)) precision))
(improve [guess]
(average guess (/ x guess)))]
(loop [guess 1.0]
(if (good-enough? guess)
guess
(recur (improve guess)))))))
এবার এটাকে ভেঙে দেখা যাক। প্রথমত এটা একটি মাল্টি-এরিটি ফাংশন। অর্থাৎ যদি শুধু সঙ্খ্যা দেওয়া হয় তবে ০.০০১ প্রেসিশনে বর্গমূল বের করবে। আর প্রেসিশন বলে দিলে সেই প্রেসিশনে। এরপর আমরা letfn ব্যবহার করে কয়েকটি লোকাল ফাংশন ডিফাইন করেছি:
(abs [x]
(if (< x 0)
(- x)
x))
এই ফাংশনটি একটি সঙ্খ্যার পরম মান বা এবসলিউট ভ্যালু রিটার্ন করবে।
(square [x]
(* x x))
(average [& args]
(/ (apply + args) (count args)))
square এবং average ফাংশনদ্বয় যথাক্রমে বর্গ ও গড় রিটার্ন করবে।
(good-enough? [guess]
(< (abs (- (square guess) x))
precision))
এই ফাংশনটি Boolean রিটার্ন করবে। guess একটি নম্বর, যেটিকে বর্গ করা হবে, তারপর তার থেকে মূল সঙ্খ্যাটি বিয়োগ করা হবে। ফলাফলের পরম মান যদি প্রেসিশন থেকে ছোট হয় তবে ট্রু, নাহলে ফলস্ রিটার্ন করবে।
(improve [guess]
(average guess (/ x guess)))
এটি দিয়ে আমরা গেজ করা বর্গমূল থেকে আরো কাছের সঙ্খ্যা বের করবো। গেজ করা সঙ্খ্যা এবং মূলসঙ্খ্যাকে গেজ করা সঙ্খ্যা দ্বারা ভাগ করার ফলাফলের গড় এটি রিটার্ন করবে।
এবার ফাংশনের মূল প্রসিডিউর:
(loop [guess 1.0]
(if (good-enough? guess)
guess
(recur (improve guess))))
এটা একটা সাধারণ লুপ। যেটি প্রথমে বর্গমূল হিসেবে 1.0 গেজ করবে। তারপর good-enough ফাংশনের সাহায্যে দেখবে গেজটি ঠিক আছে কিনা। ঠিক থাকলে ফলাফল রিটার্ন করবে। নাহলে improve ফাংশনের মাধ্যমে ইম্প্রুভ করবে এবং লুপ সচল রাখবে।
এবার আমরা ফাংশনটি ব্যবহার করছি:
boot.user> (sqrt 3)
1.7321428571428572
boot.user> (sqrt 3 0.00001)
1.7320508100147274
boot.user> (sqrt 3 0.1)
1.75
আমরা প্রথমে ডিফল্ট প্রেসিশন অর্থাৎ 0.001 প্রেসিশনে 3 এর বর্গমূল বের করলাম তারপর প্রেসিশন বাড়িয়ে ও কমিয়ে দেখলাম।