Skip to content

Commit dd6dc04

Browse files
committed
feat(math): adding copySign, radians, degrees, integer?, factorial, binomialCoeff, permutations, close?, euclideanDistance, gcd and lcm
1 parent 505a178 commit dd6dc04

File tree

2 files changed

+220
-7
lines changed

2 files changed

+220
-7
lines changed

Math.ark

Lines changed: 140 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,10 @@
232232
# @details Square roots can't be taken for negative numbers for obvious reasons.
233233
# @param _x the number
234234
# @author https://github.com/SuperFola
235-
(let sqrt (fun (_x) (exp (* 0.5 (ln _x)))))
235+
(let sqrt (fun (_x)
236+
(if (= 0 _x)
237+
0
238+
(exp (* 0.5 (ln _x))))))
236239

237240
# @brief Run the fibonacci function on a number
238241
# @param n the number
@@ -311,7 +314,7 @@
311314
# @author https://github.com/Gryfenfer97
312315
(let log10 (fun (x) (log x 10)))
313316

314-
# @brief Returns the quotient of the euclidian division of a and b
317+
# @brief Returns the quotient of the euclidean division of a and b
315318
# @param a the dividend
316319
# @param b the divisor
317320
# =begin
@@ -445,3 +448,138 @@
445448
# =end
446449
# @author https://github.com/SuperFola
447450
(let improvementRatioPercentage (fun (_a _b) (* 100 (- (/ _a _b) 1))))
451+
452+
# @brief Copy the sign of a given number
453+
# @param _x number
454+
# =begin
455+
# (print (math:copySign 5)) # 1
456+
# (print (math:copySign -3)) # -1
457+
# =end
458+
# @author https://github.com/SuperFola
459+
(let copySign (fun (_x)
460+
(if (< _x 0)
461+
-1
462+
1)))
463+
464+
# @brief Convert an angle in degrees to radians
465+
# @param _degrees
466+
# =begin
467+
# (print (math:radians 90)) # pi/2
468+
# =end
469+
# @author https://github.com/SuperFola
470+
(let radians (fun (_degrees)
471+
(/ (* _degrees pi) 180)))
472+
473+
# @brief Convert an angle in radians to degrees
474+
# @param _radians
475+
# =begin
476+
# (print (math:radians (/ math:pi 2))) # 90
477+
# =end
478+
# @author https://github.com/SuperFola
479+
(let degrees (fun (_radians)
480+
(/ (* 180 _radians) pi)))
481+
482+
# @brief Check if a given number is an integer
483+
# @param _x
484+
# =begin
485+
# (print (math:integer 1)) # true
486+
# (print (math:integer 1.000001)) # false
487+
# =end
488+
# @author https://github.com/SuperFola
489+
(let integer? (fun (_x)
490+
(= (ceil _x) (floor _x))))
491+
492+
# @brief Compute the factorial of a number
493+
# @param _n
494+
# =begin
495+
# (print (math:factorial 5)) # 120
496+
# =end
497+
# @author https://github.com/SuperFola
498+
(let factorial (fun ((mut _n))
499+
(if (< _n 0)
500+
0
501+
{
502+
(mut _res 1)
503+
(while (> _n 0) {
504+
(set _res (* _res _n))
505+
(set _n (- _n 1)) })
506+
_res })))
507+
508+
# @brief Compute the binomial coefficient (n k)
509+
# @details Evaluates to n! / (k! * (n - k)!) when k <= n and evaluates to zero when k > n.
510+
# @param _n total number of items
511+
# @param _k number of items that will be picked
512+
# @author https://github.com/SuperFola
513+
(let binomialCoeff (fun (_n _k)
514+
(if (<= _k _n)
515+
(/
516+
(factorial _n)
517+
(*
518+
(factorial _k)
519+
(factorial (- _n _k))))
520+
0)))
521+
522+
# @brief Compute the number of ways to choose k items from n items without repetition and with order
523+
# @details Evaluates to n! / (n - k)! when k <= n and evaluates to zero when k > n.
524+
# @param _n total number of items
525+
# @param _k number of items to pick
526+
# @author https://github.com/SuperFola
527+
(let permutations (fun (_n _k)
528+
(if (<= _k _n)
529+
(/
530+
(factorial _n)
531+
(factorial (- _n _k)))
532+
0)))
533+
534+
# @brief Compare two real numbers and return true if the first one is near the second one (1e-7 precision)
535+
# @param _n first number
536+
# @param _target target number
537+
# @author https://github.com/SuperFola
538+
(let close? (fun (_n _target) {
539+
# todo: make epsilon configurable
540+
(let _epsilon 1e-7)
541+
(and (< (- _target _epsilon) _n) (< _n (+ _target _epsilon))) }))
542+
543+
# @brief Compute the euclidean distance between two vectors of the same size
544+
# @param _a first vector, eg [1 4]
545+
# @param _b second vector, eg [5 8]
546+
# =begin
547+
# (let v1 [1 2 3])
548+
# (let v2 [7 9 8])
549+
# (print (math:euclideanDistance v1 v2)) # 10.488088481701517
550+
# =end
551+
# @author https://github.com/SuperFola
552+
(let euclideanDistance (fun (_a _b) {
553+
(assert (and (= (len _a) (len _b)) (!= 0 (len _a))) "Expected non-empty vectors to have the same size")
554+
555+
(mut _dist 0)
556+
(mut _i 0)
557+
(while (< _i (len _a)) {
558+
(let _diff (- (@ _a _i) (@ _b _i)))
559+
(set _dist (+ _dist (* _diff _diff)))
560+
(set _i (+ _i 1)) })
561+
(sqrt _dist) }))
562+
563+
# @brief Compute the greatest common divisor of two numbers
564+
# @param _a number
565+
# @param _b number
566+
# =begin
567+
# (print (math:gcd 48 18)) # 6
568+
# =end
569+
# @author https://github.com/SuperFola
570+
(let gcd (fun (_a _b)
571+
(if (= 0 _b)
572+
_a
573+
(gcd _b (mod _a _b)))))
574+
575+
# @brief Compute the least common multiplier of two numbers
576+
# @param _a number
577+
# @param _b number
578+
# =begin
579+
# (print (math:lcm 4 6)) # 12
580+
# =end
581+
# @author https://github.com/SuperFola
582+
(let lcm (fun (_a _b)
583+
(*
584+
(abs _a)
585+
(/ (abs _b) (gcd _a _b)))))

