aboutsummaryrefslogtreecommitdiff
path: root/stdlib/source/lux/data/number.lux
diff options
context:
space:
mode:
Diffstat (limited to 'stdlib/source/lux/data/number.lux')
-rw-r--r--stdlib/source/lux/data/number.lux961
1 files changed, 9 insertions, 952 deletions
diff --git a/stdlib/source/lux/data/number.lux b/stdlib/source/lux/data/number.lux
index f297f2788..9e658bd52 100644
--- a/stdlib/source/lux/data/number.lux
+++ b/stdlib/source/lux/data/number.lux
@@ -1,670 +1,15 @@
-(.module: {#.doc "Implementations of common structures for Lux's primitive number types."}
+(.module:
[lux #*
[control
- number
- [monoid (#+ Monoid)]
- [equivalence (#+ Equivalence)]
- hash
- ["." order (#+ Order)]
- enum
- interval
[codec (#+ Codec)]]
[data
["." error (#+ Error)]
- ["." maybe]
- ["." text (#+ Char)]
- [collection
- ["." array (#+ Array)]]]
- ["." function]
- ["." math]]
+ ["." text]]]
[/
- ["." i64]])
-
-(do-template [<type> <test>]
- [(structure: #export _ (Equivalence <type>)
- (def: = <test>))]
-
- [ Nat n/=]
- [ Int i/=]
- [ Rev r/=]
- [Frac f/=]
- )
-
-(do-template [<type> <eq> <lt> <lte> <gt> <gte>]
- [(structure: #export _ (Order <type>)
- (def: eq <eq>)
- (def: < <lt>)
- (def: <= <lte>)
- (def: > <gt>)
- (def: >= <gte>))]
-
- [ Nat Equivalence<Nat> n/< n/<= n/> n/>=]
- [ Int Equivalence<Int> i/< i/<= i/> i/>=]
- [Rev Equivalence<Rev> r/< r/<= r/> r/>=]
- [Frac Equivalence<Frac> f/< f/<= f/> f/>=]
- )
-
-(do-template [<type> <order> <succ> <pred>]
- [(structure: #export _ (Enum <type>)
- (def: order <order>)
- (def: succ <succ>)
- (def: pred <pred>))]
-
- [Nat Order<Nat> inc dec]
- [Int Order<Int> inc dec]
- [Frac Order<Frac> (f/+ ("lux frac smallest")) (f/- ("lux frac smallest"))]
- [Rev Order<Rev> inc dec]
- )
-
-(do-template [<type> <enum> <top> <bottom>]
- [(structure: #export _ (Interval <type>)
- (def: enum <enum>)
- (def: top <top>)
- (def: bottom <bottom>))]
-
- [ Nat Enum<Nat> (:coerce Nat -1) 0]
- [ Int Enum<Int> +9_223_372_036_854_775_807 -9_223_372_036_854_775_808]
- [Frac Enum<Frac> ("lux frac max") ("lux frac min")]
- [ Rev Enum<Rev> (:coerce Rev -1) (:coerce Rev 0)]
- )
-
-(structure: #export _ (Number Nat)
- (def: + n/+)
- (def: - n/-)
- (def: * n/*)
- (def: / n//)
- (def: % n/%)
- (def: (negate value) (n/- (:: Interval<Nat> top) value))
- (def: abs function.identity)
- (def: (signum x)
- (case x
- 0 0
- _ 1))
- )
-
-(do-template [<type> <order> <+> <-> <*> </> <%> <=> <<> <0> <1> <-1>]
- [(structure: #export _ (Number <type>)
- (def: + <+>)
- (def: - <->)
- (def: * <*>)
- (def: / </>)
- (def: % <%>)
- (def: negate (<*> <-1>))
- (def: (abs x)
- (if (<<> <0> x)
- (<*> <-1> x)
- x))
- (def: (signum x)
- (cond (<=> <0> x) <0>
- (<<> <0> x) <-1>
- ## else
- <1>))
- )]
-
- [ Int Order<Int> i/+ i/- i/* i// i/% i/= i/< +0 +1 -1]
- [Frac Order<Frac> f/+ f/- f/* f// f/% f/= f/< +0.0 +1.0 -1.0]
- )
-
-(structure: #export _ (Number Rev)
- (def: + r/+)
- (def: - r/-)
- (def: * r/*)
- (def: / r//)
- (def: % r/%)
- (def: (negate x) (r/- x (:coerce Rev -1)))
- (def: abs function.identity)
- (def: (signum x)
- (:coerce Rev -1)))
-
-(do-template [<name> <type> <identity> <compose>]
- [(structure: #export <name> (Monoid <type>)
- (def: identity <identity>)
- (def: compose <compose>))]
-
- [ Add@Monoid<Nat> Nat 0 n/+]
- [ Mul@Monoid<Nat> Nat 1 n/*]
- [ Max@Monoid<Nat> Nat (:: Interval<Nat> bottom) n/max]
- [ Min@Monoid<Nat> Nat (:: Interval<Nat> top) n/min]
- [ Add@Monoid<Int> Int +0 i/+]
- [ Mul@Monoid<Int> Int +1 i/*]
- [ Max@Monoid<Int> Int (:: Interval<Int> bottom) i/max]
- [ Min@Monoid<Int> Int (:: Interval<Int> top) i/min]
- [Add@Monoid<Frac> Frac +0.0 f/+]
- [Mul@Monoid<Frac> Frac +1.0 f/*]
- [Max@Monoid<Frac> Frac (:: Interval<Frac> bottom) f/max]
- [Min@Monoid<Frac> Frac (:: Interval<Frac> top) f/min]
- [ Add@Monoid<Rev> Rev (:: Interval<Rev> bottom) r/+]
- [ Mul@Monoid<Rev> Rev (:: Interval<Rev> top) r/*]
- [ Max@Monoid<Rev> Rev (:: Interval<Rev> bottom) r/max]
- [ Min@Monoid<Rev> Rev (:: Interval<Rev> top) r/min]
- )
-
-(do-template [<name> <numerator> <doc>]
- [(def: #export <name>
- {#.doc <doc>}
- Frac
- (f// +0.0 <numerator>))]
-
- [not-a-number +0.0 "Not a number."]
- [positive-infinity +1.0 "Positive infinity."]
- [negative-infinity -1.0 "Negative infinity."]
- )
-
-(def: #export (not-a-number? number)
- {#.doc "Tests whether a frac is actually not-a-number."}
- (-> Frac Bit)
- (not (f/= number number)))
-
-(def: #export (frac? value)
- (-> Frac Bit)
- (not (or (not-a-number? value)
- (f/= positive-infinity value)
- (f/= negative-infinity value))))
-
-(do-template [<type> <encoder> <decoder> <error>]
- [(structure: #export _ (Codec Text <type>)
- (def: (encode x)
- (<encoder> [x]))
-
- (def: (decode input)
- (case (<decoder> [input])
- (#.Some value)
- (#error.Success value)
-
- #.None
- (#error.Failure <error>))))]
-
- [Frac "lux frac encode" "lux frac decode" "Could not decode Frac"]
- )
-
-(def: (get-char! full idx)
- (-> Text Nat Char)
- ("lux text char" full idx))
-
-(def: (binary-character value)
- (-> Nat (Maybe Text))
- (case value
- 0 (#.Some "0")
- 1 (#.Some "1")
- _ #.None))
-
-(def: (binary-value digit)
- (-> Char (Maybe Nat))
- (case digit
- (^ (char "0")) (#.Some 0)
- (^ (char "1")) (#.Some 1)
- _ #.None))
-
-(def: (octal-character value)
- (-> Nat (Maybe Text))
- (case value
- 0 (#.Some "0")
- 1 (#.Some "1")
- 2 (#.Some "2")
- 3 (#.Some "3")
- 4 (#.Some "4")
- 5 (#.Some "5")
- 6 (#.Some "6")
- 7 (#.Some "7")
- _ #.None))
-
-(def: (octal-value digit)
- (-> Char (Maybe Nat))
- (case digit
- (^ (char "0")) (#.Some 0)
- (^ (char "1")) (#.Some 1)
- (^ (char "2")) (#.Some 2)
- (^ (char "3")) (#.Some 3)
- (^ (char "4")) (#.Some 4)
- (^ (char "5")) (#.Some 5)
- (^ (char "6")) (#.Some 6)
- (^ (char "7")) (#.Some 7)
- _ #.None))
-
-(def: (decimal-character value)
- (-> Nat (Maybe Text))
- (case value
- 0 (#.Some "0")
- 1 (#.Some "1")
- 2 (#.Some "2")
- 3 (#.Some "3")
- 4 (#.Some "4")
- 5 (#.Some "5")
- 6 (#.Some "6")
- 7 (#.Some "7")
- 8 (#.Some "8")
- 9 (#.Some "9")
- _ #.None))
-
-(def: (decimal-value digit)
- (-> Char (Maybe Nat))
- (case digit
- (^ (char "0")) (#.Some 0)
- (^ (char "1")) (#.Some 1)
- (^ (char "2")) (#.Some 2)
- (^ (char "3")) (#.Some 3)
- (^ (char "4")) (#.Some 4)
- (^ (char "5")) (#.Some 5)
- (^ (char "6")) (#.Some 6)
- (^ (char "7")) (#.Some 7)
- (^ (char "8")) (#.Some 8)
- (^ (char "9")) (#.Some 9)
- _ #.None))
-
-(def: (hexadecimal-character value)
- (-> Nat (Maybe Text))
- (case value
- 0 (#.Some "0")
- 1 (#.Some "1")
- 2 (#.Some "2")
- 3 (#.Some "3")
- 4 (#.Some "4")
- 5 (#.Some "5")
- 6 (#.Some "6")
- 7 (#.Some "7")
- 8 (#.Some "8")
- 9 (#.Some "9")
- 10 (#.Some "A")
- 11 (#.Some "B")
- 12 (#.Some "C")
- 13 (#.Some "D")
- 14 (#.Some "E")
- 15 (#.Some "F")
- _ #.None))
-
-(def: (hexadecimal-value digit)
- (-> Char (Maybe Nat))
- (case digit
- (^ (char "0")) (#.Some 0)
- (^ (char "1")) (#.Some 1)
- (^ (char "2")) (#.Some 2)
- (^ (char "3")) (#.Some 3)
- (^ (char "4")) (#.Some 4)
- (^ (char "5")) (#.Some 5)
- (^ (char "6")) (#.Some 6)
- (^ (char "7")) (#.Some 7)
- (^ (char "8")) (#.Some 8)
- (^ (char "9")) (#.Some 9)
- (^or (^ (char "a")) (^ (char "A"))) (#.Some 10)
- (^or (^ (char "b")) (^ (char "B"))) (#.Some 11)
- (^or (^ (char "c")) (^ (char "C"))) (#.Some 12)
- (^or (^ (char "d")) (^ (char "D"))) (#.Some 13)
- (^or (^ (char "e")) (^ (char "E"))) (#.Some 14)
- (^or (^ (char "f")) (^ (char "F"))) (#.Some 15)
- _ #.None))
-
-(do-template [<struct> <base> <to-character> <to-value> <error>]
- [(structure: #export <struct> (Codec Text Nat)
- (def: (encode value)
- (loop [input value
- output ""]
- (let [digit (maybe.assume (<to-character> (n/% <base> input)))
- output' ("lux text concat" digit output)
- input' (n// <base> input)]
- (if (n/= 0 input')
- output'
- (recur input' output')))))
-
- (def: (decode repr)
- (let [input-size ("lux text size" repr)]
- (if (n/> 0 input-size)
- (loop [idx 0
- output 0]
- (if (n/< input-size idx)
- (case (<to-value> (get-char! repr idx))
- #.None
- (#error.Failure ("lux text concat" <error> repr))
-
- (#.Some digit-value)
- (recur (inc idx)
- (|> output (n/* <base>) (n/+ digit-value))))
- (#error.Success output)))
- (#error.Failure ("lux text concat" <error> repr))))))]
-
- [Binary@Codec<Text,Nat> 2 binary-character binary-value "Invalid binary syntax for Nat: "]
- [Octal@Codec<Text,Nat> 8 octal-character octal-value "Invalid octal syntax for Nat: "]
- [_ 10 decimal-character decimal-value "Invalid syntax for Nat: "]
- [Hex@Codec<Text,Nat> 16 hexadecimal-character hexadecimal-value "Invalid hexadecimal syntax for Nat: "]
- )
-
-(def: (int/sign!! value)
- (-> Int Text)
- (if (i/< +0 value)
- "-"
- "+"))
-
-(def: (int/sign?? representation)
- (-> Text (Maybe Int))
- (case (get-char! representation 0)
- (^ (char "-"))
- (#.Some -1)
-
- (^ (char "+"))
- (#.Some +1)
-
- _
- #.None))
-
-(def: (int-decode-loop input-size repr sign <base> <to-value> <error>)
- (-> Nat Text Int Int (-> Char (Maybe Nat)) Text (Error Int))
- (loop [idx 1
- output +0]
- (if (n/< input-size idx)
- (case (<to-value> (get-char! repr idx))
- #.None
- (#error.Failure <error>)
-
- (#.Some digit-value)
- (recur (inc idx)
- (|> output (i/* <base>) (i/+ (.int digit-value)))))
- (#error.Success (i/* sign output)))))
-
-(do-template [<struct> <base> <to-character> <to-value> <error>]
- [(structure: #export <struct> (Codec Text Int)
- (def: (encode value)
- (if (i/= +0 value)
- "+0"
- (loop [input (|> value (i// <base>) (:: Number<Int> abs))
- output (|> value (i/% <base>) (:: Number<Int> abs) .nat
- <to-character>
- maybe.assume)]
- (if (i/= +0 input)
- ("lux text concat" (int/sign!! value) output)
- (let [digit (maybe.assume (<to-character> (.nat (i/% <base> input))))]
- (recur (i// <base> input)
- ("lux text concat" digit output)))))))
-
- (def: (decode repr)
- (let [input-size ("lux text size" repr)]
- (if (n/> 1 input-size)
- (case (int/sign?? repr)
- (#.Some sign)
- (int-decode-loop input-size repr sign <base> <to-value> <error>)
-
- #.None
- (#error.Failure <error>))
- (#error.Failure <error>)))))]
-
- [Binary@Codec<Text,Int> +2 binary-character binary-value "Invalid binary syntax for Int: "]
- [Octal@Codec<Text,Int> +8 octal-character octal-value "Invalid octal syntax for Int: "]
- [_ +10 decimal-character decimal-value "Invalid syntax for Int: "]
- [Hex@Codec<Text,Int> +16 hexadecimal-character hexadecimal-value "Invalid hexadecimal syntax for Int: "]
- )
-
-(def: (de-prefix input)
- (-> Text Text)
- ("lux text clip" input 1 ("lux text size" input)))
-
-(do-template [<struct> <nat> <char-bit-size> <error>]
- [(with-expansions [<error-output> (as-is (#error.Failure ("lux text concat" <error> repr)))]
- (structure: #export <struct> (Codec Text Rev)
- (def: (encode value)
- (let [raw-output (de-prefix (:: <nat> encode (:coerce Nat value)))
- max-num-chars (n// <char-bit-size> 64)
- raw-size ("lux text size" raw-output)
- zero-padding (loop [zeroes-left (n/- raw-size max-num-chars)
- output ""]
- (if (n/= 0 zeroes-left)
- output
- (recur (dec zeroes-left)
- ("lux text concat" "0" output))))
- padded-output ("lux text concat" zero-padding raw-output)]
- ("lux text concat" "." padded-output)))
-
- (def: (decode repr)
- (let [repr-size ("lux text size" repr)]
- (if (n/>= 2 repr-size)
- (case ("lux text char" repr 0)
- (^ (char "."))
- (case (:: <nat> decode (de-prefix repr))
- (#error.Success output)
- (#error.Success (:coerce Rev output))
-
- _
- <error-output>)
-
- _
- <error-output>)
- <error-output>)))))]
-
- [Binary@Codec<Text,Rev> Binary@Codec<Text,Nat> 1 "Invalid binary syntax: "]
- [Octal@Codec<Text,Rev> Octal@Codec<Text,Nat> 3 "Invalid octal syntax: "]
- [Hex@Codec<Text,Rev> Hex@Codec<Text,Nat> 4 "Invalid hexadecimal syntax: "]
- )
-
-(do-template [<struct> <int> <base> <char-set> <error>]
- [(structure: #export <struct> (Codec Text Frac)
- (def: (encode value)
- (let [whole (frac-to-int value)
- whole-part (:: <int> encode whole)
- decimal (:: Number<Frac> abs (f/% +1.0 value))
- decimal-part (if (f/= +0.0 decimal)
- ".0"
- (loop [dec-left decimal
- output ""]
- (if (f/= +0.0 dec-left)
- ("lux text concat" "." output)
- (let [shifted (f/* <base> dec-left)
- digit-idx (|> shifted (f/% <base>) frac-to-int .nat)]
- (recur (f/% +1.0 shifted)
- ("lux text concat" output ("lux text clip" <char-set> digit-idx (inc digit-idx))))))))]
- ("lux text concat" whole-part decimal-part)))
-
- (def: (decode repr)
- (case ("lux text index" repr "." 0)
- (#.Some split-index)
- (let [whole-part ("lux text clip" repr 0 split-index)
- decimal-part ("lux text clip" repr (inc split-index) ("lux text size" repr))]
- (case [(:: <int> decode whole-part)
- (:: <int> decode decimal-part)]
- (^multi [(#error.Success whole) (#error.Success decimal)]
- (i/>= +0 decimal))
- (let [sign (if (i/< +0 whole)
- -1.0
- +1.0)
- div-power (loop [muls-left ("lux text size" decimal-part)
- output +1.0]
- (if (n/= 0 muls-left)
- output
- (recur (dec muls-left)
- (f/* <base> output))))
- adjusted-decimal (|> decimal int-to-frac (f// div-power))
- dec-rev (case (:: Hex@Codec<Text,Rev> decode ("lux text concat" "." decimal-part))
- (#error.Success dec-rev)
- dec-rev
-
- (#error.Failure error)
- (error! error))]
- (#error.Success (f/+ (int-to-frac whole)
- (f/* sign adjusted-decimal))))
-
- _
- (#error.Failure ("lux text concat" <error> repr))))
-
- _
- (#error.Failure ("lux text concat" <error> repr)))))]
-
- [Binary@Codec<Text,Frac> Binary@Codec<Text,Int> +2.0 "01" "Invalid binary syntax: "]
- )
-
-(def: (segment-digits chunk-size digits)
- (-> Nat Text (List Text))
- (case digits
- ""
- (list)
-
- _
- (let [num-digits ("lux text size" digits)]
- (if (n/<= chunk-size num-digits)
- (list digits)
- (let [boundary (n/- chunk-size num-digits)
- chunk ("lux text clip" digits boundary num-digits)
- remaining ("lux text clip" digits 0 boundary)]
- (list& chunk (segment-digits chunk-size remaining)))))))
-
-(def: (bin-segment-to-hex input)
- (-> Text Text)
- (case input
- "0000" "0"
- "0001" "1"
- "0010" "2"
- "0011" "3"
- "0100" "4"
- "0101" "5"
- "0110" "6"
- "0111" "7"
- "1000" "8"
- "1001" "9"
- "1010" "A"
- "1011" "B"
- "1100" "C"
- "1101" "D"
- "1110" "E"
- "1111" "F"
- _ (undefined)))
-
-(def: (hex-segment-to-bin input)
- (-> Text Text)
- (case input
- "0" "0000"
- "1" "0001"
- "2" "0010"
- "3" "0011"
- "4" "0100"
- "5" "0101"
- "6" "0110"
- "7" "0111"
- "8" "1000"
- "9" "1001"
- (^or "a" "A") "1010"
- (^or "b" "B") "1011"
- (^or "c" "C") "1100"
- (^or "d" "D") "1101"
- (^or "e" "E") "1110"
- (^or "f" "F") "1111"
- _ (undefined)))
-
-(def: (bin-segment-to-octal input)
- (-> Text Text)
- (case input
- "000" "0"
- "001" "1"
- "010" "2"
- "011" "3"
- "100" "4"
- "101" "5"
- "110" "6"
- "111" "7"
- _ (undefined)))
-
-(def: (octal-segment-to-bin input)
- (-> Text Text)
- (case input
- "0" "000"
- "1" "001"
- "2" "010"
- "3" "011"
- "4" "100"
- "5" "101"
- "6" "110"
- "7" "111"
- _ (undefined)))
-
-(def: (map f xs)
- (All [a b] (-> (-> a b) (List a) (List b)))
- (case xs
- #.Nil
- #.Nil
-
- (#.Cons x xs')
- (#.Cons (f x) (map f xs'))))
-
-(def: (re-join-chunks xs)
- (-> (List Text) Text)
- (case xs
- #.Nil
- ""
-
- (#.Cons x xs')
- ("lux text concat" x (re-join-chunks xs'))))
-
-(do-template [<from> <from-translator> <to> <to-translator> <base-bits>]
- [(def: (<from> on-left? input)
- (-> Bit Text Text)
- (let [max-num-chars (n// <base-bits> 64)
- input-size ("lux text size" input)
- zero-padding (let [num-digits-that-need-padding (n/% <base-bits> input-size)]
- (if (n/= 0 num-digits-that-need-padding)
- ""
- (loop [zeroes-left (n/- num-digits-that-need-padding
- <base-bits>)
- output ""]
- (if (n/= 0 zeroes-left)
- output
- (recur (dec zeroes-left)
- ("lux text concat" "0" output))))))
- padded-input (if on-left?
- ("lux text concat" zero-padding input)
- ("lux text concat" input zero-padding))]
- (|> padded-input
- (segment-digits <base-bits>)
- (map <from-translator>)
- re-join-chunks)))
-
- (def: <to>
- (-> Text Text)
- (|>> (segment-digits 1)
- (map <to-translator>)
- re-join-chunks))]
-
- [binary-to-hex bin-segment-to-hex hex-to-binary hex-segment-to-bin 4]
- [binary-to-octal bin-segment-to-octal octal-to-binary octal-segment-to-bin 3]
- )
-
-(do-template [<struct> <error> <from> <to>]
- [(structure: #export <struct> (Codec Text Frac)
- (def: (encode value)
- (let [sign (:: Number<Frac> signum value)
- raw-bin (:: Binary@Codec<Text,Frac> encode value)
- dot-idx (maybe.assume ("lux text index" raw-bin "." 0))
- whole-part ("lux text clip" raw-bin
- (if (f/= -1.0 sign) 1 0)
- dot-idx)
- decimal-part ("lux text clip" raw-bin (inc dot-idx) ("lux text size" raw-bin))
- hex-output (|> (<from> #0 decimal-part)
- ("lux text concat" ".")
- ("lux text concat" (<from> #1 whole-part))
- ("lux text concat" (if (f/= -1.0 sign) "-" "")))]
- hex-output))
-
- (def: (decode repr)
- (let [sign (case ("lux text index" repr "-" 0)
- (#.Some 0)
- -1.0
-
- _
- +1.0)]
- (case ("lux text index" repr "." 0)
- (#.Some split-index)
- (let [whole-part ("lux text clip" repr 1 split-index)
- decimal-part ("lux text clip" repr (inc split-index) ("lux text size" repr))
- as-binary (|> (<to> decimal-part)
- ("lux text concat" ".")
- ("lux text concat" (<to> whole-part))
- ("lux text concat" (if (f/= -1.0 sign) "-" "+")))]
- (case (:: Binary@Codec<Text,Frac> decode as-binary)
- (#error.Failure _)
- (#error.Failure ("lux text concat" <error> repr))
-
- output
- output))
-
- _
- (#error.Failure ("lux text concat" <error> repr))))))]
-
- [Octal@Codec<Text,Frac> "Invalid octaladecimal syntax: " binary-to-octal octal-to-binary]
- [Hex@Codec<Text,Frac> "Invalid hexadecimal syntax: " binary-to-hex hex-to-binary]
- )
+ ["/." nat]
+ ["/." int]
+ ["/." rev]
+ ["/." frac]])
(macro: (encoding-doc tokens state)
(case tokens
@@ -725,301 +70,13 @@
_
(#error.Failure <error>)))]
- [bin Binary@Codec<Text,Nat> Binary@Codec<Text,Int> Binary@Codec<Text,Rev> Binary@Codec<Text,Frac>
+ [bin /nat.binary /int.binary /rev.binary /frac.binary
"Invalid binary syntax."
(encoding-doc "binary" (bin "+11001001") (bin "+11_00_10_01"))]
- [oct Octal@Codec<Text,Nat> Octal@Codec<Text,Int> Octal@Codec<Text,Rev> Octal@Codec<Text,Frac>
+ [oct /nat.octal /int.octal /rev.octal /frac.octal
"Invalid octal syntax."
(encoding-doc "octal" (oct "+615243") (oct "+615_243"))]
- [hex Hex@Codec<Text,Nat> Hex@Codec<Text,Int> Hex@Codec<Text,Rev> Hex@Codec<Text,Frac>
+ [hex /nat.hex /int.hex /rev.hex /frac.hex
"Invalid hexadecimal syntax."
(encoding-doc "hexadecimal" (hex "deadBEEF") (hex "dead_BEEF"))]
)
-
-## The following code allows one to encode/decode Rev numbers as text.
-## This is not a simple algorithm, and it requires subverting the Rev
-## abstraction a bit.
-## It takes into account the fact that Rev numbers are represented by
-## Lux as 64-bit integers.
-## A valid way to model them is as Lux's Nat type.
-## This is a somewhat hackish way to do things, but it allows one to
-## write the encoding/decoding algorithm once, in pure Lux, rather
-## than having to implement it on the compiler for every platform
-## targeted by Lux.
-(type: Digits (Array Nat))
-
-(def: (make-digits _)
- (-> Any Digits)
- (array.new i64.width))
-
-(def: (digits-get idx digits)
- (-> Nat Digits Nat)
- (|> digits (array.read idx) (maybe.default 0)))
-
-(def: digits-put
- (-> Nat Nat Digits Digits)
- array.write)
-
-(def: (prepend left right)
- (-> Text Text Text)
- ("lux text concat" left right))
-
-(def: (digits-times-5! idx output)
- (-> Nat Digits Digits)
- (loop [idx idx
- carry 0
- output output]
- (if (i/>= +0 (:coerce Int idx))
- (let [raw (|> (digits-get idx output)
- (n/* 5)
- (n/+ carry))]
- (recur (dec idx)
- (n// 10 raw)
- (digits-put idx (n/% 10 raw) output)))
- output)))
-
-(def: (digits-power power)
- (-> Nat Digits)
- (loop [times power
- output (|> (make-digits [])
- (digits-put power 1))]
- (if (i/>= +0 (:coerce Int times))
- (recur (dec times)
- (digits-times-5! power output))
- output)))
-
-(def: (digits-to-text digits)
- (-> Digits Text)
- (loop [idx (dec i64.width)
- all-zeroes? #1
- output ""]
- (if (i/>= +0 (:coerce Int idx))
- (let [digit (digits-get idx digits)]
- (if (and (n/= 0 digit)
- all-zeroes?)
- (recur (dec idx) #1 output)
- (recur (dec idx)
- #0
- ("lux text concat"
- (:: Codec<Text,Int> encode (:coerce Int digit))
- output))))
- (if all-zeroes?
- "0"
- output))))
-
-(def: (digits-add param subject)
- (-> Digits Digits Digits)
- (loop [idx (dec i64.width)
- carry 0
- output (make-digits [])]
- (if (i/>= +0 (:coerce Int idx))
- (let [raw ($_ n/+
- carry
- (digits-get idx param)
- (digits-get idx subject))]
- (recur (dec idx)
- (n// 10 raw)
- (digits-put idx (n/% 10 raw) output)))
- output)))
-
-(def: (text-to-digits input)
- (-> Text (Maybe Digits))
- (let [length ("lux text size" input)]
- (if (n/<= i64.width length)
- (loop [idx 0
- output (make-digits [])]
- (if (n/< length idx)
- (case ("lux text index" "+0123456789" ("lux text clip" input idx (inc idx)) 0)
- #.None
- #.None
-
- (#.Some digit)
- (recur (inc idx)
- (digits-put idx digit output)))
- (#.Some output)))
- #.None)))
-
-(def: (digits-lt param subject)
- (-> Digits Digits Bit)
- (loop [idx 0]
- (and (n/< i64.width idx)
- (let [pd (digits-get idx param)
- sd (digits-get idx subject)]
- (if (n/= pd sd)
- (recur (inc idx))
- (n/< pd sd))))))
-
-(def: (digits-sub-once! idx param subject)
- (-> Nat Nat Digits Digits)
- (let [sd (digits-get idx subject)]
- (if (n/>= param sd)
- (digits-put idx (n/- param sd) subject)
- (let [diff (|> sd
- (n/+ 10)
- (n/- param))]
- (|> subject
- (digits-put idx diff)
- (digits-sub-once! (dec idx) 1))))))
-
-(def: (digits-sub! param subject)
- (-> Digits Digits Digits)
- (loop [idx (dec i64.width)
- output subject]
- (if (i/>= +0 (.int idx))
- (recur (dec idx)
- (digits-sub-once! idx (digits-get idx param) output))
- output)))
-
-(structure: #export _ (Codec Text Rev)
- (def: (encode input)
- (let [input (:coerce Nat input)
- last-idx (dec i64.width)]
- (if (n/= 0 input)
- ".0"
- (loop [idx last-idx
- digits (make-digits [])]
- (if (i/>= +0 (:coerce Int idx))
- (if (i64.set? idx input)
- (let [digits' (digits-add (digits-power (n/- idx last-idx))
- digits)]
- (recur (dec idx)
- digits'))
- (recur (dec idx)
- digits))
- ("lux text concat" "." (digits-to-text digits))
- )))))
-
- (def: (decode input)
- (let [length ("lux text size" input)
- dotted? (case ("lux text index" input "." 0)
- (#.Some 0)
- #1
-
- _
- #0)]
- (if (and dotted?
- (n/<= (inc i64.width) length))
- (case (text-to-digits ("lux text clip" input 1 length))
- (#.Some digits)
- (loop [digits digits
- idx 0
- output 0]
- (if (n/< i64.width idx)
- (let [power (digits-power idx)]
- (if (digits-lt power digits)
- ## Skip power
- (recur digits (inc idx) output)
- (recur (digits-sub! power digits)
- (inc idx)
- (i64.set (n/- idx (dec i64.width)) output))))
- (#error.Success (:coerce Rev output))))
-
- #.None
- (#error.Failure ("lux text concat" "Wrong syntax for Rev: " input)))
- (#error.Failure ("lux text concat" "Wrong syntax for Rev: " input))))
- ))
-
-(def: (log2 input)
- (-> Frac Frac)
- (f// (math.log +2.0)
- (math.log input)))
-
-(def: double-bias Nat 1023)
-
-(def: mantissa-size Nat 52)
-(def: exponent-size Nat 11)
-
-(def: #export (frac-to-bits input)
- (-> Frac I64)
- (i64 (cond (not-a-number? input)
- (hex "7FF7FFFFFFFFFFFF")
-
- (f/= positive-infinity input)
- (hex "7FF0000000000000")
-
- (f/= negative-infinity input)
- (hex "FFF0000000000000")
-
- (f/= +0.0 input)
- (let [reciprocal (f// input +1.0)]
- (if (f/= positive-infinity reciprocal)
- ## Positive zero
- (hex "0000000000000000")
- ## Negative zero
- (hex "8000000000000000")))
-
- ## else
- (let [sign (:: Number<Frac> signum input)
- input (:: Number<Frac> abs input)
- exponent (math.floor (log2 input))
- exponent-mask (|> 1 (i64.left-shift exponent-size) dec)
- mantissa (|> input
- ## Normalize
- (f// (math.pow exponent +2.0))
- ## Make it int-equivalent
- (f/* (math.pow +52.0 +2.0)))
- sign-bit (if (f/= -1.0 sign) 1 0)
- exponent-bits (|> exponent frac-to-int .nat (n/+ double-bias) (i64.and exponent-mask))
- mantissa-bits (|> mantissa frac-to-int .nat)]
- ($_ i64.or
- (i64.left-shift 63 sign-bit)
- (i64.left-shift mantissa-size exponent-bits)
- (i64.clear mantissa-size mantissa-bits)))
- )))
-
-(do-template [<getter> <mask> <size> <offset>]
- [(def: <mask> (|> 1 (i64.left-shift <size>) dec (i64.left-shift <offset>)))
- (def: (<getter> input)
- (-> (I64 Any) I64)
- (|> input (i64.and <mask>) (i64.logical-right-shift <offset>) i64))]
-
- [mantissa mantissa-mask mantissa-size 0]
- [exponent exponent-mask exponent-size mantissa-size]
- [sign sign-mask 1 (n/+ exponent-size mantissa-size)]
- )
-
-(def: #export (bits-to-frac input)
- (-> (I64 Any) Frac)
- (let [S (sign input)
- E (exponent input)
- M (mantissa input)]
- (cond (n/= (hex "7FF") E)
- (if (n/= 0 M)
- (if (n/= 0 S)
- positive-infinity
- negative-infinity)
- not-a-number)
-
- (and (n/= 0 E) (n/= 0 M))
- (if (n/= 0 S)
- +0.0
- (f/* -1.0 +0.0))
-
- ## else
- (let [normalized (|> M (i64.set mantissa-size)
- .int int-to-frac
- (f// (math.pow +52.0 +2.0)))
- power (math.pow (|> E (n/- double-bias)
- .int int-to-frac)
- +2.0)
- shifted (f/* power
- normalized)]
- (if (n/= 0 S)
- shifted
- (f/* -1.0 shifted))))))
-
-(structure: #export _ (Hash Nat)
- (def: eq Equivalence<Nat>)
- (def: hash function.identity))
-
-(structure: #export _ (Hash Int)
- (def: eq Equivalence<Int>)
- (def: hash .nat))
-
-(structure: #export _ (Hash Frac)
- (def: eq Equivalence<Frac>)
- (def: hash frac-to-bits))
-
-(structure: #export _ (Hash Rev)
- (def: eq Equivalence<Rev>)
- (def: hash (|>> (:coerce Nat))))