diff options
Diffstat (limited to 'stdlib/source/lux/math/number/int.lux')
-rw-r--r-- | stdlib/source/lux/math/number/int.lux | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/stdlib/source/lux/math/number/int.lux b/stdlib/source/lux/math/number/int.lux new file mode 100644 index 000000000..ec4df8389 --- /dev/null +++ b/stdlib/source/lux/math/number/int.lux @@ -0,0 +1,253 @@ +(.module: + [lux #* + [abstract + [hash (#+ Hash)] + [enum (#+ Enum)] + [interval (#+ Interval)] + [monoid (#+ Monoid)] + [equivalence (#+ Equivalence)] + [codec (#+ Codec)] + [predicate (#+ Predicate)] + ["." order (#+ Order)]] + [control + ["." try (#+ Try)]] + [data + [text (#+ Char)] + ["." maybe]]] + ["." // #_ + ["#." nat] + ["#." i64]]) + +(def: #export (= reference sample) + {#.doc "Int(eger) equivalence."} + (-> Int Int Bit) + ("lux i64 =" reference sample)) + +(def: #export (< reference sample) + {#.doc "Int(eger) less-than."} + (-> Int Int Bit) + ("lux i64 <" reference sample)) + +(def: #export (<= reference sample) + {#.doc "Int(eger) less-than or equal."} + (-> Int Int Bit) + (if ("lux i64 <" reference sample) + #1 + ("lux i64 =" reference sample))) + +(def: #export (> reference sample) + {#.doc "Int(eger) greater-than."} + (-> Int Int Bit) + ("lux i64 <" sample reference)) + +(def: #export (>= reference sample) + {#.doc "Int(eger) greater-than or equal."} + (-> Int Int Bit) + (if ("lux i64 <" sample reference) + #1 + ("lux i64 =" reference sample))) + +(template [<comparison> <name>] + [(def: #export <name> + (Predicate Int) + (<comparison> +0))] + + [..> positive?] + [..< negative?] + [..= zero?] + ) + +(template [<name> <test> <doc>] + [(def: #export (<name> left right) + {#.doc <doc>} + (-> Int Int Int) + (if (<test> right left) + left + right))] + + [min ..< "Int(eger) minimum."] + [max ..> "Int(eger) maximum."] + ) + +(template [<name> <op> <doc>] + [(def: #export (<name> param subject) + {#.doc <doc>} + (-> Int Int Int) + (<op> param subject))] + + [+ "lux i64 +" "Int(eger) addition."] + [- "lux i64 -" "Int(eger) substraction."] + [* "lux i64 *" "Int(eger) multiplication."] + [/ "lux i64 /" "Int(eger) division."] + [% "lux i64 %" "Int(eger) remainder."] + ) + +(def: #export (/% param subject) + (-> Int Int [Int Int]) + [(../ param subject) + (..% param subject)]) + +(def: #export (negate value) + (-> Int Int) + (..- value +0)) + +(def: #export (abs x) + (-> Int Int) + (if (..< +0 x) + (..* -1 x) + x)) + +(def: #export (signum x) + (-> Int Int) + (cond (..= +0 x) +0 + (..< +0 x) -1 + ## else + +1)) + +## https://rob.conery.io/2018/08/21/mod-and-remainder-are-not-the-same/ +(def: #export (mod divisor dividend) + (All [m] (-> Int Int Int)) + (let [remainder (..% divisor dividend)] + (if (or (and (..< +0 divisor) + (..> +0 remainder)) + (and (..> +0 divisor) + (..< +0 remainder))) + (..+ divisor remainder) + remainder))) + +(def: #export even? + (-> Int Bit) + (|>> (..% +2) ("lux i64 =" +0))) + +(def: #export odd? + (-> Int Bit) + (|>> ..even? not)) + +(def: #export (gcd a b) + {#.doc "Greatest Common Divisor."} + (-> Int Int Int) + (case b + +0 a + _ (gcd b (..% b a)))) + +(def: #export (co-prime? a b) + (-> Int Int Bit) + (..= +1 (..gcd a b))) + +## https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm +(def: #export (extended_gcd a b) + {#.doc "Extended euclidean algorithm."} + (-> Int Int [[Int Int] Int]) + (loop [x +1 x1 +0 + y +0 y1 +1 + a1 a b1 b] + (case b1 + +0 [[x y] a1] + _ (let [q (/ b1 a1)] + (recur x1 (- (* q x1) x) + y1 (- (* q y1) y) + b1 (- (* q b1) a1)))))) + +(def: #export (lcm a b) + {#.doc "Least Common Multiple."} + (-> Int Int Int) + (case [a b] + (^or [_ +0] [+0 _]) + +0 + + _ + (|> a (/ (gcd a b)) (* b)) + )) + +(def: #export frac + (-> Int Frac) + (|>> "lux i64 f64")) + +(structure: #export equivalence + (Equivalence Int) + + (def: = ..=)) + +(structure: #export order + (Order Int) + + (def: &equivalence ..equivalence) + (def: < ..<)) + +(structure: #export enum + (Enum Int) + + (def: &order ..order) + (def: succ inc) + (def: pred dec)) + +## TODO: Find out why the numeric literals fail during JS compilation. +(structure: #export interval + (Interval Int) + + (def: &enum ..enum) + (def: top + ## +9,223,372,036,854,775,807 + (let [half (//i64.left_shift 62 +1)] + (+ half + (dec half)))) + (def: bottom + ## -9,223,372,036,854,775,808 + (//i64.left_shift 63 +1))) + +(template [<name> <compose> <identity>] + [(structure: #export <name> + (Monoid Int) + + (def: identity <identity>) + (def: compose <compose>))] + + [addition ..+ +0] + [multiplication ..* +1] + [maximum ..max (\ ..interval bottom)] + [minimum ..min (\ ..interval top)] + ) + +(def: -sign "-") +(def: +sign "+") + +(template [<struct> <codec> <error>] + [(structure: #export <struct> + (Codec Text Int) + + (def: (encode value) + (if (..< +0 value) + (|> value inc ..negate .nat inc (\ <codec> encode) ("lux text concat" ..-sign)) + (|> value .nat (\ <codec> encode) ("lux text concat" ..+sign)))) + + (def: (decode repr) + (let [input_size ("lux text size" repr)] + (if (//nat.> 1 input_size) + (case ("lux text clip" 0 1 repr) + (^ (static ..+sign)) + (|> repr + ("lux text clip" 1 input_size) + (\ <codec> decode) + (\ try.functor map .int)) + + (^ (static ..-sign)) + (|> repr + ("lux text clip" 1 input_size) + (\ <codec> decode) + (\ try.functor map (|>> dec .int ..negate dec))) + + _ + (#try.Failure <error>)) + (#try.Failure <error>)))))] + + [binary //nat.binary "Invalid binary syntax for Int: "] + [octal //nat.octal "Invalid octal syntax for Int: "] + [decimal //nat.decimal "Invalid syntax for Int: "] + [hex //nat.hex "Invalid hexadecimal syntax for Int: "] + ) + +(structure: #export hash + (Hash Int) + + (def: &equivalence ..equivalence) + (def: hash .nat)) |