tests/math-tests.ark

Lines changed: 80 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -168,10 +168,85 @@
168168
(test:expect (< (math:abs (- (math:complex-module c4) 12.649110640673517)) 0.0001)) })
169169

170170
(test:case "vectors" {
171-
(test:eq 32 (math:dotProduct [1 2 3] [4 5 6]))
172-
(test:eq 3 (math:dotProduct [1 3 -5] [4 -2 -1])) })
171+
(test:eq (math:dotProduct [1 2 3] [4 5 6]) 32)
172+
(test:eq (math:dotProduct [1 3 -5] [4 -2 -1]) 3) })
173173

174174
(test:case "improvementRatioPercentage" {
175-
(test:eq 0 (math:improvementRatioPercentage 12 12))
176-
(test:eq 100 (math:improvementRatioPercentage 24 12))
177-
(test:eq 50 (math:improvementRatioPercentage 18 12)) }) })
175+
(test:eq (math:improvementRatioPercentage 12 12) 0)
176+
(test:eq (math:improvementRatioPercentage 24 12) 100)
177+
(test:eq (math:improvementRatioPercentage 18 12) 50) })
178+
179+
(test:case "copySign" {
180+
(test:eq (math:copySign 0) 1)
181+
(test:eq (math:copySign -1) -1)
182+
(test:eq (math:copySign math:Inf) 1) })
183+
184+
(test:case "degrees, radians" {
185+
(test:eq (math:degrees (math:radians 0)) 0)
186+
(test:eq (math:degrees (math:radians 20)) 20)
187+
(test:eq (math:degrees (math:radians 40)) 40)
188+
(test:eq (math:degrees (math:radians 70)) 70)
189+
(test:eq (math:degrees (math:radians 70)) 70)
190+
(test:eq (math:degrees (math:radians 90)) 90)
191+
(test:eq (math:degrees math:pi) 180)
192+
(test:eq (math:degrees (/ math:pi 2)) 90)
193+
(test:eq (math:radians 180) math:pi)
194+
(test:eq (math:radians 90) (/ math:pi 2)) })
195+
196+
(test:case "integer?" {
197+
(test:expect (math:integer? 0))
198+
(test:expect (math:integer? 10.0))
199+
(test:expect (math:integer? -1))
200+
(test:expect (math:integer? math:Inf))
201+
(test:expect (not (math:integer? 1.5)))
202+
(test:expect (not (math:integer? 0.5)))
203+
(test:expect (not (math:integer? -0.5)))
204+
(test:expect (not (math:integer? -1.5))) })
205+
206+
(test:case "factorial" {
207+
(test:eq (math:factorial -10) 0)
208+
(test:eq (math:factorial 0) 1)
209+
(test:eq (math:factorial 1) 1)
210+
(test:eq (math:factorial 2) 2)
211+
(test:eq (math:factorial 3) 6)
212+
(test:eq (math:factorial 4) 24)
213+
(test:eq (math:factorial 5) 120) })
214+
215+
(test:case "binomialCoeff" {
216+
(test:eq (math:binomialCoeff 4 6) 0)
217+
(test:eq (math:binomialCoeff 10 10) 1)
218+
(test:eq (math:binomialCoeff 4 0) 1)
219+
(test:eq (math:binomialCoeff 4 1) 4)
220+
(test:eq (math:binomialCoeff 4 2) 6)
221+
(test:eq (math:binomialCoeff 4 3) 4)
222+
(test:eq (math:binomialCoeff 4 4) 1) })
223+
224+
(test:case "permutations" {
225+
(test:eq (math:permutations 5 3) 60)
226+
(test:eq (math:permutations 6 1) 6)
227+
(test:eq (math:permutations 6 2) 30)
228+
(test:eq (math:permutations 6 3) 120)
229+
(test:eq (math:permutations 6 4) 360)
230+
(test:eq (math:permutations 6 5) 720)
231+
(test:eq (math:permutations 6 6) 720) })
232+
233+
(test:case "close?" {
234+
(test:expect (math:close? 1 1))
235+
(test:expect (math:close? 0.99999999 1))
236+
(test:expect (not (math:close? 0.9999999 1)))
237+
(test:expect (not (math:close? 2 1)))
238+
(test:expect (not (math:close? 1.5 1))) })
239+
240+
(test:case "euclideanDistance" {
241+
(test:eq (math:euclideanDistance [1] [1]) 0)
242+
(test:eq (math:euclideanDistance [1] [2]) 1)
243+
(test:expect (math:close? (math:euclideanDistance [0 0] [3 4]) 5)) })
244+
245+
(test:case "gcd, lcm" {
246+
(test:eq (math:gcd 48 18) 6)
247+
(test:eq (math:gcd 18 48) 6)
248+
(test:eq (math:gcd 42 56) 14)
249+
250+
(test:eq (math:lcm 4 6) 12)
251+
(test:eq (math:lcm 48 180) 720) })
252+
})

0 commit comments

Comments
 (0)