(.module: [library [lux #* ["_" test (#+ Test)] ["@" target] ["." ffi] [abstract [monad (#+ do)] [\\spec ["$." equivalence] ["$." hash] ["$." order] ["$." monoid] ["$." codec]]] [data ["." bit ("#\." equivalence)]] [math ["." random (#+ Random)]]]] [\\library ["." / [// #* ["n" nat] ["i" int] ["r" rev] ["." i64]]]]) (def: random (Random Frac) (\ random.monad map (|>> (i.% +1,000,000) i.frac) random.int)) (def: constant Test (do random.monad [sample random.safe_frac] ($_ _.and (_.cover [/.biggest] (/.<= /.biggest sample)) (_.cover [/.positive_infinity] (/.< /.positive_infinity sample)) (_.cover [/.smallest] (bit\= (/.positive? sample) (/.>= /.smallest sample))) (_.cover [/.negative_infinity] (/.> /.negative_infinity sample)) (_.cover [/.not_a_number /.not_a_number?] (and (/.not_a_number? /.not_a_number) (not (or (/.= /.not_a_number sample) (/.not_a_number? sample))))) ))) (def: predicate Test (do {! random.monad} [sample ..random shift (\ ! map /.abs ..random)] ($_ _.and (_.cover [/.negative?] (bit\= (/.negative? sample) (/.< +0.0 sample))) (_.cover [/.positive?] (bit\= (/.positive? sample) (/.> +0.0 sample))) (_.cover [/.zero?] (bit\= (/.zero? sample) (/.= +0.0 sample))) (_.cover [/.approximately?] (and (/.approximately? /.smallest sample sample) (/.approximately? (/.+ +1.0 shift) sample (/.+ shift sample)))) (_.cover [/.number?] (and (not (/.number? /.not_a_number)) (not (/.number? /.positive_infinity)) (not (/.number? /.negative_infinity)) (/.number? sample))) ))) (def: conversion Test ($_ _.and (do {! random.monad} [expected (\ ! map (n.% 1,000,000) random.nat)] (_.cover [/.nat] (|> expected n.frac /.nat (n.= expected)))) (do {! random.monad} [expected (\ ! map (i.% +1,000,000) random.int)] (_.cover [/.int] (|> expected i.frac /.int (i.= expected)))) (do {! random.monad} [expected (\ ! map (|>> (i64.left_shift 52) .rev) random.nat)] (_.cover [/.rev] (|> expected r.frac /.rev (r.= expected)))) )) (def: signature Test (`` ($_ _.and (_.for [/.equivalence /.=] ($equivalence.spec /.equivalence random.safe_frac)) (_.for [/.hash] ($hash.spec /.hash random.frac)) (_.for [/.order /.<] ($order.spec /.order random.safe_frac)) (~~ (template [ ] [(_.for [ ] ($monoid.spec /.equivalence ..random))] [/.+ /.addition] [/.* /.multiplication] [/.min /.minimum] [/.max /.maximum] )) (~~ (template [] [(_.for [] ($codec.spec /.equivalence random.safe_frac))] [/.binary] [/.octal] [/.decimal] [/.hex] )) ))) (with_expansions [ (as_is (ffi.import: java/lang/Double ["#::." (#static doubleToRawLongBits [double] long) (#static longBitsToDouble [long] double)]))] (for {@.old (as_is ) @.jvm (as_is )} (as_is))) (def: #export test Test (<| (_.covering /._) (_.for [.Frac]) ($_ _.and (do random.monad [left random.safe_frac right random.safe_frac] ($_ _.and (_.cover [/.>] (bit\= (/.> left right) (/.< right left))) (_.cover [/.<= /.>=] (bit\= (/.<= left right) (/.>= right left))) )) (do random.monad [sample random.safe_frac] ($_ _.and (_.cover [/.-] (and (/.= +0.0 (/.- sample sample)) (/.= sample (/.- +0.0 sample)) (/.= (/.negate sample) (/.- sample +0.0)))) (_.cover [/./] (and (/.= +1.0 (/./ sample sample)) (/.= sample (/./ +1.0 sample)))) (_.cover [/.abs] (bit\= (/.> sample (/.abs sample)) (/.negative? sample))) (_.cover [/.signum] (/.= (/.abs sample) (/.* (/.signum sample) sample))) )) (do random.monad [left (random.filter (|>> (/.= +0.0) not) ..random) right ..random] ($_ _.and (_.cover [/.%] (let [rem (/.% left right) div (|> right (/.- rem) (/./ left))] (/.= right (|> div (/.* left) (/.+ rem))))) (_.cover [/./%] (let [[div rem] (/./% left right)] (and (/.= div (/./ left right)) (/.= rem (/.% left right))))) (_.cover [/.mod] (and (/.= (/.signum left) (/.signum (/.mod left right))) (/.= (/.signum right) (/.signum (/.% left right))) (if (/.= (/.signum left) (/.signum right)) (/.= (/.% left right) (/.mod left right)) (or (and (/.= +0.0 (/.% left right)) (/.= +0.0 (/.mod left right))) (/.= (/.+ left (/.% left right)) (/.mod left right)))))) )) (with_expansions [ ($_ _.and (let [test (: (-> Frac Bit) (function (_ value) (n.= (.nat (java/lang/Double::doubleToRawLongBits value)) (/.to_bits value))))] (do random.monad [sample random.frac] (_.cover [/.to_bits] (and (test sample) (test /.biggest) (test /.smallest) (test /.not_a_number) (test /.positive_infinity) (test /.negative_infinity))))) (do random.monad [sample random.i64] (_.cover [/.from_bits] (let [expected (java/lang/Double::longBitsToDouble sample) actual (/.from_bits sample)] (or (/.= expected actual) (and (/.not_a_number? expected) (/.not_a_number? actual)))))) )] (for {@.old @.jvm } (let [test (: (-> Frac Bit) (function (_ expected) (let [actual (|> expected /.to_bits /.from_bits)] (or (/.= expected actual) (and (/.not_a_number? expected) (/.not_a_number? actual))))))] (do random.monad [sample random.frac] (_.cover [/.to_bits /.from_bits] (and (test sample) (test /.biggest) (test /.smallest) (test /.not_a_number) (test /.positive_infinity) (test /.negative_infinity))))))) (do random.monad [expected random.safe_frac] (_.cover [/.negate] (let [subtraction! (/.= +0.0 (/.+ (/.negate expected) expected)) inverse! (|> expected /.negate /.negate (/.= expected))] (and subtraction! inverse!)))) ..constant ..predicate ..conversion ..signature )))