diff --git a/Math.ark b/Math.ark index 05a2eba..2b11c8f 100644 --- a/Math.ark +++ b/Math.ark @@ -158,6 +158,234 @@ # @author https://github.com/SuperFola (let NaN builtin__math:NaN) +# @brief Count the number of '1' bits in the given value +# @param value the Number, must be an integer +# =begin +# (math:countOnes 5) # 2 +# =end +# @author https://github.com/SuperFola +# @require 4.6.0 Requires ArkScript 4.6.0 or later +(let countOnes (fun (_x) (builtin__math:countOnes _x))) + +# @brief Count the number of '0' bits in the given value +# @param value the Number, must be an integer +# =begin +# (math:countZeros 5) # 1 +# =end +# @author https://github.com/SuperFola +# @require 4.6.0 Requires ArkScript 4.6.0 or later +(let countZeros (fun (_x) (builtin__math:countZeros _x))) + +# @brief Invert a number on 64 bits +# @param value Number, must be an integer +# =begin +# (math:bitNot 5) # -6 +# =end +# @author https://github.com/SuperFola +# @require 4.6.0 Requires ArkScript 4.6.0 or later +(let bitNot (fun (_x) (builtin__math:bitNot _x))) + +# @brief Bitwise and +# @param lhs Number, must be an integer +# @param rhs Number, must be an integer +# =begin +# (math:bitAnd 4 12) # 4 +# (math:bitAnd 4 10) # 0 +# =end +# @author https://github.com/SuperFola +# @require 4.6.0 Requires ArkScript 4.6.0 or later +(let bitAnd (fun (_a _b) (builtin__math:bitAnd _a _b))) + +# @brief Bitwise or +# @param lhs Number, must be an integer +# @param rhs Number, must be an integer +# =begin +# (math:bitOr 4 10) # 14 +# (math:bitOr 4 1) # 5 +# =end +# @author https://github.com/SuperFola +# @require 4.6.0 Requires ArkScript 4.6.0 or later +(let bitOr (fun (_a _b) (builtin__math:bitOr _a _b))) + +# @brief Bitwise exclusive or of lhs and rhs +# @param lhs Number, must be an integer +# @param rhs Number, must be an integer +# =begin +# (math:bitXor 4 12) # 8 +# (math:bitXor 4 10) # 14 +# =end +# @author https://github.com/SuperFola +# @require 4.6.0 Requires ArkScript 4.6.0 or later +(let bitXor (fun (_a _b) (builtin__math:bitXor _a _b))) + +# @brief Left bit shift +# @param lhs Number, must be an integer +# @param rhs Number, must be an integer +# =begin +# (math:lshift 3 2) # 12 +# =end +# @author https://github.com/SuperFola +# @require 4.6.0 Requires ArkScript 4.6.0 or later +(let lshift (fun (_a _b) (builtin__math:lshift _a _b))) + +# @brief Right bit shift +# @param lhs Number, must be an integer +# @param rhs Number, must be an integer +# =begin +# (math:rshift 13 2) # 3 +# (math:rshift -14 2) # -4 +# =end +# @author https://github.com/SuperFola +# @require 4.6.0 Requires ArkScript 4.6.0 or later +(let rshift (fun (_a _b) (builtin__math:rshift _a _b))) + +# @brief Finds the smallest integral power of 2 not less than the given value +# @param value Number, must be an integer +# =begin +# (math:bitCeil 4) # 4 +# (math:bitCeil 7) # 8 +# (math:bitCeil 8) # 8 +# =end +# @author https://github.com/SuperFola +# @require 4.6.0 Requires ArkScript 4.6.0 or later +(let bitCeil (fun (_x) (builtin__math:bitCeil _x))) + +# @brief Finds the largest integral power of 2 not greater than the given value +# @param value Number, must be an integer +# =begin +# (math:bitFloor 4) # 4 +# (math:bitFloor 7) # 4 +# (math:bitFloor 8) # 8 +# =end +# @author https://github.com/SuperFola +# @require 4.6.0 Requires ArkScript 4.6.0 or later +(let bitFloor (fun (_x) (builtin__math:bitFloor _x))) + +# @brief Finds the smallest number of bits needed to represent the given value +# @param value Number, must be an integer +# =begin +# (math:bitWidth 2) # 2 +# (math:bitWidth 7) # 3 +# (math:bitWidth 8) # 4 +# =end +# @author https://github.com/SuperFola +# @require 4.6.0 Requires ArkScript 4.6.0 or later +(let bitWidth (fun (_x) (builtin__math:bitWidth _x))) + +# @brief Counts the number of consecutive 0 bits, starting from the most significant bit +# @param n Number, must be an integer +# @param bits Number of bits to represent n in, must be an integer +# =begin +# (math:countLeftZeros 30 8) # 3 +# (math:countLeftZeros 227 8) # 0 +# =end +# @author https://github.com/SuperFola +# @require 4.6.0 Requires ArkScript 4.6.0 or later +(let countLeftZeros (fun (_n _bits) (builtin__math:countLeftZeros _n _bits))) + +# @brief Counts the number of consecutive 1 bits, starting from the most significant bit +# @param n Number, must be an integer +# @param bits Number of bits to represent n in, must be an integer +# =begin +# (math:countLeftOnes 30 8) # 4 +# (math:countLeftOnes 227 8) # 3 +# =end +# @author https://github.com/SuperFola +# @require 4.6.0 Requires ArkScript 4.6.0 or later +(let countLeftOnes (fun (_n _bits) (builtin__math:countLeftOnes _n _bits))) + +# @brief Counts the number of consecutive 0 bits, starting from the least significant bit +# @param n Number, must be an integer +# @param bits Number of bits to represent n in, must be an integer +# =begin +# (math:countRightZeros 30 8) # 1 +# (math:countRightZeros 227 8) # 0 +# =end +# @author https://github.com/SuperFola +# @require 4.6.0 Requires ArkScript 4.6.0 or later +(let countRightZeros (fun (_n _bits) (builtin__math:countRightZeros _n _bits))) + +# @brief Counts the number of consecutive 1 bits, starting from the least significant bit +# @param n Number, must be an integer +# @param bits Number of bits to represent n in, must be an integer +# =begin +# (math:countRightOnes 30 8) # 0 +# (math:countRightOnes 227 8) # 2 +# =end +# @author https://github.com/SuperFola +# @require 4.6.0 Requires ArkScript 4.6.0 or later +(let countRightOnes (fun (_n _bits) (builtin__math:countRightOnes _n _bits))) + +# @brief Computes the result of bitwise left-rotation of _x by _count +# @param _x Number, must be an integer +# @param _count Number, must be an integer +# @param _bytecount Number of bytes to shift on, must be an integer +# =begin +# (math:circularLeftShift 29 4 1) # 209 +# (math:circularLeftShift 29 9 1) # 58 +# =end +# @author https://github.com/SuperFola +# @require 4.6.0 Requires ArkScript 4.6.0 or later +(let circularLeftShift (fun (_x (mut _count) _bytecount) { + (assert (and (>= _bytecount 1) (<= _bytecount 8)) "bytecount must be in [1, 8]") + (let _max (- (* 8 _bytecount) 1)) + (let _mask (- (lshift 1 (* 8 _bytecount)) 1)) + (set _count (bitAnd _count _max)) + (bitAnd (bitOr (lshift _x _count) (rshift _x (bitAnd (* -1 _count) _max))) _mask) })) + +# @brief Computes the result of bitwise left-rotation of _x by _count +# @param _x Number, must be an integer +# @param _count Number, must be an integer +# @param _bytecount Number of bytes to shift on, must be an integer +# =begin +# (math:circularRightShift 29 9 1) # 142 +# (math:circularRightShift 29 2 1) # 71 +# =end +# @author https://github.com/SuperFola +# @require 4.6.0 Requires ArkScript 4.6.0 or later +(let circularRightShift (fun (_x (mut _count) _bytecount) { + (assert (and (>= _bytecount 1) (<= _bytecount 8)) "bytecount must be in [1, 8]") + (let _max (- (* 8 _bytecount) 1)) + (let _mask (- (lshift 1 (* 8 _bytecount)) 1)) + (set _count (bitAnd _count _max)) + (bitAnd (bitOr (rshift _x _count) (lshift _x (bitAnd (* -1 _count) _max))) _mask) })) + +(let _base_conversion_alphabet "0123456789abcdefghijklmnopqrstuvwxyz") + +# @brief Convert a number in a another base (in [2, 36[) +# @param _x Number, must be an integer +# @param _base Number, must be an integer +# =begin +# (math:toBase 10 2) # "1010" +# (math:toBase 165 16) # "a5" +# =end +# @author https://github.com/SuperFola +# @require 4.6.0 Requires ArkScript 4.6.0 or later +(let toBase (fun ((mut _x) _base) { + (assert (and (> _base 1) (< _base 36)) "Base must be in [2, 36[") + (mut _out "") + (while _x { + (set _out (+ (@ _base_conversion_alphabet (mod _x _base)) _out)) + (set _x (floordiv _x _base)) }) + _out })) + +# @brief Count the digits of a number in a given base (in [2, 36[) +# @param _x Number, must be an integer +# @param _base Number, must be an integer +# =begin +# (math:countDigits 10 2) # 4 +# (math:countDigits 165 16) # 2 +# =end +# @author https://github.com/SuperFola +# @require 4.6.0 Requires ArkScript 4.6.0 or later +(let countDigits (fun ((mut _x) _base) { + (assert (and (> _base 1) (< _base 36)) "Base must be in [2, 36[") + (mut _out 0) + (while _x { + (set _out (+ 1 _out)) + (set _x (floordiv _x _base)) }) + _out })) + # @brief Return the absolute value of a number # @param _x the number to get the absolute value of # @author https://github.com/rstefanic @@ -214,7 +442,23 @@ # @param _x the number to pow # @param _a the exponent # @author https://github.com/SuperFola -(let pow (fun (_x _a) (exp (* _a (ln _x))))) +(let pow (fun ((mut _x) (mut _a)) { + (if (= 0 (mod _a 1)) + (if (= 1 _a) + _x + (if (= 0 _a) + 1 + { + (let _c _x) + (if (> _a 0) + (while (> _a 1) { + (set _x (* _c _x)) + (set _a (- _a 1)) }) + (while (<= _a 0) { + (set _x (/ _x _c)) + (set _a (+ _a 1)) })) + _x })) + (exp (* _a (ln _x)))) })) # @brief Get the square root of a number # @details Square roots can't be taken for negative numbers for obvious reasons. diff --git a/Testing.ark b/Testing.ark index 796bac5..9cecffa 100644 --- a/Testing.ark +++ b/Testing.ark @@ -261,7 +261,9 @@ (set testing:_suite (testing:_make_suite ($repr _name))) (let ($symcat _name "-output") (testing:_runner - ($repr _name) + ($if (= "String" ($type _name)) + _name + ($repr _name)) (fun () ($as-is { _body })))) diff --git a/tests/math-tests.ark b/tests/math-tests.ark index 20de42d..6c9e36f 100644 --- a/tests/math-tests.ark +++ b/tests/math-tests.ark @@ -29,7 +29,65 @@ (test:eq (builtin__math:tanh 5) (math:tanh 5)) (test:eq (builtin__math:acosh 5) (math:acosh 5)) (test:eq (builtin__math:asinh 5) (math:asinh 5)) - (test:eq (builtin__math:atanh 0.5) (math:atanh 0.5)) }) + (test:eq (builtin__math:atanh 0.5) (math:atanh 0.5)) + (test:eq (builtin__math:countOnes 1234) (math:countOnes 1234)) + (test:eq (builtin__math:countZeros 1234) (math:countZeros 1234)) + (test:eq (builtin__math:bitNot 1234) (math:bitNot 1234)) + (test:eq (builtin__math:bitAnd 1234 5678) (math:bitAnd 1234 5678)) + (test:eq (builtin__math:bitOr 1234 5678) (math:bitOr 1234 5678)) + (test:eq (builtin__math:bitXor 1234 5678) (math:bitXor 1234 5678)) + (test:eq (builtin__math:lshift 1234 2) (math:lshift 1234 2)) + (test:eq (builtin__math:rshift 1234 6) (math:rshift 1234 6)) + (test:eq (builtin__math:bitCeil 1234) (math:bitCeil 1234)) + (test:eq (builtin__math:bitFloor 1234) (math:bitFloor 1234)) + (test:eq (builtin__math:bitWidth 1234) (math:bitWidth 1234)) + (test:eq (builtin__math:countLeftZeros 1234 32) (math:countLeftZeros 1234 32)) + (test:eq (builtin__math:countLeftOnes 1234 32) (math:countLeftOnes 1234 32)) + (test:eq (builtin__math:countRightZeros 1234 32) (math:countRightZeros 1234 32)) + (test:eq (builtin__math:countRightOnes 1234 32) (math:countRightOnes 1234 32)) }) + + (test:case "bitwise" { + (test:eq (math:countOnes 5) 2) + (test:eq (math:countOnes 63) 6) + (test:eq (math:countZeros 63) 58) + (test:eq (math:countZeros 65535) 48) + + (test:eq (math:bitNot 5) -6) + (test:eq (math:bitAnd 4 12) 4) + (test:eq (math:bitAnd 4 10) 0) + (test:eq (math:bitOr 4 10) 14) + (test:eq (math:bitOr 4 1) 5) + (test:eq (math:bitXor 4 12) 8) + (test:eq (math:bitXor 4 10) 14) + (test:eq (math:lshift 3 2) 12) + (test:eq (math:rshift 13 2) 3) + (test:eq (math:rshift -14 2) -4) + + (test:eq (math:countLeftZeros 30 8) 3) + (test:eq (math:countLeftZeros 227 8) 0) + (test:eq (math:countLeftOnes 30 5) 4) + (test:eq (math:countLeftOnes 30 8) 0) + (test:eq (math:countLeftOnes 227 8) 3) + (test:eq (math:countRightZeros 30 8) 1) + (test:eq (math:countRightZeros 227 8) 0) + (test:eq (math:countRightOnes 30 8) 0) + (test:eq (math:countRightOnes 227 8) 2) + + (test:eq (math:circularLeftShift 29 4 1) 209) + (test:eq (math:circularLeftShift 29 9 1) 58) + (test:eq (math:circularRightShift 29 9 1) 142) + (test:eq (math:circularRightShift 29 2 1) 71) }) + + (test:case "toBase" { + (test:eq (math:toBase 10 10) "10") + (test:eq (math:toBase 10 16) "a") + (test:eq (math:toBase 10 2) "1010") + (test:eq (math:toBase 165 16) "a5") }) + + (test:case "countDigits" { + (test:eq (math:countDigits 10 2) 4) + (test:eq (math:countDigits 10 10) 2) + (test:eq (math:countDigits 165 16) 2) }) (test:case "abs" { (test:eq (math:abs -1) 1) @@ -80,6 +138,8 @@ (test:case "pow" { (test:eq (math:pow 2 2) 4) + (test:eq (math:pow 2 3) 8) + (test:eq (math:pow 2 -3) 0.125) (test:eq (math:pow 4 0.5) 2) }) (test:case "clamp" { diff --git a/tests/string-tests.ark b/tests/string-tests.ark index 9c0f598..378df90 100644 --- a/tests/string-tests.ark +++ b/tests/string-tests.ark @@ -75,7 +75,7 @@ (test:eq (string:toUpper "ABCDEFGHIJKLMNOPQRSTUVWXYZ") "ABCDEFGHIJKLMNOPQRSTUVWXYZ") }) (test:case "reverse" { - (test:eq (string:reverse "dlrow olleh") "hello world" ) + (test:eq (string:reverse "dlrow olleh") "hello world") (test:eq (string:reverse "") "") (test:eq (string:reverse "a") "a") }) diff --git a/tests/switch-tests.ark b/tests/switch-tests.ark index 865523a..85491de 100644 --- a/tests/switch-tests.ark +++ b/tests/switch-tests.ark @@ -9,7 +9,7 @@ (test:expect true)) called })) -(test:suite switch { +(test:suite "switch" { (switch 12 0 (test:expect false) -1 (test:expect false)