aboutsummaryrefslogtreecommitdiff
path: root/stdlib/source/lux/math/number/int.lux
diff options
context:
space:
mode:
Diffstat (limited to 'stdlib/source/lux/math/number/int.lux')
-rw-r--r--stdlib/source/lux/math/number/int.lux253
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))