From 1750f350ab40b132f5940801cc09c8e28504c7b7 Mon Sep 17 00:00:00 2001 From: Sigilante Date: Thu, 11 Jun 2026 10:28:08 -0500 Subject: [PATCH 01/28] math: jet-anchor structure for @rd exp + vere jet mirror Wrap math.hoon's width doors in a %math engine DOOR under the shared %non chapter (=< math preserves the /+ math + rd:math API), mirroring /lib/lagoon's %non/%lagoon jet structure, with ~/ hints on the rd door and exp arm. The engine MUST be a door (^| =+ [rnd] ~/ %math |%): a sample-less ~/-core anchors its parent to the dashboard root, so the jet never attaches (found by tracing _cj_hot_mean in the runtime). Mirror the vere-side C jet into libmath/vere/ (jets/i/math.c + tree-registration.snippet.c + README) for hand-maintained cross-repo sync -- the runtime jets live in urbit/vere (PR to follow). Add libmath/tools/rd_exp_check.c, the SoftFloat-f64 reference proving the jet is bit-exact to the Hoon. @rd exp verified jetted (34us vs ~970us interpreted), bit-exact 0x4005.bf0a.8b14.576a. Co-Authored-By: Claude Opus 4.8 --- libmath/desk/lib/math.hoon | 7884 +++++++++-------- libmath/tools/rd_exp_check.c | 76 + libmath/vere/README.md | 59 + libmath/vere/jets/i/math.c | 108 + libmath/vere/jets/tree-registration.snippet.c | 35 + 5 files changed, 4229 insertions(+), 3933 deletions(-) create mode 100644 libmath/tools/rd_exp_check.c create mode 100644 libmath/vere/README.md create mode 100644 libmath/vere/jets/i/math.c create mode 100644 libmath/vere/jets/tree-registration.snippet.c diff --git a/libmath/desk/lib/math.hoon b/libmath/desk/lib/math.hoon index c979042..7608f11 100644 --- a/libmath/desk/lib/math.hoon +++ b/libmath/desk/lib/math.hoon @@ -3,3976 +3,3994 @@ :: :: Pure Hoon implementations of (often naive) formally correct algorithms. :: +:: This file's value is the %math engine core (via =< math below), so users +:: still write `/+ math` and `(exp:rd:math ...)` / `~(exp rd:math [%n rtol])`. +:: +:: Jet structure (mirrors /lib/lagoon's %non/%lagoon): the file |% is anchored +:: %non (`~% %non ..part ~`), and %math is its child engine CORE. The engine +:: MUST be a door (`^| =+ [rnd] ~/ %math |%`), not a bare |% -- a sample-less +:: ~/-core anchors its parent to the dashboard root, so the jets never attach. +:: See vere pkg/noun/jets/i/math.c + the _13x_non__math_* blocks in tree.c. +=< math +~% %non ..part ~ |% -++ rs +++ math ^| - |_ $: r=$?(%n %u %d %z) :: round nearest, up, down, to zero - rtol=_.1e-5 :: relative tolerance for precision of operations - == - :: mathematics constants to single precision - :: +tau: @rs - :: - :: Returns the value 2*pi (OEIS A019692). - :: Examples - :: > tau - :: .6.2831855 - :: Source - ++ tau .6.2831855 - :: +pi: @rs - :: - :: Returns the value pi (OEIS A000796). - :: Examples - :: > pi - :: .3.1415927 - :: Source - ++ pi .3.1415927 - :: +e: @rs - :: - :: Returns the value e (Euler's constant) (OEIS A001113). - :: Examples - :: > e - :: .2.7182817 - :: Source - ++ e .2.7182817 - :: +phi: @rs - :: - :: Returns the value phi (golden ratio) (OEIS A001622). - :: Examples - :: > phi - :: .1.618034 - :: Source - ++ phi .1.618034 - :: +sqt2: @rs - :: - :: Returns the value sqrt(2) (OEIS A002193). - :: Examples - :: > sqt2 - :: .1.4142135 - :: Source - ++ sqt2 .1.4142135 - :: +invsqt2: @rs - :: - :: Returns the value 1/sqrt(2) (OEIS A010503). - :: Examples - :: > invsqt2 - :: .70710677 - :: Source - ++ invsqt2 .70710677 - :: +log2: @rs - :: - :: Returns the value log(2) (OEIS A002162). - :: Examples - :: > log2 - :: .6931472 - :: Source - ++ log2 .0.6931472 - :: +invlog2: @rs - :: - :: Returns the value 1/log(2). - :: Examples - :: > invlog2 - :: 1.442695 - :: Source - ++ invlog2 .1.442695 - :: +log10: @rs - :: - :: Returns the value log(10) (OEIS A002392). - :: Examples - :: > log10 - :: .2.3025851 - :: Source - ++ log10 .2.3025851 - :: +huge: @rs - :: - :: Returns the value of the largest representable number. - :: Examples - :: > huge - :: .3.4028235e+38 - :: Source - ++ huge `@rs`0x7f80.0000 :: 3.40282346638528859812e+38 - :: +tiny: @rs - :: - :: Returns the smallest representable positive (subnormal) number, 2^-149. - :: (Not the smallest NORMAL, which is 2^-126 = .1.1754944e-38.) - :: Examples - :: > tiny - :: .1e-45 - :: Source - ++ tiny `@rs`0x1 :: 1.40129846432481707092e-45 - :: - :: Operations - :: - :: +sea: @rs -> fn - :: - :: Returns the +$fn representation of a floating-point atom. - :: Examples - :: > (sea .1) - :: [%f s=%.y e=-23 a=8.388.608] - :: > (sea .1.1) - :: [%f s=%.y e=-23 a=9.227.469] - :: Source - ++ sea sea:^rs - :: +bit: fn -> @rs - :: - :: Returns the floating-point atom of a +$fn representation. - :: Examples - :: > (bit [%f s=%.y e=-23 a=8.388.608]) - :: .1 - :: > (bit [%f s=%.y e=-23 a=9.227.469]) - :: .1.1 - :: Source - ++ bit bit:^rs - :: +sun: @ud -> @rs - :: - :: Returns the floating-point atom of an unsigned integer atom. - :: Examples - :: > (sun 1) - :: .1 - :: > (sun 1.000) - :: .1e3 - :: Source - ++ sun sun:^rs - :: +san: @sd -> @rs - :: - :: Returns the floating-point atom of a signed integer atom. - :: Examples - :: > (san --1) - :: .1 - :: > (san -1) - :: .-1 - :: Source - ++ san san:^rs - ::++ exp exp:^rs :: no pass-through because of exp function - :: +toi: @rs -> @sd - :: - :: Returns the unitized signed integer atom of a rounded floating-point atom. - :: Examples - :: > (toi .1) - :: [~ --1] - :: > (toi .1.1) - :: [~ --1] - :: Source - ++ toi toi:^rs - :: +drg: @rs -> dn - :: - :: Returns the decimal form of a floating-point atom using the Dragon4 - :: algorithm. - :: Examples - :: > (drg .1) - :: [%d s=%.y e=--0 a=1] - :: > (drg .1.1) - :: [%d s=%.y e=-1 a=11] - :: Source - ++ drg drg:^rs - :: +grd: dn -> @rs - :: - :: Returns the floating-point atom of a decimal form. - :: Examples - :: > (grd [%d s=%.y e=--0 a=1]) - :: .1 - :: > (grd [%d s=%.y e=-1 a=11]) - :: .1.1 - :: Source - ++ grd grd:^rs - :: - :: Comparison - :: - :: +lth: [@rs @rs] -> ? - :: - :: Returns the comparison of two floating-point atoms, less than. - :: Examples - :: > (lth .1 .2) - :: %.y - :: > (lth .2 .1) - :: %.n - :: > (lth .1 .1) - :: %.n - :: Source - ++ lth lth:^rs - :: +lte: [@rs @rs] -> ? - :: - :: Returns the comparison of two floating-point atoms, less than or equal to. - :: Examples - :: > (lte .1 .2) - :: %.y - :: > (lte .2 .1) - :: %.n - :: > (lte .1 .1) - :: %.y - :: Source - ++ lte lte:^rs - :: +leq: [@rs @rs] -> ? - :: - :: Returns the comparison of two floating-point atoms, less than or equal to. - :: Alias for +lte. - :: Examples - :: > (leq .1 .2) - :: %.y - :: > (leq .2 .1) - :: %.n - :: > (leq .1 .1) - :: %.y - :: Source - ++ leq lte:^rs - :: +equ: [@rs @rs] -> ? - :: - :: Returns the comparison of two floating-point atoms, equal to. - :: Examples - :: > (equ .1 .2) - :: %.n - :: > (equ .2 .1) - :: %.n - :: > (equ .1 .1) - :: %.y - :: Source - ++ equ equ:^rs - :: +gth: [@rs @rs] -> ? - :: - :: Returns the comparison of two floating-point atoms, greater than. - :: Examples - :: > (gth .1 .2) - :: %.n - :: > (gth .2 .1) - :: %.y - :: > (gth .1 .1) - :: %.n - :: Source - ++ gth gth:^rs - :: +gte: [@rs @rs] -> ? - :: - :: Returns the comparison of two floating-point atoms, greater than or equal to. - :: Examples - :: > (gte .1 .2) - :: %.n - :: > (gte .2 .1) - :: %.y - :: > (gte .1 .1) - :: %.y - :: Source - ++ gte gte:^rs - :: +geq: [@rs @rs] -> ? - :: - :: Returns the comparison of two floating-point atoms, greater than or equal to. - :: Alias for +gte. - :: Examples - :: > (geq .1 .2) - :: %.n - :: > (geq .2 .1) - :: %.y - :: > (geq .1 .1) - :: %.y - :: Source - ++ geq gte:^rs - :: +neq: [@rs @rs] -> ? - :: - :: Returns the comparison of two floating-point atoms, not equal to. - :: Examples - :: > (neq .1 .2) - :: %.y - :: > (neq .2 .1) - :: %.y - :: > (neq .1 .1) - :: %.n - :: Source - ++ neq |=([a=@rs b=@rs] ^-(? !(equ:^rs a b))) - :: +is-close: [@rs @rs] -> ? - :: - :: Returns the comparison of two floating-point atoms, within a relative - :: tolerance (provided by the +rs door). - :: Examples - :: > (is-close .1 .2) - :: %.n - :: > (is-close .1 .1000001) - :: %.y - :: > (~(is-close rs [%z .1e-8]) .1 .1000001) - :: %.n - :: Source - ++ is-close - |= [p=@rs r=@rs] - (lth (abs (sub p r)) rtol) - :: +all-close: [@rs (list @rs)] -> ? - :: - :: Returns the comparison of a floating-point atom to a list of floating- - :: point atoms, within a relative tolerance (provided by the +rs door). - :: Examples - :: > (all-close .1 ~[.1 .2]) - :: %.n - :: > (all-close .1 ~[.1 .1.000001]) - :: %.y - :: > (~(all-close rs [%z .1e-8]) .1 ~[.1 .1000001]) - :: %.n - :: Source - ++ all-close - |= [p=@rs q=(list @rs)] - =/ i 0 - =/ n (lent q) - |- ^- ? - ?: =(n i) - %.y - ?. (is-close p (snag i q)) - %.n - $(i +(i)) - :: +is-int: @rs -> ? - :: - :: Returns whether a floating-point value is an integer (no fractional part). - :: Examples - :: > (is-int .1) - :: %.y - :: > (is-int .1.1) - :: %.n - :: Source - ++ is-int - |= x=@rs ^- ? - (equ x (san (need (toi x)))) - :: - :: Algebraic - :: - :: +add: [@rs @rs] -> @rs - :: - :: Returns the sum of two floating-point atoms. - :: Examples - :: > (add .1 .2) - :: .3 - :: Source - ++ add add:^rs - :: +sub: [@rs @rs] -> @rs - :: - :: Returns the difference of two floating-point atoms. - :: Examples - :: > (sub .1 .2) - :: .-1 - :: Source - ++ sub sub:^rs - :: +mul: [@rs @rs] -> @rs - :: - :: Returns the product of two floating-point atoms. - :: Examples - :: > (mul .1 .2) - :: .2 - :: > (mul .2 .3) - :: .6 - :: Source - ++ mul mul:^rs - :: +div: [@rs @rs] -> @rs - :: - :: Returns the quotient of two floating-point atoms. - :: Examples - :: > (div .1 .2) - :: .0.5 - :: Source - ++ div div:^rs - :: +mod: [@rs @rs] -> @rs - :: - :: Returns the modulus of two floating-point atoms. - :: Examples - :: > (mod .1 .2) - :: .1 - :: > (mod .100 .8) - :: .4 - :: Source - ++ mod - |= [a=@rs b=@rs] ^- @rs - ?: (lth a .0) - (sub b (mod (neg a) b)) - (sub a (mul b (san (need (toi (div a b)))))) :: a - b * floor(a / b) - :: +fma: [@rs @rs @rs] -> @rs - :: - :: Returns the fused multiply-add of three floating-point atoms. - :: Examples - :: > (fma .1 .2 .3) - :: .5 - :: > (fma .2 .3 .4) - :: .10 - :: Source - ++ fma fma:^rs - :: +sig: @rs -> ? - :: - :: Returns the sign of a floating-point atom. - :: Examples - :: > (sig .1) - :: %.y - :: > (sig .-1) - :: %.n - :: Source - ++ sig |=(x=@rs =(0 (rsh [0 31] x))) - :: +sgn: @rs -> ? - :: - :: Returns the sign of a floating-point atom. - :: Alias for +sig. - :: Examples - :: > (sgn .1) - :: %.y - :: > (sgn .-1) - :: %.n - :: Source - ++ sgn sig - :: +neg: @rs -> @rs - :: - :: Returns the negation of a floating-point atom. - :: Examples - :: > (neg .1) - :: .-1 - :: > (neg .-1) - :: .1 - :: Source - ++ neg |=(x=@rs (sub .0 x)) - :: +factorial: @rs -> @rs - :: - :: Returns the factorial of a floating-point atom. Assumes integer input. - :: Examples - :: > (factorial .1) - :: .1 - :: > (factorial .2) - :: .2 - :: > (factorial .3) - :: .6 - :: Source - ++ factorial - |= x=@rs ^- @rs - ?> (gte x .0) - =/ t=@rs .1 - ?: (is-close x .0) - t - |- ^- @rs - ?: (is-close x .1) - t - $(x (sub x .1), t (mul t x)) - :: +abs: @rs -> @rs - :: - :: Returns the absolute value of a floating-point atom. - :: Examples - :: > (abs .1) - :: .1 - :: > (abs .-1) - :: .1 - :: Source - ++ abs - |= x=@rs ^- @rs - ?:((sgn x) x (neg x)) - :: +exp: @rs -> @rs - :: - :: Returns the exponential of a floating-point atom. - :: Examples - :: > (exp .1) - :: .2.7182808 - :: > (exp .2) - :: .7.389052 - :: > (~(exp rs [%z .1e-8]) .2) - :: .7.389053 - :: > (exp .inf) - :: .inf - :: Source - ++ exp - |= x=@rs ^- @rs - :: Chebyshev: x = k*ln2 + r (Cody-Waite reduction); exp(x) = 2^k * P(r), - :: P a degree-6 minimax polynomial faithful to <=1 ULP. Internals are - :: forced to round-nearest-even: a correctly-rounded transcendental does - :: not take a rounding-mode axis (and the SoftFloat jet will match this). - :: +scale2 is a correctly-rounded ldexp that stays exact across the normal - :: range and rounds exactly once into the overflow/subnormal tails. - =/ pow2 |=(j=@s `@rs`(lsh [0 23] (abs:si (sum:si j --127)))) - =/ scale2 - |= [p=@rs k=@s] ^- @rs - ?: (syn:si (dif:si k --128)) :: k>127: (p*2^127)*2^(k-127) - (~(mul ^rs %n) (~(mul ^rs %n) p (pow2 --127)) (pow2 (dif:si k --127))) - ?: !(syn:si (sum:si k --126)) :: k<-126: (p*2^(k+24))*2^-24 - (~(mul ^rs %n) (~(mul ^rs %n) p (pow2 (sum:si k --24))) (pow2 -24)) - (~(mul ^rs %n) p (pow2 k)) - ?: !(~(equ ^rs %n) x x) `@rs`0x7fc0.0000 :: exp(NaN) -> NaN - ?: =(x `@rs`0x7f80.0000) `@rs`0x7f80.0000 :: exp(+inf) -> inf - ?: =(x `@rs`0xff80.0000) `@rs`0x0 :: exp(-inf) -> 0 - =/ log2e `@rs`0x3fb8.aa3b - =/ ln2hi `@rs`0x3f31.7200 - =/ ln2lo `@rs`0x35bf.be8e - =/ k=@s (need (~(toi ^rs %n) (~(mul ^rs %n) x log2e))) - ?: (syn:si (dif:si k --129)) `@rs`0x7f80.0000 :: overflow -> inf - ?: !(syn:si (sum:si k --150)) `@rs`0x0 :: underflow -> 0 - =/ ka (~(sun ^rs %n) (abs:si k)) - =/ kf ?:((syn:si k) ka (~(sub ^rs %n) .0 ka)) :: k as @rs - =/ r - %- ~(sub ^rs %n) - :- (~(sub ^rs %n) x (~(mul ^rs %n) kf ln2hi)) - (~(mul ^rs %n) kf ln2lo) - =/ cs=(list @rs) - :~ `@rs`0x3f80.0000 `@rs`0x3f80.0000 `@rs`0x3f00.0000 - `@rs`0x3e2a.aa02 `@rs`0x3d2a.aa56 `@rs`0x3c09.37d3 - `@rs`0x3ab6.ba99 - == - =/ p (roll (flop cs) |=([c=@rs acc=@rs] (~(add ^rs %n) (~(mul ^rs %n) acc r) c))) - (scale2 p k) - :: +sin: @rs -> @rs - :: - :: Returns the sine of a floating-point atom. - :: Examples - :: > (sin .1) - :: .0.84147096 - :: > (sin .2) - :: .0.9092974 - :: > (sin pi) - :: .3.1609193e-7 - :: Source - ++ sin - |= x=@rs ^- @rs - :: Reduce x = q*(pi/2) + (rhi+rlo) with a 3-part pi/2 (f32 needs the bits), - :: then fdlibm sin/cos kernels picked by q&3. Faithful to <=1 ULP for - :: |x| <~ 500. Round-nearest-even internally (the SoftFloat jet matches). - ?: !(~(equ ^rs %n) x x) `@rs`0x7fc0.0000 :: NaN - ?: |(=(x `@rs`0x7f80.0000) =(x `@rs`0xff80.0000)) `@rs`0x7fc0.0000 :: +-inf - ?: |(=(x `@rs`0x0) =(x `@rs`0x8000.0000)) x :: +-0 -> +-0 - %- trig-fin:rs-trig - [%.y `@rs`(dis x 0x7fff.ffff) (rsh [0 31] x)] - :: +cos: @rs -> @rs - :: - :: Returns the cosine of a floating-point atom. - :: Examples - :: > (cos .1) - :: .0.5403022 - :: > (cos .2) - :: .-0.41614664 - :: > (cos pi) - :: .-0.9999998 - :: Source - ++ cos - |= x=@rs ^- @rs - ?: !(~(equ ^rs %n) x x) `@rs`0x7fc0.0000 - ?: |(=(x `@rs`0x7f80.0000) =(x `@rs`0xff80.0000)) `@rs`0x7fc0.0000 - %- trig-fin:rs-trig - [%.n `@rs`(dis x 0x7fff.ffff) 0] - :: +rs-trig: shared sin/cos engine for the @rs door (see +sin / +cos). - ++ rs-trig - |% - ++ sc ^-((list @rs) :~(`@rs`0xbe2a.aaab `@rs`0x3c08.8889 `@rs`0xb950.0d01 `@rs`0x3638.ef1d `@rs`0xb2d7.322b)) - ++ cc ^-((list @rs) :~(`@rs`0x3d2a.aaab `@rs`0xbab6.0b61 `@rs`0x37d0.0d01 `@rs`0xb493.f27e `@rs`0x310f.76c7)) - ++ neg |=(a=@rs ^-(@rs (~(sub ^rs %n) `@rs`0x0 a))) - ++ ksin - |= [xx=@rs yy=@rs] ^- @rs - =/ z (~(mul ^rs %n) xx xx) - =/ r (roll (flop (tail sc)) |=([c=@rs a=@rs] (~(add ^rs %n) (~(mul ^rs %n) a z) c))) - =/ v (~(mul ^rs %n) z xx) - =/ aa (~(sub ^rs %n) (~(mul ^rs %n) `@rs`0x3f00.0000 yy) (~(mul ^rs %n) v r)) - =/ bb (~(sub ^rs %n) (~(mul ^rs %n) z aa) yy) - =/ dd (~(sub ^rs %n) bb (~(mul ^rs %n) v (head sc))) - (~(sub ^rs %n) xx dd) - ++ kcos - |= [xx=@rs yy=@rs] ^- @rs - =/ z (~(mul ^rs %n) xx xx) - =/ rc (roll (flop cc) |=([c=@rs a=@rs] (~(add ^rs %n) (~(mul ^rs %n) a z) c))) - =/ hz (~(mul ^rs %n) `@rs`0x3f00.0000 z) - =/ w2 (~(sub ^rs %n) `@rs`0x3f80.0000 hz) - =/ aa (~(sub ^rs %n) (~(sub ^rs %n) `@rs`0x3f80.0000 w2) hz) - =/ bb (~(sub ^rs %n) (~(mul ^rs %n) (~(mul ^rs %n) z z) rc) (~(mul ^rs %n) xx yy)) - (~(add ^rs %n) w2 (~(add ^rs %n) aa bb)) - :: +trig-fin: [is-sin? |x| sign-bit] -> sin x (is-sin?) or cos x - ++ trig-fin - |= [s=? ax=@rs sb=@] ^- @rs - =/ q (need (~(toi ^rs %n) (~(mul ^rs %n) ax `@rs`0x3f22.f983))) - =/ qf (~(sun ^rs %n) (abs:si q)) - =/ r1 (~(sub ^rs %n) ax (~(mul ^rs %n) qf `@rs`0x3fc9.0000)) - =/ r2 (~(sub ^rs %n) r1 (~(mul ^rs %n) qf `@rs`0x39fd.a000)) - =/ w (~(mul ^rs %n) qf `@rs`0x33a2.2169) - =/ rhi (~(sub ^rs %n) r2 w) - =/ rlo (~(sub ^rs %n) (~(sub ^rs %n) r2 rhi) w) - =/ m (dis (abs:si q) 3) - =/ ks (ksin rhi rlo) - =/ kc (kcos rhi rlo) - ?: s - =/ v ?:(=(m 0) ks ?:(=(m 1) kc ?:(=(m 2) (neg ks) (neg kc)))) - ?:(=(sb 1) (neg v) v) - ?:(=(m 0) kc ?:(=(m 1) (neg ks) ?:(=(m 2) (neg kc) ks))) - -- - :: +tan: @rs -> @rs - :: - :: Returns the tangent of a floating-point atom. - :: Examples - :: > (tan .1) - :: .1.5574079 - :: > (tan .2) - :: .-2.1850407 - :: > (tan pi) - :: .-7.0094916e-7 - :: Source - ++ tan - |= x=@rs ^- @rs - (div (sin x) (cos x)) - :: +asin: @rs -> @rs - :: - :: Returns the inverse sine of a floating-point atom. - :: Examples - :: > (asin .0) - :: .0 - :: > (asin .1) - :: .1.5707964 - :: > (asin .0.7) - :: .0.7753969 - :: - ++ asin - :: fdlibm rational kernel; see +rs-ainv. Faithful to <=1 ULP; |x|>1 -> NaN. - |= x=@rs ^- @rs - (asn:rs-ainv x) - :: +acos: @rs -> @rs - :: - :: Returns the inverse cosine of a floating-point atom. - :: Examples - :: > (acos .0) - :: .1.5707964 - :: > (acos .1) - :: .0 - :: > (acos .0.7) - :: .0.7953982 - :: - ++ acos - |= x=@rs ^- @rs - (acs:rs-ainv x) - :: +rs-ainv: shared asin/acos engine for the @rs door (rational P/Q kernel), - :: see +asin / +acos. - ++ rs-ainv - |% - ++ rr - |= t=@rs ^- @rs - =/ ps=(list @rs) :~(`@rs`0x3e2a.aa75 `@rs`0xbd2f.13ba `@rs`0xbc0d.d36b) - =/ p (~(mul ^rs %n) t (roll (flop ps) |=([c=@rs a=@rs] (~(add ^rs %n) (~(mul ^rs %n) a t) c)))) - =/ q (~(add ^rs %n) `@rs`0x3f80.0000 (~(mul ^rs %n) t `@rs`0xbf34.e5ae)) - (~(div ^rs %n) p q) - ++ asn + =+ [rnd=*?(%n %u %d %z)] + ~/ %math + |% + ++ rs + ^| + |_ $: r=$?(%n %u %d %z) :: round nearest, up, down, to zero + rtol=_.1e-5 :: relative tolerance for precision of operations + == + :: mathematics constants to single precision + :: +tau: @rs + :: + :: Returns the value 2*pi (OEIS A019692). + :: Examples + :: > tau + :: .6.2831855 + :: Source + ++ tau .6.2831855 + :: +pi: @rs + :: + :: Returns the value pi (OEIS A000796). + :: Examples + :: > pi + :: .3.1415927 + :: Source + ++ pi .3.1415927 + :: +e: @rs + :: + :: Returns the value e (Euler's constant) (OEIS A001113). + :: Examples + :: > e + :: .2.7182817 + :: Source + ++ e .2.7182817 + :: +phi: @rs + :: + :: Returns the value phi (golden ratio) (OEIS A001622). + :: Examples + :: > phi + :: .1.618034 + :: Source + ++ phi .1.618034 + :: +sqt2: @rs + :: + :: Returns the value sqrt(2) (OEIS A002193). + :: Examples + :: > sqt2 + :: .1.4142135 + :: Source + ++ sqt2 .1.4142135 + :: +invsqt2: @rs + :: + :: Returns the value 1/sqrt(2) (OEIS A010503). + :: Examples + :: > invsqt2 + :: .70710677 + :: Source + ++ invsqt2 .70710677 + :: +log2: @rs + :: + :: Returns the value log(2) (OEIS A002162). + :: Examples + :: > log2 + :: .6931472 + :: Source + ++ log2 .0.6931472 + :: +invlog2: @rs + :: + :: Returns the value 1/log(2). + :: Examples + :: > invlog2 + :: 1.442695 + :: Source + ++ invlog2 .1.442695 + :: +log10: @rs + :: + :: Returns the value log(10) (OEIS A002392). + :: Examples + :: > log10 + :: .2.3025851 + :: Source + ++ log10 .2.3025851 + :: +huge: @rs + :: + :: Returns the value of the largest representable number. + :: Examples + :: > huge + :: .3.4028235e+38 + :: Source + ++ huge `@rs`0x7f80.0000 :: 3.40282346638528859812e+38 + :: +tiny: @rs + :: + :: Returns the smallest representable positive (subnormal) number, 2^-149. + :: (Not the smallest NORMAL, which is 2^-126 = .1.1754944e-38.) + :: Examples + :: > tiny + :: .1e-45 + :: Source + ++ tiny `@rs`0x1 :: 1.40129846432481707092e-45 + :: + :: Operations + :: + :: +sea: @rs -> fn + :: + :: Returns the +$fn representation of a floating-point atom. + :: Examples + :: > (sea .1) + :: [%f s=%.y e=-23 a=8.388.608] + :: > (sea .1.1) + :: [%f s=%.y e=-23 a=9.227.469] + :: Source + ++ sea sea:^rs + :: +bit: fn -> @rs + :: + :: Returns the floating-point atom of a +$fn representation. + :: Examples + :: > (bit [%f s=%.y e=-23 a=8.388.608]) + :: .1 + :: > (bit [%f s=%.y e=-23 a=9.227.469]) + :: .1.1 + :: Source + ++ bit bit:^rs + :: +sun: @ud -> @rs + :: + :: Returns the floating-point atom of an unsigned integer atom. + :: Examples + :: > (sun 1) + :: .1 + :: > (sun 1.000) + :: .1e3 + :: Source + ++ sun sun:^rs + :: +san: @sd -> @rs + :: + :: Returns the floating-point atom of a signed integer atom. + :: Examples + :: > (san --1) + :: .1 + :: > (san -1) + :: .-1 + :: Source + ++ san san:^rs + ::++ exp exp:^rs :: no pass-through because of exp function + :: +toi: @rs -> @sd + :: + :: Returns the unitized signed integer atom of a rounded floating-point atom. + :: Examples + :: > (toi .1) + :: [~ --1] + :: > (toi .1.1) + :: [~ --1] + :: Source + ++ toi toi:^rs + :: +drg: @rs -> dn + :: + :: Returns the decimal form of a floating-point atom using the Dragon4 + :: algorithm. + :: Examples + :: > (drg .1) + :: [%d s=%.y e=--0 a=1] + :: > (drg .1.1) + :: [%d s=%.y e=-1 a=11] + :: Source + ++ drg drg:^rs + :: +grd: dn -> @rs + :: + :: Returns the floating-point atom of a decimal form. + :: Examples + :: > (grd [%d s=%.y e=--0 a=1]) + :: .1 + :: > (grd [%d s=%.y e=-1 a=11]) + :: .1.1 + :: Source + ++ grd grd:^rs + :: + :: Comparison + :: + :: +lth: [@rs @rs] -> ? + :: + :: Returns the comparison of two floating-point atoms, less than. + :: Examples + :: > (lth .1 .2) + :: %.y + :: > (lth .2 .1) + :: %.n + :: > (lth .1 .1) + :: %.n + :: Source + ++ lth lth:^rs + :: +lte: [@rs @rs] -> ? + :: + :: Returns the comparison of two floating-point atoms, less than or equal to. + :: Examples + :: > (lte .1 .2) + :: %.y + :: > (lte .2 .1) + :: %.n + :: > (lte .1 .1) + :: %.y + :: Source + ++ lte lte:^rs + :: +leq: [@rs @rs] -> ? + :: + :: Returns the comparison of two floating-point atoms, less than or equal to. + :: Alias for +lte. + :: Examples + :: > (leq .1 .2) + :: %.y + :: > (leq .2 .1) + :: %.n + :: > (leq .1 .1) + :: %.y + :: Source + ++ leq lte:^rs + :: +equ: [@rs @rs] -> ? + :: + :: Returns the comparison of two floating-point atoms, equal to. + :: Examples + :: > (equ .1 .2) + :: %.n + :: > (equ .2 .1) + :: %.n + :: > (equ .1 .1) + :: %.y + :: Source + ++ equ equ:^rs + :: +gth: [@rs @rs] -> ? + :: + :: Returns the comparison of two floating-point atoms, greater than. + :: Examples + :: > (gth .1 .2) + :: %.n + :: > (gth .2 .1) + :: %.y + :: > (gth .1 .1) + :: %.n + :: Source + ++ gth gth:^rs + :: +gte: [@rs @rs] -> ? + :: + :: Returns the comparison of two floating-point atoms, greater than or equal to. + :: Examples + :: > (gte .1 .2) + :: %.n + :: > (gte .2 .1) + :: %.y + :: > (gte .1 .1) + :: %.y + :: Source + ++ gte gte:^rs + :: +geq: [@rs @rs] -> ? + :: + :: Returns the comparison of two floating-point atoms, greater than or equal to. + :: Alias for +gte. + :: Examples + :: > (geq .1 .2) + :: %.n + :: > (geq .2 .1) + :: %.y + :: > (geq .1 .1) + :: %.y + :: Source + ++ geq gte:^rs + :: +neq: [@rs @rs] -> ? + :: + :: Returns the comparison of two floating-point atoms, not equal to. + :: Examples + :: > (neq .1 .2) + :: %.y + :: > (neq .2 .1) + :: %.y + :: > (neq .1 .1) + :: %.n + :: Source + ++ neq |=([a=@rs b=@rs] ^-(? !(equ:^rs a b))) + :: +is-close: [@rs @rs] -> ? + :: + :: Returns the comparison of two floating-point atoms, within a relative + :: tolerance (provided by the +rs door). + :: Examples + :: > (is-close .1 .2) + :: %.n + :: > (is-close .1 .1000001) + :: %.y + :: > (~(is-close rs [%z .1e-8]) .1 .1000001) + :: %.n + :: Source + ++ is-close + |= [p=@rs r=@rs] + (lth (abs (sub p r)) rtol) + :: +all-close: [@rs (list @rs)] -> ? + :: + :: Returns the comparison of a floating-point atom to a list of floating- + :: point atoms, within a relative tolerance (provided by the +rs door). + :: Examples + :: > (all-close .1 ~[.1 .2]) + :: %.n + :: > (all-close .1 ~[.1 .1.000001]) + :: %.y + :: > (~(all-close rs [%z .1e-8]) .1 ~[.1 .1000001]) + :: %.n + :: Source + ++ all-close + |= [p=@rs q=(list @rs)] + =/ i 0 + =/ n (lent q) + |- ^- ? + ?: =(n i) + %.y + ?. (is-close p (snag i q)) + %.n + $(i +(i)) + :: +is-int: @rs -> ? + :: + :: Returns whether a floating-point value is an integer (no fractional part). + :: Examples + :: > (is-int .1) + :: %.y + :: > (is-int .1.1) + :: %.n + :: Source + ++ is-int + |= x=@rs ^- ? + (equ x (san (need (toi x)))) + :: + :: Algebraic + :: + :: +add: [@rs @rs] -> @rs + :: + :: Returns the sum of two floating-point atoms. + :: Examples + :: > (add .1 .2) + :: .3 + :: Source + ++ add add:^rs + :: +sub: [@rs @rs] -> @rs + :: + :: Returns the difference of two floating-point atoms. + :: Examples + :: > (sub .1 .2) + :: .-1 + :: Source + ++ sub sub:^rs + :: +mul: [@rs @rs] -> @rs + :: + :: Returns the product of two floating-point atoms. + :: Examples + :: > (mul .1 .2) + :: .2 + :: > (mul .2 .3) + :: .6 + :: Source + ++ mul mul:^rs + :: +div: [@rs @rs] -> @rs + :: + :: Returns the quotient of two floating-point atoms. + :: Examples + :: > (div .1 .2) + :: .0.5 + :: Source + ++ div div:^rs + :: +mod: [@rs @rs] -> @rs + :: + :: Returns the modulus of two floating-point atoms. + :: Examples + :: > (mod .1 .2) + :: .1 + :: > (mod .100 .8) + :: .4 + :: Source + ++ mod + |= [a=@rs b=@rs] ^- @rs + ?: (lth a .0) + (sub b (mod (neg a) b)) + (sub a (mul b (san (need (toi (div a b)))))) :: a - b * floor(a / b) + :: +fma: [@rs @rs @rs] -> @rs + :: + :: Returns the fused multiply-add of three floating-point atoms. + :: Examples + :: > (fma .1 .2 .3) + :: .5 + :: > (fma .2 .3 .4) + :: .10 + :: Source + ++ fma fma:^rs + :: +sig: @rs -> ? + :: + :: Returns the sign of a floating-point atom. + :: Examples + :: > (sig .1) + :: %.y + :: > (sig .-1) + :: %.n + :: Source + ++ sig |=(x=@rs =(0 (rsh [0 31] x))) + :: +sgn: @rs -> ? + :: + :: Returns the sign of a floating-point atom. + :: Alias for +sig. + :: Examples + :: > (sgn .1) + :: %.y + :: > (sgn .-1) + :: %.n + :: Source + ++ sgn sig + :: +neg: @rs -> @rs + :: + :: Returns the negation of a floating-point atom. + :: Examples + :: > (neg .1) + :: .-1 + :: > (neg .-1) + :: .1 + :: Source + ++ neg |=(x=@rs (sub .0 x)) + :: +factorial: @rs -> @rs + :: + :: Returns the factorial of a floating-point atom. Assumes integer input. + :: Examples + :: > (factorial .1) + :: .1 + :: > (factorial .2) + :: .2 + :: > (factorial .3) + :: .6 + :: Source + ++ factorial |= x=@rs ^- @rs - ?: !(~(equ ^rs %n) x x) `@rs`0x7fc0.0000 - =/ sgn (rsh [0 31] x) - =/ ax `@rs`(dis x 0x7fff.ffff) - ?: (~(gth ^rs %n) ax `@rs`0x3f80.0000) `@rs`0x7fc0.0000 - ?: =(ax `@rs`0x3f80.0000) - (~(add ^rs %n) (~(mul ^rs %n) x `@rs`0x3fc9.0fdb) (~(mul ^rs %n) x `@rs`0xb33b.bd2e)) - ?: (~(lth ^rs %n) ax `@rs`0x3f00.0000) - ?: (~(lth ^rs %n) ax `@rs`0x3980.0000) x - (~(add ^rs %n) x (~(mul ^rs %n) x (rr (~(mul ^rs %n) x x)))) - =/ w (~(sub ^rs %n) `@rs`0x3f80.0000 ax) - =/ t (~(mul ^rs %n) w `@rs`0x3f00.0000) - =/ r (rr t) - =/ s (sqt t) - ?: (~(gte ^rs %n) ax `@rs`0x3f79.999a) - =/ res (~(sub ^rs %n) `@rs`0x3fc9.0fdb (~(sub ^rs %n) (~(mul ^rs %n) `@rs`0x4000.0000 (~(add ^rs %n) s (~(mul ^rs %n) s r))) `@rs`0xb33b.bd2e)) - ?:(=(sgn 1) (~(sub ^rs %n) `@rs`0x0 res) res) - =/ df `@rs`(dis s 0xffff.f000) - =/ c (~(div ^rs %n) (~(sub ^rs %n) t (~(mul ^rs %n) df df)) (~(add ^rs %n) s df)) - =/ p2 (~(sub ^rs %n) (~(mul ^rs %n) `@rs`0x4000.0000 (~(mul ^rs %n) s r)) (~(sub ^rs %n) `@rs`0xb33b.bd2e (~(mul ^rs %n) `@rs`0x4000.0000 c))) - =/ q2 (~(sub ^rs %n) `@rs`0x3f49.0fdb (~(mul ^rs %n) `@rs`0x4000.0000 df)) - =/ res (~(sub ^rs %n) `@rs`0x3f49.0fdb (~(sub ^rs %n) p2 q2)) - ?:(=(sgn 1) (~(sub ^rs %n) `@rs`0x0 res) res) - ++ acs + ?> (gte x .0) + =/ t=@rs .1 + ?: (is-close x .0) + t + |- ^- @rs + ?: (is-close x .1) + t + $(x (sub x .1), t (mul t x)) + :: +abs: @rs -> @rs + :: + :: Returns the absolute value of a floating-point atom. + :: Examples + :: > (abs .1) + :: .1 + :: > (abs .-1) + :: .1 + :: Source + ++ abs + |= x=@rs ^- @rs + ?:((sgn x) x (neg x)) + :: +exp: @rs -> @rs + :: + :: Returns the exponential of a floating-point atom. + :: Examples + :: > (exp .1) + :: .2.7182808 + :: > (exp .2) + :: .7.389052 + :: > (~(exp rs [%z .1e-8]) .2) + :: .7.389053 + :: > (exp .inf) + :: .inf + :: Source + ++ exp + |= x=@rs ^- @rs + :: Chebyshev: x = k*ln2 + r (Cody-Waite reduction); exp(x) = 2^k * P(r), + :: P a degree-6 minimax polynomial faithful to <=1 ULP. Internals are + :: forced to round-nearest-even: a correctly-rounded transcendental does + :: not take a rounding-mode axis (and the SoftFloat jet will match this). + :: +scale2 is a correctly-rounded ldexp that stays exact across the normal + :: range and rounds exactly once into the overflow/subnormal tails. + =/ pow2 |=(j=@s `@rs`(lsh [0 23] (abs:si (sum:si j --127)))) + =/ scale2 + |= [p=@rs k=@s] ^- @rs + ?: (syn:si (dif:si k --128)) :: k>127: (p*2^127)*2^(k-127) + (~(mul ^rs %n) (~(mul ^rs %n) p (pow2 --127)) (pow2 (dif:si k --127))) + ?: !(syn:si (sum:si k --126)) :: k<-126: (p*2^(k+24))*2^-24 + (~(mul ^rs %n) (~(mul ^rs %n) p (pow2 (sum:si k --24))) (pow2 -24)) + (~(mul ^rs %n) p (pow2 k)) + ?: !(~(equ ^rs %n) x x) `@rs`0x7fc0.0000 :: exp(NaN) -> NaN + ?: =(x `@rs`0x7f80.0000) `@rs`0x7f80.0000 :: exp(+inf) -> inf + ?: =(x `@rs`0xff80.0000) `@rs`0x0 :: exp(-inf) -> 0 + =/ log2e `@rs`0x3fb8.aa3b + =/ ln2hi `@rs`0x3f31.7200 + =/ ln2lo `@rs`0x35bf.be8e + =/ k=@s (need (~(toi ^rs %n) (~(mul ^rs %n) x log2e))) + ?: (syn:si (dif:si k --129)) `@rs`0x7f80.0000 :: overflow -> inf + ?: !(syn:si (sum:si k --150)) `@rs`0x0 :: underflow -> 0 + =/ ka (~(sun ^rs %n) (abs:si k)) + =/ kf ?:((syn:si k) ka (~(sub ^rs %n) .0 ka)) :: k as @rs + =/ r + %- ~(sub ^rs %n) + :- (~(sub ^rs %n) x (~(mul ^rs %n) kf ln2hi)) + (~(mul ^rs %n) kf ln2lo) + =/ cs=(list @rs) + :~ `@rs`0x3f80.0000 `@rs`0x3f80.0000 `@rs`0x3f00.0000 + `@rs`0x3e2a.aa02 `@rs`0x3d2a.aa56 `@rs`0x3c09.37d3 + `@rs`0x3ab6.ba99 + == + =/ p (roll (flop cs) |=([c=@rs acc=@rs] (~(add ^rs %n) (~(mul ^rs %n) acc r) c))) + (scale2 p k) + :: +sin: @rs -> @rs + :: + :: Returns the sine of a floating-point atom. + :: Examples + :: > (sin .1) + :: .0.84147096 + :: > (sin .2) + :: .0.9092974 + :: > (sin pi) + :: .3.1609193e-7 + :: Source + ++ sin + |= x=@rs ^- @rs + :: Reduce x = q*(pi/2) + (rhi+rlo) with a 3-part pi/2 (f32 needs the bits), + :: then fdlibm sin/cos kernels picked by q&3. Faithful to <=1 ULP for + :: |x| <~ 500. Round-nearest-even internally (the SoftFloat jet matches). + ?: !(~(equ ^rs %n) x x) `@rs`0x7fc0.0000 :: NaN + ?: |(=(x `@rs`0x7f80.0000) =(x `@rs`0xff80.0000)) `@rs`0x7fc0.0000 :: +-inf + ?: |(=(x `@rs`0x0) =(x `@rs`0x8000.0000)) x :: +-0 -> +-0 + %- trig-fin:rs-trig + [%.y `@rs`(dis x 0x7fff.ffff) (rsh [0 31] x)] + :: +cos: @rs -> @rs + :: + :: Returns the cosine of a floating-point atom. + :: Examples + :: > (cos .1) + :: .0.5403022 + :: > (cos .2) + :: .-0.41614664 + :: > (cos pi) + :: .-0.9999998 + :: Source + ++ cos |= x=@rs ^- @rs ?: !(~(equ ^rs %n) x x) `@rs`0x7fc0.0000 - =/ neg (rsh [0 31] x) - =/ ax `@rs`(dis x 0x7fff.ffff) - ?: (~(gth ^rs %n) ax `@rs`0x3f80.0000) `@rs`0x7fc0.0000 - ?: =(ax `@rs`0x3f80.0000) - ?: =(neg 0) `@rs`0x0 - (~(add ^rs %n) `@rs`0x4049.0fdb (~(mul ^rs %n) `@rs`0x4000.0000 `@rs`0xb33b.bd2e)) - ?: (~(lth ^rs %n) ax `@rs`0x3f00.0000) - ?: (~(lth ^rs %n) ax `@rs`0x3280.0000) `@rs`0x3fc9.0fdb - =/ z (~(mul ^rs %n) x x) - =/ r (rr z) - (~(sub ^rs %n) `@rs`0x3fc9.0fdb (~(sub ^rs %n) x (~(sub ^rs %n) `@rs`0xb33b.bd2e (~(mul ^rs %n) x r)))) - ?: =(neg 1) - =/ z (~(mul ^rs %n) (~(add ^rs %n) `@rs`0x3f80.0000 x) `@rs`0x3f00.0000) + ?: |(=(x `@rs`0x7f80.0000) =(x `@rs`0xff80.0000)) `@rs`0x7fc0.0000 + %- trig-fin:rs-trig + [%.n `@rs`(dis x 0x7fff.ffff) 0] + :: +rs-trig: shared sin/cos engine for the @rs door (see +sin / +cos). + ++ rs-trig + |% + ++ sc ^-((list @rs) :~(`@rs`0xbe2a.aaab `@rs`0x3c08.8889 `@rs`0xb950.0d01 `@rs`0x3638.ef1d `@rs`0xb2d7.322b)) + ++ cc ^-((list @rs) :~(`@rs`0x3d2a.aaab `@rs`0xbab6.0b61 `@rs`0x37d0.0d01 `@rs`0xb493.f27e `@rs`0x310f.76c7)) + ++ neg |=(a=@rs ^-(@rs (~(sub ^rs %n) `@rs`0x0 a))) + ++ ksin + |= [xx=@rs yy=@rs] ^- @rs + =/ z (~(mul ^rs %n) xx xx) + =/ r (roll (flop (tail sc)) |=([c=@rs a=@rs] (~(add ^rs %n) (~(mul ^rs %n) a z) c))) + =/ v (~(mul ^rs %n) z xx) + =/ aa (~(sub ^rs %n) (~(mul ^rs %n) `@rs`0x3f00.0000 yy) (~(mul ^rs %n) v r)) + =/ bb (~(sub ^rs %n) (~(mul ^rs %n) z aa) yy) + =/ dd (~(sub ^rs %n) bb (~(mul ^rs %n) v (head sc))) + (~(sub ^rs %n) xx dd) + ++ kcos + |= [xx=@rs yy=@rs] ^- @rs + =/ z (~(mul ^rs %n) xx xx) + =/ rc (roll (flop cc) |=([c=@rs a=@rs] (~(add ^rs %n) (~(mul ^rs %n) a z) c))) + =/ hz (~(mul ^rs %n) `@rs`0x3f00.0000 z) + =/ w2 (~(sub ^rs %n) `@rs`0x3f80.0000 hz) + =/ aa (~(sub ^rs %n) (~(sub ^rs %n) `@rs`0x3f80.0000 w2) hz) + =/ bb (~(sub ^rs %n) (~(mul ^rs %n) (~(mul ^rs %n) z z) rc) (~(mul ^rs %n) xx yy)) + (~(add ^rs %n) w2 (~(add ^rs %n) aa bb)) + :: +trig-fin: [is-sin? |x| sign-bit] -> sin x (is-sin?) or cos x + ++ trig-fin + |= [s=? ax=@rs sb=@] ^- @rs + =/ q (need (~(toi ^rs %n) (~(mul ^rs %n) ax `@rs`0x3f22.f983))) + =/ qf (~(sun ^rs %n) (abs:si q)) + =/ r1 (~(sub ^rs %n) ax (~(mul ^rs %n) qf `@rs`0x3fc9.0000)) + =/ r2 (~(sub ^rs %n) r1 (~(mul ^rs %n) qf `@rs`0x39fd.a000)) + =/ w (~(mul ^rs %n) qf `@rs`0x33a2.2169) + =/ rhi (~(sub ^rs %n) r2 w) + =/ rlo (~(sub ^rs %n) (~(sub ^rs %n) r2 rhi) w) + =/ m (dis (abs:si q) 3) + =/ ks (ksin rhi rlo) + =/ kc (kcos rhi rlo) + ?: s + =/ v ?:(=(m 0) ks ?:(=(m 1) kc ?:(=(m 2) (neg ks) (neg kc)))) + ?:(=(sb 1) (neg v) v) + ?:(=(m 0) kc ?:(=(m 1) (neg ks) ?:(=(m 2) (neg kc) ks))) + -- + :: +tan: @rs -> @rs + :: + :: Returns the tangent of a floating-point atom. + :: Examples + :: > (tan .1) + :: .1.5574079 + :: > (tan .2) + :: .-2.1850407 + :: > (tan pi) + :: .-7.0094916e-7 + :: Source + ++ tan + |= x=@rs ^- @rs + (div (sin x) (cos x)) + :: +asin: @rs -> @rs + :: + :: Returns the inverse sine of a floating-point atom. + :: Examples + :: > (asin .0) + :: .0 + :: > (asin .1) + :: .1.5707964 + :: > (asin .0.7) + :: .0.7753969 + :: + ++ asin + :: fdlibm rational kernel; see +rs-ainv. Faithful to <=1 ULP; |x|>1 -> NaN. + |= x=@rs ^- @rs + (asn:rs-ainv x) + :: +acos: @rs -> @rs + :: + :: Returns the inverse cosine of a floating-point atom. + :: Examples + :: > (acos .0) + :: .1.5707964 + :: > (acos .1) + :: .0 + :: > (acos .0.7) + :: .0.7953982 + :: + ++ acos + |= x=@rs ^- @rs + (acs:rs-ainv x) + :: +rs-ainv: shared asin/acos engine for the @rs door (rational P/Q kernel), + :: see +asin / +acos. + ++ rs-ainv + |% + ++ rr + |= t=@rs ^- @rs + =/ ps=(list @rs) :~(`@rs`0x3e2a.aa75 `@rs`0xbd2f.13ba `@rs`0xbc0d.d36b) + =/ p (~(mul ^rs %n) t (roll (flop ps) |=([c=@rs a=@rs] (~(add ^rs %n) (~(mul ^rs %n) a t) c)))) + =/ q (~(add ^rs %n) `@rs`0x3f80.0000 (~(mul ^rs %n) t `@rs`0xbf34.e5ae)) + (~(div ^rs %n) p q) + ++ asn + |= x=@rs ^- @rs + ?: !(~(equ ^rs %n) x x) `@rs`0x7fc0.0000 + =/ sgn (rsh [0 31] x) + =/ ax `@rs`(dis x 0x7fff.ffff) + ?: (~(gth ^rs %n) ax `@rs`0x3f80.0000) `@rs`0x7fc0.0000 + ?: =(ax `@rs`0x3f80.0000) + (~(add ^rs %n) (~(mul ^rs %n) x `@rs`0x3fc9.0fdb) (~(mul ^rs %n) x `@rs`0xb33b.bd2e)) + ?: (~(lth ^rs %n) ax `@rs`0x3f00.0000) + ?: (~(lth ^rs %n) ax `@rs`0x3980.0000) x + (~(add ^rs %n) x (~(mul ^rs %n) x (rr (~(mul ^rs %n) x x)))) + =/ w (~(sub ^rs %n) `@rs`0x3f80.0000 ax) + =/ t (~(mul ^rs %n) w `@rs`0x3f00.0000) + =/ r (rr t) + =/ s (sqt t) + ?: (~(gte ^rs %n) ax `@rs`0x3f79.999a) + =/ res (~(sub ^rs %n) `@rs`0x3fc9.0fdb (~(sub ^rs %n) (~(mul ^rs %n) `@rs`0x4000.0000 (~(add ^rs %n) s (~(mul ^rs %n) s r))) `@rs`0xb33b.bd2e)) + ?:(=(sgn 1) (~(sub ^rs %n) `@rs`0x0 res) res) + =/ df `@rs`(dis s 0xffff.f000) + =/ c (~(div ^rs %n) (~(sub ^rs %n) t (~(mul ^rs %n) df df)) (~(add ^rs %n) s df)) + =/ p2 (~(sub ^rs %n) (~(mul ^rs %n) `@rs`0x4000.0000 (~(mul ^rs %n) s r)) (~(sub ^rs %n) `@rs`0xb33b.bd2e (~(mul ^rs %n) `@rs`0x4000.0000 c))) + =/ q2 (~(sub ^rs %n) `@rs`0x3f49.0fdb (~(mul ^rs %n) `@rs`0x4000.0000 df)) + =/ res (~(sub ^rs %n) `@rs`0x3f49.0fdb (~(sub ^rs %n) p2 q2)) + ?:(=(sgn 1) (~(sub ^rs %n) `@rs`0x0 res) res) + ++ acs + |= x=@rs ^- @rs + ?: !(~(equ ^rs %n) x x) `@rs`0x7fc0.0000 + =/ neg (rsh [0 31] x) + =/ ax `@rs`(dis x 0x7fff.ffff) + ?: (~(gth ^rs %n) ax `@rs`0x3f80.0000) `@rs`0x7fc0.0000 + ?: =(ax `@rs`0x3f80.0000) + ?: =(neg 0) `@rs`0x0 + (~(add ^rs %n) `@rs`0x4049.0fdb (~(mul ^rs %n) `@rs`0x4000.0000 `@rs`0xb33b.bd2e)) + ?: (~(lth ^rs %n) ax `@rs`0x3f00.0000) + ?: (~(lth ^rs %n) ax `@rs`0x3280.0000) `@rs`0x3fc9.0fdb + =/ z (~(mul ^rs %n) x x) + =/ r (rr z) + (~(sub ^rs %n) `@rs`0x3fc9.0fdb (~(sub ^rs %n) x (~(sub ^rs %n) `@rs`0xb33b.bd2e (~(mul ^rs %n) x r)))) + ?: =(neg 1) + =/ z (~(mul ^rs %n) (~(add ^rs %n) `@rs`0x3f80.0000 x) `@rs`0x3f00.0000) + =/ s (sqt z) + =/ r (rr z) + =/ w (~(sub ^rs %n) (~(mul ^rs %n) r s) `@rs`0xb33b.bd2e) + (~(sub ^rs %n) `@rs`0x4049.0fdb (~(mul ^rs %n) `@rs`0x4000.0000 (~(add ^rs %n) s w))) + =/ z (~(mul ^rs %n) (~(sub ^rs %n) `@rs`0x3f80.0000 x) `@rs`0x3f00.0000) =/ s (sqt z) =/ r (rr z) - =/ w (~(sub ^rs %n) (~(mul ^rs %n) r s) `@rs`0xb33b.bd2e) - (~(sub ^rs %n) `@rs`0x4049.0fdb (~(mul ^rs %n) `@rs`0x4000.0000 (~(add ^rs %n) s w))) - =/ z (~(mul ^rs %n) (~(sub ^rs %n) `@rs`0x3f80.0000 x) `@rs`0x3f00.0000) - =/ s (sqt z) - =/ r (rr z) - (~(mul ^rs %n) `@rs`0x4000.0000 (~(add ^rs %n) s (~(mul ^rs %n) s r))) - -- - :: +atan: @rs -> @rs - :: - :: Returns the inverse tangent of a floating-point atom. - :: Examples - :: > (atan .1) - :: .0.7853976 - :: > (atan .2) - :: .1.1071494 - :: > (atan pi) - :: .1.2626364 - :: - ++ atan - :: fdlibm breakpoint reduction + minimax poly; odd. Round-nearest-even - :: internally (the SoftFloat jet matches). - |= x=@rs ^- @rs - ?: !(~(equ ^rs %n) x x) `@rs`0x7fc0.0000 :: NaN - ?: =(x `@rs`0x7f80.0000) `@rs`0x3fc9.0fdb :: +inf -> pi/2 - ?: =(x `@rs`0xff80.0000) `@rs`0xbfc9.0fdb :: -inf -> -pi/2 - ?: |(=(x `@rs`0x0) =(x `@rs`0x8000.0000)) x :: +-0 -> +-0 - =/ neg (rsh [0 31] x) - =/ r (ker:rs-atan `@rs`(dis x 0x7fff.ffff)) - ?:(=(neg 1) (~(sub ^rs %n) `@rs`0x0 r) r) - :: +rs-atan: atan kernel for the @rs door (reduction + poly), see +atan. - ++ rs-atan - |% - ++ at - ^- (list @rs) - :~ `@rs`0x3eaa.aaa9 `@rs`0xbe4c.ca98 `@rs`0x3e11.f50d - `@rs`0xbdda.1247 `@rs`0x3d7c.ac25 - == - ++ atred - |= ax=@rs ^- [xr=@rs hi=@rs lo=@rs dir=?] - =/ one `@rs`0x3f80.0000 - =/ two `@rs`0x4000.0000 - =/ ohf `@rs`0x3fc0.0000 - ?: (~(lth ^rs %n) ax `@rs`0x3ee0.0000) - [ax `@rs`0x0 `@rs`0x0 %.y] - ?: (~(lth ^rs %n) ax `@rs`0x3f30.0000) - :* (~(div ^rs %n) (~(sub ^rs %n) (~(add ^rs %n) ax ax) one) (~(add ^rs %n) two ax)) - `@rs`0x3eed.6338 `@rs`0x31ac.376a %.n + (~(mul ^rs %n) `@rs`0x4000.0000 (~(add ^rs %n) s (~(mul ^rs %n) s r))) + -- + :: +atan: @rs -> @rs + :: + :: Returns the inverse tangent of a floating-point atom. + :: Examples + :: > (atan .1) + :: .0.7853976 + :: > (atan .2) + :: .1.1071494 + :: > (atan pi) + :: .1.2626364 + :: + ++ atan + :: fdlibm breakpoint reduction + minimax poly; odd. Round-nearest-even + :: internally (the SoftFloat jet matches). + |= x=@rs ^- @rs + ?: !(~(equ ^rs %n) x x) `@rs`0x7fc0.0000 :: NaN + ?: =(x `@rs`0x7f80.0000) `@rs`0x3fc9.0fdb :: +inf -> pi/2 + ?: =(x `@rs`0xff80.0000) `@rs`0xbfc9.0fdb :: -inf -> -pi/2 + ?: |(=(x `@rs`0x0) =(x `@rs`0x8000.0000)) x :: +-0 -> +-0 + =/ neg (rsh [0 31] x) + =/ r (ker:rs-atan `@rs`(dis x 0x7fff.ffff)) + ?:(=(neg 1) (~(sub ^rs %n) `@rs`0x0 r) r) + :: +rs-atan: atan kernel for the @rs door (reduction + poly), see +atan. + ++ rs-atan + |% + ++ at + ^- (list @rs) + :~ `@rs`0x3eaa.aaa9 `@rs`0xbe4c.ca98 `@rs`0x3e11.f50d + `@rs`0xbdda.1247 `@rs`0x3d7c.ac25 == - ?: (~(lth ^rs %n) ax `@rs`0x3f98.0000) - :* (~(div ^rs %n) (~(sub ^rs %n) ax one) (~(add ^rs %n) ax one)) - `@rs`0x3f49.0fdb `@rs`0xb2bb.bd2e %.n + ++ atred + |= ax=@rs ^- [xr=@rs hi=@rs lo=@rs dir=?] + =/ one `@rs`0x3f80.0000 + =/ two `@rs`0x4000.0000 + =/ ohf `@rs`0x3fc0.0000 + ?: (~(lth ^rs %n) ax `@rs`0x3ee0.0000) + [ax `@rs`0x0 `@rs`0x0 %.y] + ?: (~(lth ^rs %n) ax `@rs`0x3f30.0000) + :* (~(div ^rs %n) (~(sub ^rs %n) (~(add ^rs %n) ax ax) one) (~(add ^rs %n) two ax)) + `@rs`0x3eed.6338 `@rs`0x31ac.376a %.n + == + ?: (~(lth ^rs %n) ax `@rs`0x3f98.0000) + :* (~(div ^rs %n) (~(sub ^rs %n) ax one) (~(add ^rs %n) ax one)) + `@rs`0x3f49.0fdb `@rs`0xb2bb.bd2e %.n + == + ?: (~(lth ^rs %n) ax `@rs`0x401c.0000) + :* (~(div ^rs %n) (~(sub ^rs %n) ax ohf) (~(add ^rs %n) one (~(mul ^rs %n) ohf ax))) + `@rs`0x3f7b.985f `@rs`0xb2d7.e096 %.n + == + :* (~(div ^rs %n) `@rs`0xbf80.0000 ax) + `@rs`0x3fc9.0fdb `@rs`0xb33b.bd2e %.n == - ?: (~(lth ^rs %n) ax `@rs`0x401c.0000) - :* (~(div ^rs %n) (~(sub ^rs %n) ax ohf) (~(add ^rs %n) one (~(mul ^rs %n) ohf ax))) - `@rs`0x3f7b.985f `@rs`0xb2d7.e096 %.n + ++ ker + |= ax=@rs ^- @rs + =/ q (atred ax) + =/ z (~(mul ^rs %n) xr.q xr.q) + =/ s (~(mul ^rs %n) z (roll (flop at) |=([c=@rs a=@rs] (~(add ^rs %n) (~(mul ^rs %n) a z) c)))) + ?: dir.q (~(sub ^rs %n) xr.q (~(mul ^rs %n) xr.q s)) + (~(sub ^rs %n) hi.q (~(sub ^rs %n) (~(sub ^rs %n) (~(mul ^rs %n) xr.q s) lo.q) xr.q)) + -- + :: +atan2: [@rs @rs] -> @rs + :: + :: Returns the inverse tangent of a floating-point coordinate. + :: Examples + :: > (atan2 .0 .1) + :: .0 + :: > (atan2 .-1 .0) + :: .-1.5707964 + :: > (atan2 .0.5 .-0.5) + :: .2.356195 + :: + ++ atan2 + |= [y=@rs x=@rs] ^- @rs + ?: (gth x .0) + (atan (div y x)) + ?: &((lth x .0) (gte y .0)) + (add (atan (div y x)) pi) + ?: &((lth x .0) (lth y .0)) + (sub (atan (div y x)) pi) + ?: &(=(.0 x) (gth y .0)) + (div pi .2) + ?: &(=(.0 x) (lth y .0)) + (mul .-1 (div pi .2)) + .0 :: undefined + :: +pow-n: [@rs @rs] -> @rs + :: + :: Returns the power of a floating-point atom to an integer exponent. + :: Examples + :: > (pow-n .1 .2) + :: .1 + :: > (pow-n .2 .2) + :: .4 + :: > (pow-n .2 .3) + :: .8 + :: Source + ++ pow-n + |= [x=@rs n=@rs] ^- @rs + ?: =(n .0) .1 + ?> &((gth n .0) (is-int n)) + =/ p x + |- ^- @rs + ?: (lth n .2) + p + $(n (sub n .1), p (mul p x)) + :: +log: @rs -> @rs + :: + :: Returns the natural logarithm of a floating-point atom. + :: Examples + :: > (log .1) + :: .0 + :: > (log .2) + :: .0.69314677 + :: > (~(log rs [%z .1e-8]) .2) + :: .0.6931469 + :: > (log .inf) + :: .inf + :: > (log:rs:math e:rs:math) + :: .0.999998 + :: > (~(log rs:math [%z .1e-8]) e:rs:math) + :: .0.9999994 + :: Source + ++ log + |= x=@rs ^- @rs + :: Reduce x = 2^e * m with m in [sqrt(1/2), sqrt(2)); then + :: log(x) = e*ln2 + log(1+f), f = m-1, s = f/(2+f), + :: log(1+f) = f - s*(f - 2z*P2(z)), z = s*s, P2 the atanh series + :: 1/3 + z/5 + z^2/7 + ... Faithful to <=1 ULP; round-nearest-even + :: internally (the SoftFloat jet will match this bit-for-bit). + ?: !(~(equ ^rs %n) x x) `@rs`0x7fc0.0000 :: log(NaN) -> NaN + ?: =(x `@rs`0x7f80.0000) `@rs`0x7f80.0000 :: log(+inf) -> inf + ?: |(=(x `@rs`0x0) =(x `@rs`0x8000.0000)) `@rs`0xff80.0000 :: log(+-0) -> -inf + ?: =(1 (rsh [0 31] x)) `@rs`0x7fc0.0000 :: log(x<0) -> NaN + =/ sub =(0 (dis 0xff (rsh [0 23] x))) :: subnormal? + =/ xx ?:(sub (~(mul ^rs %n) x `@rs`0x4b80.0000) x) :: *2^24 + =/ ae ?:(sub -24 --0) + =/ b `@`xx + =/ ef (dif:si (new:si %.y (dis 0xff (rsh [0 23] b))) --127) + =/ m `@rs`(con (dis b 0x7f.ffff) 0x3f80.0000) + =/ big (~(gte ^rs %n) m `@rs`0x3fb5.04f3) :: m >= sqrt(2) + =? m big (~(mul ^rs %n) m `@rs`0x3f00.0000) :: m * 0.5 + =? ef big (sum:si ef --1) + =. ef (sum:si ef ae) + =/ f (~(sub ^rs %n) m `@rs`0x3f80.0000) + =/ s (~(div ^rs %n) f (~(add ^rs %n) m `@rs`0x3f80.0000)) + =/ z (~(mul ^rs %n) s s) + =/ cs=(list @rs) + :~ `@rs`0x3eaa.aaab `@rs`0x3e4c.cccd `@rs`0x3e12.4925 + `@rs`0x3de3.8e39 `@rs`0x3dba.2e8c == - :* (~(div ^rs %n) `@rs`0xbf80.0000 ax) - `@rs`0x3fc9.0fdb `@rs`0xb33b.bd2e %.n - == - ++ ker - |= ax=@rs ^- @rs - =/ q (atred ax) - =/ z (~(mul ^rs %n) xr.q xr.q) - =/ s (~(mul ^rs %n) z (roll (flop at) |=([c=@rs a=@rs] (~(add ^rs %n) (~(mul ^rs %n) a z) c)))) - ?: dir.q (~(sub ^rs %n) xr.q (~(mul ^rs %n) xr.q s)) - (~(sub ^rs %n) hi.q (~(sub ^rs %n) (~(sub ^rs %n) (~(mul ^rs %n) xr.q s) lo.q) xr.q)) - -- - :: +atan2: [@rs @rs] -> @rs - :: - :: Returns the inverse tangent of a floating-point coordinate. - :: Examples - :: > (atan2 .0 .1) - :: .0 - :: > (atan2 .-1 .0) - :: .-1.5707964 - :: > (atan2 .0.5 .-0.5) - :: .2.356195 - :: - ++ atan2 - |= [y=@rs x=@rs] ^- @rs - ?: (gth x .0) - (atan (div y x)) - ?: &((lth x .0) (gte y .0)) - (add (atan (div y x)) pi) - ?: &((lth x .0) (lth y .0)) - (sub (atan (div y x)) pi) - ?: &(=(.0 x) (gth y .0)) - (div pi .2) - ?: &(=(.0 x) (lth y .0)) - (mul .-1 (div pi .2)) - .0 :: undefined - :: +pow-n: [@rs @rs] -> @rs - :: - :: Returns the power of a floating-point atom to an integer exponent. - :: Examples - :: > (pow-n .1 .2) - :: .1 - :: > (pow-n .2 .2) - :: .4 - :: > (pow-n .2 .3) - :: .8 - :: Source - ++ pow-n - |= [x=@rs n=@rs] ^- @rs - ?: =(n .0) .1 - ?> &((gth n .0) (is-int n)) - =/ p x - |- ^- @rs - ?: (lth n .2) - p - $(n (sub n .1), p (mul p x)) - :: +log: @rs -> @rs - :: - :: Returns the natural logarithm of a floating-point atom. - :: Examples - :: > (log .1) - :: .0 - :: > (log .2) - :: .0.69314677 - :: > (~(log rs [%z .1e-8]) .2) - :: .0.6931469 - :: > (log .inf) - :: .inf - :: > (log:rs:math e:rs:math) - :: .0.999998 - :: > (~(log rs:math [%z .1e-8]) e:rs:math) - :: .0.9999994 - :: Source - ++ log - |= x=@rs ^- @rs - :: Reduce x = 2^e * m with m in [sqrt(1/2), sqrt(2)); then - :: log(x) = e*ln2 + log(1+f), f = m-1, s = f/(2+f), - :: log(1+f) = f - s*(f - 2z*P2(z)), z = s*s, P2 the atanh series - :: 1/3 + z/5 + z^2/7 + ... Faithful to <=1 ULP; round-nearest-even - :: internally (the SoftFloat jet will match this bit-for-bit). - ?: !(~(equ ^rs %n) x x) `@rs`0x7fc0.0000 :: log(NaN) -> NaN - ?: =(x `@rs`0x7f80.0000) `@rs`0x7f80.0000 :: log(+inf) -> inf - ?: |(=(x `@rs`0x0) =(x `@rs`0x8000.0000)) `@rs`0xff80.0000 :: log(+-0) -> -inf - ?: =(1 (rsh [0 31] x)) `@rs`0x7fc0.0000 :: log(x<0) -> NaN - =/ sub =(0 (dis 0xff (rsh [0 23] x))) :: subnormal? - =/ xx ?:(sub (~(mul ^rs %n) x `@rs`0x4b80.0000) x) :: *2^24 - =/ ae ?:(sub -24 --0) - =/ b `@`xx - =/ ef (dif:si (new:si %.y (dis 0xff (rsh [0 23] b))) --127) - =/ m `@rs`(con (dis b 0x7f.ffff) 0x3f80.0000) - =/ big (~(gte ^rs %n) m `@rs`0x3fb5.04f3) :: m >= sqrt(2) - =? m big (~(mul ^rs %n) m `@rs`0x3f00.0000) :: m * 0.5 - =? ef big (sum:si ef --1) - =. ef (sum:si ef ae) - =/ f (~(sub ^rs %n) m `@rs`0x3f80.0000) - =/ s (~(div ^rs %n) f (~(add ^rs %n) m `@rs`0x3f80.0000)) - =/ z (~(mul ^rs %n) s s) - =/ cs=(list @rs) - :~ `@rs`0x3eaa.aaab `@rs`0x3e4c.cccd `@rs`0x3e12.4925 - `@rs`0x3de3.8e39 `@rs`0x3dba.2e8c - == - =/ p2 (roll (flop cs) |=([c=@rs acc=@rs] (~(add ^rs %n) (~(mul ^rs %n) acc z) c))) - =/ r (~(mul ^rs %n) (~(add ^rs %n) z z) p2) - =/ l1 (~(sub ^rs %n) f (~(mul ^rs %n) s (~(sub ^rs %n) f r))) - =/ efa (~(sun ^rs %n) (abs:si ef)) - =/ ef-f ?:((syn:si ef) efa (~(sub ^rs %n) .0 efa)) :: e as @rs - =/ hi (~(mul ^rs %n) ef-f `@rs`0x3f31.7200) :: e*ln2hi - =/ lo (~(mul ^rs %n) ef-f `@rs`0x35bf.be8e) :: e*ln2lo - (~(add ^rs %n) hi (~(add ^rs %n) l1 lo)) - :: +log-10: @rs -> @rs - :: - :: Returns the base-10 logarithm of a floating-point atom. - :: Examples - :: > (log-10 .0.1) - :: .-0.999989 - :: > (log-10 .2) - :: .0.30102932 - :: > (~(log-10 rs [%z .1e-8]) .2) - :: .0.3010301 - :: > (log-10 .inf) - :: .inf - :: Source - ++ log-10 - :: e*log10(2) + log(m)/ln10, reusing +lr so the integer part is added with - :: no division rounding (more accurate than log(x)/ln10). - |= x=@rs ^- @rs - ?: !(~(equ ^rs %n) x x) `@rs`0x7fc0.0000 - ?: =(x `@rs`0x7f80.0000) `@rs`0x7f80.0000 - ?: |(=(x `@rs`0x0) =(x `@rs`0x8000.0000)) `@rs`0xff80.0000 - ?: =(1 (rsh [0 31] x)) `@rs`0x7fc0.0000 - =/ el (lr x) - (~(add ^rs %n) (~(mul ^rs %n) ef.el `@rs`0x3e9a.209b) (~(mul ^rs %n) lm.el `@rs`0x3ede.5bd9)) - :: +log-2: @rs -> @rs - :: - :: Returns the base-2 logarithm of a floating-point atom. - :: Examples - :: > (log-2 .0.1) - :: .-3.321928 - :: > (log-2 .2) - :: .1.5849625 - :: Source - ++ log-2 - :: e + log(m)/ln2 (integer part exact); see +lr. - |= x=@rs ^- @rs - ?: !(~(equ ^rs %n) x x) `@rs`0x7fc0.0000 - ?: =(x `@rs`0x7f80.0000) `@rs`0x7f80.0000 - ?: |(=(x `@rs`0x0) =(x `@rs`0x8000.0000)) `@rs`0xff80.0000 - ?: =(1 (rsh [0 31] x)) `@rs`0x7fc0.0000 - =/ el (lr x) - (~(add ^rs %n) ef.el (~(mul ^rs %n) lm.el `@rs`0x3fb8.aa3b)) - :: +lr: log reduction for finite positive x -> [e (as @rs), log(mantissa)]. - ++ lr - |= x=@rs ^- [ef=@rs lm=@rs] - =/ sub =(0 (dis 0xff (rsh [0 23] x))) - =/ xx ?:(sub (~(mul ^rs %n) x `@rs`0x4b80.0000) x) - =/ ae ?:(sub -24 --0) - =/ b `@`xx - =/ e (dif:si (new:si %.y (dis 0xff (rsh [0 23] b))) --127) - =/ m `@rs`(con (dis b 0x7f.ffff) 0x3f80.0000) - =/ big (~(gte ^rs %n) m `@rs`0x3fb5.04f3) - =? m big (~(mul ^rs %n) m `@rs`0x3f00.0000) - =? e big (sum:si e --1) - =. e (sum:si e ae) - =/ f (~(sub ^rs %n) m `@rs`0x3f80.0000) - =/ s (~(div ^rs %n) f (~(add ^rs %n) m `@rs`0x3f80.0000)) - =/ z (~(mul ^rs %n) s s) - =/ cs=(list @rs) - :~ `@rs`0x3eaa.aaab `@rs`0x3e4c.cccd `@rs`0x3e12.4925 - `@rs`0x3de3.8e39 `@rs`0x3dba.2e8c - == - =/ p2 (roll (flop cs) |=([c=@rs a=@rs] (~(add ^rs %n) (~(mul ^rs %n) a z) c))) - =/ r (~(mul ^rs %n) (~(add ^rs %n) z z) p2) - =/ l1 (~(sub ^rs %n) f (~(mul ^rs %n) s (~(sub ^rs %n) f r))) - =/ efa (~(sun ^rs %n) (abs:si e)) - =/ ef ?:((syn:si e) efa (~(sub ^rs %n) .0 efa)) - [ef l1] - :: +pow: [@rs @rs] -> @rs - :: - :: Returns the power of a floating-point atom to a floating-point exponent. - :: Examples - :: > (pow .1 .2) - :: .1 - :: > (pow .2 .2) - :: .4 - :: > (pow .2 .3.5) - :: .11.313682 - :: > (~(pow rs:math [%z .1e-8]) .2 .3.5) - :: .11.313687 - :: Source - ++ pow - |= [x=@rs n=@rs] ^- @rs - :: fall through on positive integers (faster) - ?: &(=(n (san (need (toi n)))) (gth n .0)) (pow-n x (san (need (toi n)))) - (exp (mul n (log x))) - :: +sqrt: @rs -> @rs - :: - :: Returns the square root of a floating-point atom. - :: Alias for +sqt. - :: Examples - :: > (sqrt .1) - :: .1 - :: > (sqrt .2) - :: .1.4142128 - :: > (~(sqrt rs [%z .1e-8]) .2) - :: .1.414213 - :: Source - ++ sqrt sqt - :: +sqt: @rs -> @rs - :: - :: Returns the square root of a floating-point atom. - :: Examples - :: > (sqt .1) - :: .1 - :: > (sqt .2) - :: .1.4142135 - :: > (sqt .1e5) - :: .316.22775 - :: Source - ++ sqt - :: Correctly-rounded: delegate to the stdlib (SoftFloat) f32 square root. - |= x=@rs ^- @rs - (sqt:^rs x) - :: +cbrt: @rs -> @rs - :: - :: Returns the cube root of a floating-point atom. - :: Alias for +cbt. - :: Examples - :: > (cbrt .1) - :: .1 - :: > (cbrt .2) - :: .1.2599205 - :: > (~(cbrt rs [%z .1e-8]) .2) - :: .1.2599207 - :: Source - ++ cbrt cbt - :: +cbt: @rs -> @rs - :: - :: Returns the cube root of a floating-point atom. - :: Examples - :: > (cbt .1) - :: .1 - :: > (cbt .2) - :: .1.2599205 - :: > (~(cbt rs [%z .1e-8]) .2) - :: .1.2599207 - :: Source - ++ cbt - :: cbrt(x) = sign(x) * exp(log|x| / 3); defined for all reals (unlike pow). - |= x=@rs ^- @rs - ?: !(~(equ ^rs %n) x x) x :: NaN -> NaN - ?: |(=(x `@rs`0x0) =(x `@rs`0x8000.0000)) x :: +-0 -> +-0 - =/ ax `@rs`(dis x 0x7fff.ffff) - =/ r (exp (~(mul ^rs %n) (log ax) `@rs`0x3eaa.aaab)) - ?:(=(1 (rsh [0 31] x)) (~(sub ^rs %n) `@rs`0x0 r) r) - :: +arg: @rs -> @rs - :: - :: Returns the argument of a floating-point atom (real argument = absolute - :: value). - :: Examples - :: > (arg .1) - :: .1 - :: > (arg .-1) - :: .1 - :: Source - ++ arg abs - :: +round: [@rs @ud] -> @rs - :: - :: Returns the floating-point atom rounded to a given number of decimal - :: places. - :: Examples - :: > (round .1 0) - :: .1 - :: > (round .1.11 1) - :: .1.1 - :: > (round .1.11 2) - :: .1.11 - :: > (round .1.11 3) - :: .1.11 - :: Source - ++ round - |= [x=@rs n=@ud] ^- @rs - ?: =(.0 x) .0 - :: Calculate the order of magnitude. - =/ oom (san (need (toi (log-10 (abs x))))) - :: Calculate the scaling factor. - =/ scaling (pow .10 :(sub (sun n) oom .1)) - :: Round the mantissa to desired significant digits. - =/ rnd-mantissa (round-bankers (mul x scaling)) - :: Convert back to the original scale. - (div rnd-mantissa scaling) - :: +round-places: [@rs @ud] -> @rs - :: - :: Returns the floating-point atom rounded to a given number of decimal - :: places. This is exceptionally sensitive to off-by-one FP rounding error. - :: Examples - :: > (round-places .1 0) - :: .1 - :: > (round-places .1.11 1) - :: .1.1 - :: > (round-places .1.285 2) - :: .1.28 - :: > (round-places .4.12345 3) - :: .4.1229997 - :: Source - ++ round-places - |= [x=@rs n=@ud] ^- @rs - :: Calculate the scaling factor. - =/ scaling (pow .10 (sun n)) - :: Scale the number. - =/ scaled (mul x scaling) - :: Round the mantissa to desired significant digits. - =/ rnd-mantissa (round-bankers scaled) - :: Convert back to the original scale. - (div rnd-mantissa scaling) - :: +round-bankers: @rs -> @rs - :: - :: Returns the floating-point atom rounded to the nearest integer, with - :: ties rounded to the nearest even integer (banker's rounding). This is - :: exactly what +toi does under round-nearest (%n), which ties to even, so we - :: force %n regardless of the door's configured mode. - :: Examples - :: > (round-bankers .1.5) - :: .2 - :: > (round-bankers .2.5) - :: .2 - :: > (round-bankers .1.49) - :: .1 - :: Source - ++ round-bankers - |= x=@rs ^- @rs - (san (need (~(toi ^rs %n) x))) - -- -:: double precision -++ rd - ^| - |_ $: r=$?(%n %u %d %z) :: round nearest, up, down, to zero - rtol=_.~1e-10 :: relative tolerance for precision of operations - == - :: mathematics constants to single precision - :: +tau: @rd - :: - :: Returns the value 2*pi (OEIS A019692). - :: Examples - :: > tau - :: .~6.283185307179586 - :: Source - ++ tau .~6.283185307179586 - :: +pi: @rd - :: - :: Returns the value pi (OEIS A000796). - :: Examples - :: > pi - :: .~3.141592653589793 - :: Source - ++ pi .~3.141592653589793 - :: +e: @rd - :: - :: Returns the value e (Euler's constant) (OEIS A001113). - :: Examples - :: > e - :: .~2.718281828459045 - :: Source - ++ e .~2.718281828459045 - :: +phi: @rd - :: - :: Returns the value phi (golden ratio) (OEIS A001622). - :: Examples - :: > phi - :: .~1.618033988749895 - :: Source - ++ phi .~1.618033988749895 - :: +sqt2: @rd - :: - :: Returns the value sqrt(2) (OEIS A002193). - :: Examples - :: > sqt2 - :: .~1.414213562373095 - :: Source - ++ sqt2 .~1.4142135623730951 - :: +invsqt2: @rd - :: - :: Returns the value 1/sqrt(2) (OEIS A010503). - :: Examples - :: > invsqt2 - :: .~0.7071067811865476 - :: Source - ++ invsqt2 .~0.7071067811865476 - :: +log2: @rd - :: - :: Returns the value log(2) (OEIS A002162). - :: Examples - :: > log2 - :: .~0.6931471805599453 - :: Source - ++ log2 .~0.6931471805599453 - :: +invlog2: @rd - :: - :: Returns the value 1/log(2). - :: Examples - :: > invlog2 - :: .~1.4426950408889634 - :: Source - ++ invlog2 .~1.4426950408889634 - :: +log10: @rd - :: - :: Returns the value log(10) (OEIS A002392). - :: Examples - :: > log10 - :: .~2.302585092994046 - :: Source - ++ log10 .~2.302585092994046 - :: - :: +huge: @rd - :: - :: Returns the value of the largest representable number. - :: Examples - :: > huge - :: .~1.7976931348623157e+308 - :: Source - ++ huge `@rd`0x7fef.ffff.ffff.ffff :: 1.79769313486231570815e+308 - :: +tiny: @rd - :: - :: Returns the value of the smallest representable normal number. - :: Examples - :: > tiny - :: .~2.2250738585072014e-308 - :: Source - ++ tiny `@rd`0x10.0000.0000.0000 :: 2.22507385850720138309e-308 - :: - :: Operations - :: - :: +sea: @rd -> fn - :: - :: Returns the +$fn representation of a floating-point atom. - :: Examples - :: > (sea .~1) - :: [%f s=%.y e=-52 a=4.503.599.627.370.496] - :: > (sea .~1.1) - :: [%f s=%.y e=-52 a=4.953.959.590.107.546] - :: Source - ++ sea sea:^rd - :: +bit: fn -> @rd - :: - :: Returns the floating-point atom of a +$fn representation. - :: Examples - :: > (bit [%f s=%.y e=-52 a=4.503.599.627.370.496]) - :: .~1 - :: > (bit [%f s=%.y e=-52 a=4.953.959.590.107.546]) - :: .~1.1 - :: Source - ++ bit bit:^rd - :: +sun: @ud -> @rd - :: - :: Returns the floating-point atom of an unsigned integer atom. - :: Examples - :: > (sun 1) - :: .~1 - :: > (sun 1.000) - :: .~1e3 - :: Source - ++ sun sun:^rd - :: +san: @sd -> @rd - :: - :: Returns the floating-point atom of a signed integer atom. - :: Examples - :: > (san --1) - :: .~1 - :: > (san -1) - :: .~-1 - :: Source - ++ san san:^rd - ::++ exp exp:^rd :: no pass-through because of exp function - :: +toi: @rd -> @sd - :: - :: Returns the unitized signed integer atom of a rounded floating-point atom. - :: Examples - :: > (toi .~1) - :: [~ --1] - :: > (toi .~1.1) - :: [~ --1] - :: Source - ++ toi toi:^rd - :: +drg: @rd -> dn - :: - :: Returns the decimal form of a floating-point atom using the Dragon4 - :: algorithm. - :: Examples - :: > (drg .~1) - :: [%d s=%.y e=--0 a=1] - :: > (drg .~1.1) - :: [%d s=%.y e=-1 a=11] - :: Source - ++ drg drg:^rd - :: +grd: dn -> @rd - :: - :: Returns the floating-point atom of a decimal form. - :: Examples - :: > (grd [%d s=%.y e=--0 a=1]) - :: .~1 - :: > (grd [%d s=%.y e=-1 a=11]) - :: .~1.1 - :: Source - ++ grd grd:^rd - :: - :: Comparison - :: - :: +lth: [@rd @rd] -> ? - :: - :: Returns the comparison of two floating-point atoms, less than. - :: Examples - :: > (lth .~1 .~2) - :: %.y - :: > (lth .~2 .~1) - :: %.n - :: > (lth .~1 .~1) - :: %.n - :: Source - ++ lth lth:^rd - :: +lte: [@rd @rd] -> ? - :: - :: Returns the comparison of two floating-point atoms, less than or equal to. - :: Examples - :: > (lte .~1 .~2) - :: %.y - :: > (lte .~2 .~1) - :: %.n - :: > (lte .~1 .~1) - :: %.y - :: Source - ++ lte lte:^rd - :: +leq: [@rd @rd] -> ? - :: - :: Returns the comparison of two floating-point atoms, less than or equal to. - :: Alias for +lte. - :: Examples - :: > (leq .~1 .~2) - :: %.y - :: > (leq .~2 .~1) - :: %.n - :: > (leq .~1 .~1) - :: %.y - :: Source - ++ leq lte:^rd - :: +equ: [@rd @rd] -> ? - :: - :: Returns the comparison of two floating-point atoms, equal to. - :: Examples - :: > (equ .~1 .~2) - :: %.n - :: > (equ .~2 .~1) - :: %.n - :: > (equ .~1 .~1) - :: %.y - :: Source - ++ equ equ:^rd - :: +gth: [@rd @rd] -> ? - :: - :: Returns the comparison of two floating-point atoms, greater than. - :: Examples - :: > (gth .~1 .~2) - :: %.n - :: > (gth .~2 .~1) - :: %.y - :: > (gth .~1 .~1) - :: %.n - :: Source - ++ gth gth:^rd - :: +gte: [@rd @rd] -> ? - :: - :: Returns the comparison of two floating-point atoms, greater than or equal to. - :: Examples - :: > (gte .~1 .~2) - :: %.n - :: > (gte .~2 .~1) - :: %.y - :: > (gte .~1 .~1) - :: %.y - :: Source - ++ gte gte:^rd - :: +geq: [@rd @rd] -> ? - :: - :: Returns the comparison of two floating-point atoms, greater than or equal to. - :: Alias for +gte. - :: Examples - :: > (geq .~1 .~2) - :: %.n - :: > (geq .~2 .~1) - :: %.y - :: > (geq .~1 .~1) - :: %.y - :: Source - ++ geq gte:^rd - :: +neq: [@rd @rd] -> ? - :: - :: Returns the comparison of two floating-point atoms, not equal to. - :: Examples - :: > (neq .~1 .~2) - :: %.y - :: > (neq .~2 .~1) - :: %.y - :: > (neq .~1 .~1) - :: %.n - :: Source - ++ neq |=([a=@rd b=@rd] ^-(? !(equ:^rd a b))) - :: +is-close: [@rd @rd] -> ? - :: - :: Returns the comparison of two floating-point atoms, within a relative - :: tolerance (provided by the +rd door). - :: Examples - :: > (is-close .~1 .~2) - :: %.n - :: > (is-close .~1 .~1.0000001) - :: %.n - :: > (~(is-close rd [%z .~1e-3]) .~1 .~1.0000001) - :: %.y - :: Source - ++ is-close - |= [p=@rd r=@rd] - (lth (abs (sub p r)) rtol) - :: +all-close: [@rd (list @rd)] -> ? - :: - :: Returns the comparison of a floating-point atom to a list of floating- - :: point atoms, within a relative tolerance (provided by the +rd door). - :: Examples - :: > (all-close .~1 ~[.~1 .~2]) - :: %.n - :: > (all-close .~1 ~[.~1 .~1.0000001]) - :: %.n - :: > (~(all-close rd [%z .~1e-3]) .~1 ~[.~1 .~1.0000001]) - :: %.y - :: Source - ++ all-close - |= [p=@rd q=(list @rd)] - =/ i 0 - =/ n (lent q) - |- ^- ? - ?: =(n i) - %.y - ?. (is-close p (snag i q)) - %.n - $(i +(i)) - :: +is-int: @rd -> ? - :: - :: Returns whether a floating-point value is an integer (no fractional part). - :: Examples - :: > (is-int .~1) - :: %.y - :: > (is-int .~1.1) - :: %.n - :: Source - ++ is-int - |= x=@rd ^- ? - (equ x (san (need (toi x)))) - :: - :: Algebraic - :: - :: +add: [@rd @rd] -> @rd - :: - :: Returns the sum of two floating-point atoms. - :: Examples - :: > (add .~1 .~2) - :: .~3 - :: Source - ++ add add:^rd - :: +sub: [@rd @rd] -> @rd - :: - :: Returns the difference of two floating-point atoms. - :: Examples - :: > (sub .~1 .~2) - :: .~-1 - :: Source - ++ sub sub:^rd - :: +mul: [@rd @rd] -> @rd - :: - :: Returns the product of two floating-point atoms. - :: Examples - :: > (mul .~1 .~2) - :: .~2 - :: > (mul .~2 .~3) - :: .~6 - :: Source - ++ mul mul:^rd - :: +div: [@rd @rd] -> @rd - :: - :: Returns the quotient of two floating-point atoms. - :: Examples - :: > (div .~1 .~2) - :: .~0.5 - :: Source - ++ div div:^rd - :: +fma: [@rd @rd @rd] -> @rd - :: - :: Returns the fused multiply-add of three floating-point atoms. - :: Examples - :: > (fma .~1 .~2 .~3) - :: .~5 - :: > (fma .~2 .~3 .~4) - :: .~10 - :: Source - ++ fma fma:^rd - :: +sig: @rd -> ? - :: - :: Returns the sign of a floating-point atom. - :: Examples - :: > (sig .~1) - :: %.y - :: > (sig .~-1) - :: %.n - :: Source - ++ sig |=(x=@rd =(0 (rsh [0 63] x))) - :: +sgn: @rd -> ? - :: - :: Returns the sign of a floating-point atom. - :: Alias for +sig. - :: Examples - :: > (sgn .~1) - :: %.y - :: > (sgn .~-1) - :: %.n - :: Source - ++ sgn sig - :: +neg: @rd -> @rd - :: - :: Returns the negation of a floating-point atom. - :: Examples - :: > (neg .~1) - :: .~-1 - :: > (neg .~-1) - :: .~1 - :: Source - ++ neg |=(x=@rd (sub .~0 x)) - :: +factorial: @rd -> @rd - :: - :: Returns the factorial of a floating-point atom. Assumes integer input. - :: Examples - :: > (factorial .~1) - :: .~1 - :: > (factorial .~2) - :: .~2 - :: > (factorial .~3) - :: .~6 - :: Source - ++ factorial - |= x=@rd ^- @rd - ?> (gte x .~0) - =/ t=@rd .~1 - ?: (is-close x .~0) - t - |- ^- @rd - ?: (is-close x .~1) - t - $(x (sub x .~1), t (mul t x)) - :: +abs: @rd -> @rd - :: - :: Returns the absolute value of a floating-point atom. - :: Examples - :: > (abs .~1) - :: .~1 - :: > (abs .~-1) - :: .~1 - :: Source - ++ abs - |= x=@rd ^- @rd - ?:((sgn x) x (neg x)) - :: +exp: @rd -> @rd - :: - :: Returns the exponential of a floating-point atom. - :: Examples - :: > (exp .~1) - :: .~2.7182818284582266 - :: > (exp .~2) - :: .~7.389056098925858 - :: > (~(exp rd [%z .~1e-15]) .~2) - :: .~7.389056098930642 - :: > (exp .~inf) - :: .inf - :: Source - ++ exp - |= x=@rd ^- @rd - :: Chebyshev: x = k*ln2 + r (Cody-Waite reduction); exp(x) = 2^k * P(r), - :: P a degree-11 minimax polynomial faithful to <=1 ULP. Internals are - :: forced to round-nearest-even: a correctly-rounded transcendental does - :: not take a rounding-mode axis (and the SoftFloat jet will match this). - :: +scale2 is a correctly-rounded ldexp that stays exact across the normal - :: range and rounds exactly once into the overflow/subnormal tails. - =/ pow2 |=(j=@s `@rd`(lsh [0 52] (abs:si (sum:si j --1.023)))) - =/ scale2 - |= [p=@rd k=@s] ^- @rd - ?: (syn:si (dif:si k --1.024)) :: k>1023: (p*2^1023)*2^(k-1023) - (~(mul ^rd %n) (~(mul ^rd %n) p (pow2 --1.023)) (pow2 (dif:si k --1.023))) - ?: !(syn:si (sum:si k --1.022)) :: k<-1022: (p*2^(k+54))*2^-54 - (~(mul ^rd %n) (~(mul ^rd %n) p (pow2 (sum:si k --54))) (pow2 -54)) - (~(mul ^rd %n) p (pow2 k)) - ?: !(~(equ ^rd %n) x x) `@rd`0x7ff8.0000.0000.0000 :: NaN - ?: =(x `@rd`0x7ff0.0000.0000.0000) `@rd`0x7ff0.0000.0000.0000 :: +inf - ?: =(x `@rd`0xfff0.0000.0000.0000) `@rd`0x0 :: -inf -> 0 - =/ log2e `@rd`0x3ff7.1547.652b.82fe - =/ ln2hi `@rd`0x3fe6.2e42.fee0.0000 - =/ ln2lo `@rd`0x3dea.39ef.3579.3c76 - =/ k=@s (need (~(toi ^rd %n) (~(mul ^rd %n) x log2e))) - ?: (syn:si (dif:si k --1.025)) `@rd`0x7ff0.0000.0000.0000 :: overflow -> inf - ?: !(syn:si (sum:si k --1.075)) `@rd`0x0 :: underflow -> 0 - =/ ka (~(sun ^rd %n) (abs:si k)) - =/ kf ?:((syn:si k) ka (~(sub ^rd %n) .~0 ka)) :: k as @rd - =/ r - %- ~(sub ^rd %n) - :- (~(sub ^rd %n) x (~(mul ^rd %n) kf ln2hi)) - (~(mul ^rd %n) kf ln2lo) - =/ cs=(list @rd) - :~ `@rd`0x3ff0.0000.0000.0000 `@rd`0x3ff0.0000.0000.0000 - `@rd`0x3fe0.0000.0000.0011 `@rd`0x3fc5.5555.5555.555a - `@rd`0x3fa5.5555.5554.f0cf `@rd`0x3f81.1111.1110.f225 - `@rd`0x3f56.c16c.187f.be02 `@rd`0x3f2a.01a0.1b14.378f - `@rd`0x3efa.0199.1ac8.730a `@rd`0x3ec7.1ddf.5749.d126 - `@rd`0x3e92.8b40.57f4.4145 `@rd`0x3e5a.f631.d005.9bec - == - =/ p (roll (flop cs) |=([c=@rd acc=@rd] (~(add ^rd %n) (~(mul ^rd %n) acc r) c))) - (scale2 p k) - :: +sin: @rd -> @rd - :: - :: Returns the sine of a floating-point atom. - :: Examples - :: > (sin .~1) - :: .~0.8414709848078934 - :: > (sin .~2) - :: .~0.9092974268256406 - :: > (sin pi) - :: .~-1.698287706085482e-13 - :: Source - ++ sin - |= x=@rd ^- @rd - :: Reduce x = q*(pi/2) + (rhi+rlo) (2-part pi/2), then fdlibm sin/cos - :: kernels picked by q&3. Faithful to <=1 ULP for |x| <~ 2^22. - :: Round-nearest-even internally (the SoftFloat jet matches). - ?: !(~(equ ^rd %n) x x) `@rd`0x7ff8.0000.0000.0000 - ?: |(=(x `@rd`0x7ff0.0000.0000.0000) =(x `@rd`0xfff0.0000.0000.0000)) `@rd`0x7ff8.0000.0000.0000 - ?: |(=(x `@rd`0x0) =(x `@rd`0x8000.0000.0000.0000)) x :: +-0 -> +-0 - %- trig-fin:rd-trig - [%.y `@rd`(dis x 0x7fff.ffff.ffff.ffff) (rsh [0 63] x)] - :: +cos: @rd -> @rd - :: - :: Returns the cosine of a floating-point atom. - :: Examples - :: > (cos .~1) - :: .~0.5403023058680917 - :: > (cos .~2) - :: .~-0.41614683654756957 - :: > (cos pi) - :: .~-1.0000000000013558 - :: Source - ++ cos - |= x=@rd ^- @rd - ?: !(~(equ ^rd %n) x x) `@rd`0x7ff8.0000.0000.0000 - ?: |(=(x `@rd`0x7ff0.0000.0000.0000) =(x `@rd`0xfff0.0000.0000.0000)) `@rd`0x7ff8.0000.0000.0000 - %- trig-fin:rd-trig - [%.n `@rd`(dis x 0x7fff.ffff.ffff.ffff) 0] - :: +rd-trig: shared sin/cos engine for the @rd door (see +sin / +cos). - ++ rd-trig - |% - ++ sc - ^- (list @rd) - :~ `@rd`0xbfc5.5555.5555.5555 `@rd`0x3f81.1111.1111.1111 - `@rd`0xbf2a.01a0.1a01.a01a `@rd`0x3ec7.1de3.a556.c734 - `@rd`0xbe5a.e645.67f5.44e4 `@rd`0x3de6.1246.13a8.6d09 - `@rd`0xbd6a.e7f3.e733.b81f `@rd`0x3ce9.52c7.7030.ad4a - == - ++ cc - ^- (list @rd) - :~ `@rd`0x3fa5.5555.5555.5555 `@rd`0xbf56.c16c.16c1.6c17 - `@rd`0x3efa.01a0.1a01.a01a `@rd`0xbe92.7e4f.b778.9f5c - `@rd`0x3e21.eed8.eff8.d898 `@rd`0xbda9.3974.a8c0.7c9d - `@rd`0x3d2a.e7f3.e733.b81f `@rd`0xbca6.8278.63b9.7d97 - == - ++ neg |=(a=@rd ^-(@rd (~(sub ^rd %n) `@rd`0x0 a))) - ++ ksin - |= [xx=@rd yy=@rd] ^- @rd - =/ z (~(mul ^rd %n) xx xx) - =/ r (roll (flop (tail sc)) |=([c=@rd a=@rd] (~(add ^rd %n) (~(mul ^rd %n) a z) c))) - =/ v (~(mul ^rd %n) z xx) - =/ aa (~(sub ^rd %n) (~(mul ^rd %n) `@rd`0x3fe0.0000.0000.0000 yy) (~(mul ^rd %n) v r)) - =/ bb (~(sub ^rd %n) (~(mul ^rd %n) z aa) yy) - =/ dd (~(sub ^rd %n) bb (~(mul ^rd %n) v (head sc))) - (~(sub ^rd %n) xx dd) - ++ kcos - |= [xx=@rd yy=@rd] ^- @rd - =/ z (~(mul ^rd %n) xx xx) - =/ rc (roll (flop cc) |=([c=@rd a=@rd] (~(add ^rd %n) (~(mul ^rd %n) a z) c))) - =/ hz (~(mul ^rd %n) `@rd`0x3fe0.0000.0000.0000 z) - =/ w2 (~(sub ^rd %n) `@rd`0x3ff0.0000.0000.0000 hz) - =/ aa (~(sub ^rd %n) (~(sub ^rd %n) `@rd`0x3ff0.0000.0000.0000 w2) hz) - =/ bb (~(sub ^rd %n) (~(mul ^rd %n) (~(mul ^rd %n) z z) rc) (~(mul ^rd %n) xx yy)) - (~(add ^rd %n) w2 (~(add ^rd %n) aa bb)) - :: +trig-fin: [is-sin? |x| sign-bit] -> sin x (is-sin?) or cos x - ++ trig-fin - |= [s=? ax=@rd sb=@] ^- @rd - =/ q (need (~(toi ^rd %n) (~(mul ^rd %n) ax `@rd`0x3fe4.5f30.6dc9.c883))) - =/ qf (~(sun ^rd %n) (abs:si q)) - =/ t (~(sub ^rd %n) ax (~(mul ^rd %n) qf `@rd`0x3ff9.21fb.5440.0000)) - =/ w (~(mul ^rd %n) qf `@rd`0x3dd0.b461.1a62.6331) - =/ rhi (~(sub ^rd %n) t w) - =/ rlo (~(sub ^rd %n) (~(sub ^rd %n) t rhi) w) - =/ m (dis (abs:si q) 3) - =/ ks (ksin rhi rlo) - =/ kc (kcos rhi rlo) - ?: s - =/ v ?:(=(m 0) ks ?:(=(m 1) kc ?:(=(m 2) (neg ks) (neg kc)))) - ?:(=(sb 1) (neg v) v) - ?:(=(m 0) kc ?:(=(m 1) (neg ks) ?:(=(m 2) (neg kc) ks))) + =/ p2 (roll (flop cs) |=([c=@rs acc=@rs] (~(add ^rs %n) (~(mul ^rs %n) acc z) c))) + =/ r (~(mul ^rs %n) (~(add ^rs %n) z z) p2) + =/ l1 (~(sub ^rs %n) f (~(mul ^rs %n) s (~(sub ^rs %n) f r))) + =/ efa (~(sun ^rs %n) (abs:si ef)) + =/ ef-f ?:((syn:si ef) efa (~(sub ^rs %n) .0 efa)) :: e as @rs + =/ hi (~(mul ^rs %n) ef-f `@rs`0x3f31.7200) :: e*ln2hi + =/ lo (~(mul ^rs %n) ef-f `@rs`0x35bf.be8e) :: e*ln2lo + (~(add ^rs %n) hi (~(add ^rs %n) l1 lo)) + :: +log-10: @rs -> @rs + :: + :: Returns the base-10 logarithm of a floating-point atom. + :: Examples + :: > (log-10 .0.1) + :: .-0.999989 + :: > (log-10 .2) + :: .0.30102932 + :: > (~(log-10 rs [%z .1e-8]) .2) + :: .0.3010301 + :: > (log-10 .inf) + :: .inf + :: Source + ++ log-10 + :: e*log10(2) + log(m)/ln10, reusing +lr so the integer part is added with + :: no division rounding (more accurate than log(x)/ln10). + |= x=@rs ^- @rs + ?: !(~(equ ^rs %n) x x) `@rs`0x7fc0.0000 + ?: =(x `@rs`0x7f80.0000) `@rs`0x7f80.0000 + ?: |(=(x `@rs`0x0) =(x `@rs`0x8000.0000)) `@rs`0xff80.0000 + ?: =(1 (rsh [0 31] x)) `@rs`0x7fc0.0000 + =/ el (lr x) + (~(add ^rs %n) (~(mul ^rs %n) ef.el `@rs`0x3e9a.209b) (~(mul ^rs %n) lm.el `@rs`0x3ede.5bd9)) + :: +log-2: @rs -> @rs + :: + :: Returns the base-2 logarithm of a floating-point atom. + :: Examples + :: > (log-2 .0.1) + :: .-3.321928 + :: > (log-2 .2) + :: .1.5849625 + :: Source + ++ log-2 + :: e + log(m)/ln2 (integer part exact); see +lr. + |= x=@rs ^- @rs + ?: !(~(equ ^rs %n) x x) `@rs`0x7fc0.0000 + ?: =(x `@rs`0x7f80.0000) `@rs`0x7f80.0000 + ?: |(=(x `@rs`0x0) =(x `@rs`0x8000.0000)) `@rs`0xff80.0000 + ?: =(1 (rsh [0 31] x)) `@rs`0x7fc0.0000 + =/ el (lr x) + (~(add ^rs %n) ef.el (~(mul ^rs %n) lm.el `@rs`0x3fb8.aa3b)) + :: +lr: log reduction for finite positive x -> [e (as @rs), log(mantissa)]. + ++ lr + |= x=@rs ^- [ef=@rs lm=@rs] + =/ sub =(0 (dis 0xff (rsh [0 23] x))) + =/ xx ?:(sub (~(mul ^rs %n) x `@rs`0x4b80.0000) x) + =/ ae ?:(sub -24 --0) + =/ b `@`xx + =/ e (dif:si (new:si %.y (dis 0xff (rsh [0 23] b))) --127) + =/ m `@rs`(con (dis b 0x7f.ffff) 0x3f80.0000) + =/ big (~(gte ^rs %n) m `@rs`0x3fb5.04f3) + =? m big (~(mul ^rs %n) m `@rs`0x3f00.0000) + =? e big (sum:si e --1) + =. e (sum:si e ae) + =/ f (~(sub ^rs %n) m `@rs`0x3f80.0000) + =/ s (~(div ^rs %n) f (~(add ^rs %n) m `@rs`0x3f80.0000)) + =/ z (~(mul ^rs %n) s s) + =/ cs=(list @rs) + :~ `@rs`0x3eaa.aaab `@rs`0x3e4c.cccd `@rs`0x3e12.4925 + `@rs`0x3de3.8e39 `@rs`0x3dba.2e8c + == + =/ p2 (roll (flop cs) |=([c=@rs a=@rs] (~(add ^rs %n) (~(mul ^rs %n) a z) c))) + =/ r (~(mul ^rs %n) (~(add ^rs %n) z z) p2) + =/ l1 (~(sub ^rs %n) f (~(mul ^rs %n) s (~(sub ^rs %n) f r))) + =/ efa (~(sun ^rs %n) (abs:si e)) + =/ ef ?:((syn:si e) efa (~(sub ^rs %n) .0 efa)) + [ef l1] + :: +pow: [@rs @rs] -> @rs + :: + :: Returns the power of a floating-point atom to a floating-point exponent. + :: Examples + :: > (pow .1 .2) + :: .1 + :: > (pow .2 .2) + :: .4 + :: > (pow .2 .3.5) + :: .11.313682 + :: > (~(pow rs:math [%z .1e-8]) .2 .3.5) + :: .11.313687 + :: Source + ++ pow + |= [x=@rs n=@rs] ^- @rs + :: fall through on positive integers (faster) + ?: &(=(n (san (need (toi n)))) (gth n .0)) (pow-n x (san (need (toi n)))) + (exp (mul n (log x))) + :: +sqrt: @rs -> @rs + :: + :: Returns the square root of a floating-point atom. + :: Alias for +sqt. + :: Examples + :: > (sqrt .1) + :: .1 + :: > (sqrt .2) + :: .1.4142128 + :: > (~(sqrt rs [%z .1e-8]) .2) + :: .1.414213 + :: Source + ++ sqrt sqt + :: +sqt: @rs -> @rs + :: + :: Returns the square root of a floating-point atom. + :: Examples + :: > (sqt .1) + :: .1 + :: > (sqt .2) + :: .1.4142135 + :: > (sqt .1e5) + :: .316.22775 + :: Source + ++ sqt + :: Correctly-rounded: delegate to the stdlib (SoftFloat) f32 square root. + |= x=@rs ^- @rs + (sqt:^rs x) + :: +cbrt: @rs -> @rs + :: + :: Returns the cube root of a floating-point atom. + :: Alias for +cbt. + :: Examples + :: > (cbrt .1) + :: .1 + :: > (cbrt .2) + :: .1.2599205 + :: > (~(cbrt rs [%z .1e-8]) .2) + :: .1.2599207 + :: Source + ++ cbrt cbt + :: +cbt: @rs -> @rs + :: + :: Returns the cube root of a floating-point atom. + :: Examples + :: > (cbt .1) + :: .1 + :: > (cbt .2) + :: .1.2599205 + :: > (~(cbt rs [%z .1e-8]) .2) + :: .1.2599207 + :: Source + ++ cbt + :: cbrt(x) = sign(x) * exp(log|x| / 3); defined for all reals (unlike pow). + |= x=@rs ^- @rs + ?: !(~(equ ^rs %n) x x) x :: NaN -> NaN + ?: |(=(x `@rs`0x0) =(x `@rs`0x8000.0000)) x :: +-0 -> +-0 + =/ ax `@rs`(dis x 0x7fff.ffff) + =/ r (exp (~(mul ^rs %n) (log ax) `@rs`0x3eaa.aaab)) + ?:(=(1 (rsh [0 31] x)) (~(sub ^rs %n) `@rs`0x0 r) r) + :: +arg: @rs -> @rs + :: + :: Returns the argument of a floating-point atom (real argument = absolute + :: value). + :: Examples + :: > (arg .1) + :: .1 + :: > (arg .-1) + :: .1 + :: Source + ++ arg abs + :: +round: [@rs @ud] -> @rs + :: + :: Returns the floating-point atom rounded to a given number of decimal + :: places. + :: Examples + :: > (round .1 0) + :: .1 + :: > (round .1.11 1) + :: .1.1 + :: > (round .1.11 2) + :: .1.11 + :: > (round .1.11 3) + :: .1.11 + :: Source + ++ round + |= [x=@rs n=@ud] ^- @rs + ?: =(.0 x) .0 + :: Calculate the order of magnitude. + =/ oom (san (need (toi (log-10 (abs x))))) + :: Calculate the scaling factor. + =/ scaling (pow .10 :(sub (sun n) oom .1)) + :: Round the mantissa to desired significant digits. + =/ rnd-mantissa (round-bankers (mul x scaling)) + :: Convert back to the original scale. + (div rnd-mantissa scaling) + :: +round-places: [@rs @ud] -> @rs + :: + :: Returns the floating-point atom rounded to a given number of decimal + :: places. This is exceptionally sensitive to off-by-one FP rounding error. + :: Examples + :: > (round-places .1 0) + :: .1 + :: > (round-places .1.11 1) + :: .1.1 + :: > (round-places .1.285 2) + :: .1.28 + :: > (round-places .4.12345 3) + :: .4.1229997 + :: Source + ++ round-places + |= [x=@rs n=@ud] ^- @rs + :: Calculate the scaling factor. + =/ scaling (pow .10 (sun n)) + :: Scale the number. + =/ scaled (mul x scaling) + :: Round the mantissa to desired significant digits. + =/ rnd-mantissa (round-bankers scaled) + :: Convert back to the original scale. + (div rnd-mantissa scaling) + :: +round-bankers: @rs -> @rs + :: + :: Returns the floating-point atom rounded to the nearest integer, with + :: ties rounded to the nearest even integer (banker's rounding). This is + :: exactly what +toi does under round-nearest (%n), which ties to even, so we + :: force %n regardless of the door's configured mode. + :: Examples + :: > (round-bankers .1.5) + :: .2 + :: > (round-bankers .2.5) + :: .2 + :: > (round-bankers .1.49) + :: .1 + :: Source + ++ round-bankers + |= x=@rs ^- @rs + (san (need (~(toi ^rs %n) x))) -- - :: +tan: @rd -> @rd - :: - :: Returns the tangent of a floating-point atom. - :: Examples - :: > (tan .~1) - :: .~1.5574077246550349 - :: > (tan .~2) - :: .~-2.185039863259177 - :: > (tan pi) - :: .~-2.6535896228476087e-6 - :: Source - ++ tan - :: Dedicated fdlibm __kernel_tan (faithful <=1 ULP); the sin/cos ratio is - :: ~2 ULP. q*pi/2 reduction, odd q uses the -cot path. See +rd-tan. - |= x=@rd ^- @rd - (main:rd-tan x) - :: +rd-tan: dedicated tangent kernel for the @rd door, see +tan. - ++ rd-tan - |% - ++ redq - |= ax=@rd ^- [q=@s rhi=@rd rlo=@rd] - =/ q (need (~(toi ^rd %n) (~(mul ^rd %n) ax `@rd`0x3fe4.5f30.6dc9.c883))) - =/ qf (~(sun ^rd %n) (abs:si q)) - =/ t (~(sub ^rd %n) ax (~(mul ^rd %n) qf `@rd`0x3ff9.21fb.5440.0000)) - =/ w (~(mul ^rd %n) qf `@rd`0x3dd0.b461.1a62.6331) - =/ rhi (~(sub ^rd %n) t w) - =/ rlo (~(sub ^rd %n) (~(sub ^rd %n) t rhi) w) - [q rhi rlo] - ++ ktan - |= [x=@rd y=@rd iy=@s] ^- @rd - =/ hxneg (rsh [0 63] x) - =/ big (~(gte ^rd %n) `@rd`(dis x 0x7fff.ffff.ffff.ffff) `@rd`0x3fe5.9428.0000.0000) - =/ xa ?:(=(hxneg 1) (~(sub ^rd %n) `@rd`0x0 x) x) - =/ ya ?:(=(hxneg 1) (~(sub ^rd %n) `@rd`0x0 y) y) - =/ xr - ?. big x - (~(add ^rd %n) (~(sub ^rd %n) `@rd`0x3fe9.21fb.5444.2d18 xa) (~(sub ^rd %n) `@rd`0x3c81.a626.3314.5c07 ya)) - =/ yr ?:(big `@rd`0x0 y) - =/ z (~(mul ^rd %n) xr xr) - =/ w (~(mul ^rd %n) z z) - =/ rl=(list @rd) - :~ `@rd`0x3fc1.1111.1110.fe7a `@rd`0x3f96.64f4.8406.d637 - `@rd`0x3f6d.6d22.c956.0328 `@rd`0x3f43.44d8.f2f2.6501 - `@rd`0x3f14.7e88.a037.92a6 `@rd`0xbef3.75cb.db60.5373 + :: double precision + ++ rd + ~/ %rd + ^| + |_ $: r=$?(%n %u %d %z) :: round nearest, up, down, to zero + rtol=_.~1e-10 :: relative tolerance for precision of operations == - =/ vl=(list @rd) - :~ `@rd`0x3fab.a1ba.1bb3.41fe `@rd`0x3f82.26e3.e96e.8493 - `@rd`0x3f57.dbc8.fee0.8315 `@rd`0x3f30.26f7.1a8d.1068 - `@rd`0x3f12.b80f.32f0.a7e9 `@rd`0x3efb.2a70.74bf.7ad4 + :: mathematics constants to single precision + :: +tau: @rd + :: + :: Returns the value 2*pi (OEIS A019692). + :: Examples + :: > tau + :: .~6.283185307179586 + :: Source + ++ tau .~6.283185307179586 + :: +pi: @rd + :: + :: Returns the value pi (OEIS A000796). + :: Examples + :: > pi + :: .~3.141592653589793 + :: Source + ++ pi .~3.141592653589793 + :: +e: @rd + :: + :: Returns the value e (Euler's constant) (OEIS A001113). + :: Examples + :: > e + :: .~2.718281828459045 + :: Source + ++ e .~2.718281828459045 + :: +phi: @rd + :: + :: Returns the value phi (golden ratio) (OEIS A001622). + :: Examples + :: > phi + :: .~1.618033988749895 + :: Source + ++ phi .~1.618033988749895 + :: +sqt2: @rd + :: + :: Returns the value sqrt(2) (OEIS A002193). + :: Examples + :: > sqt2 + :: .~1.414213562373095 + :: Source + ++ sqt2 .~1.4142135623730951 + :: +invsqt2: @rd + :: + :: Returns the value 1/sqrt(2) (OEIS A010503). + :: Examples + :: > invsqt2 + :: .~0.7071067811865476 + :: Source + ++ invsqt2 .~0.7071067811865476 + :: +log2: @rd + :: + :: Returns the value log(2) (OEIS A002162). + :: Examples + :: > log2 + :: .~0.6931471805599453 + :: Source + ++ log2 .~0.6931471805599453 + :: +invlog2: @rd + :: + :: Returns the value 1/log(2). + :: Examples + :: > invlog2 + :: .~1.4426950408889634 + :: Source + ++ invlog2 .~1.4426950408889634 + :: +log10: @rd + :: + :: Returns the value log(10) (OEIS A002392). + :: Examples + :: > log10 + :: .~2.302585092994046 + :: Source + ++ log10 .~2.302585092994046 + :: + :: +huge: @rd + :: + :: Returns the value of the largest representable number. + :: Examples + :: > huge + :: .~1.7976931348623157e+308 + :: Source + ++ huge `@rd`0x7fef.ffff.ffff.ffff :: 1.79769313486231570815e+308 + :: +tiny: @rd + :: + :: Returns the value of the smallest representable normal number. + :: Examples + :: > tiny + :: .~2.2250738585072014e-308 + :: Source + ++ tiny `@rd`0x10.0000.0000.0000 :: 2.22507385850720138309e-308 + :: + :: Operations + :: + :: +sea: @rd -> fn + :: + :: Returns the +$fn representation of a floating-point atom. + :: Examples + :: > (sea .~1) + :: [%f s=%.y e=-52 a=4.503.599.627.370.496] + :: > (sea .~1.1) + :: [%f s=%.y e=-52 a=4.953.959.590.107.546] + :: Source + ++ sea sea:^rd + :: +bit: fn -> @rd + :: + :: Returns the floating-point atom of a +$fn representation. + :: Examples + :: > (bit [%f s=%.y e=-52 a=4.503.599.627.370.496]) + :: .~1 + :: > (bit [%f s=%.y e=-52 a=4.953.959.590.107.546]) + :: .~1.1 + :: Source + ++ bit bit:^rd + :: +sun: @ud -> @rd + :: + :: Returns the floating-point atom of an unsigned integer atom. + :: Examples + :: > (sun 1) + :: .~1 + :: > (sun 1.000) + :: .~1e3 + :: Source + ++ sun sun:^rd + :: +san: @sd -> @rd + :: + :: Returns the floating-point atom of a signed integer atom. + :: Examples + :: > (san --1) + :: .~1 + :: > (san -1) + :: .~-1 + :: Source + ++ san san:^rd + ::++ exp exp:^rd :: no pass-through because of exp function + :: +toi: @rd -> @sd + :: + :: Returns the unitized signed integer atom of a rounded floating-point atom. + :: Examples + :: > (toi .~1) + :: [~ --1] + :: > (toi .~1.1) + :: [~ --1] + :: Source + ++ toi toi:^rd + :: +drg: @rd -> dn + :: + :: Returns the decimal form of a floating-point atom using the Dragon4 + :: algorithm. + :: Examples + :: > (drg .~1) + :: [%d s=%.y e=--0 a=1] + :: > (drg .~1.1) + :: [%d s=%.y e=-1 a=11] + :: Source + ++ drg drg:^rd + :: +grd: dn -> @rd + :: + :: Returns the floating-point atom of a decimal form. + :: Examples + :: > (grd [%d s=%.y e=--0 a=1]) + :: .~1 + :: > (grd [%d s=%.y e=-1 a=11]) + :: .~1.1 + :: Source + ++ grd grd:^rd + :: + :: Comparison + :: + :: +lth: [@rd @rd] -> ? + :: + :: Returns the comparison of two floating-point atoms, less than. + :: Examples + :: > (lth .~1 .~2) + :: %.y + :: > (lth .~2 .~1) + :: %.n + :: > (lth .~1 .~1) + :: %.n + :: Source + ++ lth lth:^rd + :: +lte: [@rd @rd] -> ? + :: + :: Returns the comparison of two floating-point atoms, less than or equal to. + :: Examples + :: > (lte .~1 .~2) + :: %.y + :: > (lte .~2 .~1) + :: %.n + :: > (lte .~1 .~1) + :: %.y + :: Source + ++ lte lte:^rd + :: +leq: [@rd @rd] -> ? + :: + :: Returns the comparison of two floating-point atoms, less than or equal to. + :: Alias for +lte. + :: Examples + :: > (leq .~1 .~2) + :: %.y + :: > (leq .~2 .~1) + :: %.n + :: > (leq .~1 .~1) + :: %.y + :: Source + ++ leq lte:^rd + :: +equ: [@rd @rd] -> ? + :: + :: Returns the comparison of two floating-point atoms, equal to. + :: Examples + :: > (equ .~1 .~2) + :: %.n + :: > (equ .~2 .~1) + :: %.n + :: > (equ .~1 .~1) + :: %.y + :: Source + ++ equ equ:^rd + :: +gth: [@rd @rd] -> ? + :: + :: Returns the comparison of two floating-point atoms, greater than. + :: Examples + :: > (gth .~1 .~2) + :: %.n + :: > (gth .~2 .~1) + :: %.y + :: > (gth .~1 .~1) + :: %.n + :: Source + ++ gth gth:^rd + :: +gte: [@rd @rd] -> ? + :: + :: Returns the comparison of two floating-point atoms, greater than or equal to. + :: Examples + :: > (gte .~1 .~2) + :: %.n + :: > (gte .~2 .~1) + :: %.y + :: > (gte .~1 .~1) + :: %.y + :: Source + ++ gte gte:^rd + :: +geq: [@rd @rd] -> ? + :: + :: Returns the comparison of two floating-point atoms, greater than or equal to. + :: Alias for +gte. + :: Examples + :: > (geq .~1 .~2) + :: %.n + :: > (geq .~2 .~1) + :: %.y + :: > (geq .~1 .~1) + :: %.y + :: Source + ++ geq gte:^rd + :: +neq: [@rd @rd] -> ? + :: + :: Returns the comparison of two floating-point atoms, not equal to. + :: Examples + :: > (neq .~1 .~2) + :: %.y + :: > (neq .~2 .~1) + :: %.y + :: > (neq .~1 .~1) + :: %.n + :: Source + ++ neq |=([a=@rd b=@rd] ^-(? !(equ:^rd a b))) + :: +is-close: [@rd @rd] -> ? + :: + :: Returns the comparison of two floating-point atoms, within a relative + :: tolerance (provided by the +rd door). + :: Examples + :: > (is-close .~1 .~2) + :: %.n + :: > (is-close .~1 .~1.0000001) + :: %.n + :: > (~(is-close rd [%z .~1e-3]) .~1 .~1.0000001) + :: %.y + :: Source + ++ is-close + |= [p=@rd r=@rd] + (lth (abs (sub p r)) rtol) + :: +all-close: [@rd (list @rd)] -> ? + :: + :: Returns the comparison of a floating-point atom to a list of floating- + :: point atoms, within a relative tolerance (provided by the +rd door). + :: Examples + :: > (all-close .~1 ~[.~1 .~2]) + :: %.n + :: > (all-close .~1 ~[.~1 .~1.0000001]) + :: %.n + :: > (~(all-close rd [%z .~1e-3]) .~1 ~[.~1 .~1.0000001]) + :: %.y + :: Source + ++ all-close + |= [p=@rd q=(list @rd)] + =/ i 0 + =/ n (lent q) + |- ^- ? + ?: =(n i) + %.y + ?. (is-close p (snag i q)) + %.n + $(i +(i)) + :: +is-int: @rd -> ? + :: + :: Returns whether a floating-point value is an integer (no fractional part). + :: Examples + :: > (is-int .~1) + :: %.y + :: > (is-int .~1.1) + :: %.n + :: Source + ++ is-int + |= x=@rd ^- ? + (equ x (san (need (toi x)))) + :: + :: Algebraic + :: + :: +add: [@rd @rd] -> @rd + :: + :: Returns the sum of two floating-point atoms. + :: Examples + :: > (add .~1 .~2) + :: .~3 + :: Source + ++ add add:^rd + :: +sub: [@rd @rd] -> @rd + :: + :: Returns the difference of two floating-point atoms. + :: Examples + :: > (sub .~1 .~2) + :: .~-1 + :: Source + ++ sub sub:^rd + :: +mul: [@rd @rd] -> @rd + :: + :: Returns the product of two floating-point atoms. + :: Examples + :: > (mul .~1 .~2) + :: .~2 + :: > (mul .~2 .~3) + :: .~6 + :: Source + ++ mul mul:^rd + :: +div: [@rd @rd] -> @rd + :: + :: Returns the quotient of two floating-point atoms. + :: Examples + :: > (div .~1 .~2) + :: .~0.5 + :: Source + ++ div div:^rd + :: +fma: [@rd @rd @rd] -> @rd + :: + :: Returns the fused multiply-add of three floating-point atoms. + :: Examples + :: > (fma .~1 .~2 .~3) + :: .~5 + :: > (fma .~2 .~3 .~4) + :: .~10 + :: Source + ++ fma fma:^rd + :: +sig: @rd -> ? + :: + :: Returns the sign of a floating-point atom. + :: Examples + :: > (sig .~1) + :: %.y + :: > (sig .~-1) + :: %.n + :: Source + ++ sig |=(x=@rd =(0 (rsh [0 63] x))) + :: +sgn: @rd -> ? + :: + :: Returns the sign of a floating-point atom. + :: Alias for +sig. + :: Examples + :: > (sgn .~1) + :: %.y + :: > (sgn .~-1) + :: %.n + :: Source + ++ sgn sig + :: +neg: @rd -> @rd + :: + :: Returns the negation of a floating-point atom. + :: Examples + :: > (neg .~1) + :: .~-1 + :: > (neg .~-1) + :: .~1 + :: Source + ++ neg |=(x=@rd (sub .~0 x)) + :: +factorial: @rd -> @rd + :: + :: Returns the factorial of a floating-point atom. Assumes integer input. + :: Examples + :: > (factorial .~1) + :: .~1 + :: > (factorial .~2) + :: .~2 + :: > (factorial .~3) + :: .~6 + :: Source + ++ factorial + |= x=@rd ^- @rd + ?> (gte x .~0) + =/ t=@rd .~1 + ?: (is-close x .~0) + t + |- ^- @rd + ?: (is-close x .~1) + t + $(x (sub x .~1), t (mul t x)) + :: +abs: @rd -> @rd + :: + :: Returns the absolute value of a floating-point atom. + :: Examples + :: > (abs .~1) + :: .~1 + :: > (abs .~-1) + :: .~1 + :: Source + ++ abs + |= x=@rd ^- @rd + ?:((sgn x) x (neg x)) + :: +exp: @rd -> @rd + :: + :: Returns the exponential of a floating-point atom. + :: Examples + :: > (exp .~1) + :: .~2.7182818284582266 + :: > (exp .~2) + :: .~7.389056098925858 + :: > (~(exp rd [%z .~1e-15]) .~2) + :: .~7.389056098930642 + :: > (exp .~inf) + :: .inf + :: Source + ++ exp + ~/ %exp + |= x=@rd ^- @rd + :: Chebyshev: x = k*ln2 + r (Cody-Waite reduction); exp(x) = 2^k * P(r), + :: P a degree-11 minimax polynomial faithful to <=1 ULP. Internals are + :: forced to round-nearest-even: a correctly-rounded transcendental does + :: not take a rounding-mode axis (and the SoftFloat jet will match this). + :: +scale2 is a correctly-rounded ldexp that stays exact across the normal + :: range and rounds exactly once into the overflow/subnormal tails. + =/ pow2 |=(j=@s `@rd`(lsh [0 52] (abs:si (sum:si j --1.023)))) + =/ scale2 + |= [p=@rd k=@s] ^- @rd + ?: (syn:si (dif:si k --1.024)) :: k>1023: (p*2^1023)*2^(k-1023) + (~(mul ^rd %n) (~(mul ^rd %n) p (pow2 --1.023)) (pow2 (dif:si k --1.023))) + ?: !(syn:si (sum:si k --1.022)) :: k<-1022: (p*2^(k+54))*2^-54 + (~(mul ^rd %n) (~(mul ^rd %n) p (pow2 (sum:si k --54))) (pow2 -54)) + (~(mul ^rd %n) p (pow2 k)) + ?: !(~(equ ^rd %n) x x) `@rd`0x7ff8.0000.0000.0000 :: NaN + ?: =(x `@rd`0x7ff0.0000.0000.0000) `@rd`0x7ff0.0000.0000.0000 :: +inf + ?: =(x `@rd`0xfff0.0000.0000.0000) `@rd`0x0 :: -inf -> 0 + =/ log2e `@rd`0x3ff7.1547.652b.82fe + =/ ln2hi `@rd`0x3fe6.2e42.fee0.0000 + =/ ln2lo `@rd`0x3dea.39ef.3579.3c76 + =/ k=@s (need (~(toi ^rd %n) (~(mul ^rd %n) x log2e))) + ?: (syn:si (dif:si k --1.025)) `@rd`0x7ff0.0000.0000.0000 :: overflow -> inf + ?: !(syn:si (sum:si k --1.075)) `@rd`0x0 :: underflow -> 0 + =/ ka (~(sun ^rd %n) (abs:si k)) + =/ kf ?:((syn:si k) ka (~(sub ^rd %n) .~0 ka)) :: k as @rd + =/ r + %- ~(sub ^rd %n) + :- (~(sub ^rd %n) x (~(mul ^rd %n) kf ln2hi)) + (~(mul ^rd %n) kf ln2lo) + =/ cs=(list @rd) + :~ `@rd`0x3ff0.0000.0000.0000 `@rd`0x3ff0.0000.0000.0000 + `@rd`0x3fe0.0000.0000.0011 `@rd`0x3fc5.5555.5555.555a + `@rd`0x3fa5.5555.5554.f0cf `@rd`0x3f81.1111.1110.f225 + `@rd`0x3f56.c16c.187f.be02 `@rd`0x3f2a.01a0.1b14.378f + `@rd`0x3efa.0199.1ac8.730a `@rd`0x3ec7.1ddf.5749.d126 + `@rd`0x3e92.8b40.57f4.4145 `@rd`0x3e5a.f631.d005.9bec == - =/ rr (roll (flop rl) |=([c=@rd a=@rd] (~(add ^rd %n) (~(mul ^rd %n) a w) c))) - =/ vv (~(mul ^rd %n) z (roll (flop vl) |=([c=@rd a=@rd] (~(add ^rd %n) (~(mul ^rd %n) a w) c)))) - =/ s (~(mul ^rd %n) z xr) - =/ r (~(add ^rd %n) yr (~(mul ^rd %n) z (~(add ^rd %n) (~(mul ^rd %n) s (~(add ^rd %n) rr vv)) yr))) - =. r (~(add ^rd %n) r (~(mul ^rd %n) `@rd`0x3fd5.5555.5555.5563 s)) - =/ w2 (~(add ^rd %n) xr r) - ?: big - =/ fac ?:(=(hxneg 1) `@rd`0xbff0.0000.0000.0000 `@rd`0x3ff0.0000.0000.0000) - =/ v ?:(=(iy --1) `@rd`0x3ff0.0000.0000.0000 `@rd`0xbff0.0000.0000.0000) - %+ ~(mul ^rd %n) fac - %+ ~(sub ^rd %n) v - %+ ~(mul ^rd %n) `@rd`0x4000.0000.0000.0000 - %+ ~(sub ^rd %n) xr - (~(sub ^rd %n) (~(div ^rd %n) (~(mul ^rd %n) w2 w2) (~(add ^rd %n) w2 v)) r) - ?: =(iy --1) w2 - =/ zz `@rd`(dis w2 0xffff.ffff.0000.0000) - =/ vv2 (~(sub ^rd %n) r (~(sub ^rd %n) zz xr)) - =/ a (~(div ^rd %n) `@rd`0xbff0.0000.0000.0000 w2) - =/ tt `@rd`(dis a 0xffff.ffff.0000.0000) - =/ ss (~(add ^rd %n) `@rd`0x3ff0.0000.0000.0000 (~(mul ^rd %n) tt zz)) - (~(add ^rd %n) tt (~(mul ^rd %n) a (~(add ^rd %n) ss (~(mul ^rd %n) tt vv2)))) - ++ main + =/ p (roll (flop cs) |=([c=@rd acc=@rd] (~(add ^rd %n) (~(mul ^rd %n) acc r) c))) + (scale2 p k) + :: +sin: @rd -> @rd + :: + :: Returns the sine of a floating-point atom. + :: Examples + :: > (sin .~1) + :: .~0.8414709848078934 + :: > (sin .~2) + :: .~0.9092974268256406 + :: > (sin pi) + :: .~-1.698287706085482e-13 + :: Source + ++ sin |= x=@rd ^- @rd + :: Reduce x = q*(pi/2) + (rhi+rlo) (2-part pi/2), then fdlibm sin/cos + :: kernels picked by q&3. Faithful to <=1 ULP for |x| <~ 2^22. + :: Round-nearest-even internally (the SoftFloat jet matches). ?: !(~(equ ^rd %n) x x) `@rd`0x7ff8.0000.0000.0000 ?: |(=(x `@rd`0x7ff0.0000.0000.0000) =(x `@rd`0xfff0.0000.0000.0000)) `@rd`0x7ff8.0000.0000.0000 - ?: |(=(x `@rd`0x0) =(x `@rd`0x8000.0000.0000.0000)) x - =/ neg (rsh [0 63] x) - =/ ax `@rd`(dis x 0x7fff.ffff.ffff.ffff) - =/ red (redq ax) - =/ iy ?:(=(0 (dis (abs:si q.red) 1)) --1 -1) - =/ t (ktan rhi.red rlo.red iy) - ?:(=(neg 1) (~(sub ^rd %n) `@rd`0x0 t) t) - -- - :: +asin: @rd -> @rd - :: - :: Returns the inverse sine of a floating-point atom. - :: Examples - :: > (asin .~0) - :: .~0 - :: > (asin .~1) - :: .~1.5707963267948966 - :: > (asin .~0.7) - :: .~0.7753974965943197 - :: - ++ asin - :: fdlibm rational kernel; see +rd-ainv. Faithful to <=1 ULP; |x|>1 -> NaN. - |= x=@rd ^- @rd - (asn:rd-ainv x) - :: +acos: @rd -> @rd - :: - :: Returns the inverse cosine of a floating-point atom. - :: Examples - :: > (acos .~0) - :: .~1.5707963267948966 - :: > (acos .~1) - :: .~0 - :: > (acos .~0.7) - :: .~0.7953988301652518 - :: - ++ acos - |= x=@rd ^- @rd - (acs:rd-ainv x) - :: +rd-ainv: shared asin/acos engine for the @rd door (rational P/Q kernel), - :: see +asin / +acos. - ++ rd-ainv - |% - ++ rr - |= t=@rd ^- @rd - =/ ps=(list @rd) - :~ `@rd`0x3fc5.5555.5555.5555 `@rd`0xbfd4.d612.03eb.6f7d - `@rd`0x3fc9.c155.0e88.4455 `@rd`0xbfa4.8228.b568.8f3b - `@rd`0x3f49.efe0.7501.b288 `@rd`0x3f02.3de1.0dfd.f709 + ?: |(=(x `@rd`0x0) =(x `@rd`0x8000.0000.0000.0000)) x :: +-0 -> +-0 + %- trig-fin:rd-trig + [%.y `@rd`(dis x 0x7fff.ffff.ffff.ffff) (rsh [0 63] x)] + :: +cos: @rd -> @rd + :: + :: Returns the cosine of a floating-point atom. + :: Examples + :: > (cos .~1) + :: .~0.5403023058680917 + :: > (cos .~2) + :: .~-0.41614683654756957 + :: > (cos pi) + :: .~-1.0000000000013558 + :: Source + ++ cos + |= x=@rd ^- @rd + ?: !(~(equ ^rd %n) x x) `@rd`0x7ff8.0000.0000.0000 + ?: |(=(x `@rd`0x7ff0.0000.0000.0000) =(x `@rd`0xfff0.0000.0000.0000)) `@rd`0x7ff8.0000.0000.0000 + %- trig-fin:rd-trig + [%.n `@rd`(dis x 0x7fff.ffff.ffff.ffff) 0] + :: +rd-trig: shared sin/cos engine for the @rd door (see +sin / +cos). + ++ rd-trig + |% + ++ sc + ^- (list @rd) + :~ `@rd`0xbfc5.5555.5555.5555 `@rd`0x3f81.1111.1111.1111 + `@rd`0xbf2a.01a0.1a01.a01a `@rd`0x3ec7.1de3.a556.c734 + `@rd`0xbe5a.e645.67f5.44e4 `@rd`0x3de6.1246.13a8.6d09 + `@rd`0xbd6a.e7f3.e733.b81f `@rd`0x3ce9.52c7.7030.ad4a == - =/ qs=(list @rd) - :~ `@rd`0xc003.3a27.1c8a.2d4b `@rd`0x4000.2ae5.9c59.8ac8 - `@rd`0xbfe6.066c.1b8d.0159 `@rd`0x3fb3.b8c5.b12e.9282 + ++ cc + ^- (list @rd) + :~ `@rd`0x3fa5.5555.5555.5555 `@rd`0xbf56.c16c.16c1.6c17 + `@rd`0x3efa.01a0.1a01.a01a `@rd`0xbe92.7e4f.b778.9f5c + `@rd`0x3e21.eed8.eff8.d898 `@rd`0xbda9.3974.a8c0.7c9d + `@rd`0x3d2a.e7f3.e733.b81f `@rd`0xbca6.8278.63b9.7d97 == - =/ p (~(mul ^rd %n) t (roll (flop ps) |=([c=@rd a=@rd] (~(add ^rd %n) (~(mul ^rd %n) a t) c)))) - =/ q (~(add ^rd %n) `@rd`0x3ff0.0000.0000.0000 (~(mul ^rd %n) t (roll (flop qs) |=([c=@rd a=@rd] (~(add ^rd %n) (~(mul ^rd %n) a t) c))))) - (~(div ^rd %n) p q) - ++ asn + ++ neg |=(a=@rd ^-(@rd (~(sub ^rd %n) `@rd`0x0 a))) + ++ ksin + |= [xx=@rd yy=@rd] ^- @rd + =/ z (~(mul ^rd %n) xx xx) + =/ r (roll (flop (tail sc)) |=([c=@rd a=@rd] (~(add ^rd %n) (~(mul ^rd %n) a z) c))) + =/ v (~(mul ^rd %n) z xx) + =/ aa (~(sub ^rd %n) (~(mul ^rd %n) `@rd`0x3fe0.0000.0000.0000 yy) (~(mul ^rd %n) v r)) + =/ bb (~(sub ^rd %n) (~(mul ^rd %n) z aa) yy) + =/ dd (~(sub ^rd %n) bb (~(mul ^rd %n) v (head sc))) + (~(sub ^rd %n) xx dd) + ++ kcos + |= [xx=@rd yy=@rd] ^- @rd + =/ z (~(mul ^rd %n) xx xx) + =/ rc (roll (flop cc) |=([c=@rd a=@rd] (~(add ^rd %n) (~(mul ^rd %n) a z) c))) + =/ hz (~(mul ^rd %n) `@rd`0x3fe0.0000.0000.0000 z) + =/ w2 (~(sub ^rd %n) `@rd`0x3ff0.0000.0000.0000 hz) + =/ aa (~(sub ^rd %n) (~(sub ^rd %n) `@rd`0x3ff0.0000.0000.0000 w2) hz) + =/ bb (~(sub ^rd %n) (~(mul ^rd %n) (~(mul ^rd %n) z z) rc) (~(mul ^rd %n) xx yy)) + (~(add ^rd %n) w2 (~(add ^rd %n) aa bb)) + :: +trig-fin: [is-sin? |x| sign-bit] -> sin x (is-sin?) or cos x + ++ trig-fin + |= [s=? ax=@rd sb=@] ^- @rd + =/ q (need (~(toi ^rd %n) (~(mul ^rd %n) ax `@rd`0x3fe4.5f30.6dc9.c883))) + =/ qf (~(sun ^rd %n) (abs:si q)) + =/ t (~(sub ^rd %n) ax (~(mul ^rd %n) qf `@rd`0x3ff9.21fb.5440.0000)) + =/ w (~(mul ^rd %n) qf `@rd`0x3dd0.b461.1a62.6331) + =/ rhi (~(sub ^rd %n) t w) + =/ rlo (~(sub ^rd %n) (~(sub ^rd %n) t rhi) w) + =/ m (dis (abs:si q) 3) + =/ ks (ksin rhi rlo) + =/ kc (kcos rhi rlo) + ?: s + =/ v ?:(=(m 0) ks ?:(=(m 1) kc ?:(=(m 2) (neg ks) (neg kc)))) + ?:(=(sb 1) (neg v) v) + ?:(=(m 0) kc ?:(=(m 1) (neg ks) ?:(=(m 2) (neg kc) ks))) + -- + :: +tan: @rd -> @rd + :: + :: Returns the tangent of a floating-point atom. + :: Examples + :: > (tan .~1) + :: .~1.5574077246550349 + :: > (tan .~2) + :: .~-2.185039863259177 + :: > (tan pi) + :: .~-2.6535896228476087e-6 + :: Source + ++ tan + :: Dedicated fdlibm __kernel_tan (faithful <=1 ULP); the sin/cos ratio is + :: ~2 ULP. q*pi/2 reduction, odd q uses the -cot path. See +rd-tan. |= x=@rd ^- @rd - ?: !(~(equ ^rd %n) x x) `@rd`0x7ff8.0000.0000.0000 - =/ sgn (rsh [0 63] x) - =/ ax `@rd`(dis x 0x7fff.ffff.ffff.ffff) - ?: (~(gth ^rd %n) ax `@rd`0x3ff0.0000.0000.0000) `@rd`0x7ff8.0000.0000.0000 - ?: =(ax `@rd`0x3ff0.0000.0000.0000) - (~(add ^rd %n) (~(mul ^rd %n) x `@rd`0x3ff9.21fb.5444.2d18) (~(mul ^rd %n) x `@rd`0x3c91.a626.3314.5c07)) - ?: (~(lth ^rd %n) ax `@rd`0x3fe0.0000.0000.0000) - ?: (~(lth ^rd %n) ax `@rd`0x3e50.0000.0000.0000) x - =/ t (~(mul ^rd %n) x x) - (~(add ^rd %n) x (~(mul ^rd %n) x (rr t))) - =/ w (~(sub ^rd %n) `@rd`0x3ff0.0000.0000.0000 ax) - =/ t (~(mul ^rd %n) w `@rd`0x3fe0.0000.0000.0000) - =/ r (rr t) - =/ s (sqt t) - ?: (~(gte ^rd %n) ax `@rd`0x3fef.3333.0000.0000) - =/ res (~(sub ^rd %n) `@rd`0x3ff9.21fb.5444.2d18 (~(sub ^rd %n) (~(mul ^rd %n) `@rd`0x4000.0000.0000.0000 (~(add ^rd %n) s (~(mul ^rd %n) s r))) `@rd`0x3c91.a626.3314.5c07)) + (main:rd-tan x) + :: +rd-tan: dedicated tangent kernel for the @rd door, see +tan. + ++ rd-tan + |% + ++ redq + |= ax=@rd ^- [q=@s rhi=@rd rlo=@rd] + =/ q (need (~(toi ^rd %n) (~(mul ^rd %n) ax `@rd`0x3fe4.5f30.6dc9.c883))) + =/ qf (~(sun ^rd %n) (abs:si q)) + =/ t (~(sub ^rd %n) ax (~(mul ^rd %n) qf `@rd`0x3ff9.21fb.5440.0000)) + =/ w (~(mul ^rd %n) qf `@rd`0x3dd0.b461.1a62.6331) + =/ rhi (~(sub ^rd %n) t w) + =/ rlo (~(sub ^rd %n) (~(sub ^rd %n) t rhi) w) + [q rhi rlo] + ++ ktan + |= [x=@rd y=@rd iy=@s] ^- @rd + =/ hxneg (rsh [0 63] x) + =/ big (~(gte ^rd %n) `@rd`(dis x 0x7fff.ffff.ffff.ffff) `@rd`0x3fe5.9428.0000.0000) + =/ xa ?:(=(hxneg 1) (~(sub ^rd %n) `@rd`0x0 x) x) + =/ ya ?:(=(hxneg 1) (~(sub ^rd %n) `@rd`0x0 y) y) + =/ xr + ?. big x + (~(add ^rd %n) (~(sub ^rd %n) `@rd`0x3fe9.21fb.5444.2d18 xa) (~(sub ^rd %n) `@rd`0x3c81.a626.3314.5c07 ya)) + =/ yr ?:(big `@rd`0x0 y) + =/ z (~(mul ^rd %n) xr xr) + =/ w (~(mul ^rd %n) z z) + =/ rl=(list @rd) + :~ `@rd`0x3fc1.1111.1110.fe7a `@rd`0x3f96.64f4.8406.d637 + `@rd`0x3f6d.6d22.c956.0328 `@rd`0x3f43.44d8.f2f2.6501 + `@rd`0x3f14.7e88.a037.92a6 `@rd`0xbef3.75cb.db60.5373 + == + =/ vl=(list @rd) + :~ `@rd`0x3fab.a1ba.1bb3.41fe `@rd`0x3f82.26e3.e96e.8493 + `@rd`0x3f57.dbc8.fee0.8315 `@rd`0x3f30.26f7.1a8d.1068 + `@rd`0x3f12.b80f.32f0.a7e9 `@rd`0x3efb.2a70.74bf.7ad4 + == + =/ rr (roll (flop rl) |=([c=@rd a=@rd] (~(add ^rd %n) (~(mul ^rd %n) a w) c))) + =/ vv (~(mul ^rd %n) z (roll (flop vl) |=([c=@rd a=@rd] (~(add ^rd %n) (~(mul ^rd %n) a w) c)))) + =/ s (~(mul ^rd %n) z xr) + =/ r (~(add ^rd %n) yr (~(mul ^rd %n) z (~(add ^rd %n) (~(mul ^rd %n) s (~(add ^rd %n) rr vv)) yr))) + =. r (~(add ^rd %n) r (~(mul ^rd %n) `@rd`0x3fd5.5555.5555.5563 s)) + =/ w2 (~(add ^rd %n) xr r) + ?: big + =/ fac ?:(=(hxneg 1) `@rd`0xbff0.0000.0000.0000 `@rd`0x3ff0.0000.0000.0000) + =/ v ?:(=(iy --1) `@rd`0x3ff0.0000.0000.0000 `@rd`0xbff0.0000.0000.0000) + %+ ~(mul ^rd %n) fac + %+ ~(sub ^rd %n) v + %+ ~(mul ^rd %n) `@rd`0x4000.0000.0000.0000 + %+ ~(sub ^rd %n) xr + (~(sub ^rd %n) (~(div ^rd %n) (~(mul ^rd %n) w2 w2) (~(add ^rd %n) w2 v)) r) + ?: =(iy --1) w2 + =/ zz `@rd`(dis w2 0xffff.ffff.0000.0000) + =/ vv2 (~(sub ^rd %n) r (~(sub ^rd %n) zz xr)) + =/ a (~(div ^rd %n) `@rd`0xbff0.0000.0000.0000 w2) + =/ tt `@rd`(dis a 0xffff.ffff.0000.0000) + =/ ss (~(add ^rd %n) `@rd`0x3ff0.0000.0000.0000 (~(mul ^rd %n) tt zz)) + (~(add ^rd %n) tt (~(mul ^rd %n) a (~(add ^rd %n) ss (~(mul ^rd %n) tt vv2)))) + ++ main + |= x=@rd ^- @rd + ?: !(~(equ ^rd %n) x x) `@rd`0x7ff8.0000.0000.0000 + ?: |(=(x `@rd`0x7ff0.0000.0000.0000) =(x `@rd`0xfff0.0000.0000.0000)) `@rd`0x7ff8.0000.0000.0000 + ?: |(=(x `@rd`0x0) =(x `@rd`0x8000.0000.0000.0000)) x + =/ neg (rsh [0 63] x) + =/ ax `@rd`(dis x 0x7fff.ffff.ffff.ffff) + =/ red (redq ax) + =/ iy ?:(=(0 (dis (abs:si q.red) 1)) --1 -1) + =/ t (ktan rhi.red rlo.red iy) + ?:(=(neg 1) (~(sub ^rd %n) `@rd`0x0 t) t) + -- + :: +asin: @rd -> @rd + :: + :: Returns the inverse sine of a floating-point atom. + :: Examples + :: > (asin .~0) + :: .~0 + :: > (asin .~1) + :: .~1.5707963267948966 + :: > (asin .~0.7) + :: .~0.7753974965943197 + :: + ++ asin + :: fdlibm rational kernel; see +rd-ainv. Faithful to <=1 ULP; |x|>1 -> NaN. + |= x=@rd ^- @rd + (asn:rd-ainv x) + :: +acos: @rd -> @rd + :: + :: Returns the inverse cosine of a floating-point atom. + :: Examples + :: > (acos .~0) + :: .~1.5707963267948966 + :: > (acos .~1) + :: .~0 + :: > (acos .~0.7) + :: .~0.7953988301652518 + :: + ++ acos + |= x=@rd ^- @rd + (acs:rd-ainv x) + :: +rd-ainv: shared asin/acos engine for the @rd door (rational P/Q kernel), + :: see +asin / +acos. + ++ rd-ainv + |% + ++ rr + |= t=@rd ^- @rd + =/ ps=(list @rd) + :~ `@rd`0x3fc5.5555.5555.5555 `@rd`0xbfd4.d612.03eb.6f7d + `@rd`0x3fc9.c155.0e88.4455 `@rd`0xbfa4.8228.b568.8f3b + `@rd`0x3f49.efe0.7501.b288 `@rd`0x3f02.3de1.0dfd.f709 + == + =/ qs=(list @rd) + :~ `@rd`0xc003.3a27.1c8a.2d4b `@rd`0x4000.2ae5.9c59.8ac8 + `@rd`0xbfe6.066c.1b8d.0159 `@rd`0x3fb3.b8c5.b12e.9282 + == + =/ p (~(mul ^rd %n) t (roll (flop ps) |=([c=@rd a=@rd] (~(add ^rd %n) (~(mul ^rd %n) a t) c)))) + =/ q (~(add ^rd %n) `@rd`0x3ff0.0000.0000.0000 (~(mul ^rd %n) t (roll (flop qs) |=([c=@rd a=@rd] (~(add ^rd %n) (~(mul ^rd %n) a t) c))))) + (~(div ^rd %n) p q) + ++ asn + |= x=@rd ^- @rd + ?: !(~(equ ^rd %n) x x) `@rd`0x7ff8.0000.0000.0000 + =/ sgn (rsh [0 63] x) + =/ ax `@rd`(dis x 0x7fff.ffff.ffff.ffff) + ?: (~(gth ^rd %n) ax `@rd`0x3ff0.0000.0000.0000) `@rd`0x7ff8.0000.0000.0000 + ?: =(ax `@rd`0x3ff0.0000.0000.0000) + (~(add ^rd %n) (~(mul ^rd %n) x `@rd`0x3ff9.21fb.5444.2d18) (~(mul ^rd %n) x `@rd`0x3c91.a626.3314.5c07)) + ?: (~(lth ^rd %n) ax `@rd`0x3fe0.0000.0000.0000) + ?: (~(lth ^rd %n) ax `@rd`0x3e50.0000.0000.0000) x + =/ t (~(mul ^rd %n) x x) + (~(add ^rd %n) x (~(mul ^rd %n) x (rr t))) + =/ w (~(sub ^rd %n) `@rd`0x3ff0.0000.0000.0000 ax) + =/ t (~(mul ^rd %n) w `@rd`0x3fe0.0000.0000.0000) + =/ r (rr t) + =/ s (sqt t) + ?: (~(gte ^rd %n) ax `@rd`0x3fef.3333.0000.0000) + =/ res (~(sub ^rd %n) `@rd`0x3ff9.21fb.5444.2d18 (~(sub ^rd %n) (~(mul ^rd %n) `@rd`0x4000.0000.0000.0000 (~(add ^rd %n) s (~(mul ^rd %n) s r))) `@rd`0x3c91.a626.3314.5c07)) + ?:(=(sgn 1) (~(sub ^rd %n) `@rd`0x0 res) res) + =/ df `@rd`(dis s 0xffff.ffff.0000.0000) + =/ c (~(div ^rd %n) (~(sub ^rd %n) t (~(mul ^rd %n) df df)) (~(add ^rd %n) s df)) + =/ p2 (~(sub ^rd %n) (~(mul ^rd %n) `@rd`0x4000.0000.0000.0000 (~(mul ^rd %n) s r)) (~(sub ^rd %n) `@rd`0x3c91.a626.3314.5c07 (~(mul ^rd %n) `@rd`0x4000.0000.0000.0000 c))) + =/ q2 (~(sub ^rd %n) `@rd`0x3fe9.21fb.5444.2d18 (~(mul ^rd %n) `@rd`0x4000.0000.0000.0000 df)) + =/ res (~(sub ^rd %n) `@rd`0x3fe9.21fb.5444.2d18 (~(sub ^rd %n) p2 q2)) ?:(=(sgn 1) (~(sub ^rd %n) `@rd`0x0 res) res) - =/ df `@rd`(dis s 0xffff.ffff.0000.0000) - =/ c (~(div ^rd %n) (~(sub ^rd %n) t (~(mul ^rd %n) df df)) (~(add ^rd %n) s df)) - =/ p2 (~(sub ^rd %n) (~(mul ^rd %n) `@rd`0x4000.0000.0000.0000 (~(mul ^rd %n) s r)) (~(sub ^rd %n) `@rd`0x3c91.a626.3314.5c07 (~(mul ^rd %n) `@rd`0x4000.0000.0000.0000 c))) - =/ q2 (~(sub ^rd %n) `@rd`0x3fe9.21fb.5444.2d18 (~(mul ^rd %n) `@rd`0x4000.0000.0000.0000 df)) - =/ res (~(sub ^rd %n) `@rd`0x3fe9.21fb.5444.2d18 (~(sub ^rd %n) p2 q2)) - ?:(=(sgn 1) (~(sub ^rd %n) `@rd`0x0 res) res) - ++ acs + ++ acs + |= x=@rd ^- @rd + ?: !(~(equ ^rd %n) x x) `@rd`0x7ff8.0000.0000.0000 + =/ neg (rsh [0 63] x) + =/ ax `@rd`(dis x 0x7fff.ffff.ffff.ffff) + ?: (~(gth ^rd %n) ax `@rd`0x3ff0.0000.0000.0000) `@rd`0x7ff8.0000.0000.0000 + ?: =(ax `@rd`0x3ff0.0000.0000.0000) + ?: =(neg 0) `@rd`0x0 + (~(add ^rd %n) `@rd`0x4009.21fb.5444.2d18 (~(mul ^rd %n) `@rd`0x4000.0000.0000.0000 `@rd`0x3c91.a626.3314.5c07)) + ?: (~(lth ^rd %n) ax `@rd`0x3fe0.0000.0000.0000) + ?: (~(lth ^rd %n) ax `@rd`0x3c60.0000.0000.0000) `@rd`0x3ff9.21fb.5444.2d18 + =/ z (~(mul ^rd %n) x x) + =/ r (rr z) + (~(sub ^rd %n) `@rd`0x3ff9.21fb.5444.2d18 (~(sub ^rd %n) x (~(sub ^rd %n) `@rd`0x3c91.a626.3314.5c07 (~(mul ^rd %n) x r)))) + ?: =(neg 1) + =/ z (~(mul ^rd %n) (~(add ^rd %n) `@rd`0x3ff0.0000.0000.0000 x) `@rd`0x3fe0.0000.0000.0000) + =/ s (sqt z) + =/ r (rr z) + =/ w (~(sub ^rd %n) (~(mul ^rd %n) r s) `@rd`0x3c91.a626.3314.5c07) + (~(sub ^rd %n) `@rd`0x4009.21fb.5444.2d18 (~(mul ^rd %n) `@rd`0x4000.0000.0000.0000 (~(add ^rd %n) s w))) + =/ z (~(mul ^rd %n) (~(sub ^rd %n) `@rd`0x3ff0.0000.0000.0000 x) `@rd`0x3fe0.0000.0000.0000) + =/ s (sqt z) + =/ df `@rd`(dis s 0xffff.ffff.0000.0000) + =/ c (~(div ^rd %n) (~(sub ^rd %n) z (~(mul ^rd %n) df df)) (~(add ^rd %n) s df)) + =/ r (rr z) + =/ w (~(add ^rd %n) (~(mul ^rd %n) r s) c) + (~(mul ^rd %n) `@rd`0x4000.0000.0000.0000 (~(add ^rd %n) df w)) + -- + :: +atan: @rd -> @rd + :: + :: Returns the inverse tangent of a floating-point atom. + :: Examples + :: > (atan .~1) + :: .~0.7853981633821053 + :: > (atan .~2) + :: .~1.1071487178081938 + :: > (atan pi) + :: .~1.2626272558398273 + :: + ++ atan + :: fdlibm breakpoint reduction + minimax poly; odd. Round-nearest-even + :: internally (the SoftFloat jet matches). |= x=@rd ^- @rd - ?: !(~(equ ^rd %n) x x) `@rd`0x7ff8.0000.0000.0000 + ?: !(~(equ ^rd %n) x x) `@rd`0x7ff8.0000.0000.0000 :: NaN + ?: =(x `@rd`0x7ff0.0000.0000.0000) `@rd`0x3ff9.21fb.5444.2d18 :: +inf -> pi/2 + ?: =(x `@rd`0xfff0.0000.0000.0000) `@rd`0xbff9.21fb.5444.2d18 :: -inf -> -pi/2 + ?: |(=(x `@rd`0x0) =(x `@rd`0x8000.0000.0000.0000)) x :: +-0 -> +-0 =/ neg (rsh [0 63] x) - =/ ax `@rd`(dis x 0x7fff.ffff.ffff.ffff) - ?: (~(gth ^rd %n) ax `@rd`0x3ff0.0000.0000.0000) `@rd`0x7ff8.0000.0000.0000 - ?: =(ax `@rd`0x3ff0.0000.0000.0000) - ?: =(neg 0) `@rd`0x0 - (~(add ^rd %n) `@rd`0x4009.21fb.5444.2d18 (~(mul ^rd %n) `@rd`0x4000.0000.0000.0000 `@rd`0x3c91.a626.3314.5c07)) - ?: (~(lth ^rd %n) ax `@rd`0x3fe0.0000.0000.0000) - ?: (~(lth ^rd %n) ax `@rd`0x3c60.0000.0000.0000) `@rd`0x3ff9.21fb.5444.2d18 - =/ z (~(mul ^rd %n) x x) - =/ r (rr z) - (~(sub ^rd %n) `@rd`0x3ff9.21fb.5444.2d18 (~(sub ^rd %n) x (~(sub ^rd %n) `@rd`0x3c91.a626.3314.5c07 (~(mul ^rd %n) x r)))) - ?: =(neg 1) - =/ z (~(mul ^rd %n) (~(add ^rd %n) `@rd`0x3ff0.0000.0000.0000 x) `@rd`0x3fe0.0000.0000.0000) - =/ s (sqt z) - =/ r (rr z) - =/ w (~(sub ^rd %n) (~(mul ^rd %n) r s) `@rd`0x3c91.a626.3314.5c07) - (~(sub ^rd %n) `@rd`0x4009.21fb.5444.2d18 (~(mul ^rd %n) `@rd`0x4000.0000.0000.0000 (~(add ^rd %n) s w))) - =/ z (~(mul ^rd %n) (~(sub ^rd %n) `@rd`0x3ff0.0000.0000.0000 x) `@rd`0x3fe0.0000.0000.0000) - =/ s (sqt z) - =/ df `@rd`(dis s 0xffff.ffff.0000.0000) - =/ c (~(div ^rd %n) (~(sub ^rd %n) z (~(mul ^rd %n) df df)) (~(add ^rd %n) s df)) - =/ r (rr z) - =/ w (~(add ^rd %n) (~(mul ^rd %n) r s) c) - (~(mul ^rd %n) `@rd`0x4000.0000.0000.0000 (~(add ^rd %n) df w)) - -- - :: +atan: @rd -> @rd - :: - :: Returns the inverse tangent of a floating-point atom. - :: Examples - :: > (atan .~1) - :: .~0.7853981633821053 - :: > (atan .~2) - :: .~1.1071487178081938 - :: > (atan pi) - :: .~1.2626272558398273 - :: - ++ atan - :: fdlibm breakpoint reduction + minimax poly; odd. Round-nearest-even - :: internally (the SoftFloat jet matches). - |= x=@rd ^- @rd - ?: !(~(equ ^rd %n) x x) `@rd`0x7ff8.0000.0000.0000 :: NaN - ?: =(x `@rd`0x7ff0.0000.0000.0000) `@rd`0x3ff9.21fb.5444.2d18 :: +inf -> pi/2 - ?: =(x `@rd`0xfff0.0000.0000.0000) `@rd`0xbff9.21fb.5444.2d18 :: -inf -> -pi/2 - ?: |(=(x `@rd`0x0) =(x `@rd`0x8000.0000.0000.0000)) x :: +-0 -> +-0 - =/ neg (rsh [0 63] x) - =/ r (ker:rd-atan `@rd`(dis x 0x7fff.ffff.ffff.ffff)) - ?:(=(neg 1) (~(sub ^rd %n) `@rd`0x0 r) r) - :: +rd-atan: atan kernel for the @rd door (reduction + poly), see +atan. - ++ rd-atan - |% - ++ at - ^- (list @rd) - :~ `@rd`0x3fd5.5555.5555.550d `@rd`0xbfc9.9999.9998.ebc4 - `@rd`0x3fc2.4924.9200.83ff `@rd`0xbfbc.71c6.fe23.1671 - `@rd`0x3fb7.45cd.c54c.206e `@rd`0xbfb3.b0f2.af74.9a6d - `@rd`0x3fb1.0d66.a0d0.3d51 `@rd`0xbfad.de2d.52de.fd9a - `@rd`0x3fa9.7b4b.2476.0deb `@rd`0xbfa2.b444.2c6a.6c2f - `@rd`0x3f90.ad3a.e322.da11 - == - ++ atred - |= ax=@rd ^- [xr=@rd hi=@rd lo=@rd dir=?] - =/ one `@rd`0x3ff0.0000.0000.0000 - =/ two `@rd`0x4000.0000.0000.0000 - =/ ohf `@rd`0x3ff8.0000.0000.0000 - ?: (~(lth ^rd %n) ax `@rd`0x3fdc.0000.0000.0000) - [ax `@rd`0x0 `@rd`0x0 %.y] - ?: (~(lth ^rd %n) ax `@rd`0x3fe6.0000.0000.0000) - :* (~(div ^rd %n) (~(sub ^rd %n) (~(add ^rd %n) ax ax) one) (~(add ^rd %n) two ax)) - `@rd`0x3fdd.ac67.0561.bb4f `@rd`0x3c7a.2b7f.222f.65e2 %.n + =/ r (ker:rd-atan `@rd`(dis x 0x7fff.ffff.ffff.ffff)) + ?:(=(neg 1) (~(sub ^rd %n) `@rd`0x0 r) r) + :: +rd-atan: atan kernel for the @rd door (reduction + poly), see +atan. + ++ rd-atan + |% + ++ at + ^- (list @rd) + :~ `@rd`0x3fd5.5555.5555.550d `@rd`0xbfc9.9999.9998.ebc4 + `@rd`0x3fc2.4924.9200.83ff `@rd`0xbfbc.71c6.fe23.1671 + `@rd`0x3fb7.45cd.c54c.206e `@rd`0xbfb3.b0f2.af74.9a6d + `@rd`0x3fb1.0d66.a0d0.3d51 `@rd`0xbfad.de2d.52de.fd9a + `@rd`0x3fa9.7b4b.2476.0deb `@rd`0xbfa2.b444.2c6a.6c2f + `@rd`0x3f90.ad3a.e322.da11 == - ?: (~(lth ^rd %n) ax `@rd`0x3ff3.0000.0000.0000) - :* (~(div ^rd %n) (~(sub ^rd %n) ax one) (~(add ^rd %n) ax one)) - `@rd`0x3fe9.21fb.5444.2d18 `@rd`0x3c81.a626.3314.5c07 %.n + ++ atred + |= ax=@rd ^- [xr=@rd hi=@rd lo=@rd dir=?] + =/ one `@rd`0x3ff0.0000.0000.0000 + =/ two `@rd`0x4000.0000.0000.0000 + =/ ohf `@rd`0x3ff8.0000.0000.0000 + ?: (~(lth ^rd %n) ax `@rd`0x3fdc.0000.0000.0000) + [ax `@rd`0x0 `@rd`0x0 %.y] + ?: (~(lth ^rd %n) ax `@rd`0x3fe6.0000.0000.0000) + :* (~(div ^rd %n) (~(sub ^rd %n) (~(add ^rd %n) ax ax) one) (~(add ^rd %n) two ax)) + `@rd`0x3fdd.ac67.0561.bb4f `@rd`0x3c7a.2b7f.222f.65e2 %.n + == + ?: (~(lth ^rd %n) ax `@rd`0x3ff3.0000.0000.0000) + :* (~(div ^rd %n) (~(sub ^rd %n) ax one) (~(add ^rd %n) ax one)) + `@rd`0x3fe9.21fb.5444.2d18 `@rd`0x3c81.a626.3314.5c07 %.n + == + ?: (~(lth ^rd %n) ax `@rd`0x4003.8000.0000.0000) + :* (~(div ^rd %n) (~(sub ^rd %n) ax ohf) (~(add ^rd %n) one (~(mul ^rd %n) ohf ax))) + `@rd`0x3fef.730b.d281.f69b `@rd`0x3c70.0788.7af0.cbbd %.n + == + :* (~(div ^rd %n) `@rd`0xbff0.0000.0000.0000 ax) + `@rd`0x3ff9.21fb.5444.2d18 `@rd`0x3c91.a626.3314.5c07 %.n == - ?: (~(lth ^rd %n) ax `@rd`0x4003.8000.0000.0000) - :* (~(div ^rd %n) (~(sub ^rd %n) ax ohf) (~(add ^rd %n) one (~(mul ^rd %n) ohf ax))) - `@rd`0x3fef.730b.d281.f69b `@rd`0x3c70.0788.7af0.cbbd %.n + ++ ker + |= ax=@rd ^- @rd + =/ q (atred ax) + =/ z (~(mul ^rd %n) xr.q xr.q) + =/ s (~(mul ^rd %n) z (roll (flop at) |=([c=@rd a=@rd] (~(add ^rd %n) (~(mul ^rd %n) a z) c)))) + ?: dir.q (~(sub ^rd %n) xr.q (~(mul ^rd %n) xr.q s)) + (~(sub ^rd %n) hi.q (~(sub ^rd %n) (~(sub ^rd %n) (~(mul ^rd %n) xr.q s) lo.q) xr.q)) + -- + :: +atan2: [@rd @rd] -> @rd + :: + :: Returns the inverse tangent of a floating-point coordinate. + :: Examples + :: > (atan2 .~0 .~1) + :: .~0 + :: > (atan2 .~-1 .~0) + :: .~-1.5707963267948966 + :: > (atan2 .~0.5 .~-0.5) + :: .~2.3561944902107888 + :: + ++ atan2 + |= [y=@rd x=@rd] ^- @rd + ?: (gth x .~0) + (atan (div y x)) + ?: &((lth x .~0) (gte y .~0)) + (add (atan (div y x)) pi) + ?: &((lth x .~0) (lth y .~0)) + (sub (atan (div y x)) pi) + ?: &(=(.~0 x) (gth y .~0)) + (div pi .~2) + ?: &(=(.~0 x) (lth y .~0)) + (mul .~-1 (div pi .~2)) + .~0 :: undefined + :: +pow-n: [@rd @rd] -> @rd + :: + :: Returns the power of a floating-point atom to an integer exponent. + :: Examples + :: > (pow-n .1 .2) + :: .1 + :: > (pow-n .2 .2) + :: .4 + :: > (pow-n .2 .3) + :: .8 + :: Source + ++ pow-n + |= [x=@rd n=@rd] ^- @rd + ?: =(n .~0) .~1 + ?> &((gth n .~0) (is-int n)) + =/ p x + |- ^- @rd + ?: (lth n .~2) + p + $(n (sub n .~1), p (mul p x)) + :: +log: @rd -> @rd + :: + :: Returns the natural logarithm of a floating-point atom. + :: Examples + :: > (log .~1) + :: .~0 + :: > (log .~2) + :: .~0.6931471805589156 + :: > (~(log rd [%z .~1e-15]) .~2) + :: .~0.693147180559944 + :: > (log .~inf) + :: .~inf + :: Source + ++ log + |= x=@rd ^- @rd + :: Reduce x = 2^e * m with m in [sqrt(1/2), sqrt(2)); then + :: log(x) = e*ln2 + log(1+f), f = m-1, s = f/(2+f), + :: log(1+f) = f - s*(f - 2z*P2(z)), z = s*s, P2 the atanh series + :: 1/3 + z/5 + z^2/7 + ... Faithful to <=1 ULP; round-nearest-even + :: internally (the SoftFloat jet will match this bit-for-bit). + ?: !(~(equ ^rd %n) x x) `@rd`0x7ff8.0000.0000.0000 :: NaN + ?: =(x `@rd`0x7ff0.0000.0000.0000) `@rd`0x7ff0.0000.0000.0000 :: +inf + ?: |(=(x `@rd`0x0) =(x `@rd`0x8000.0000.0000.0000)) `@rd`0xfff0.0000.0000.0000 :: +-0 -> -inf + ?: =(1 (rsh [0 63] x)) `@rd`0x7ff8.0000.0000.0000 :: x<0 -> NaN + =/ sub =(0 (dis 0x7ff (rsh [0 52] x))) :: subnormal? + =/ xx ?:(sub (~(mul ^rd %n) x `@rd`0x4350.0000.0000.0000) x) :: *2^54 + =/ ae ?:(sub -54 --0) + =/ b `@`xx + =/ ef (dif:si (new:si %.y (dis 0x7ff (rsh [0 52] b))) --1.023) + =/ m `@rd`(con (dis b 0xf.ffff.ffff.ffff) 0x3ff0.0000.0000.0000) + =/ big (~(gte ^rd %n) m `@rd`0x3ff6.a09e.667f.3bcd) :: m >= sqrt(2) + =? m big (~(mul ^rd %n) m `@rd`0x3fe0.0000.0000.0000) :: m * 0.5 + =? ef big (sum:si ef --1) + =. ef (sum:si ef ae) + =/ f (~(sub ^rd %n) m `@rd`0x3ff0.0000.0000.0000) + =/ s (~(div ^rd %n) f (~(add ^rd %n) m `@rd`0x3ff0.0000.0000.0000)) + =/ z (~(mul ^rd %n) s s) + =/ cs=(list @rd) + :~ `@rd`0x3fd5.5555.5555.5555 `@rd`0x3fc9.9999.9999.999a + `@rd`0x3fc2.4924.9249.2492 `@rd`0x3fbc.71c7.1c71.c71c + `@rd`0x3fb7.45d1.745d.1746 `@rd`0x3fb3.b13b.13b1.3b14 + `@rd`0x3fb1.1111.1111.1111 `@rd`0x3fae.1e1e.1e1e.1e1e + `@rd`0x3faa.f286.bca1.af28 `@rd`0x3fa8.6186.1861.8618 == - :* (~(div ^rd %n) `@rd`0xbff0.0000.0000.0000 ax) - `@rd`0x3ff9.21fb.5444.2d18 `@rd`0x3c91.a626.3314.5c07 %.n - == - ++ ker - |= ax=@rd ^- @rd - =/ q (atred ax) - =/ z (~(mul ^rd %n) xr.q xr.q) - =/ s (~(mul ^rd %n) z (roll (flop at) |=([c=@rd a=@rd] (~(add ^rd %n) (~(mul ^rd %n) a z) c)))) - ?: dir.q (~(sub ^rd %n) xr.q (~(mul ^rd %n) xr.q s)) - (~(sub ^rd %n) hi.q (~(sub ^rd %n) (~(sub ^rd %n) (~(mul ^rd %n) xr.q s) lo.q) xr.q)) + =/ p2 (roll (flop cs) |=([c=@rd acc=@rd] (~(add ^rd %n) (~(mul ^rd %n) acc z) c))) + =/ r (~(mul ^rd %n) (~(add ^rd %n) z z) p2) + =/ l1 (~(sub ^rd %n) f (~(mul ^rd %n) s (~(sub ^rd %n) f r))) + =/ efa (~(sun ^rd %n) (abs:si ef)) + =/ ef-f ?:((syn:si ef) efa (~(sub ^rd %n) .~0 efa)) :: e as @rd + =/ hi (~(mul ^rd %n) ef-f `@rd`0x3fe6.2e42.fee0.0000) :: e*ln2hi + =/ lo (~(mul ^rd %n) ef-f `@rd`0x3dea.39ef.3579.3c76) :: e*ln2lo + (~(add ^rd %n) hi (~(add ^rd %n) l1 lo)) + :: +log-10: @rd -> @rd + :: + :: Returns the base-10 logarithm of a floating-point atom. + :: Examples + :: > (log-10 .~0.1) + :: .~-0.9999999999082912 + :: > (log-10 .~2) + :: .~0.30102999566353394 + :: > (~(log-10 rd [%z .~1e-8]) .~2) + :: .~0.30102999562024696 + :: Source + ++ log-10 + :: e*log10(2) + log(m)/ln10, reusing +lr so the integer part is added with + :: no division rounding (more accurate than log(x)/ln10). + |= x=@rd ^- @rd + ?: !(~(equ ^rd %n) x x) `@rd`0x7ff8.0000.0000.0000 + ?: =(x `@rd`0x7ff0.0000.0000.0000) `@rd`0x7ff0.0000.0000.0000 + ?: |(=(x `@rd`0x0) =(x `@rd`0x8000.0000.0000.0000)) `@rd`0xfff0.0000.0000.0000 + ?: =(1 (rsh [0 63] x)) `@rd`0x7ff8.0000.0000.0000 + =/ el (lr x) + (~(add ^rd %n) (~(mul ^rd %n) ef.el `@rd`0x3fd3.4413.509f.79ff) (~(mul ^rd %n) lm.el `@rd`0x3fdb.cb7b.1526.e50e)) + :: +log-2: @rd -> @rd + :: + :: Returns the base-2 logarithm of a floating-point atom. + :: Examples + :: > (log-2 .~2) + :: .~1 + :: > (log-2 .~0.1) + :: .~-3.321928094887362 + :: Source + ++ log-2 + :: e + log(m)/ln2 (integer part exact); see +lr. + |= x=@rd ^- @rd + ?: !(~(equ ^rd %n) x x) `@rd`0x7ff8.0000.0000.0000 + ?: =(x `@rd`0x7ff0.0000.0000.0000) `@rd`0x7ff0.0000.0000.0000 + ?: |(=(x `@rd`0x0) =(x `@rd`0x8000.0000.0000.0000)) `@rd`0xfff0.0000.0000.0000 + ?: =(1 (rsh [0 63] x)) `@rd`0x7ff8.0000.0000.0000 + =/ el (lr x) + (~(add ^rd %n) ef.el (~(mul ^rd %n) lm.el `@rd`0x3ff7.1547.652b.82fe)) + :: +lr: log reduction for finite positive x -> [e (as @rd), log(mantissa)]. + ++ lr + |= x=@rd ^- [ef=@rd lm=@rd] + =/ sub =(0 (dis 0x7ff (rsh [0 52] x))) + =/ xx ?:(sub (~(mul ^rd %n) x `@rd`0x4350.0000.0000.0000) x) + =/ ae ?:(sub -54 --0) + =/ b `@`xx + =/ e (dif:si (new:si %.y (dis 0x7ff (rsh [0 52] b))) --1.023) + =/ m `@rd`(con (dis b 0xf.ffff.ffff.ffff) 0x3ff0.0000.0000.0000) + =/ big (~(gte ^rd %n) m `@rd`0x3ff6.a09e.667f.3bcd) + =? m big (~(mul ^rd %n) m `@rd`0x3fe0.0000.0000.0000) + =? e big (sum:si e --1) + =. e (sum:si e ae) + =/ f (~(sub ^rd %n) m `@rd`0x3ff0.0000.0000.0000) + =/ s (~(div ^rd %n) f (~(add ^rd %n) m `@rd`0x3ff0.0000.0000.0000)) + =/ z (~(mul ^rd %n) s s) + =/ cs=(list @rd) + :~ `@rd`0x3fd5.5555.5555.5555 `@rd`0x3fc9.9999.9999.999a + `@rd`0x3fc2.4924.9249.2492 `@rd`0x3fbc.71c7.1c71.c71c + `@rd`0x3fb7.45d1.745d.1746 `@rd`0x3fb3.b13b.13b1.3b14 + `@rd`0x3fb1.1111.1111.1111 `@rd`0x3fae.1e1e.1e1e.1e1e + `@rd`0x3faa.f286.bca1.af28 `@rd`0x3fa8.6186.1861.8618 + == + =/ p2 (roll (flop cs) |=([c=@rd a=@rd] (~(add ^rd %n) (~(mul ^rd %n) a z) c))) + =/ r (~(mul ^rd %n) (~(add ^rd %n) z z) p2) + =/ l1 (~(sub ^rd %n) f (~(mul ^rd %n) s (~(sub ^rd %n) f r))) + =/ efa (~(sun ^rd %n) (abs:si e)) + =/ ef ?:((syn:si e) efa (~(sub ^rd %n) .~0 efa)) + [ef l1] + :: +pow: [@rd @rd] -> @rd + :: + :: Returns the power of a floating-point atom to a floating-point exponent. + :: Examples + :: > (pow .~1 .~2) + :: .~1 + :: > (pow .~2 .~2) + :: .~4 + :: > (pow .~2 .~3.5) + :: .~11.313708498941306 + :: > (~(pow rd [%z .~1e-15]) .~2 .~3.5) + :: .~11.313708498984685 + :: Source + ++ pow + |= [x=@rd n=@rd] ^- @rd + :: fall through on positive integers (faster) + ?: &(=(n (san (need (toi n)))) (gth n .~0)) (pow-n x (san (need (toi n)))) + (exp (mul n (log x))) + :: +sqrt: @rd -> @rd + :: + :: Returns the square root of a floating-point atom. + :: Alias for +sqt. + :: Examples + :: > (sqrt .~1) + :: .~1 + :: > (sqrt .~2) + :: .~1.4142135623721421 + :: > (~(sqrt rd [%z .~1e-15]) .~2) + :: .~1.4142135623730923 + :: Source + ++ sqrt sqt + :: +sqt: @rd -> @rd + :: + :: Returns the square root of a floating-point atom. + :: Examples + :: > (sqt .~1) + :: .~1 + :: > (sqt .~2) + :: .~1.414213562373095 + :: > (sqt 1e5) + :: .~316.2277660168379 + :: Source + ++ sqt + :: Correctly-rounded f64 square root. The stdlib f64 root is only + :: faithful (off by up to 1 ULP), so seed with it and apply one Markstein + :: correction (r = x - g*g via fma; g + (0.5/g)*r), which lands on the + :: correctly-rounded value -- matching the SoftFloat sqrt jet bit-for-bit. + |= x=@rd ^- @rd + ?: !(~(equ ^rd %n) x x) `@rd`0x7ff8.0000.0000.0000 :: NaN + ?: =(x `@rd`0x7ff0.0000.0000.0000) `@rd`0x7ff0.0000.0000.0000 :: +inf + ?: |(=(x `@rd`0x0) =(x `@rd`0x8000.0000.0000.0000)) x :: +-0 + ?: =(1 (rsh [0 63] x)) `@rd`0x7ff8.0000.0000.0000 :: x<0 -> NaN + =/ g (sqt:^rd x) :: faithful seed + =/ h (~(div ^rd %n) `@rd`0x3fe0.0000.0000.0000 g) :: 0.5/g + =/ r (~(fma ^rd %n) (~(sub ^rd %n) `@rd`0x0 g) g x) :: x - g*g + (~(fma ^rd %n) h r g) :: g + h*r + :: +cbrt: @rd -> @rd + :: + :: Returns the cube root of a floating-point atom. + :: Alias for +cbt. + :: Examples + :: > (cbrt .~1) + :: .~1 + :: > (cbrt .~2) + :: .~1.2599210498943176 + :: > (~(cbrt rd [%z .~1e-15]) .~2) + :: .~1.2599210498948716 + :: Source + ++ cbrt cbt + :: +cbt: @rd -> @rd + :: + :: Returns the cube root of a floating-point atom. + :: Examples + :: > (cbt .~1) + :: .~1 + :: > (cbt .~2) + :: .~1.2599210498943176 + :: > (~(cbt rd [%z .~1e-15]) .~2) + :: .~1.2599210498948716 + :: Source + ++ cbt + :: cbrt(x) = sign(x) * exp(log|x| / 3); defined for all reals (unlike pow). + |= x=@rd ^- @rd + ?: !(~(equ ^rd %n) x x) x :: NaN -> NaN + ?: |(=(x `@rd`0x0) =(x `@rd`0x8000.0000.0000.0000)) x :: +-0 -> +-0 + =/ ax `@rd`(dis x 0x7fff.ffff.ffff.ffff) + =/ r (exp (~(mul ^rd %n) (log ax) `@rd`0x3fd5.5555.5555.5555)) + ?:(=(1 (rsh [0 63] x)) (~(sub ^rd %n) `@rd`0x0 r) r) + :: +arg: @rd -> @rd + :: + :: Returns the argument of a floating-point atom (real argument = absolute + :: value). + :: Examples + :: > (arg .~1) + :: .~1 + :: > (arg .~-1) + :: .~1 + :: Source + ++ arg abs + :: +round: [@rs @ud] -> @rs + :: + :: Returns the floating-point atom rounded to a given number of decimal + :: places. + :: Examples + :: > (round .1 0) + :: .1 + :: > (round .1.11 1) + :: .1.1 + :: > (round .1.11 2) + :: .1.11 + :: > (round .1.11 3) + :: .1.11 + :: Source + ++ round + |= [x=@rd n=@ud] ^- @rd + ?: =(.~0 x) .~0 + :: Calculate the order of magnitude. + =/ oom (san (need (toi (log-10 (abs x))))) + :: Calculate the scaling factor. + =/ scaling (pow .~10 :(sub (sun n) oom .~1)) + :: Round the mantissa to desired significant digits. + =/ rnd-mantissa (round-bankers (mul x scaling)) + :: Convert back to the original scale. + (div rnd-mantissa scaling) + :: +round-places: [@rs @ud] -> @rs + :: + :: Returns the floating-point atom rounded to a given number of decimal + :: places. This is exceptionally sensitive to off-by-one FP rounding error. + :: Examples + :: > (round-places .1 0) + :: .1 + :: > (round-places .1.11 1) + :: .1.1 + :: > (round-places .1.285 2) + :: .1.28 + :: > (round-places .4.12345 3) + :: .4.1229997 + :: Source + ++ round-places + |= [x=@rd n=@ud] ^- @rd + :: Calculate the scaling factor. + =/ scaling (pow .~10 (sun n)) + :: Scale the number. + =/ scaled (mul x scaling) + :: Round the mantissa to desired significant digits. + =/ rnd-mantissa (round-bankers scaled) + :: Convert back to the original scale. + (div rnd-mantissa scaling) + :: +round-bankers: @rs -> @rs + :: + :: Returns the floating-point atom rounded to the nearest integer, with ties + :: rounded to the nearest even integer (banker's rounding). This is exactly + :: what +toi does under round-nearest (%n), which ties to even, so we force + :: %n regardless of the door's configured mode. + :: Examples + :: > (round-bankers .~1.5) + :: .~2 + :: > (round-bankers .~2.5) + :: .~2 + :: > (round-bankers .~1.49) + :: .~1 + :: Source + ++ round-bankers + |= x=@rd ^- @rd + (san (need (~(toi ^rd %n) x))) -- - :: +atan2: [@rd @rd] -> @rd - :: - :: Returns the inverse tangent of a floating-point coordinate. - :: Examples - :: > (atan2 .~0 .~1) - :: .~0 - :: > (atan2 .~-1 .~0) - :: .~-1.5707963267948966 - :: > (atan2 .~0.5 .~-0.5) - :: .~2.3561944902107888 - :: - ++ atan2 - |= [y=@rd x=@rd] ^- @rd - ?: (gth x .~0) - (atan (div y x)) - ?: &((lth x .~0) (gte y .~0)) - (add (atan (div y x)) pi) - ?: &((lth x .~0) (lth y .~0)) - (sub (atan (div y x)) pi) - ?: &(=(.~0 x) (gth y .~0)) - (div pi .~2) - ?: &(=(.~0 x) (lth y .~0)) - (mul .~-1 (div pi .~2)) - .~0 :: undefined - :: +pow-n: [@rd @rd] -> @rd - :: - :: Returns the power of a floating-point atom to an integer exponent. - :: Examples - :: > (pow-n .1 .2) - :: .1 - :: > (pow-n .2 .2) - :: .4 - :: > (pow-n .2 .3) - :: .8 - :: Source - ++ pow-n - |= [x=@rd n=@rd] ^- @rd - ?: =(n .~0) .~1 - ?> &((gth n .~0) (is-int n)) - =/ p x - |- ^- @rd - ?: (lth n .~2) - p - $(n (sub n .~1), p (mul p x)) - :: +log: @rd -> @rd - :: - :: Returns the natural logarithm of a floating-point atom. - :: Examples - :: > (log .~1) - :: .~0 - :: > (log .~2) - :: .~0.6931471805589156 - :: > (~(log rd [%z .~1e-15]) .~2) - :: .~0.693147180559944 - :: > (log .~inf) - :: .~inf - :: Source - ++ log - |= x=@rd ^- @rd - :: Reduce x = 2^e * m with m in [sqrt(1/2), sqrt(2)); then - :: log(x) = e*ln2 + log(1+f), f = m-1, s = f/(2+f), - :: log(1+f) = f - s*(f - 2z*P2(z)), z = s*s, P2 the atanh series - :: 1/3 + z/5 + z^2/7 + ... Faithful to <=1 ULP; round-nearest-even - :: internally (the SoftFloat jet will match this bit-for-bit). - ?: !(~(equ ^rd %n) x x) `@rd`0x7ff8.0000.0000.0000 :: NaN - ?: =(x `@rd`0x7ff0.0000.0000.0000) `@rd`0x7ff0.0000.0000.0000 :: +inf - ?: |(=(x `@rd`0x0) =(x `@rd`0x8000.0000.0000.0000)) `@rd`0xfff0.0000.0000.0000 :: +-0 -> -inf - ?: =(1 (rsh [0 63] x)) `@rd`0x7ff8.0000.0000.0000 :: x<0 -> NaN - =/ sub =(0 (dis 0x7ff (rsh [0 52] x))) :: subnormal? - =/ xx ?:(sub (~(mul ^rd %n) x `@rd`0x4350.0000.0000.0000) x) :: *2^54 - =/ ae ?:(sub -54 --0) - =/ b `@`xx - =/ ef (dif:si (new:si %.y (dis 0x7ff (rsh [0 52] b))) --1.023) - =/ m `@rd`(con (dis b 0xf.ffff.ffff.ffff) 0x3ff0.0000.0000.0000) - =/ big (~(gte ^rd %n) m `@rd`0x3ff6.a09e.667f.3bcd) :: m >= sqrt(2) - =? m big (~(mul ^rd %n) m `@rd`0x3fe0.0000.0000.0000) :: m * 0.5 - =? ef big (sum:si ef --1) - =. ef (sum:si ef ae) - =/ f (~(sub ^rd %n) m `@rd`0x3ff0.0000.0000.0000) - =/ s (~(div ^rd %n) f (~(add ^rd %n) m `@rd`0x3ff0.0000.0000.0000)) - =/ z (~(mul ^rd %n) s s) - =/ cs=(list @rd) - :~ `@rd`0x3fd5.5555.5555.5555 `@rd`0x3fc9.9999.9999.999a - `@rd`0x3fc2.4924.9249.2492 `@rd`0x3fbc.71c7.1c71.c71c - `@rd`0x3fb7.45d1.745d.1746 `@rd`0x3fb3.b13b.13b1.3b14 - `@rd`0x3fb1.1111.1111.1111 `@rd`0x3fae.1e1e.1e1e.1e1e - `@rd`0x3faa.f286.bca1.af28 `@rd`0x3fa8.6186.1861.8618 - == - =/ p2 (roll (flop cs) |=([c=@rd acc=@rd] (~(add ^rd %n) (~(mul ^rd %n) acc z) c))) - =/ r (~(mul ^rd %n) (~(add ^rd %n) z z) p2) - =/ l1 (~(sub ^rd %n) f (~(mul ^rd %n) s (~(sub ^rd %n) f r))) - =/ efa (~(sun ^rd %n) (abs:si ef)) - =/ ef-f ?:((syn:si ef) efa (~(sub ^rd %n) .~0 efa)) :: e as @rd - =/ hi (~(mul ^rd %n) ef-f `@rd`0x3fe6.2e42.fee0.0000) :: e*ln2hi - =/ lo (~(mul ^rd %n) ef-f `@rd`0x3dea.39ef.3579.3c76) :: e*ln2lo - (~(add ^rd %n) hi (~(add ^rd %n) l1 lo)) - :: +log-10: @rd -> @rd - :: - :: Returns the base-10 logarithm of a floating-point atom. - :: Examples - :: > (log-10 .~0.1) - :: .~-0.9999999999082912 - :: > (log-10 .~2) - :: .~0.30102999566353394 - :: > (~(log-10 rd [%z .~1e-8]) .~2) - :: .~0.30102999562024696 - :: Source - ++ log-10 - :: e*log10(2) + log(m)/ln10, reusing +lr so the integer part is added with - :: no division rounding (more accurate than log(x)/ln10). - |= x=@rd ^- @rd - ?: !(~(equ ^rd %n) x x) `@rd`0x7ff8.0000.0000.0000 - ?: =(x `@rd`0x7ff0.0000.0000.0000) `@rd`0x7ff0.0000.0000.0000 - ?: |(=(x `@rd`0x0) =(x `@rd`0x8000.0000.0000.0000)) `@rd`0xfff0.0000.0000.0000 - ?: =(1 (rsh [0 63] x)) `@rd`0x7ff8.0000.0000.0000 - =/ el (lr x) - (~(add ^rd %n) (~(mul ^rd %n) ef.el `@rd`0x3fd3.4413.509f.79ff) (~(mul ^rd %n) lm.el `@rd`0x3fdb.cb7b.1526.e50e)) - :: +log-2: @rd -> @rd - :: - :: Returns the base-2 logarithm of a floating-point atom. - :: Examples - :: > (log-2 .~2) - :: .~1 - :: > (log-2 .~0.1) - :: .~-3.321928094887362 - :: Source - ++ log-2 - :: e + log(m)/ln2 (integer part exact); see +lr. - |= x=@rd ^- @rd - ?: !(~(equ ^rd %n) x x) `@rd`0x7ff8.0000.0000.0000 - ?: =(x `@rd`0x7ff0.0000.0000.0000) `@rd`0x7ff0.0000.0000.0000 - ?: |(=(x `@rd`0x0) =(x `@rd`0x8000.0000.0000.0000)) `@rd`0xfff0.0000.0000.0000 - ?: =(1 (rsh [0 63] x)) `@rd`0x7ff8.0000.0000.0000 - =/ el (lr x) - (~(add ^rd %n) ef.el (~(mul ^rd %n) lm.el `@rd`0x3ff7.1547.652b.82fe)) - :: +lr: log reduction for finite positive x -> [e (as @rd), log(mantissa)]. - ++ lr - |= x=@rd ^- [ef=@rd lm=@rd] - =/ sub =(0 (dis 0x7ff (rsh [0 52] x))) - =/ xx ?:(sub (~(mul ^rd %n) x `@rd`0x4350.0000.0000.0000) x) - =/ ae ?:(sub -54 --0) - =/ b `@`xx - =/ e (dif:si (new:si %.y (dis 0x7ff (rsh [0 52] b))) --1.023) - =/ m `@rd`(con (dis b 0xf.ffff.ffff.ffff) 0x3ff0.0000.0000.0000) - =/ big (~(gte ^rd %n) m `@rd`0x3ff6.a09e.667f.3bcd) - =? m big (~(mul ^rd %n) m `@rd`0x3fe0.0000.0000.0000) - =? e big (sum:si e --1) - =. e (sum:si e ae) - =/ f (~(sub ^rd %n) m `@rd`0x3ff0.0000.0000.0000) - =/ s (~(div ^rd %n) f (~(add ^rd %n) m `@rd`0x3ff0.0000.0000.0000)) - =/ z (~(mul ^rd %n) s s) - =/ cs=(list @rd) - :~ `@rd`0x3fd5.5555.5555.5555 `@rd`0x3fc9.9999.9999.999a - `@rd`0x3fc2.4924.9249.2492 `@rd`0x3fbc.71c7.1c71.c71c - `@rd`0x3fb7.45d1.745d.1746 `@rd`0x3fb3.b13b.13b1.3b14 - `@rd`0x3fb1.1111.1111.1111 `@rd`0x3fae.1e1e.1e1e.1e1e - `@rd`0x3faa.f286.bca1.af28 `@rd`0x3fa8.6186.1861.8618 - == - =/ p2 (roll (flop cs) |=([c=@rd a=@rd] (~(add ^rd %n) (~(mul ^rd %n) a z) c))) - =/ r (~(mul ^rd %n) (~(add ^rd %n) z z) p2) - =/ l1 (~(sub ^rd %n) f (~(mul ^rd %n) s (~(sub ^rd %n) f r))) - =/ efa (~(sun ^rd %n) (abs:si e)) - =/ ef ?:((syn:si e) efa (~(sub ^rd %n) .~0 efa)) - [ef l1] - :: +pow: [@rd @rd] -> @rd - :: - :: Returns the power of a floating-point atom to a floating-point exponent. - :: Examples - :: > (pow .~1 .~2) - :: .~1 - :: > (pow .~2 .~2) - :: .~4 - :: > (pow .~2 .~3.5) - :: .~11.313708498941306 - :: > (~(pow rd [%z .~1e-15]) .~2 .~3.5) - :: .~11.313708498984685 - :: Source - ++ pow - |= [x=@rd n=@rd] ^- @rd - :: fall through on positive integers (faster) - ?: &(=(n (san (need (toi n)))) (gth n .~0)) (pow-n x (san (need (toi n)))) - (exp (mul n (log x))) - :: +sqrt: @rd -> @rd - :: - :: Returns the square root of a floating-point atom. - :: Alias for +sqt. - :: Examples - :: > (sqrt .~1) - :: .~1 - :: > (sqrt .~2) - :: .~1.4142135623721421 - :: > (~(sqrt rd [%z .~1e-15]) .~2) - :: .~1.4142135623730923 - :: Source - ++ sqrt sqt - :: +sqt: @rd -> @rd - :: - :: Returns the square root of a floating-point atom. - :: Examples - :: > (sqt .~1) - :: .~1 - :: > (sqt .~2) - :: .~1.414213562373095 - :: > (sqt 1e5) - :: .~316.2277660168379 - :: Source - ++ sqt - :: Correctly-rounded f64 square root. The stdlib f64 root is only - :: faithful (off by up to 1 ULP), so seed with it and apply one Markstein - :: correction (r = x - g*g via fma; g + (0.5/g)*r), which lands on the - :: correctly-rounded value -- matching the SoftFloat sqrt jet bit-for-bit. - |= x=@rd ^- @rd - ?: !(~(equ ^rd %n) x x) `@rd`0x7ff8.0000.0000.0000 :: NaN - ?: =(x `@rd`0x7ff0.0000.0000.0000) `@rd`0x7ff0.0000.0000.0000 :: +inf - ?: |(=(x `@rd`0x0) =(x `@rd`0x8000.0000.0000.0000)) x :: +-0 - ?: =(1 (rsh [0 63] x)) `@rd`0x7ff8.0000.0000.0000 :: x<0 -> NaN - =/ g (sqt:^rd x) :: faithful seed - =/ h (~(div ^rd %n) `@rd`0x3fe0.0000.0000.0000 g) :: 0.5/g - =/ r (~(fma ^rd %n) (~(sub ^rd %n) `@rd`0x0 g) g x) :: x - g*g - (~(fma ^rd %n) h r g) :: g + h*r - :: +cbrt: @rd -> @rd - :: - :: Returns the cube root of a floating-point atom. - :: Alias for +cbt. - :: Examples - :: > (cbrt .~1) - :: .~1 - :: > (cbrt .~2) - :: .~1.2599210498943176 - :: > (~(cbrt rd [%z .~1e-15]) .~2) - :: .~1.2599210498948716 - :: Source - ++ cbrt cbt - :: +cbt: @rd -> @rd - :: - :: Returns the cube root of a floating-point atom. - :: Examples - :: > (cbt .~1) - :: .~1 - :: > (cbt .~2) - :: .~1.2599210498943176 - :: > (~(cbt rd [%z .~1e-15]) .~2) - :: .~1.2599210498948716 - :: Source - ++ cbt - :: cbrt(x) = sign(x) * exp(log|x| / 3); defined for all reals (unlike pow). - |= x=@rd ^- @rd - ?: !(~(equ ^rd %n) x x) x :: NaN -> NaN - ?: |(=(x `@rd`0x0) =(x `@rd`0x8000.0000.0000.0000)) x :: +-0 -> +-0 - =/ ax `@rd`(dis x 0x7fff.ffff.ffff.ffff) - =/ r (exp (~(mul ^rd %n) (log ax) `@rd`0x3fd5.5555.5555.5555)) - ?:(=(1 (rsh [0 63] x)) (~(sub ^rd %n) `@rd`0x0 r) r) - :: +arg: @rd -> @rd - :: - :: Returns the argument of a floating-point atom (real argument = absolute - :: value). - :: Examples - :: > (arg .~1) - :: .~1 - :: > (arg .~-1) - :: .~1 - :: Source - ++ arg abs - :: +round: [@rs @ud] -> @rs - :: - :: Returns the floating-point atom rounded to a given number of decimal - :: places. - :: Examples - :: > (round .1 0) - :: .1 - :: > (round .1.11 1) - :: .1.1 - :: > (round .1.11 2) - :: .1.11 - :: > (round .1.11 3) - :: .1.11 - :: Source - ++ round - |= [x=@rd n=@ud] ^- @rd - ?: =(.~0 x) .~0 - :: Calculate the order of magnitude. - =/ oom (san (need (toi (log-10 (abs x))))) - :: Calculate the scaling factor. - =/ scaling (pow .~10 :(sub (sun n) oom .~1)) - :: Round the mantissa to desired significant digits. - =/ rnd-mantissa (round-bankers (mul x scaling)) - :: Convert back to the original scale. - (div rnd-mantissa scaling) - :: +round-places: [@rs @ud] -> @rs - :: - :: Returns the floating-point atom rounded to a given number of decimal - :: places. This is exceptionally sensitive to off-by-one FP rounding error. - :: Examples - :: > (round-places .1 0) - :: .1 - :: > (round-places .1.11 1) - :: .1.1 - :: > (round-places .1.285 2) - :: .1.28 - :: > (round-places .4.12345 3) - :: .4.1229997 - :: Source - ++ round-places - |= [x=@rd n=@ud] ^- @rd - :: Calculate the scaling factor. - =/ scaling (pow .~10 (sun n)) - :: Scale the number. - =/ scaled (mul x scaling) - :: Round the mantissa to desired significant digits. - =/ rnd-mantissa (round-bankers scaled) - :: Convert back to the original scale. - (div rnd-mantissa scaling) - :: +round-bankers: @rs -> @rs - :: - :: Returns the floating-point atom rounded to the nearest integer, with ties - :: rounded to the nearest even integer (banker's rounding). This is exactly - :: what +toi does under round-nearest (%n), which ties to even, so we force - :: %n regardless of the door's configured mode. - :: Examples - :: > (round-bankers .~1.5) - :: .~2 - :: > (round-bankers .~2.5) - :: .~2 - :: > (round-bankers .~1.49) - :: .~1 - :: Source - ++ round-bankers - |= x=@rd ^- @rd - (san (need (~(toi ^rd %n) x))) - -- -:: half precision -++ rh - ^| - |_ $: r=$?(%n %u %d %z) :: round nearest, up, down, to zero - rtol=_.~~1e-2 :: relative tolerance for precision of operations - == - :: mathematics constants to half precision - :: +tau: @rh - :: - :: Returns the value 2*pi (OEIS A019692). - :: Examples - :: > tau - :: .~~6.28 - :: Source - ++ tau .~~6.28 - :: +pi: @rh - :: - :: Returns the value pi (OEIS A000796). - :: Examples - :: > pi - :: .~~3.14 - :: Source - ++ pi .~~3.14 - :: +e: @rh - :: - :: Returns the value e (Euler's constant) (OEIS A001113). - :: Examples - :: > e - :: .~~2.72 - :: Source - ++ e .~~2.719 - :: +phi: @rh - :: - :: Returns the value phi (golden ratio) (OEIS A001622). - :: Examples - :: > phi - :: .~~1.62 - :: Source - ++ phi .~~1.618 - :: +sqt2: @rh - :: - :: Returns the value sqrt(2) (OEIS A002193). - :: Examples - :: > sqt2 - :: .~~1.414 - :: Source - ++ sqt2 .~~1.414 - :: +invsqt2: @rh - :: - :: Returns the value 1/sqrt(2) (OEIS A010503). - :: Examples - :: > invsqt2 - :: .~~0.707 - :: Source - ++ invsqt2 .~~0.707 - :: +log2: @rh - :: - :: Returns the value log(2) (OEIS A002162). - :: Examples - :: > log2 - :: .~~0.693 - :: Source - ++ log2 .~~0.6934 - :: +invlog2: @rh - :: - :: Returns the value 1/log(2). - :: Examples - :: > invlog2 - :: .~~1.443 - :: Source - ++ invlog2 .~~1.443 - :: +log10: @rh - :: - :: Returns the value log(10) (OEIS A002392). - :: Examples - :: > log10 - :: .~~2.303 - :: Source - ++ log10 .~~2.303 - :: +huge: @rh - :: - :: Returns the value of the largest representable number. - :: Examples - :: > huge - :: .~~6.55e+04 - :: Source - ++ huge `@rh`0x7bff :: 6.55e+04 - :: +tiny: @rh - :: - :: Returns the smallest representable positive (subnormal) number, 2^-24. - :: (Not the smallest NORMAL, which is 2^-14 = .~~6.10e-05.) - :: Examples - :: > tiny - :: .~~6e-8 - :: Source - ++ tiny `@rh`0x1 :: 6e-08 - :: - :: Operations - :: - :: +sea: @rh -> fn - :: - :: Returns the +$fn representation of a floating-point atom. - :: Examples - :: > (sea .~~1) - :: [%f s=%.y e=-10 a=1.024] - :: > (sea .~~1.1) - :: [%f s=%.y e=-10 a=1.126] - :: Source - ++ sea sea:^rh - :: +bit: fn -> @rh - :: - :: Returns the floating-point atom of a +$fn representation. - :: Examples - :: > (bit [%f s=%.y e=-10 a=1.024]) - :: .~~1 - :: > (bit [%f s=%.y e=-10 a=1.126]) - :: .~~1.1 - :: Source - ++ bit bit:^rh - :: +sun: @ud -> @rh - :: - :: Returns the floating-point atom of an unsigned integer atom. - :: Examples - :: > (sun 1) - :: .~~1 - :: > (sun 1.000) - :: .~~1e3 - :: Source - ++ sun sun:^rh - :: +san: @sd -> @rh - :: - :: Returns the floating-point atom of a signed integer atom. - :: Examples - :: > (san --1) - :: .~~1 - :: > (san -1) - :: .~-1 - :: Source - ++ san san:^rh - ::++ exp exp:^rh :: no pass-through because of exp function - :: +toi: @rh -> @sd - :: - :: Returns the unitized signed integer atom of a rounded floating-point atom. - :: Examples - :: > (toi .~~1) - :: [~ --1] - :: > (toi .~~1.1) - :: [~ --1] - :: Source - ++ toi toi:^rh - :: +drg: @rh -> dn - :: - :: Returns the decimal form of a floating-point atom using the Dragon4 - :: algorithm. - :: Examples - :: > (drg .~~1) - :: [%d s=%.y e=--0 a=1] - :: > (drg .~~1.1) - :: [%d s=%.y e=-1 a=11] - :: Source - ++ drg drg:^rh - :: +grd: dn -> @rh - :: - :: Returns the floating-point atom of a decimal form. - :: Examples - :: > (grd [%d s=%.y e=--0 a=1]) - :: .~~1 - :: > (grd [%d s=%.y e=-1 a=11]) - :: .~~1.1 - :: Source - ++ grd grd:^rh - :: - :: Comparison - :: - :: +lth: [@rh @rh] -> ? - :: - :: Returns the comparison of two floating-point atoms, less than. - :: Examples - :: > (lth .~~1 .~~2) - :: %.y - :: > (lth .~~2 .~~1) - :: %.n - :: > (lth .~~1 .~~1) - :: %.n - :: Source - ++ lth lth:^rh - :: +lte: [@rh @rh] -> ? - :: - :: Returns the comparison of two floating-point atoms, less than or equal to. - :: Examples - :: > (lte .~~1 .~~2) - :: %.y - :: > (lte .~~2 .~~1) - :: %.n - :: > (lte .~~1 .~~1) - :: %.y - :: Source - ++ lte lte:^rh - :: +leq: [@rh @rh] -> ? - :: - :: Returns the comparison of two floating-point atoms, less than or equal to. - :: Alias for +lte. - :: Examples - :: > (leq .~~1 .~~2) - :: %.y - :: > (leq .~~2 .~~1) - :: %.n - :: > (leq .~~1 .~~1) - :: %.y - :: Source - ++ leq lte:^rh - :: +equ: [@rh @rh] -> ? - :: - :: Returns the comparison of two floating-point atoms, equal to. - :: Examples - :: > (equ .~~1 .~~2) - :: %.n - :: > (equ .~~2 .~~1) - :: %.n - :: > (equ .~~1 .~~1) - :: %.y - :: Source - ++ equ equ:^rh - :: +gth: [@rh @rh] -> ? - :: - :: Returns the comparison of two floating-point atoms, greater than. - :: Examples - :: > (gth .~~1 .~~2) - :: %.n - :: > (gth .~~2 .~~1) - :: %.y - :: > (gth .~~1 .~~1) - :: %.n - :: Source - ++ gth gth:^rh - :: +gte: [@rh @rh] -> ? - :: - :: Returns the comparison of two floating-point atoms, greater than or equal to. - :: Examples - :: > (gte .~~1 .~~2) - :: %.n - :: > (gte .~~2 .~~1) - :: %.y - :: > (gte .~~1 .~~1) - :: %.y - :: Source - ++ gte gte:^rh - :: +geq: [@rh @rh] -> ? - :: - :: Returns the comparison of two floating-point atoms, greater than or equal to. - :: Alias for +gte. - :: Examples - :: > (geq .~~1 .~~2) - :: %.n - :: > (geq .~~2 .~~1) - :: %.y - :: > (geq .~~1 .~~1) - :: %.y - :: Source - ++ geq gte:^rh - :: +neq: [@rh @rh] -> ? - :: - :: Returns the comparison of two floating-point atoms, not equal to. - :: Examples - :: > (neq .~~1 .~~2) - :: %.y - :: > (neq .~~2 .~~1) - :: %.y - :: > (neq .~~1 .~~1) - :: %.n - :: Source - ++ neq |=([a=@rh b=@rh] ^-(? !(equ:^rh a b))) - :: +is-close: [@rh @rh] -> ? - :: - :: Returns the comparison of two floating-point atoms, within a relative - :: tolerance (provided by the +rh door). - :: Examples - :: > (is-close .~~1 .~~2) - :: %.n - :: > (is-close .~~1 .~~1.0000001) - :: %.n - :: > (~(is-close rh [%z .~~1e-3]) .~~1 .~~1.0001) - :: %.y - :: Source - ++ is-close - |= [p=@rh r=@rh] - (lth (abs (sub p r)) rtol) - :: +all-close: [@rh (list @rh)] -> ? - :: - :: Returns the comparison of a floating-point atom to a list of floating- - :: point atoms, within a relative tolerance (provided by the +rh door). - :: Examples - :: > (all-close .~~1 ~[.~~1 .~~2]) - :: %.n - :: > (all-close .~~1 ~[.~~1 .~~1.0000001]) - :: %.n - :: > (~(all-close rh [%z .~~1e-3]) .~~1 ~[.~~1 .~~1.0001]) - :: %.y - :: Source - ++ all-close - |= [p=@rh q=(list @rh)] - =/ i 0 - =/ n (lent q) - |- ^- ? - ?: =(n i) - %.y - ?. (is-close p (snag i q)) - %.n - $(i +(i)) - :: +is-int: @rh -> ? - :: - :: Returns whether a floating-point value is an integer (no fractional part). - :: Examples - :: > (is-int .~~1) - :: %.y - :: > (is-int .~~1.1) - :: %.n - :: Source - ++ is-int - |= x=@rh ^- ? - (equ x (san (need (toi x)))) - :: - :: Algebraic - :: - :: +add: [@rh @rh] -> @rh - :: - :: Returns the sum of two floating-point atoms. - :: Examples - :: > (add .~~1 .~~2) - :: .~~3 - :: Source - ++ add add:^rh - :: +sub: [@rh @rh] -> @rh - :: - :: Returns the difference of two floating-point atoms. - :: Examples - :: > (sub .~~1 .~~2) - :: .~~-1 - :: Source - ++ sub sub:^rh - :: +mul: [@rh @rh] -> @rh - :: - :: Returns the product of two floating-point atoms. - :: Examples - :: > (mul .~~1 .~~2) - :: .~~2 - :: Source - ++ mul mul:^rh - :: +div: [@rh @rh] -> @rh - :: - :: Returns the quotient of two floating-point atoms. - :: Examples - :: > (div .~~1 .~~2) - :: .~~0.5 - :: Source - ++ div div:^rh - :: +fma: [@rh @rh @rh] -> @rh - :: - :: Returns the fused multiply-add of three floating-point atoms. - :: Examples - :: > (fma .~~1 .~~2 .~~3) - :: .~~5 - :: > (fma .~~2 .~~3 .~~4) - :: .~~10 - :: Source - ++ fma fma:^rh - :: +sig: @rh -> ? - :: - :: Returns the sign of a floating-point atom. - :: Examples - :: > (sig .~~1) - :: %.y - :: > (sig .~~-1) - :: %.n - :: Source - ++ sig |=(x=@rh =(0 (rsh [0 15] x))) - :: +sgn: @rh -> ? - :: - :: Returns the sign of a floating-point atom. - :: Alias for +sig. - :: Examples - :: > (sgn .~~1) - :: %.y - :: > (sgn .~~-1) - :: %.n - :: Source - ++ sgn sig - :: +neg: @rh -> @rh - :: - :: Returns the negation of a floating-point atom. - :: Examples - :: > (neg .~~1) - :: .~~-1 - :: > (neg .~~-1) - :: .~~1 - :: Source - ++ neg |=(x=@rh (sub .~~0 x)) - :: +factorial: @rh -> @rh - :: - :: Returns the factorial of a floating-point atom. Assumes integer input. - :: Examples - :: > (factorial .~~1) - :: .~~1 - :: > (factorial .~~2) - :: .~~2 - :: > (factorial .~~3) - :: .~~6 - :: Source - ++ factorial - |= x=@rh ^- @rh - ?> (gte x .~~0) - =/ t=@rh .~~1 - ?: (is-close x .~~0) - t - |- ^- @rh - ?: (is-close x .~~1) - t - $(x (sub x .~~1), t (mul t x)) - :: +abs: @rh -> @rh - :: - :: Returns the absolute value of a floating-point atom. - :: Examples - :: > (abs .~~1) - :: .~~1 - :: > (abs .~~-1) - :: .~~1 - :: Source - ++ abs - |= x=@rh ^- @rh - ?:((sgn x) x (neg x)) - :: +exp: @rh -> @rh - :: - :: Returns the exponential of a floating-point atom. - :: Examples - :: > (exp .~~1) - :: .~~2.715 - :: > (exp .~~2) - :: .~~7.375 - :: > (~(exp rh [%z .~~1e-1]) .~~2) - :: .~~7.348 - :: > (exp .~~inf) - :: .inf - :: Source - :: +widen-hs: f16 -> f32, exact. +narrow-sh: f32 -> f16, correctly-rounded - :: RNE. The @rh transcendentals compute in the (more precise) @rs door and - :: round the result down -- correctly-rounded for f16, since an f32 result is - :: ~2^13 times finer than an f16 ULP. - ++ widen-hs - |= h=@rh ^- @ - =/ hh `@`h - =/ s (lsh [0 16] (dis hh 0x8000)) - =/ e (dis (rsh [0 10] hh) 0x1f) - =/ m (dis hh 0x3ff) - ?: =(e 0x1f) (con s (con 0x7f80.0000 (lsh [0 13] m))) - ?: =(e 0) - ?: =(m 0) s - (con s `@`(~(mul rs [%n .1e-5]) (~(sun rs [%n .1e-5]) m) `@rs`0x3380.0000)) - (con s (con (lsh [0 23] (^add e 112)) (lsh [0 13] m))) - ++ narrow-sh - |= uu=@rs ^- @ - =/ u `@`uu - =/ s (dis (rsh [0 16] u) 0x8000) - =/ e (dis (rsh [0 23] u) 0xff) - =/ m (dis u 0x7f.ffff) - ?: =(e 0xff) (con s ?:(=(m 0) 0x7c00 0x7e00)) - ?: (^gte e 143) (con s 0x7c00) - ?: (^gte e 113) - =/ ne (^sub e 112) - =/ mant (rsh [0 13] m) - =/ rem (dis m 0x1fff) - =/ rup ?|((^gth rem 0x1000) &(=(rem 0x1000) =(1 (dis mant 1)))) - (con s (^add (lsh [0 10] ne) (^add mant ?:(rup 1 0)))) - ?: (^lth e 102) (con s 0x0) - =/ shift (^sub 126 e) - =/ mf (con 0x80.0000 m) - =/ mant (rsh [0 shift] mf) - =/ half (bex (dec shift)) - =/ rem (dis mf (dec (bex shift))) - =/ rup ?|((^gth rem half) &(=(rem half) =(1 (dis mant 1)))) - (con s (^add mant ?:(rup 1 0))) - ++ exp - :: compute in @rs, round to f16 (see +narrow-sh). - |= x=@rh ^- @rh - `@rh`(narrow-sh (~(exp rs [%n .1e-5]) `@rs`(widen-hs x))) - :: +sin: @rh -> @rh - :: - :: Returns the sine of a floating-point atom. - :: Examples - :: > (sin .~~1) - :: .~~0.8413 - :: > (sin .~~2) - :: .~~0.9087 - :: > (sin pi) - :: .~~3.437e-3 - :: Source - ++ sin - |= x=@rh ^- @rh - `@rh`(narrow-sh (~(sin rs [%n .1e-5]) `@rs`(widen-hs x))) - :: +cos: @rh -> @rh - :: - :: Returns the cosine of a floating-point atom. - :: Examples - :: > (cos .~~1) - :: .~~0.54 - :: > (cos .~~2) - :: .~~-0.4158 - :: > (cos pi) - :: .~~-1.001 - :: Source - ++ cos - |= x=@rh ^- @rh - `@rh`(narrow-sh (~(cos rs [%n .1e-5]) `@rs`(widen-hs x))) - :: +tan: @rh -> @rh - :: - :: Returns the tangent of a floating-point atom. - :: Examples - :: > (tan .~~1) - :: .~~1.558 - :: > (tan .~~2) - :: .~~-2.186 - :: > (tan pi) - :: .~~-3.433e-3 - :: Source - ++ tan - |= x=@rh ^- @rh - `@rh`(narrow-sh (~(tan rs [%n .1e-5]) `@rs`(widen-hs x))) - :: +asin: @rh -> @rh - :: - :: Returns the inverse sine of a floating-point atom. - :: Examples - :: > (asin .~~0) - :: .~~0 - :: > (asin .~~1) - :: .~~1.57 - :: > (asin .~~0.7) - :: .~~0.7773 - :: - ++ asin - |= x=@rh ^- @rh - `@rh`(narrow-sh (~(asin rs [%n .1e-5]) `@rs`(widen-hs x))) - :: +acos: @rh -> @rh - :: - :: Returns the inverse cosine of a floating-point atom. - :: Examples - :: > (acos .~~0) - :: .~~1.57 - :: > (acos .~~1) - :: .~~0 - :: > (acos .~~0.7) - :: .~~0.7964 - :: - ++ acos - |= x=@rh ^- @rh - `@rh`(narrow-sh (~(acos rs [%n .1e-5]) `@rs`(widen-hs x))) - :: +atan: @rh -> @rh - :: - :: Returns the inverse tangent of a floating-point atom. - :: Examples - :: > (atan .~~1) - :: .~~0.7866 - :: > (atan .~~2) - :: .~~1.111 - :: > (atan pi) - :: .~~1.281 - :: - ++ atan - |= x=@rh ^- @rh - `@rh`(narrow-sh (~(atan rs [%n .1e-5]) `@rs`(widen-hs x))) - :: +atan2: [@rh @rh] -> @rh - :: - :: Returns the inverse tangent of a floating-point coordinate. - :: Examples - :: > (atan2 .~~0 .~~1) - :: .~~0 - :: > (atan2 .~~-1 .~~0) - :: .~~-1.57 - :: > (atan2 .~~0.5 .~~-0.5) - :: .~~2.354 - :: - ++ atan2 - |= [y=@rh x=@rh] ^- @rh - `@rh`(narrow-sh (~(atan2 rs [%n .1e-5]) `@rs`(widen-hs y) `@rs`(widen-hs x))) - :: +pow-n: [@rh @rh] -> @rh - :: - :: Returns the power of a floating-point atom to an integer exponent. - :: Examples - :: > (pow-n .~~1 .~~2) - :: .~~1 - :: > (pow-n .~~2 .~~2) - :: .~~4 - :: > (pow-n .~~2 .~~3) - :: .~~8 - :: Source - ++ pow-n - |= [x=@rh n=@rh] ^- @rh - `@rh`(narrow-sh (~(pow-n rs [%n .1e-5]) `@rs`(widen-hs x) `@rs`(widen-hs n))) - :: +log: @rh -> @rh - :: - :: Returns the natural logarithm of a floating-point atom. - :: Examples - :: > (log .~~1) - :: .~~0 - :: > (log .~~2) - :: .~~0.6914 - :: > (~(log rh [%z .~~1e-1]) .~~2) - :: .~~0.6904 - ++ log - |= x=@rh ^- @rh - `@rh`(narrow-sh (~(log rs [%n .1e-5]) `@rs`(widen-hs x))) - :: +log-10: @rh -> @rh - :: - :: Returns the base-10 logarithm of a floating-point atom. - :: Examples - :: TODO - :: Source - ++ log-10 - |= x=@rh ^- @rh - `@rh`(narrow-sh (~(log-10 rs [%n .1e-5]) `@rs`(widen-hs x))) - :: +log-2: @rh -> @rh - :: - :: Returns the base-2 logarithm of a floating-point atom. - :: Examples - :: TODO - :: Source - ++ log-2 - |= x=@rh ^- @rh - `@rh`(narrow-sh (~(log-2 rs [%n .1e-5]) `@rs`(widen-hs x))) - :: +pow: [@rh @rh] -> @rh - :: - :: Returns the power of a floating-point atom to a floating-point exponent. - :: Examples - :: > (pow .~~1 .~~2) - :: .~~1 - :: > (pow .~~2 .~~2) - :: .~~4 - :: > (~(pow rh:math [%z .~~1e-1]) .~~2 .~~3.5) - :: .~~11.14 - :: Source - ++ pow - |= [x=@rh n=@rh] ^- @rh - `@rh`(narrow-sh (~(pow rs [%n .1e-5]) `@rs`(widen-hs x) `@rs`(widen-hs n))) - :: +sqrt: @rh -> @rh - :: - :: Returns the square root of a floating-point atom. - :: Alias for +sqt. - :: Examples - :: > (sqrt .~~1) - :: .~~1 - :: > (sqrt .~~2) - :: .~~1.412 - :: > (~(sqrt rh [%z .~~1e-1]) .~~2) - :: .~~1.404 - :: Source - ++ sqrt sqt - :: +sqt: @rh -> @rh - :: - :: Returns the square root of a floating-point atom. - :: Examples - :: > (sqt .~~1) - :: .~~1 - :: > (sqt .~~2) - :: .~~1.414 - :: > (sqt .~~1e3) - :: .~~31.61 - :: Source - ++ sqt - |= x=@rh ^- @rh - `@rh`(narrow-sh (~(sqt rs [%n .1e-5]) `@rs`(widen-hs x))) - :: +cbrt: @rh -> @rh - :: - :: Returns the cube root of a floating-point atom. - :: Alias for +cbt. - :: Examples - :: > (cbrt .~~1) - :: .~~1 - :: > (cbrt .~~2) - :: .~~1.258 - :: > (~(cbrt rh [%z .~~1e-1]) .~~2) - :: .~~1.256 - :: Source - ++ cbrt cbt - :: +cbt: @rh -> @rh - :: - :: Returns the cube root of a floating-point atom. - :: Examples - :: > (cbt .~~1) - :: .~~1 - :: > (cbt .~~2) - :: .~~1.258 - :: > (~(cbt rh [%z .~~1e-1]) .~~2) - :: .~~1.256 - :: Source - ++ cbt - |= x=@rh ^- @rh - `@rh`(narrow-sh (~(cbt rs [%n .1e-5]) `@rs`(widen-hs x))) - :: +arg: @rh -> @rh - :: - :: Returns the argument of a floating-point atom (real argument = absolute - :: value). - :: Examples - :: > (arg .~~1) - :: .~~1 - :: > (arg .~-1) - :: .~~1 - :: Source - ++ arg abs - -- -:: quad precision -++ rq - ^| - |_ $: r=$?(%n %u %d %z) :: round nearest, up, down, to zero - rtol=_.~~~1e-20 :: relative tolerance for precision of operations - == - :: mathematics constants to quad precision - :: +tau: @rq - :: - :: Returns the value 2*pi (OEIS A019692). - :: Examples - :: > tau - :: .~~~6.2831853071795864769252867665590056 - :: Source - ++ tau .~~~6.2831853071795864769252867665590056 - :: +pi: @rq - :: - :: Returns the value pi (OEIS A000796). - :: Examples - :: > pi - :: .~~~3.1415926535897932384626433832795028 - :: Source - ++ pi .~~~3.1415926535897932384626433832795028 - :: +e: @rq - :: - :: Returns the value e (Euler's constant) (OEIS A001113). - :: Examples - :: > e - :: .~~~2.7182818284590452353602874713526623 - :: Source - ++ e .~~~2.7182818284590452353602874713526623 - :: +phi: @rq - :: - :: Returns the value phi (golden ratio) (OEIS A001622). - :: Examples - :: > phi - :: .~~~1.6180339887498948482045868343656382 - :: Source - ++ phi .~~~1.6180339887498948482045868343656382 - :: +sqt2: @rq - :: - :: Returns the value sqrt(2) (OEIS A002193). - :: Examples - :: > sqt2 - :: .~~~1.414213562373095048801688724209698 - :: Source - ++ sqt2 .~~~1.414213562373095048801688724209698 - :: +invsqt2: @rq - :: - :: Returns the value 1/sqrt(2) (OEIS A010503). - :: Examples - :: > invsqt2 - :: .~~~0.707106781186547524400844362104849 - :: Source - ++ invsqt2 .~~~0.707106781186547524400844362104849 - :: +log2: @rq - :: - :: Returns the value log(2) (OEIS A002162). - :: Examples - :: > log2 - :: .~~~0.6931471805599453094172321214581766 - :: Source - ++ log2 .~~~0.6931471805599453094172321214581766 - :: +invlog2: @rq - :: - :: Returns the value 1/log(2). - :: Examples - :: > invlog2 - :: .~~~1.442695040888963387004650940070860 - :: Source - ++ invlog2 .~~~1.442695040888963387004650940070860 :: TODO check - :: +log10: @rq - :: - :: Returns the value log(10) (OEIS A002392). - :: Examples - :: > log10 - :: .~~~2.302585092994045684017991454684364 - :: Source - ++ log10 .~~~2.302585092994045684017991454684364 - :: +huge: @rq - :: - :: Returns the value of the largest representable number. - :: Examples - :: > huge - :: .~~~1.189731495357231765085759326628007e4932 - :: Source - ++ huge `@rq`0x7ffe.ffff.ffff.ffff.ffff.ffff.ffff.ffff.ffff :: 1.18973149535723176508575932662800702e4932 - :: +tiny: @rq - :: - :: Returns the value of the smallest representable normal number. - :: Examples - :: > tiny - :: .~~~3.3621031431120935062626778173217526e-4932 - :: Source - ++ tiny `@rq`0x1.0000.0000.0000.0000.0000.0000.0000.0000 :: 3.36210314311209350626267781732175260e-4932 - :: - :: Operations - :: - :: +sea: @rq -> fn - :: - :: Returns the +$fn representation of a floating-point atom. - :: Examples - :: > (sea .~~~1) - :: [%f s=%.y e=-112 a=5.192.296.858.534.827.628.530.496.329.220.096] - :: > (sea .~~~1.1) - :: [%f s=%.y e=-112 a=5.711.526.544.388.310.391.383.545.962.142.106] - :: Source - ++ sea sea:^rq - :: +bit: fn -> @rq - :: - :: Returns the floating-point atom of a +$fn representation. - :: Examples - :: > (bit [%f s=%.y e=-112 a=5.192.296.858.534.827.628.530.496.329.220.096]) - :: .~~~1 - :: > (bit [%f s=%.y e=-112 a=5.711.526.544.388.310.391.383.545.962.142.106]) - :: .~~~1.1 - :: Source - ++ bit bit:^rq - :: +sun: @ud -> @rq - :: - :: Returns the floating-point atom of an unsigned integer atom. - :: Examples - :: > (sun 1) - :: .~~~1 - :: > (sun 1.000) - :: .~~~1e3 - :: Source - ++ sun sun:^rq - :: +san: @sd -> @rq - :: - :: Returns the floating-point atom of a signed integer atom. - :: Examples - :: > (san --1) - :: .~~~1 - :: > (san -1) - :: .~~~-1 - :: Source - ++ san san:^rq - ::++ exp exp:^rq :: no pass-through because of exp function - :: +toi: @rq -> @sd - :: - :: Returns the unitized signed integer atom of a rounded floating-point atom. - :: Examples - :: > (toi .~~~1) - :: [~ --1] - :: > (toi .~~~1.1) - :: [~ --1] - :: Source - ++ toi toi:^rq - :: +drg: @rq -> dn - :: - :: Returns the decimal form of a floating-point atom using the Dragon4 - :: algorithm. - :: Examples - :: > (drg .~~~1) - :: [%d s=%.y e=--0 a=1] - :: > (drg .~~~1.1) - :: [%d s=%.y e=-1 a=11] - :: Source - ++ drg drg:^rq - :: +grd: dn -> @rq - :: - :: Returns the floating-point atom of a decimal form. - :: Examples - :: > (grd [%d s=%.y e=--0 a=1]) - :: .~~~1 - :: > (grd [%d s=%.y e=-1 a=11]) - :: .~~~1.1 - :: Source - ++ grd grd:^rq - :: - :: Comparison - :: - :: +lth: [@rq @rq] -> ? - :: - :: Returns the comparison of two floating-point atoms, less than. - :: Examples - :: > (lth .~~~1 .~~~2) - :: %.y - :: > (lth .~~~2 .~~~1) - :: %.n - :: > (lth .~~~1 .~~~1) - :: %.n - :: Source - ++ lth lth:^rq - :: +lte: [@rq @rq] -> ? - :: - :: Returns the comparison of two floating-point atoms, less than or equal to. - :: Examples - :: > (lte .~~~1 .~~~2) - :: %.y - :: > (lte .~~~2 .~~~1) - :: %.n - :: > (lte .~~~1 .~~~1) - :: %.y - :: Source - ++ lte lte:^rq - :: +leq: [@rq @rq] -> ? - :: - :: Returns the comparison of two floating-point atoms, less than or equal to. - :: Alias for +lte. - :: Examples - :: > (leq .~~~1 .~~~2) - :: %.y - :: > (leq .~~~2 .~~~1) - :: %.n - :: > (leq .~~~1 .~~~1) - :: %.y - :: Source - ++ leq lte:^rq - :: +equ: [@rq @rq] -> ? - :: - :: Returns the comparison of two floating-point atoms, equal to. - :: Examples - :: > (equ .~~~1 .~~~2) - :: %.n - :: > (equ .~~~2 .~~~1) - :: %.n - :: > (equ .~~~1 .~~~1) - :: %.y - :: Source - ++ equ equ:^rq - :: +gth: [@rq @rq] -> ? - :: - :: Returns the comparison of two floating-point atoms, greater than. - :: Examples - :: > (gth .~~~1 .~~~2) - :: %.n - :: > (gth .~~~2 .~~~1) - :: %.y - :: > (gth .~~~1 .~~~1) - :: %.n - :: Source - ++ gth gth:^rq - :: +gte: [@rq @rq] -> ? - :: - :: Returns the comparison of two floating-point atoms, greater than or equal to. - :: Examples - :: > (gte .~~~1 .~~~2) - :: %.n - :: > (gte .~~~2 .~~~1) - :: %.y - :: > (gte .~~~1 .~~~1) - :: %.y - :: Source - ++ gte gte:^rq - :: +geq: [@rq @rq] -> ? - :: - :: Returns the comparison of two floating-point atoms, greater than or equal to. - :: Alias for +gte. - :: Examples - :: > (geq .~~~1 .~~~2) - :: %.n - :: > (geq .~~~2 .~~~1) - :: %.y - :: > (geq .~~~1 .~~~1) - :: %.y - :: Source - ++ geq gte:^rq - :: +neq: [@rq @rq] -> ? - :: - :: Returns the comparison of two floating-point atoms, not equal to. - :: Examples - :: > (neq .~~~1 .~~~2) - :: %.y - :: > (neq .~~~2 .~~~1) - :: %.y - :: > (neq .~~~1 .~~~1) - :: %.n - :: Source - ++ neq |=([a=@rq b=@rq] ^-(? !(equ:^rq a b))) - :: +is-close: [@rq @rq] -> ? - :: - :: Returns the comparison of two floating-point atoms, within a relative - :: tolerance (provided by the +rq door). - :: Examples - :: > (is-close .~~~1 .~~~2) - :: %.n - :: > (is-close .~~~1 .~~~1.0000001) - :: %.n - :: > (~(is-close rq [%z .~~~1e-3]) .~~~1 .~~~1.0001) - :: %.y - :: > (~(is-close rq [%z .~~~1e-30]) .~~~1 .~~~1.0001) - :: %.n - :: Source - ++ is-close - |= [p=@rq r=@rq] - (lth (abs (sub p r)) rtol) - :: +all-close: [@rq (list @rq)] -> ? - :: - :: Returns the comparison of a floating-point atom to a list of floating- - :: point atoms, within a relative tolerance (provided by the +rq door). - :: Examples - :: > (all-close .~~~1 ~[.~~~1 .~~~2]) - :: %.n - :: > (all-close .~~~1 ~[.~~~1 .~~~1.0000001]) - :: %.n - :: > (~(all-close rq [%z .~~~1e-3]) .~~~1 ~[.~~~1 .~~~1.0001]) - :: %.y - :: Source - ++ all-close - |= [p=@rq q=(list @rq)] - =/ i 0 - =/ n (lent q) - |- ^- ? - ?: =(n i) - %.y - ?. (is-close p (snag i q)) - %.n - $(i +(i)) - :: +is-int: @rq -> ? - :: - :: Returns whether a floating-point value is an integer (no fractional part). - :: Examples - :: > (is-int .~~~1) - :: %.y - :: > (is-int .~~~1.1) - :: %.n - :: Source - ++ is-int - |= x=@rq ^- ? - (equ x (san (need (toi x)))) - :: - :: Algebraic - :: - :: +add: [@rq @rq] -> @rq - :: - :: Returns the sum of two floating-point atoms. - :: Examples - :: > (add .~~~1 .~~~2) - :: .~~~3 - :: Source - ++ add add:^rq - :: +sub: [@rq @rq] -> @rq - :: - :: Returns the difference of two floating-point atoms. - :: Examples - :: > (sub .~~~1 .~~~2) - :: .~~~-1 - :: Source - ++ sub sub:^rq - :: +mul: [@rq @rq] -> @rq - :: - :: Returns the product of two floating-point atoms. - :: Examples - :: > (mul .~~~1 .~~~2) - :: .~~~2 - :: Source - ++ mul mul:^rq - :: +div: [@rq @rq] -> @rq - :: - :: Returns the quotient of two floating-point atoms. - :: Examples - :: > (div .~~~1 .~~~2) - :: .~~~0.5 - :: Source - ++ div div:^rq - :: +fma: [@rq @rq @rq] -> @rq - :: - :: Returns the fused multiply-add of three floating-point atoms. - :: Examples - :: > (fma .~~~1 .~~~2 .~~~3) - :: .~~~5 - :: > (fma .~~~2 .~~~3 .~~~4) - :: .~~~10 - :: Source - ++ fma fma:^rq - :: +sig: @rq -> ? - :: - :: Returns the sign of a floating-point atom. - :: Examples - :: > (sig .~~~1) - :: %.y - :: > (sig .~~~-1) - :: %.n - :: Source - ++ sig |=(x=@rq =(0 (rsh [0 127] x))) - :: +sgn: @rq -> ? - :: - :: Returns the sign of a floating-point atom. - :: Alias for +sig. - :: Examples - :: > (sgn .~~~1) - :: %.y - :: > (sgn .~~~-1) - :: %.n - :: Source - ++ sgn sig - :: +neg: @rq -> @rq - :: - :: Returns the negation of a floating-point atom. - :: Examples - :: > (neg .~~~1) - :: .~~~-1 - :: > (neg .~~~-1) - :: .~~~1 - :: Source - ++ neg |=(x=@rq (sub .~~~0 x)) - :: +factorial: @rq -> @rq - :: - :: Returns the factorial of a floating-point atom. Assumes integer input. - :: Examples - :: > (factorial .~~~1) - :: .~~~1 - :: > (factorial .~~~2) - :: .~~~2 - :: > (factorial .~~~3) - :: .~~~6 - :: Source - ++ factorial - |= x=@rq ^- @rq - ?> (gte x .~~~0) - =/ t=@rq .~~~1 - ?: (is-close x .~~~0) - t - |- ^- @rq - ?: (is-close x .~~~1) - t - $(x (sub x .~~~1), t (mul t x)) - :: +abs: @rq -> @rq - :: - :: Returns the absolute value of a floating-point atom. - :: Examples - :: > (abs .~~~1) - :: .~~~1 - :: > (abs .~~~-1) - :: .~~~1 - :: Source - ++ abs - |= x=@rq ^- @rq - ?:((sgn x) x (neg x)) - :: +exp: @rq -> @rq - :: - :: Returns the exponential of a floating-point atom. - :: Examples - :: > (exp .~~~1) - :: .~~~2.7182818284590452353602471108690483 - :: > (exp .~~~2) - :: .~~~7.389056098930650227230362414146335 - :: > (~(exp rq [%z .~~~1e-20]) .~~~2) - :: .~~~7.389056098930650227230362414146335 - :: > (exp .~~~inf) - :: .~~~inf - :: Source - ++ exp - :: Cody-Waite reduction + degree-24 minimax (f128); round-nearest-even - :: internally (matches the SoftFloat jet, see tools/rq_check.c). - |= x=@rq ^- @rq - =/ pow2 |=(j=@s `@rq`(lsh [0 112] (abs:si (sum:si j --16.383)))) - =/ scale2 - |= [p=@rq k=@s] ^- @rq - ?: (syn:si (dif:si k --16.384)) - (~(mul ^rq %n) (~(mul ^rq %n) p (pow2 --16.383)) (pow2 (dif:si k --16.383))) - ?: !(syn:si (sum:si k --16.382)) - (~(mul ^rq %n) (~(mul ^rq %n) p (pow2 (sum:si k --112))) (pow2 -112)) - (~(mul ^rq %n) p (pow2 k)) - ?: !(~(equ ^rq %n) x x) `@rq`0x7fff.8000.0000.0000.0000.0000.0000.0000 - ?: =(x `@rq`0x7fff.0000.0000.0000.0000.0000.0000.0000) `@rq`0x7fff.0000.0000.0000.0000.0000.0000.0000 - ?: =(x `@rq`0xffff.0000.0000.0000.0000.0000.0000.0000) `@rq`0x0 - =/ log2e `@rq`0x3fff.7154.7652.b82f.e177.7d0f.fda0.d23a - =/ ln2hi `@rq`0x3ffe.62e4.2fef.a39e.f357.93c8.0000.0000 - =/ ln2lo `@rq`0xbfad.319f.f034.2542.fc32.f366.359d.274a - =/ k=@s (need (~(toi ^rq %n) (~(mul ^rq %n) x log2e))) - ?: (syn:si (dif:si k --16.385)) `@rq`0x7fff.0000.0000.0000.0000.0000.0000.0000 - ?: !(syn:si (sum:si k --16.494)) `@rq`0x0 - =/ ka (~(sun ^rq %n) (abs:si k)) - =/ kf ?:((syn:si k) ka (~(sub ^rq %n) `@rq`0x0 ka)) - =/ r - %- ~(sub ^rq %n) - :- (~(sub ^rq %n) x (~(mul ^rq %n) kf ln2hi)) - (~(mul ^rq %n) kf ln2lo) - =/ cs=(list @rq) - :~ `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000 `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000 - `@rq`0x3ffe.0000.0000.0000.0000.0000.0000.0000 `@rq`0x3ffc.5555.5555.5555.5555.5555.5555.5555 - `@rq`0x3ffa.5555.5555.5555.5555.5555.5555.5555 `@rq`0x3ff8.1111.1111.1111.1111.1111.1111.1111 - `@rq`0x3ff5.6c16.c16c.16c1.6c16.c16c.16c1.6c17 `@rq`0x3ff2.a01a.01a0.1a01.a01a.01a0.1a01.a3e8 - `@rq`0x3fef.a01a.01a0.1a01.a01a.01a0.1a01.a146 `@rq`0x3fec.71de.3a55.6c73.38fa.ac1c.88a5.a526 - `@rq`0x3fe9.27e4.fb77.89f5.c72e.f016.d3d6.e867 `@rq`0x3fe5.ae64.567f.544e.38fe.7483.63c4.6e8b - `@rq`0x3fe2.1eed.8eff.8d89.7b54.4dab.18f4.75c5 `@rq`0x3fde.6124.613a.86d0.97c9.f3ae.babb.2423 - `@rq`0x3fda.9397.4a8c.07c9.d20b.83c7.f94d.17d8 `@rq`0x3fd6.ae7f.3e73.3b81.f5f4.284f.0d74.f9e7 - `@rq`0x3fd2.ae7f.3e73.3b81.f417.b4d2.7c5f.92a9 `@rq`0x3fce.952c.7703.0a99.6a41.9e67.4779.c97c - `@rq`0x3fca.6827.863b.97b5.0466.ff8c.8b42.b3df `@rq`0x3fc6.2f49.b469.f892.874b.7a68.6d81.9241 - `@rq`0x3fc1.e542.ba42.7463.bb3b.32a1.1bb5.f139 `@rq`0x3fbd.71b8.db9f.7f73.c938.90ff.9ab5.5cbb - `@rq`0x3fb9.0ce3.8aab.7bd7.6efc.0717.eae7.85a1 `@rq`0x3fb4.7693.274b.ab2a.cb3f.4f7e.dfaa.2666 - `@rq`0x3faf.f362.9154.e0a7.61cb.0e23.655d.47cb - == - =/ p (roll (flop cs) |=([c=@rq acc=@rq] (~(add ^rq %n) (~(mul ^rq %n) acc r) c))) - (scale2 p k) - :: +sin: @rq -> @rq - :: - :: Returns the sine of a floating-point atom. - :: Examples - :: > (sin .~~~1) - :: .~~~0.8414709848078965066525022572525196 - :: > (sin .~~~2) - :: .~~~0.9092974268256816953960201260866781 - :: > (sin pi) - :: .~~~2.4143733100361875441251426417684949e-23 - :: Source - ++ sin - :: q*pi/2 reduction + fdlibm kernels (f128); see +rq-trig. - |= x=@rq ^- @rq - ?: !(~(equ ^rq %n) x x) `@rq`0x7fff.8000.0000.0000.0000.0000.0000.0000 - ?: |(=(x `@rq`0x7fff.0000.0000.0000.0000.0000.0000.0000) =(x `@rq`0xffff.0000.0000.0000.0000.0000.0000.0000)) `@rq`0x7fff.8000.0000.0000.0000.0000.0000.0000 - ?: |(=(x `@rq`0x0) =(x `@rq`0x8000.0000.0000.0000.0000.0000.0000.0000)) x - %- trig-fin:rq-trig - [%.y `@rq`(dis x 0x7fff.ffff.ffff.ffff.ffff.ffff.ffff.ffff) (rsh [0 127] x)] - ++ rq-trig - |% - ++ sc - ^- (list @rq) - :~ `@rq`0xbffc.5555.5555.5555.5555.5555.5555.5555 - `@rq`0x3ff8.1111.1111.1111.1111.1111.1111.1111 - `@rq`0xbff2.a01a.01a0.1a01.a01a.01a0.1a01.a01a - `@rq`0x3fec.71de.3a55.6c73.38fa.ac1c.88e5.0017 - `@rq`0xbfe5.ae64.567f.544e.38fe.747e.4b83.7dc7 - `@rq`0x3fde.6124.613a.86d0.97ca.3833.1d23.af68 - `@rq`0xbfd6.ae7f.3e73.3b81.f11d.8656.b0ee.8cb0 - `@rq`0x3fce.952c.7703.0ad4.a6b2.6051.9777.1b00 - `@rq`0xbfc6.2f49.b468.1415.724c.a1ec.3b7b.9675 - `@rq`0x3fbd.71b8.ef6d.cf57.18be.f146.fcee.6e45 - `@rq`0xbfb4.761b.4131.6381.9d97.b870.4dd7.f628 - `@rq`0x3fab.3f3c.cdd1.65fa.8d4e.44a4.1977.6f11 - `@rq`0xbfa1.d1ab.1c2d.ccea.320a.9a18.f15d.4277 - `@rq`0x3f98.259f.98b4.358a.d7ab.e30e.7766.f129 - `@rq`0xbf8e.434d.2e78.3f5b.c42e.1ee4.6fa6.bfc4 - `@rq`0x3f84.3981.254d.d0d5.1b53.82cd.ffa9.7422 - == - ++ cc - ^- (list @rq) - :~ `@rq`0x3ffa.5555.5555.5555.5555.5555.5555.5555 - `@rq`0xbff5.6c16.c16c.16c1.6c16.c16c.16c1.6c17 - `@rq`0x3fef.a01a.01a0.1a01.a01a.01a0.1a01.a01a - `@rq`0xbfe9.27e4.fb77.89f5.c72e.f016.d3ea.6679 - `@rq`0x3fe2.1eed.8eff.8d89.7b54.4da9.87ac.fe85 - `@rq`0xbfda.9397.4a8c.07c9.d20b.adf1.45df.a3e5 - `@rq`0x3fd2.ae7f.3e73.3b81.f11d.8656.b0ee.8cb0 - `@rq`0xbfca.6827.863b.97d9.77bb.0048.86a2.c2ab - `@rq`0x3fc1.e542.ba40.2022.507a.9cad.2bf8.f0bb - `@rq`0xbfb9.0ce3.96db.7f85.2945.0c90.b7f3.38ec - `@rq`0x3faf.f2cf.0197.2f57.7cca.4b40.67ca.9d8a - `@rq`0xbfa6.88e8.5fc6.a4e5.9a38.f205.0ba6.b015 - `@rq`0x3f9d.0a18.a263.5085.d373.c5c5.1c35.4a8d - `@rq`0xbf93.3932.c504.7d60.e60c.aded.4c29.89c5 - `@rq`0x3f89.434d.2e78.3f5b.c42e.1ee4.6fa6.bfc4 - `@rq`0xbf7f.2710.231c.0fd7.a13f.8a2b.4af9.d6b7 - == - ++ neg |=(a=@rq ^-(@rq (~(sub ^rq %n) `@rq`0x0 a))) - ++ ksin - |= [xx=@rq yy=@rq] ^- @rq - =/ z (~(mul ^rq %n) xx xx) - =/ r (roll (flop (tail sc)) |=([c=@rq a=@rq] (~(add ^rq %n) (~(mul ^rq %n) a z) c))) - =/ v (~(mul ^rq %n) z xx) - =/ aa (~(sub ^rq %n) (~(mul ^rq %n) `@rq`0x3ffe.0000.0000.0000.0000.0000.0000.0000 yy) (~(mul ^rq %n) v r)) - =/ bb (~(sub ^rq %n) (~(mul ^rq %n) z aa) yy) - =/ dd (~(sub ^rq %n) bb (~(mul ^rq %n) v (head sc))) - (~(sub ^rq %n) xx dd) - ++ kcos - |= [xx=@rq yy=@rq] ^- @rq - =/ z (~(mul ^rq %n) xx xx) - =/ rc (roll (flop cc) |=([c=@rq a=@rq] (~(add ^rq %n) (~(mul ^rq %n) a z) c))) - =/ hz (~(mul ^rq %n) `@rq`0x3ffe.0000.0000.0000.0000.0000.0000.0000 z) - =/ w2 (~(sub ^rq %n) `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000 hz) - =/ aa (~(sub ^rq %n) (~(sub ^rq %n) `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000 w2) hz) - =/ bb (~(sub ^rq %n) (~(mul ^rq %n) (~(mul ^rq %n) z z) rc) (~(mul ^rq %n) xx yy)) - (~(add ^rq %n) w2 (~(add ^rq %n) aa bb)) - ++ trig-fin - |= [s=? ax=@rq sb=@] ^- @rq - =/ q (need (~(toi ^rq %n) (~(mul ^rq %n) ax `@rq`0x3ffe.45f3.06dc.9c88.2a53.f84e.afa3.ea6a))) - =/ qf (~(sun ^rq %n) (abs:si q)) - =/ t (~(sub ^rq %n) ax (~(mul ^rq %n) qf `@rq`0x3fff.921f.b544.42d1.8460.0000.0000.0000)) - =/ w (~(mul ^rq %n) qf `@rq`0x3fc2.3131.98a2.e037.0734.4a40.9382.229a) - =/ rhi (~(sub ^rq %n) t w) - =/ rlo (~(sub ^rq %n) (~(sub ^rq %n) t rhi) w) - =/ m (dis (abs:si q) 3) - =/ ks (ksin rhi rlo) - =/ kc (kcos rhi rlo) - ?: s - =/ v ?:(=(m 0) ks ?:(=(m 1) kc ?:(=(m 2) (neg ks) (neg kc)))) - ?:(=(sb 1) (neg v) v) - ?:(=(m 0) kc ?:(=(m 1) (neg ks) ?:(=(m 2) (neg kc) ks))) + :: half precision + ++ rh + ^| + |_ $: r=$?(%n %u %d %z) :: round nearest, up, down, to zero + rtol=_.~~1e-2 :: relative tolerance for precision of operations + == + :: mathematics constants to half precision + :: +tau: @rh + :: + :: Returns the value 2*pi (OEIS A019692). + :: Examples + :: > tau + :: .~~6.28 + :: Source + ++ tau .~~6.28 + :: +pi: @rh + :: + :: Returns the value pi (OEIS A000796). + :: Examples + :: > pi + :: .~~3.14 + :: Source + ++ pi .~~3.14 + :: +e: @rh + :: + :: Returns the value e (Euler's constant) (OEIS A001113). + :: Examples + :: > e + :: .~~2.72 + :: Source + ++ e .~~2.719 + :: +phi: @rh + :: + :: Returns the value phi (golden ratio) (OEIS A001622). + :: Examples + :: > phi + :: .~~1.62 + :: Source + ++ phi .~~1.618 + :: +sqt2: @rh + :: + :: Returns the value sqrt(2) (OEIS A002193). + :: Examples + :: > sqt2 + :: .~~1.414 + :: Source + ++ sqt2 .~~1.414 + :: +invsqt2: @rh + :: + :: Returns the value 1/sqrt(2) (OEIS A010503). + :: Examples + :: > invsqt2 + :: .~~0.707 + :: Source + ++ invsqt2 .~~0.707 + :: +log2: @rh + :: + :: Returns the value log(2) (OEIS A002162). + :: Examples + :: > log2 + :: .~~0.693 + :: Source + ++ log2 .~~0.6934 + :: +invlog2: @rh + :: + :: Returns the value 1/log(2). + :: Examples + :: > invlog2 + :: .~~1.443 + :: Source + ++ invlog2 .~~1.443 + :: +log10: @rh + :: + :: Returns the value log(10) (OEIS A002392). + :: Examples + :: > log10 + :: .~~2.303 + :: Source + ++ log10 .~~2.303 + :: +huge: @rh + :: + :: Returns the value of the largest representable number. + :: Examples + :: > huge + :: .~~6.55e+04 + :: Source + ++ huge `@rh`0x7bff :: 6.55e+04 + :: +tiny: @rh + :: + :: Returns the smallest representable positive (subnormal) number, 2^-24. + :: (Not the smallest NORMAL, which is 2^-14 = .~~6.10e-05.) + :: Examples + :: > tiny + :: .~~6e-8 + :: Source + ++ tiny `@rh`0x1 :: 6e-08 + :: + :: Operations + :: + :: +sea: @rh -> fn + :: + :: Returns the +$fn representation of a floating-point atom. + :: Examples + :: > (sea .~~1) + :: [%f s=%.y e=-10 a=1.024] + :: > (sea .~~1.1) + :: [%f s=%.y e=-10 a=1.126] + :: Source + ++ sea sea:^rh + :: +bit: fn -> @rh + :: + :: Returns the floating-point atom of a +$fn representation. + :: Examples + :: > (bit [%f s=%.y e=-10 a=1.024]) + :: .~~1 + :: > (bit [%f s=%.y e=-10 a=1.126]) + :: .~~1.1 + :: Source + ++ bit bit:^rh + :: +sun: @ud -> @rh + :: + :: Returns the floating-point atom of an unsigned integer atom. + :: Examples + :: > (sun 1) + :: .~~1 + :: > (sun 1.000) + :: .~~1e3 + :: Source + ++ sun sun:^rh + :: +san: @sd -> @rh + :: + :: Returns the floating-point atom of a signed integer atom. + :: Examples + :: > (san --1) + :: .~~1 + :: > (san -1) + :: .~-1 + :: Source + ++ san san:^rh + ::++ exp exp:^rh :: no pass-through because of exp function + :: +toi: @rh -> @sd + :: + :: Returns the unitized signed integer atom of a rounded floating-point atom. + :: Examples + :: > (toi .~~1) + :: [~ --1] + :: > (toi .~~1.1) + :: [~ --1] + :: Source + ++ toi toi:^rh + :: +drg: @rh -> dn + :: + :: Returns the decimal form of a floating-point atom using the Dragon4 + :: algorithm. + :: Examples + :: > (drg .~~1) + :: [%d s=%.y e=--0 a=1] + :: > (drg .~~1.1) + :: [%d s=%.y e=-1 a=11] + :: Source + ++ drg drg:^rh + :: +grd: dn -> @rh + :: + :: Returns the floating-point atom of a decimal form. + :: Examples + :: > (grd [%d s=%.y e=--0 a=1]) + :: .~~1 + :: > (grd [%d s=%.y e=-1 a=11]) + :: .~~1.1 + :: Source + ++ grd grd:^rh + :: + :: Comparison + :: + :: +lth: [@rh @rh] -> ? + :: + :: Returns the comparison of two floating-point atoms, less than. + :: Examples + :: > (lth .~~1 .~~2) + :: %.y + :: > (lth .~~2 .~~1) + :: %.n + :: > (lth .~~1 .~~1) + :: %.n + :: Source + ++ lth lth:^rh + :: +lte: [@rh @rh] -> ? + :: + :: Returns the comparison of two floating-point atoms, less than or equal to. + :: Examples + :: > (lte .~~1 .~~2) + :: %.y + :: > (lte .~~2 .~~1) + :: %.n + :: > (lte .~~1 .~~1) + :: %.y + :: Source + ++ lte lte:^rh + :: +leq: [@rh @rh] -> ? + :: + :: Returns the comparison of two floating-point atoms, less than or equal to. + :: Alias for +lte. + :: Examples + :: > (leq .~~1 .~~2) + :: %.y + :: > (leq .~~2 .~~1) + :: %.n + :: > (leq .~~1 .~~1) + :: %.y + :: Source + ++ leq lte:^rh + :: +equ: [@rh @rh] -> ? + :: + :: Returns the comparison of two floating-point atoms, equal to. + :: Examples + :: > (equ .~~1 .~~2) + :: %.n + :: > (equ .~~2 .~~1) + :: %.n + :: > (equ .~~1 .~~1) + :: %.y + :: Source + ++ equ equ:^rh + :: +gth: [@rh @rh] -> ? + :: + :: Returns the comparison of two floating-point atoms, greater than. + :: Examples + :: > (gth .~~1 .~~2) + :: %.n + :: > (gth .~~2 .~~1) + :: %.y + :: > (gth .~~1 .~~1) + :: %.n + :: Source + ++ gth gth:^rh + :: +gte: [@rh @rh] -> ? + :: + :: Returns the comparison of two floating-point atoms, greater than or equal to. + :: Examples + :: > (gte .~~1 .~~2) + :: %.n + :: > (gte .~~2 .~~1) + :: %.y + :: > (gte .~~1 .~~1) + :: %.y + :: Source + ++ gte gte:^rh + :: +geq: [@rh @rh] -> ? + :: + :: Returns the comparison of two floating-point atoms, greater than or equal to. + :: Alias for +gte. + :: Examples + :: > (geq .~~1 .~~2) + :: %.n + :: > (geq .~~2 .~~1) + :: %.y + :: > (geq .~~1 .~~1) + :: %.y + :: Source + ++ geq gte:^rh + :: +neq: [@rh @rh] -> ? + :: + :: Returns the comparison of two floating-point atoms, not equal to. + :: Examples + :: > (neq .~~1 .~~2) + :: %.y + :: > (neq .~~2 .~~1) + :: %.y + :: > (neq .~~1 .~~1) + :: %.n + :: Source + ++ neq |=([a=@rh b=@rh] ^-(? !(equ:^rh a b))) + :: +is-close: [@rh @rh] -> ? + :: + :: Returns the comparison of two floating-point atoms, within a relative + :: tolerance (provided by the +rh door). + :: Examples + :: > (is-close .~~1 .~~2) + :: %.n + :: > (is-close .~~1 .~~1.0000001) + :: %.n + :: > (~(is-close rh [%z .~~1e-3]) .~~1 .~~1.0001) + :: %.y + :: Source + ++ is-close + |= [p=@rh r=@rh] + (lth (abs (sub p r)) rtol) + :: +all-close: [@rh (list @rh)] -> ? + :: + :: Returns the comparison of a floating-point atom to a list of floating- + :: point atoms, within a relative tolerance (provided by the +rh door). + :: Examples + :: > (all-close .~~1 ~[.~~1 .~~2]) + :: %.n + :: > (all-close .~~1 ~[.~~1 .~~1.0000001]) + :: %.n + :: > (~(all-close rh [%z .~~1e-3]) .~~1 ~[.~~1 .~~1.0001]) + :: %.y + :: Source + ++ all-close + |= [p=@rh q=(list @rh)] + =/ i 0 + =/ n (lent q) + |- ^- ? + ?: =(n i) + %.y + ?. (is-close p (snag i q)) + %.n + $(i +(i)) + :: +is-int: @rh -> ? + :: + :: Returns whether a floating-point value is an integer (no fractional part). + :: Examples + :: > (is-int .~~1) + :: %.y + :: > (is-int .~~1.1) + :: %.n + :: Source + ++ is-int + |= x=@rh ^- ? + (equ x (san (need (toi x)))) + :: + :: Algebraic + :: + :: +add: [@rh @rh] -> @rh + :: + :: Returns the sum of two floating-point atoms. + :: Examples + :: > (add .~~1 .~~2) + :: .~~3 + :: Source + ++ add add:^rh + :: +sub: [@rh @rh] -> @rh + :: + :: Returns the difference of two floating-point atoms. + :: Examples + :: > (sub .~~1 .~~2) + :: .~~-1 + :: Source + ++ sub sub:^rh + :: +mul: [@rh @rh] -> @rh + :: + :: Returns the product of two floating-point atoms. + :: Examples + :: > (mul .~~1 .~~2) + :: .~~2 + :: Source + ++ mul mul:^rh + :: +div: [@rh @rh] -> @rh + :: + :: Returns the quotient of two floating-point atoms. + :: Examples + :: > (div .~~1 .~~2) + :: .~~0.5 + :: Source + ++ div div:^rh + :: +fma: [@rh @rh @rh] -> @rh + :: + :: Returns the fused multiply-add of three floating-point atoms. + :: Examples + :: > (fma .~~1 .~~2 .~~3) + :: .~~5 + :: > (fma .~~2 .~~3 .~~4) + :: .~~10 + :: Source + ++ fma fma:^rh + :: +sig: @rh -> ? + :: + :: Returns the sign of a floating-point atom. + :: Examples + :: > (sig .~~1) + :: %.y + :: > (sig .~~-1) + :: %.n + :: Source + ++ sig |=(x=@rh =(0 (rsh [0 15] x))) + :: +sgn: @rh -> ? + :: + :: Returns the sign of a floating-point atom. + :: Alias for +sig. + :: Examples + :: > (sgn .~~1) + :: %.y + :: > (sgn .~~-1) + :: %.n + :: Source + ++ sgn sig + :: +neg: @rh -> @rh + :: + :: Returns the negation of a floating-point atom. + :: Examples + :: > (neg .~~1) + :: .~~-1 + :: > (neg .~~-1) + :: .~~1 + :: Source + ++ neg |=(x=@rh (sub .~~0 x)) + :: +factorial: @rh -> @rh + :: + :: Returns the factorial of a floating-point atom. Assumes integer input. + :: Examples + :: > (factorial .~~1) + :: .~~1 + :: > (factorial .~~2) + :: .~~2 + :: > (factorial .~~3) + :: .~~6 + :: Source + ++ factorial + |= x=@rh ^- @rh + ?> (gte x .~~0) + =/ t=@rh .~~1 + ?: (is-close x .~~0) + t + |- ^- @rh + ?: (is-close x .~~1) + t + $(x (sub x .~~1), t (mul t x)) + :: +abs: @rh -> @rh + :: + :: Returns the absolute value of a floating-point atom. + :: Examples + :: > (abs .~~1) + :: .~~1 + :: > (abs .~~-1) + :: .~~1 + :: Source + ++ abs + |= x=@rh ^- @rh + ?:((sgn x) x (neg x)) + :: +exp: @rh -> @rh + :: + :: Returns the exponential of a floating-point atom. + :: Examples + :: > (exp .~~1) + :: .~~2.715 + :: > (exp .~~2) + :: .~~7.375 + :: > (~(exp rh [%z .~~1e-1]) .~~2) + :: .~~7.348 + :: > (exp .~~inf) + :: .inf + :: Source + :: +widen-hs: f16 -> f32, exact. +narrow-sh: f32 -> f16, correctly-rounded + :: RNE. The @rh transcendentals compute in the (more precise) @rs door and + :: round the result down -- correctly-rounded for f16, since an f32 result is + :: ~2^13 times finer than an f16 ULP. + ++ widen-hs + |= h=@rh ^- @ + =/ hh `@`h + =/ s (lsh [0 16] (dis hh 0x8000)) + =/ e (dis (rsh [0 10] hh) 0x1f) + =/ m (dis hh 0x3ff) + ?: =(e 0x1f) (con s (con 0x7f80.0000 (lsh [0 13] m))) + ?: =(e 0) + ?: =(m 0) s + (con s `@`(~(mul rs [%n .1e-5]) (~(sun rs [%n .1e-5]) m) `@rs`0x3380.0000)) + (con s (con (lsh [0 23] (^add e 112)) (lsh [0 13] m))) + ++ narrow-sh + |= uu=@rs ^- @ + =/ u `@`uu + =/ s (dis (rsh [0 16] u) 0x8000) + =/ e (dis (rsh [0 23] u) 0xff) + =/ m (dis u 0x7f.ffff) + ?: =(e 0xff) (con s ?:(=(m 0) 0x7c00 0x7e00)) + ?: (^gte e 143) (con s 0x7c00) + ?: (^gte e 113) + =/ ne (^sub e 112) + =/ mant (rsh [0 13] m) + =/ rem (dis m 0x1fff) + =/ rup ?|((^gth rem 0x1000) &(=(rem 0x1000) =(1 (dis mant 1)))) + (con s (^add (lsh [0 10] ne) (^add mant ?:(rup 1 0)))) + ?: (^lth e 102) (con s 0x0) + =/ shift (^sub 126 e) + =/ mf (con 0x80.0000 m) + =/ mant (rsh [0 shift] mf) + =/ half (bex (dec shift)) + =/ rem (dis mf (dec (bex shift))) + =/ rup ?|((^gth rem half) &(=(rem half) =(1 (dis mant 1)))) + (con s (^add mant ?:(rup 1 0))) + ++ exp + :: compute in @rs, round to f16 (see +narrow-sh). + |= x=@rh ^- @rh + `@rh`(narrow-sh (~(exp rs [%n .1e-5]) `@rs`(widen-hs x))) + :: +sin: @rh -> @rh + :: + :: Returns the sine of a floating-point atom. + :: Examples + :: > (sin .~~1) + :: .~~0.8413 + :: > (sin .~~2) + :: .~~0.9087 + :: > (sin pi) + :: .~~3.437e-3 + :: Source + ++ sin + |= x=@rh ^- @rh + `@rh`(narrow-sh (~(sin rs [%n .1e-5]) `@rs`(widen-hs x))) + :: +cos: @rh -> @rh + :: + :: Returns the cosine of a floating-point atom. + :: Examples + :: > (cos .~~1) + :: .~~0.54 + :: > (cos .~~2) + :: .~~-0.4158 + :: > (cos pi) + :: .~~-1.001 + :: Source + ++ cos + |= x=@rh ^- @rh + `@rh`(narrow-sh (~(cos rs [%n .1e-5]) `@rs`(widen-hs x))) + :: +tan: @rh -> @rh + :: + :: Returns the tangent of a floating-point atom. + :: Examples + :: > (tan .~~1) + :: .~~1.558 + :: > (tan .~~2) + :: .~~-2.186 + :: > (tan pi) + :: .~~-3.433e-3 + :: Source + ++ tan + |= x=@rh ^- @rh + `@rh`(narrow-sh (~(tan rs [%n .1e-5]) `@rs`(widen-hs x))) + :: +asin: @rh -> @rh + :: + :: Returns the inverse sine of a floating-point atom. + :: Examples + :: > (asin .~~0) + :: .~~0 + :: > (asin .~~1) + :: .~~1.57 + :: > (asin .~~0.7) + :: .~~0.7773 + :: + ++ asin + |= x=@rh ^- @rh + `@rh`(narrow-sh (~(asin rs [%n .1e-5]) `@rs`(widen-hs x))) + :: +acos: @rh -> @rh + :: + :: Returns the inverse cosine of a floating-point atom. + :: Examples + :: > (acos .~~0) + :: .~~1.57 + :: > (acos .~~1) + :: .~~0 + :: > (acos .~~0.7) + :: .~~0.7964 + :: + ++ acos + |= x=@rh ^- @rh + `@rh`(narrow-sh (~(acos rs [%n .1e-5]) `@rs`(widen-hs x))) + :: +atan: @rh -> @rh + :: + :: Returns the inverse tangent of a floating-point atom. + :: Examples + :: > (atan .~~1) + :: .~~0.7866 + :: > (atan .~~2) + :: .~~1.111 + :: > (atan pi) + :: .~~1.281 + :: + ++ atan + |= x=@rh ^- @rh + `@rh`(narrow-sh (~(atan rs [%n .1e-5]) `@rs`(widen-hs x))) + :: +atan2: [@rh @rh] -> @rh + :: + :: Returns the inverse tangent of a floating-point coordinate. + :: Examples + :: > (atan2 .~~0 .~~1) + :: .~~0 + :: > (atan2 .~~-1 .~~0) + :: .~~-1.57 + :: > (atan2 .~~0.5 .~~-0.5) + :: .~~2.354 + :: + ++ atan2 + |= [y=@rh x=@rh] ^- @rh + `@rh`(narrow-sh (~(atan2 rs [%n .1e-5]) `@rs`(widen-hs y) `@rs`(widen-hs x))) + :: +pow-n: [@rh @rh] -> @rh + :: + :: Returns the power of a floating-point atom to an integer exponent. + :: Examples + :: > (pow-n .~~1 .~~2) + :: .~~1 + :: > (pow-n .~~2 .~~2) + :: .~~4 + :: > (pow-n .~~2 .~~3) + :: .~~8 + :: Source + ++ pow-n + |= [x=@rh n=@rh] ^- @rh + `@rh`(narrow-sh (~(pow-n rs [%n .1e-5]) `@rs`(widen-hs x) `@rs`(widen-hs n))) + :: +log: @rh -> @rh + :: + :: Returns the natural logarithm of a floating-point atom. + :: Examples + :: > (log .~~1) + :: .~~0 + :: > (log .~~2) + :: .~~0.6914 + :: > (~(log rh [%z .~~1e-1]) .~~2) + :: .~~0.6904 + ++ log + |= x=@rh ^- @rh + `@rh`(narrow-sh (~(log rs [%n .1e-5]) `@rs`(widen-hs x))) + :: +log-10: @rh -> @rh + :: + :: Returns the base-10 logarithm of a floating-point atom. + :: Examples + :: TODO + :: Source + ++ log-10 + |= x=@rh ^- @rh + `@rh`(narrow-sh (~(log-10 rs [%n .1e-5]) `@rs`(widen-hs x))) + :: +log-2: @rh -> @rh + :: + :: Returns the base-2 logarithm of a floating-point atom. + :: Examples + :: TODO + :: Source + ++ log-2 + |= x=@rh ^- @rh + `@rh`(narrow-sh (~(log-2 rs [%n .1e-5]) `@rs`(widen-hs x))) + :: +pow: [@rh @rh] -> @rh + :: + :: Returns the power of a floating-point atom to a floating-point exponent. + :: Examples + :: > (pow .~~1 .~~2) + :: .~~1 + :: > (pow .~~2 .~~2) + :: .~~4 + :: > (~(pow rh:math [%z .~~1e-1]) .~~2 .~~3.5) + :: .~~11.14 + :: Source + ++ pow + |= [x=@rh n=@rh] ^- @rh + `@rh`(narrow-sh (~(pow rs [%n .1e-5]) `@rs`(widen-hs x) `@rs`(widen-hs n))) + :: +sqrt: @rh -> @rh + :: + :: Returns the square root of a floating-point atom. + :: Alias for +sqt. + :: Examples + :: > (sqrt .~~1) + :: .~~1 + :: > (sqrt .~~2) + :: .~~1.412 + :: > (~(sqrt rh [%z .~~1e-1]) .~~2) + :: .~~1.404 + :: Source + ++ sqrt sqt + :: +sqt: @rh -> @rh + :: + :: Returns the square root of a floating-point atom. + :: Examples + :: > (sqt .~~1) + :: .~~1 + :: > (sqt .~~2) + :: .~~1.414 + :: > (sqt .~~1e3) + :: .~~31.61 + :: Source + ++ sqt + |= x=@rh ^- @rh + `@rh`(narrow-sh (~(sqt rs [%n .1e-5]) `@rs`(widen-hs x))) + :: +cbrt: @rh -> @rh + :: + :: Returns the cube root of a floating-point atom. + :: Alias for +cbt. + :: Examples + :: > (cbrt .~~1) + :: .~~1 + :: > (cbrt .~~2) + :: .~~1.258 + :: > (~(cbrt rh [%z .~~1e-1]) .~~2) + :: .~~1.256 + :: Source + ++ cbrt cbt + :: +cbt: @rh -> @rh + :: + :: Returns the cube root of a floating-point atom. + :: Examples + :: > (cbt .~~1) + :: .~~1 + :: > (cbt .~~2) + :: .~~1.258 + :: > (~(cbt rh [%z .~~1e-1]) .~~2) + :: .~~1.256 + :: Source + ++ cbt + |= x=@rh ^- @rh + `@rh`(narrow-sh (~(cbt rs [%n .1e-5]) `@rs`(widen-hs x))) + :: +arg: @rh -> @rh + :: + :: Returns the argument of a floating-point atom (real argument = absolute + :: value). + :: Examples + :: > (arg .~~1) + :: .~~1 + :: > (arg .~-1) + :: .~~1 + :: Source + ++ arg abs -- - :: +cos: @rq -> @rq - :: - :: Returns the cosine of a floating-point atom. - :: Examples - :: > (cos .~~~1) - :: .~~~0.5403023058681397174009349981817251 - :: > (cos .~~~2) - :: .~~~-0.41614683654714238699756419777191616 - :: > (cos pi) - :: .~~~-1.0000000000000000000000021077555518 - :: Source - ++ cos - |= x=@rq ^- @rq - ?: !(~(equ ^rq %n) x x) `@rq`0x7fff.8000.0000.0000.0000.0000.0000.0000 - ?: |(=(x `@rq`0x7fff.0000.0000.0000.0000.0000.0000.0000) =(x `@rq`0xffff.0000.0000.0000.0000.0000.0000.0000)) `@rq`0x7fff.8000.0000.0000.0000.0000.0000.0000 - %- trig-fin:rq-trig - [%.n `@rq`(dis x 0x7fff.ffff.ffff.ffff.ffff.ffff.ffff.ffff) 0] - :: +tan: @rq -> @rq - :: - :: Returns the tangent of a floating-point atom. - :: Examples - :: > (tan .~~~1) - :: .~~~1.5574077246549022305069793269617903 - :: > (tan .~~~2) - :: .~~~-2.1850398632615189916433278966958165 - :: > (tan pi) - :: .~~~-2.1850398632615189916433278966958165 - :: Source - ++ tan - |= x=@rq ^- @rq - (div (sin x) (cos x)) - :: +asin: @rq -> @rq - :: - :: Returns the inverse sine of a floating-point atom. - :: Examples - :: > (asin .~~~0) - :: .~~~0 - :: > (asin .~~~1) - :: .~~~1.5707963267948966192313216916397514 - :: > (asin .~~~0.7) - :: .~~~0.7753974966107530637394463388579305 - :: - ++ asin - :: fdlibm rational-form kernel (poly R, deg-30) + sqrt head/tail; f128. - |= x=@rq ^- @rq - (asn:rq-ainv x) - ++ acos - |= x=@rq ^- @rq - (acs:rq-ainv x) - ++ rq-ainv - |% - ++ rr - |= t=@rq ^- @rq + :: quad precision + ++ rq + ^| + |_ $: r=$?(%n %u %d %z) :: round nearest, up, down, to zero + rtol=_.~~~1e-20 :: relative tolerance for precision of operations + == + :: mathematics constants to quad precision + :: +tau: @rq + :: + :: Returns the value 2*pi (OEIS A019692). + :: Examples + :: > tau + :: .~~~6.2831853071795864769252867665590056 + :: Source + ++ tau .~~~6.2831853071795864769252867665590056 + :: +pi: @rq + :: + :: Returns the value pi (OEIS A000796). + :: Examples + :: > pi + :: .~~~3.1415926535897932384626433832795028 + :: Source + ++ pi .~~~3.1415926535897932384626433832795028 + :: +e: @rq + :: + :: Returns the value e (Euler's constant) (OEIS A001113). + :: Examples + :: > e + :: .~~~2.7182818284590452353602874713526623 + :: Source + ++ e .~~~2.7182818284590452353602874713526623 + :: +phi: @rq + :: + :: Returns the value phi (golden ratio) (OEIS A001622). + :: Examples + :: > phi + :: .~~~1.6180339887498948482045868343656382 + :: Source + ++ phi .~~~1.6180339887498948482045868343656382 + :: +sqt2: @rq + :: + :: Returns the value sqrt(2) (OEIS A002193). + :: Examples + :: > sqt2 + :: .~~~1.414213562373095048801688724209698 + :: Source + ++ sqt2 .~~~1.414213562373095048801688724209698 + :: +invsqt2: @rq + :: + :: Returns the value 1/sqrt(2) (OEIS A010503). + :: Examples + :: > invsqt2 + :: .~~~0.707106781186547524400844362104849 + :: Source + ++ invsqt2 .~~~0.707106781186547524400844362104849 + :: +log2: @rq + :: + :: Returns the value log(2) (OEIS A002162). + :: Examples + :: > log2 + :: .~~~0.6931471805599453094172321214581766 + :: Source + ++ log2 .~~~0.6931471805599453094172321214581766 + :: +invlog2: @rq + :: + :: Returns the value 1/log(2). + :: Examples + :: > invlog2 + :: .~~~1.442695040888963387004650940070860 + :: Source + ++ invlog2 .~~~1.442695040888963387004650940070860 :: TODO check + :: +log10: @rq + :: + :: Returns the value log(10) (OEIS A002392). + :: Examples + :: > log10 + :: .~~~2.302585092994045684017991454684364 + :: Source + ++ log10 .~~~2.302585092994045684017991454684364 + :: +huge: @rq + :: + :: Returns the value of the largest representable number. + :: Examples + :: > huge + :: .~~~1.189731495357231765085759326628007e4932 + :: Source + ++ huge `@rq`0x7ffe.ffff.ffff.ffff.ffff.ffff.ffff.ffff.ffff :: 1.18973149535723176508575932662800702e4932 + :: +tiny: @rq + :: + :: Returns the value of the smallest representable normal number. + :: Examples + :: > tiny + :: .~~~3.3621031431120935062626778173217526e-4932 + :: Source + ++ tiny `@rq`0x1.0000.0000.0000.0000.0000.0000.0000.0000 :: 3.36210314311209350626267781732175260e-4932 + :: + :: Operations + :: + :: +sea: @rq -> fn + :: + :: Returns the +$fn representation of a floating-point atom. + :: Examples + :: > (sea .~~~1) + :: [%f s=%.y e=-112 a=5.192.296.858.534.827.628.530.496.329.220.096] + :: > (sea .~~~1.1) + :: [%f s=%.y e=-112 a=5.711.526.544.388.310.391.383.545.962.142.106] + :: Source + ++ sea sea:^rq + :: +bit: fn -> @rq + :: + :: Returns the floating-point atom of a +$fn representation. + :: Examples + :: > (bit [%f s=%.y e=-112 a=5.192.296.858.534.827.628.530.496.329.220.096]) + :: .~~~1 + :: > (bit [%f s=%.y e=-112 a=5.711.526.544.388.310.391.383.545.962.142.106]) + :: .~~~1.1 + :: Source + ++ bit bit:^rq + :: +sun: @ud -> @rq + :: + :: Returns the floating-point atom of an unsigned integer atom. + :: Examples + :: > (sun 1) + :: .~~~1 + :: > (sun 1.000) + :: .~~~1e3 + :: Source + ++ sun sun:^rq + :: +san: @sd -> @rq + :: + :: Returns the floating-point atom of a signed integer atom. + :: Examples + :: > (san --1) + :: .~~~1 + :: > (san -1) + :: .~~~-1 + :: Source + ++ san san:^rq + ::++ exp exp:^rq :: no pass-through because of exp function + :: +toi: @rq -> @sd + :: + :: Returns the unitized signed integer atom of a rounded floating-point atom. + :: Examples + :: > (toi .~~~1) + :: [~ --1] + :: > (toi .~~~1.1) + :: [~ --1] + :: Source + ++ toi toi:^rq + :: +drg: @rq -> dn + :: + :: Returns the decimal form of a floating-point atom using the Dragon4 + :: algorithm. + :: Examples + :: > (drg .~~~1) + :: [%d s=%.y e=--0 a=1] + :: > (drg .~~~1.1) + :: [%d s=%.y e=-1 a=11] + :: Source + ++ drg drg:^rq + :: +grd: dn -> @rq + :: + :: Returns the floating-point atom of a decimal form. + :: Examples + :: > (grd [%d s=%.y e=--0 a=1]) + :: .~~~1 + :: > (grd [%d s=%.y e=-1 a=11]) + :: .~~~1.1 + :: Source + ++ grd grd:^rq + :: + :: Comparison + :: + :: +lth: [@rq @rq] -> ? + :: + :: Returns the comparison of two floating-point atoms, less than. + :: Examples + :: > (lth .~~~1 .~~~2) + :: %.y + :: > (lth .~~~2 .~~~1) + :: %.n + :: > (lth .~~~1 .~~~1) + :: %.n + :: Source + ++ lth lth:^rq + :: +lte: [@rq @rq] -> ? + :: + :: Returns the comparison of two floating-point atoms, less than or equal to. + :: Examples + :: > (lte .~~~1 .~~~2) + :: %.y + :: > (lte .~~~2 .~~~1) + :: %.n + :: > (lte .~~~1 .~~~1) + :: %.y + :: Source + ++ lte lte:^rq + :: +leq: [@rq @rq] -> ? + :: + :: Returns the comparison of two floating-point atoms, less than or equal to. + :: Alias for +lte. + :: Examples + :: > (leq .~~~1 .~~~2) + :: %.y + :: > (leq .~~~2 .~~~1) + :: %.n + :: > (leq .~~~1 .~~~1) + :: %.y + :: Source + ++ leq lte:^rq + :: +equ: [@rq @rq] -> ? + :: + :: Returns the comparison of two floating-point atoms, equal to. + :: Examples + :: > (equ .~~~1 .~~~2) + :: %.n + :: > (equ .~~~2 .~~~1) + :: %.n + :: > (equ .~~~1 .~~~1) + :: %.y + :: Source + ++ equ equ:^rq + :: +gth: [@rq @rq] -> ? + :: + :: Returns the comparison of two floating-point atoms, greater than. + :: Examples + :: > (gth .~~~1 .~~~2) + :: %.n + :: > (gth .~~~2 .~~~1) + :: %.y + :: > (gth .~~~1 .~~~1) + :: %.n + :: Source + ++ gth gth:^rq + :: +gte: [@rq @rq] -> ? + :: + :: Returns the comparison of two floating-point atoms, greater than or equal to. + :: Examples + :: > (gte .~~~1 .~~~2) + :: %.n + :: > (gte .~~~2 .~~~1) + :: %.y + :: > (gte .~~~1 .~~~1) + :: %.y + :: Source + ++ gte gte:^rq + :: +geq: [@rq @rq] -> ? + :: + :: Returns the comparison of two floating-point atoms, greater than or equal to. + :: Alias for +gte. + :: Examples + :: > (geq .~~~1 .~~~2) + :: %.n + :: > (geq .~~~2 .~~~1) + :: %.y + :: > (geq .~~~1 .~~~1) + :: %.y + :: Source + ++ geq gte:^rq + :: +neq: [@rq @rq] -> ? + :: + :: Returns the comparison of two floating-point atoms, not equal to. + :: Examples + :: > (neq .~~~1 .~~~2) + :: %.y + :: > (neq .~~~2 .~~~1) + :: %.y + :: > (neq .~~~1 .~~~1) + :: %.n + :: Source + ++ neq |=([a=@rq b=@rq] ^-(? !(equ:^rq a b))) + :: +is-close: [@rq @rq] -> ? + :: + :: Returns the comparison of two floating-point atoms, within a relative + :: tolerance (provided by the +rq door). + :: Examples + :: > (is-close .~~~1 .~~~2) + :: %.n + :: > (is-close .~~~1 .~~~1.0000001) + :: %.n + :: > (~(is-close rq [%z .~~~1e-3]) .~~~1 .~~~1.0001) + :: %.y + :: > (~(is-close rq [%z .~~~1e-30]) .~~~1 .~~~1.0001) + :: %.n + :: Source + ++ is-close + |= [p=@rq r=@rq] + (lth (abs (sub p r)) rtol) + :: +all-close: [@rq (list @rq)] -> ? + :: + :: Returns the comparison of a floating-point atom to a list of floating- + :: point atoms, within a relative tolerance (provided by the +rq door). + :: Examples + :: > (all-close .~~~1 ~[.~~~1 .~~~2]) + :: %.n + :: > (all-close .~~~1 ~[.~~~1 .~~~1.0000001]) + :: %.n + :: > (~(all-close rq [%z .~~~1e-3]) .~~~1 ~[.~~~1 .~~~1.0001]) + :: %.y + :: Source + ++ all-close + |= [p=@rq q=(list @rq)] + =/ i 0 + =/ n (lent q) + |- ^- ? + ?: =(n i) + %.y + ?. (is-close p (snag i q)) + %.n + $(i +(i)) + :: +is-int: @rq -> ? + :: + :: Returns whether a floating-point value is an integer (no fractional part). + :: Examples + :: > (is-int .~~~1) + :: %.y + :: > (is-int .~~~1.1) + :: %.n + :: Source + ++ is-int + |= x=@rq ^- ? + (equ x (san (need (toi x)))) + :: + :: Algebraic + :: + :: +add: [@rq @rq] -> @rq + :: + :: Returns the sum of two floating-point atoms. + :: Examples + :: > (add .~~~1 .~~~2) + :: .~~~3 + :: Source + ++ add add:^rq + :: +sub: [@rq @rq] -> @rq + :: + :: Returns the difference of two floating-point atoms. + :: Examples + :: > (sub .~~~1 .~~~2) + :: .~~~-1 + :: Source + ++ sub sub:^rq + :: +mul: [@rq @rq] -> @rq + :: + :: Returns the product of two floating-point atoms. + :: Examples + :: > (mul .~~~1 .~~~2) + :: .~~~2 + :: Source + ++ mul mul:^rq + :: +div: [@rq @rq] -> @rq + :: + :: Returns the quotient of two floating-point atoms. + :: Examples + :: > (div .~~~1 .~~~2) + :: .~~~0.5 + :: Source + ++ div div:^rq + :: +fma: [@rq @rq @rq] -> @rq + :: + :: Returns the fused multiply-add of three floating-point atoms. + :: Examples + :: > (fma .~~~1 .~~~2 .~~~3) + :: .~~~5 + :: > (fma .~~~2 .~~~3 .~~~4) + :: .~~~10 + :: Source + ++ fma fma:^rq + :: +sig: @rq -> ? + :: + :: Returns the sign of a floating-point atom. + :: Examples + :: > (sig .~~~1) + :: %.y + :: > (sig .~~~-1) + :: %.n + :: Source + ++ sig |=(x=@rq =(0 (rsh [0 127] x))) + :: +sgn: @rq -> ? + :: + :: Returns the sign of a floating-point atom. + :: Alias for +sig. + :: Examples + :: > (sgn .~~~1) + :: %.y + :: > (sgn .~~~-1) + :: %.n + :: Source + ++ sgn sig + :: +neg: @rq -> @rq + :: + :: Returns the negation of a floating-point atom. + :: Examples + :: > (neg .~~~1) + :: .~~~-1 + :: > (neg .~~~-1) + :: .~~~1 + :: Source + ++ neg |=(x=@rq (sub .~~~0 x)) + :: +factorial: @rq -> @rq + :: + :: Returns the factorial of a floating-point atom. Assumes integer input. + :: Examples + :: > (factorial .~~~1) + :: .~~~1 + :: > (factorial .~~~2) + :: .~~~2 + :: > (factorial .~~~3) + :: .~~~6 + :: Source + ++ factorial + |= x=@rq ^- @rq + ?> (gte x .~~~0) + =/ t=@rq .~~~1 + ?: (is-close x .~~~0) + t + |- ^- @rq + ?: (is-close x .~~~1) + t + $(x (sub x .~~~1), t (mul t x)) + :: +abs: @rq -> @rq + :: + :: Returns the absolute value of a floating-point atom. + :: Examples + :: > (abs .~~~1) + :: .~~~1 + :: > (abs .~~~-1) + :: .~~~1 + :: Source + ++ abs + |= x=@rq ^- @rq + ?:((sgn x) x (neg x)) + :: +exp: @rq -> @rq + :: + :: Returns the exponential of a floating-point atom. + :: Examples + :: > (exp .~~~1) + :: .~~~2.7182818284590452353602471108690483 + :: > (exp .~~~2) + :: .~~~7.389056098930650227230362414146335 + :: > (~(exp rq [%z .~~~1e-20]) .~~~2) + :: .~~~7.389056098930650227230362414146335 + :: > (exp .~~~inf) + :: .~~~inf + :: Source + ++ exp + :: Cody-Waite reduction + degree-24 minimax (f128); round-nearest-even + :: internally (matches the SoftFloat jet, see tools/rq_check.c). + |= x=@rq ^- @rq + =/ pow2 |=(j=@s `@rq`(lsh [0 112] (abs:si (sum:si j --16.383)))) + =/ scale2 + |= [p=@rq k=@s] ^- @rq + ?: (syn:si (dif:si k --16.384)) + (~(mul ^rq %n) (~(mul ^rq %n) p (pow2 --16.383)) (pow2 (dif:si k --16.383))) + ?: !(syn:si (sum:si k --16.382)) + (~(mul ^rq %n) (~(mul ^rq %n) p (pow2 (sum:si k --112))) (pow2 -112)) + (~(mul ^rq %n) p (pow2 k)) + ?: !(~(equ ^rq %n) x x) `@rq`0x7fff.8000.0000.0000.0000.0000.0000.0000 + ?: =(x `@rq`0x7fff.0000.0000.0000.0000.0000.0000.0000) `@rq`0x7fff.0000.0000.0000.0000.0000.0000.0000 + ?: =(x `@rq`0xffff.0000.0000.0000.0000.0000.0000.0000) `@rq`0x0 + =/ log2e `@rq`0x3fff.7154.7652.b82f.e177.7d0f.fda0.d23a + =/ ln2hi `@rq`0x3ffe.62e4.2fef.a39e.f357.93c8.0000.0000 + =/ ln2lo `@rq`0xbfad.319f.f034.2542.fc32.f366.359d.274a + =/ k=@s (need (~(toi ^rq %n) (~(mul ^rq %n) x log2e))) + ?: (syn:si (dif:si k --16.385)) `@rq`0x7fff.0000.0000.0000.0000.0000.0000.0000 + ?: !(syn:si (sum:si k --16.494)) `@rq`0x0 + =/ ka (~(sun ^rq %n) (abs:si k)) + =/ kf ?:((syn:si k) ka (~(sub ^rq %n) `@rq`0x0 ka)) + =/ r + %- ~(sub ^rq %n) + :- (~(sub ^rq %n) x (~(mul ^rq %n) kf ln2hi)) + (~(mul ^rq %n) kf ln2lo) =/ cs=(list @rq) - :~ `@rq`0x3f80.8991.2e54.d43f.83f4.00d5.0d55.a7e8 `@rq`0x3ffc.5555.5555.5555.5555.5555.5555.5552 - `@rq`0x3ffb.3333.3333.3333.3333.3333.3333.5009 `@rq`0x3ffa.6db6.db6d.b6db.6db6.db6d.b668.951b - `@rq`0x3ff9.f1c7.1c71.c71c.71c7.1c72.bac1.ec0e `@rq`0x3ff9.6e8b.a2e8.ba2e.8ba2.e81a.a31a.41d8 - `@rq`0x3ff9.1c4e.c4ec.4ec4.ec4f.0b6f.e680.df37 `@rq`0x3ff8.c999.9999.9999.996c.f372.753e.7c99 - `@rq`0x3ff8.7a87.8787.8787.9217.7cc3.2753.53f7 `@rq`0x3ff8.3fde.50d7.9433.f7f1.afe5.cbea.c090 - `@rq`0x3ff8.12ef.3cf3.cf83.f127.037c.33f0.fb5b `@rq`0x3ff7.df3b.d37a.5ede.5c11.4e9d.a47d.edfd - `@rq`0x3ff7.a686.3d72.3133.909e.0729.7f5e.2958 `@rq`0x3ff7.782d.d9f3.ff64.52ce.6cb8.56ef.901f - `@rq`0x3ff7.51ba.328f.884c.2fdb.62f4.1c70.9bd1 `@rq`0x3ff7.3168.1fe6.e02d.b0d4.9614.21ef.a7ec - `@rq`0x3ff7.15ef.e556.e52a.3408.e80b.5b3f.8641 `@rq`0x3ff6.fc96.253e.cb71.1812.7122.68a4.5b42 - `@rq`0x3ff6.d4a8.2428.408a.ebe9.bc6e.47ec.09af `@rq`0x3ff6.aa37.7fe9.13f6.c0a9.facb.9451.1de4 - `@rq`0x3ff6.b48c.a21a.48d1.8473.7463.fe86.56d8 `@rq`0x3ff5.7e9a.a4b5.b4c4.e391.3451.8885.e78f - `@rq`0x3ff8.1906.4c51.85fa.a0d0.3ab9.c514.26b2 `@rq`0xbff9.300f.0da2.da1e.1c08.5f96.2a89.aacc - `@rq`0x3ffb.0643.398c.dbcb.97d2.5a1b.e10b.6c8a `@rq`0xbffc.27ed.3dd5.cd82.528e.0d54.bf4f.5e05 - `@rq`0x3ffd.1d64.319b.e957.ad88.0c8c.d533.b68b `@rq`0xbffd.9731.e485.678b.81c3.902a.2c54.acc7 - `@rq`0x3ffd.ae10.872f.69b7.a99a.a13d.6e9c.d204 `@rq`0xbffd.228f.c652.7609.25c1.64c7.f610.91fa - `@rq`0x3ffb.9aa4.ca63.cbd7.2c15.b8ad.9b23.77ce + :~ `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000 `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000 + `@rq`0x3ffe.0000.0000.0000.0000.0000.0000.0000 `@rq`0x3ffc.5555.5555.5555.5555.5555.5555.5555 + `@rq`0x3ffa.5555.5555.5555.5555.5555.5555.5555 `@rq`0x3ff8.1111.1111.1111.1111.1111.1111.1111 + `@rq`0x3ff5.6c16.c16c.16c1.6c16.c16c.16c1.6c17 `@rq`0x3ff2.a01a.01a0.1a01.a01a.01a0.1a01.a3e8 + `@rq`0x3fef.a01a.01a0.1a01.a01a.01a0.1a01.a146 `@rq`0x3fec.71de.3a55.6c73.38fa.ac1c.88a5.a526 + `@rq`0x3fe9.27e4.fb77.89f5.c72e.f016.d3d6.e867 `@rq`0x3fe5.ae64.567f.544e.38fe.7483.63c4.6e8b + `@rq`0x3fe2.1eed.8eff.8d89.7b54.4dab.18f4.75c5 `@rq`0x3fde.6124.613a.86d0.97c9.f3ae.babb.2423 + `@rq`0x3fda.9397.4a8c.07c9.d20b.83c7.f94d.17d8 `@rq`0x3fd6.ae7f.3e73.3b81.f5f4.284f.0d74.f9e7 + `@rq`0x3fd2.ae7f.3e73.3b81.f417.b4d2.7c5f.92a9 `@rq`0x3fce.952c.7703.0a99.6a41.9e67.4779.c97c + `@rq`0x3fca.6827.863b.97b5.0466.ff8c.8b42.b3df `@rq`0x3fc6.2f49.b469.f892.874b.7a68.6d81.9241 + `@rq`0x3fc1.e542.ba42.7463.bb3b.32a1.1bb5.f139 `@rq`0x3fbd.71b8.db9f.7f73.c938.90ff.9ab5.5cbb + `@rq`0x3fb9.0ce3.8aab.7bd7.6efc.0717.eae7.85a1 `@rq`0x3fb4.7693.274b.ab2a.cb3f.4f7e.dfaa.2666 + `@rq`0x3faf.f362.9154.e0a7.61cb.0e23.655d.47cb + == + =/ p (roll (flop cs) |=([c=@rq acc=@rq] (~(add ^rq %n) (~(mul ^rq %n) acc r) c))) + (scale2 p k) + :: +sin: @rq -> @rq + :: + :: Returns the sine of a floating-point atom. + :: Examples + :: > (sin .~~~1) + :: .~~~0.8414709848078965066525022572525196 + :: > (sin .~~~2) + :: .~~~0.9092974268256816953960201260866781 + :: > (sin pi) + :: .~~~2.4143733100361875441251426417684949e-23 + :: Source + ++ sin + :: q*pi/2 reduction + fdlibm kernels (f128); see +rq-trig. + |= x=@rq ^- @rq + ?: !(~(equ ^rq %n) x x) `@rq`0x7fff.8000.0000.0000.0000.0000.0000.0000 + ?: |(=(x `@rq`0x7fff.0000.0000.0000.0000.0000.0000.0000) =(x `@rq`0xffff.0000.0000.0000.0000.0000.0000.0000)) `@rq`0x7fff.8000.0000.0000.0000.0000.0000.0000 + ?: |(=(x `@rq`0x0) =(x `@rq`0x8000.0000.0000.0000.0000.0000.0000.0000)) x + %- trig-fin:rq-trig + [%.y `@rq`(dis x 0x7fff.ffff.ffff.ffff.ffff.ffff.ffff.ffff) (rsh [0 127] x)] + ++ rq-trig + |% + ++ sc + ^- (list @rq) + :~ `@rq`0xbffc.5555.5555.5555.5555.5555.5555.5555 + `@rq`0x3ff8.1111.1111.1111.1111.1111.1111.1111 + `@rq`0xbff2.a01a.01a0.1a01.a01a.01a0.1a01.a01a + `@rq`0x3fec.71de.3a55.6c73.38fa.ac1c.88e5.0017 + `@rq`0xbfe5.ae64.567f.544e.38fe.747e.4b83.7dc7 + `@rq`0x3fde.6124.613a.86d0.97ca.3833.1d23.af68 + `@rq`0xbfd6.ae7f.3e73.3b81.f11d.8656.b0ee.8cb0 + `@rq`0x3fce.952c.7703.0ad4.a6b2.6051.9777.1b00 + `@rq`0xbfc6.2f49.b468.1415.724c.a1ec.3b7b.9675 + `@rq`0x3fbd.71b8.ef6d.cf57.18be.f146.fcee.6e45 + `@rq`0xbfb4.761b.4131.6381.9d97.b870.4dd7.f628 + `@rq`0x3fab.3f3c.cdd1.65fa.8d4e.44a4.1977.6f11 + `@rq`0xbfa1.d1ab.1c2d.ccea.320a.9a18.f15d.4277 + `@rq`0x3f98.259f.98b4.358a.d7ab.e30e.7766.f129 + `@rq`0xbf8e.434d.2e78.3f5b.c42e.1ee4.6fa6.bfc4 + `@rq`0x3f84.3981.254d.d0d5.1b53.82cd.ffa9.7422 + == + ++ cc + ^- (list @rq) + :~ `@rq`0x3ffa.5555.5555.5555.5555.5555.5555.5555 + `@rq`0xbff5.6c16.c16c.16c1.6c16.c16c.16c1.6c17 + `@rq`0x3fef.a01a.01a0.1a01.a01a.01a0.1a01.a01a + `@rq`0xbfe9.27e4.fb77.89f5.c72e.f016.d3ea.6679 + `@rq`0x3fe2.1eed.8eff.8d89.7b54.4da9.87ac.fe85 + `@rq`0xbfda.9397.4a8c.07c9.d20b.adf1.45df.a3e5 + `@rq`0x3fd2.ae7f.3e73.3b81.f11d.8656.b0ee.8cb0 + `@rq`0xbfca.6827.863b.97d9.77bb.0048.86a2.c2ab + `@rq`0x3fc1.e542.ba40.2022.507a.9cad.2bf8.f0bb + `@rq`0xbfb9.0ce3.96db.7f85.2945.0c90.b7f3.38ec + `@rq`0x3faf.f2cf.0197.2f57.7cca.4b40.67ca.9d8a + `@rq`0xbfa6.88e8.5fc6.a4e5.9a38.f205.0ba6.b015 + `@rq`0x3f9d.0a18.a263.5085.d373.c5c5.1c35.4a8d + `@rq`0xbf93.3932.c504.7d60.e60c.aded.4c29.89c5 + `@rq`0x3f89.434d.2e78.3f5b.c42e.1ee4.6fa6.bfc4 + `@rq`0xbf7f.2710.231c.0fd7.a13f.8a2b.4af9.d6b7 == - (roll (flop cs) |=([c=@rq a=@rq] (~(add ^rq %n) (~(mul ^rq %n) a t) c))) - ++ asn + ++ neg |=(a=@rq ^-(@rq (~(sub ^rq %n) `@rq`0x0 a))) + ++ ksin + |= [xx=@rq yy=@rq] ^- @rq + =/ z (~(mul ^rq %n) xx xx) + =/ r (roll (flop (tail sc)) |=([c=@rq a=@rq] (~(add ^rq %n) (~(mul ^rq %n) a z) c))) + =/ v (~(mul ^rq %n) z xx) + =/ aa (~(sub ^rq %n) (~(mul ^rq %n) `@rq`0x3ffe.0000.0000.0000.0000.0000.0000.0000 yy) (~(mul ^rq %n) v r)) + =/ bb (~(sub ^rq %n) (~(mul ^rq %n) z aa) yy) + =/ dd (~(sub ^rq %n) bb (~(mul ^rq %n) v (head sc))) + (~(sub ^rq %n) xx dd) + ++ kcos + |= [xx=@rq yy=@rq] ^- @rq + =/ z (~(mul ^rq %n) xx xx) + =/ rc (roll (flop cc) |=([c=@rq a=@rq] (~(add ^rq %n) (~(mul ^rq %n) a z) c))) + =/ hz (~(mul ^rq %n) `@rq`0x3ffe.0000.0000.0000.0000.0000.0000.0000 z) + =/ w2 (~(sub ^rq %n) `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000 hz) + =/ aa (~(sub ^rq %n) (~(sub ^rq %n) `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000 w2) hz) + =/ bb (~(sub ^rq %n) (~(mul ^rq %n) (~(mul ^rq %n) z z) rc) (~(mul ^rq %n) xx yy)) + (~(add ^rq %n) w2 (~(add ^rq %n) aa bb)) + ++ trig-fin + |= [s=? ax=@rq sb=@] ^- @rq + =/ q (need (~(toi ^rq %n) (~(mul ^rq %n) ax `@rq`0x3ffe.45f3.06dc.9c88.2a53.f84e.afa3.ea6a))) + =/ qf (~(sun ^rq %n) (abs:si q)) + =/ t (~(sub ^rq %n) ax (~(mul ^rq %n) qf `@rq`0x3fff.921f.b544.42d1.8460.0000.0000.0000)) + =/ w (~(mul ^rq %n) qf `@rq`0x3fc2.3131.98a2.e037.0734.4a40.9382.229a) + =/ rhi (~(sub ^rq %n) t w) + =/ rlo (~(sub ^rq %n) (~(sub ^rq %n) t rhi) w) + =/ m (dis (abs:si q) 3) + =/ ks (ksin rhi rlo) + =/ kc (kcos rhi rlo) + ?: s + =/ v ?:(=(m 0) ks ?:(=(m 1) kc ?:(=(m 2) (neg ks) (neg kc)))) + ?:(=(sb 1) (neg v) v) + ?:(=(m 0) kc ?:(=(m 1) (neg ks) ?:(=(m 2) (neg kc) ks))) + -- + :: +cos: @rq -> @rq + :: + :: Returns the cosine of a floating-point atom. + :: Examples + :: > (cos .~~~1) + :: .~~~0.5403023058681397174009349981817251 + :: > (cos .~~~2) + :: .~~~-0.41614683654714238699756419777191616 + :: > (cos pi) + :: .~~~-1.0000000000000000000000021077555518 + :: Source + ++ cos |= x=@rq ^- @rq ?: !(~(equ ^rq %n) x x) `@rq`0x7fff.8000.0000.0000.0000.0000.0000.0000 - =/ sgn (rsh [0 127] x) - =/ ax `@rq`(dis x 0x7fff.ffff.ffff.ffff.ffff.ffff.ffff.ffff) - ?: (~(gth ^rq %n) ax `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000) `@rq`0x7fff.8000.0000.0000.0000.0000.0000.0000 - ?: =(ax `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000) (~(add ^rq %n) (~(mul ^rq %n) x `@rq`0x3fff.921f.b544.42d1.8469.898c.c517.01b8) (~(mul ^rq %n) x `@rq`0x3f8c.cd12.9024.e088.a67c.c740.20bb.ea64)) - ?: (~(lth ^rq %n) ax `@rq`0x3ffe.0000.0000.0000.0000.0000.0000.0000) - ?: (~(lth ^rq %n) ax `@rq`0x3fc6.0000.0000.0000.0000.0000.0000.0000) x - (~(add ^rq %n) x (~(mul ^rq %n) x (rr (~(mul ^rq %n) x x)))) - =/ w (~(sub ^rq %n) `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000 ax) - =/ t (~(mul ^rq %n) w `@rq`0x3ffe.0000.0000.0000.0000.0000.0000.0000) - =/ r (rr t) - =/ s (sqt t) - ?: (~(gte ^rq %n) ax `@rq`0x3ffe.f333.3333.3333.3333.3333.3333.3333) - =/ res (~(sub ^rq %n) `@rq`0x3fff.921f.b544.42d1.8469.898c.c517.01b8 (~(sub ^rq %n) (~(mul ^rq %n) `@rq`0x4000.0000.0000.0000.0000.0000.0000.0000 (~(add ^rq %n) s (~(mul ^rq %n) s r))) `@rq`0x3f8c.cd12.9024.e088.a67c.c740.20bb.ea64)) + ?: |(=(x `@rq`0x7fff.0000.0000.0000.0000.0000.0000.0000) =(x `@rq`0xffff.0000.0000.0000.0000.0000.0000.0000)) `@rq`0x7fff.8000.0000.0000.0000.0000.0000.0000 + %- trig-fin:rq-trig + [%.n `@rq`(dis x 0x7fff.ffff.ffff.ffff.ffff.ffff.ffff.ffff) 0] + :: +tan: @rq -> @rq + :: + :: Returns the tangent of a floating-point atom. + :: Examples + :: > (tan .~~~1) + :: .~~~1.5574077246549022305069793269617903 + :: > (tan .~~~2) + :: .~~~-2.1850398632615189916433278966958165 + :: > (tan pi) + :: .~~~-2.1850398632615189916433278966958165 + :: Source + ++ tan + |= x=@rq ^- @rq + (div (sin x) (cos x)) + :: +asin: @rq -> @rq + :: + :: Returns the inverse sine of a floating-point atom. + :: Examples + :: > (asin .~~~0) + :: .~~~0 + :: > (asin .~~~1) + :: .~~~1.5707963267948966192313216916397514 + :: > (asin .~~~0.7) + :: .~~~0.7753974966107530637394463388579305 + :: + ++ asin + :: fdlibm rational-form kernel (poly R, deg-30) + sqrt head/tail; f128. + |= x=@rq ^- @rq + (asn:rq-ainv x) + ++ acos + |= x=@rq ^- @rq + (acs:rq-ainv x) + ++ rq-ainv + |% + ++ rr + |= t=@rq ^- @rq + =/ cs=(list @rq) + :~ `@rq`0x3f80.8991.2e54.d43f.83f4.00d5.0d55.a7e8 `@rq`0x3ffc.5555.5555.5555.5555.5555.5555.5552 + `@rq`0x3ffb.3333.3333.3333.3333.3333.3333.5009 `@rq`0x3ffa.6db6.db6d.b6db.6db6.db6d.b668.951b + `@rq`0x3ff9.f1c7.1c71.c71c.71c7.1c72.bac1.ec0e `@rq`0x3ff9.6e8b.a2e8.ba2e.8ba2.e81a.a31a.41d8 + `@rq`0x3ff9.1c4e.c4ec.4ec4.ec4f.0b6f.e680.df37 `@rq`0x3ff8.c999.9999.9999.996c.f372.753e.7c99 + `@rq`0x3ff8.7a87.8787.8787.9217.7cc3.2753.53f7 `@rq`0x3ff8.3fde.50d7.9433.f7f1.afe5.cbea.c090 + `@rq`0x3ff8.12ef.3cf3.cf83.f127.037c.33f0.fb5b `@rq`0x3ff7.df3b.d37a.5ede.5c11.4e9d.a47d.edfd + `@rq`0x3ff7.a686.3d72.3133.909e.0729.7f5e.2958 `@rq`0x3ff7.782d.d9f3.ff64.52ce.6cb8.56ef.901f + `@rq`0x3ff7.51ba.328f.884c.2fdb.62f4.1c70.9bd1 `@rq`0x3ff7.3168.1fe6.e02d.b0d4.9614.21ef.a7ec + `@rq`0x3ff7.15ef.e556.e52a.3408.e80b.5b3f.8641 `@rq`0x3ff6.fc96.253e.cb71.1812.7122.68a4.5b42 + `@rq`0x3ff6.d4a8.2428.408a.ebe9.bc6e.47ec.09af `@rq`0x3ff6.aa37.7fe9.13f6.c0a9.facb.9451.1de4 + `@rq`0x3ff6.b48c.a21a.48d1.8473.7463.fe86.56d8 `@rq`0x3ff5.7e9a.a4b5.b4c4.e391.3451.8885.e78f + `@rq`0x3ff8.1906.4c51.85fa.a0d0.3ab9.c514.26b2 `@rq`0xbff9.300f.0da2.da1e.1c08.5f96.2a89.aacc + `@rq`0x3ffb.0643.398c.dbcb.97d2.5a1b.e10b.6c8a `@rq`0xbffc.27ed.3dd5.cd82.528e.0d54.bf4f.5e05 + `@rq`0x3ffd.1d64.319b.e957.ad88.0c8c.d533.b68b `@rq`0xbffd.9731.e485.678b.81c3.902a.2c54.acc7 + `@rq`0x3ffd.ae10.872f.69b7.a99a.a13d.6e9c.d204 `@rq`0xbffd.228f.c652.7609.25c1.64c7.f610.91fa + `@rq`0x3ffb.9aa4.ca63.cbd7.2c15.b8ad.9b23.77ce + == + (roll (flop cs) |=([c=@rq a=@rq] (~(add ^rq %n) (~(mul ^rq %n) a t) c))) + ++ asn + |= x=@rq ^- @rq + ?: !(~(equ ^rq %n) x x) `@rq`0x7fff.8000.0000.0000.0000.0000.0000.0000 + =/ sgn (rsh [0 127] x) + =/ ax `@rq`(dis x 0x7fff.ffff.ffff.ffff.ffff.ffff.ffff.ffff) + ?: (~(gth ^rq %n) ax `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000) `@rq`0x7fff.8000.0000.0000.0000.0000.0000.0000 + ?: =(ax `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000) (~(add ^rq %n) (~(mul ^rq %n) x `@rq`0x3fff.921f.b544.42d1.8469.898c.c517.01b8) (~(mul ^rq %n) x `@rq`0x3f8c.cd12.9024.e088.a67c.c740.20bb.ea64)) + ?: (~(lth ^rq %n) ax `@rq`0x3ffe.0000.0000.0000.0000.0000.0000.0000) + ?: (~(lth ^rq %n) ax `@rq`0x3fc6.0000.0000.0000.0000.0000.0000.0000) x + (~(add ^rq %n) x (~(mul ^rq %n) x (rr (~(mul ^rq %n) x x)))) + =/ w (~(sub ^rq %n) `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000 ax) + =/ t (~(mul ^rq %n) w `@rq`0x3ffe.0000.0000.0000.0000.0000.0000.0000) + =/ r (rr t) + =/ s (sqt t) + ?: (~(gte ^rq %n) ax `@rq`0x3ffe.f333.3333.3333.3333.3333.3333.3333) + =/ res (~(sub ^rq %n) `@rq`0x3fff.921f.b544.42d1.8469.898c.c517.01b8 (~(sub ^rq %n) (~(mul ^rq %n) `@rq`0x4000.0000.0000.0000.0000.0000.0000.0000 (~(add ^rq %n) s (~(mul ^rq %n) s r))) `@rq`0x3f8c.cd12.9024.e088.a67c.c740.20bb.ea64)) + ?:(=(sgn 1) (~(sub ^rq %n) `@rq`0x0 res) res) + =/ df `@rq`(dis s 0xffff.ffff.ffff.ffff.ff00.0000.0000.0000) + =/ c (~(div ^rq %n) (~(sub ^rq %n) t (~(mul ^rq %n) df df)) (~(add ^rq %n) s df)) + =/ p2 (~(sub ^rq %n) (~(mul ^rq %n) `@rq`0x4000.0000.0000.0000.0000.0000.0000.0000 (~(mul ^rq %n) s r)) (~(sub ^rq %n) `@rq`0x3f8c.cd12.9024.e088.a67c.c740.20bb.ea64 (~(mul ^rq %n) `@rq`0x4000.0000.0000.0000.0000.0000.0000.0000 c))) + =/ q2 (~(sub ^rq %n) `@rq`0x3ffe.921f.b544.42d1.8469.898c.c517.01b8 (~(mul ^rq %n) `@rq`0x4000.0000.0000.0000.0000.0000.0000.0000 df)) + =/ res (~(sub ^rq %n) `@rq`0x3ffe.921f.b544.42d1.8469.898c.c517.01b8 (~(sub ^rq %n) p2 q2)) ?:(=(sgn 1) (~(sub ^rq %n) `@rq`0x0 res) res) - =/ df `@rq`(dis s 0xffff.ffff.ffff.ffff.ff00.0000.0000.0000) - =/ c (~(div ^rq %n) (~(sub ^rq %n) t (~(mul ^rq %n) df df)) (~(add ^rq %n) s df)) - =/ p2 (~(sub ^rq %n) (~(mul ^rq %n) `@rq`0x4000.0000.0000.0000.0000.0000.0000.0000 (~(mul ^rq %n) s r)) (~(sub ^rq %n) `@rq`0x3f8c.cd12.9024.e088.a67c.c740.20bb.ea64 (~(mul ^rq %n) `@rq`0x4000.0000.0000.0000.0000.0000.0000.0000 c))) - =/ q2 (~(sub ^rq %n) `@rq`0x3ffe.921f.b544.42d1.8469.898c.c517.01b8 (~(mul ^rq %n) `@rq`0x4000.0000.0000.0000.0000.0000.0000.0000 df)) - =/ res (~(sub ^rq %n) `@rq`0x3ffe.921f.b544.42d1.8469.898c.c517.01b8 (~(sub ^rq %n) p2 q2)) - ?:(=(sgn 1) (~(sub ^rq %n) `@rq`0x0 res) res) - ++ acs + ++ acs + |= x=@rq ^- @rq + ?: !(~(equ ^rq %n) x x) `@rq`0x7fff.8000.0000.0000.0000.0000.0000.0000 + =/ neg (rsh [0 127] x) + =/ ax `@rq`(dis x 0x7fff.ffff.ffff.ffff.ffff.ffff.ffff.ffff) + ?: (~(gth ^rq %n) ax `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000) `@rq`0x7fff.8000.0000.0000.0000.0000.0000.0000 + ?: =(ax `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000) + ?: =(neg 0) `@rq`0x0 + (~(add ^rq %n) `@rq`0x4000.921f.b544.42d1.8469.898c.c517.01b8 (~(mul ^rq %n) `@rq`0x4000.0000.0000.0000.0000.0000.0000.0000 `@rq`0x3f8c.cd12.9024.e088.a67c.c740.20bb.ea64)) + ?: (~(lth ^rq %n) ax `@rq`0x3ffe.0000.0000.0000.0000.0000.0000.0000) + ?: (~(lth ^rq %n) ax `@rq`0x3f87.0000.0000.0000.0000.0000.0000.0000) `@rq`0x3fff.921f.b544.42d1.8469.898c.c517.01b8 + =/ z (~(mul ^rq %n) x x) + =/ r (rr z) + (~(sub ^rq %n) `@rq`0x3fff.921f.b544.42d1.8469.898c.c517.01b8 (~(sub ^rq %n) x (~(sub ^rq %n) `@rq`0x3f8c.cd12.9024.e088.a67c.c740.20bb.ea64 (~(mul ^rq %n) x r)))) + ?: =(neg 1) + =/ z (~(mul ^rq %n) (~(add ^rq %n) `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000 x) `@rq`0x3ffe.0000.0000.0000.0000.0000.0000.0000) + =/ s (sqt z) + =/ r (rr z) + =/ w (~(sub ^rq %n) (~(mul ^rq %n) r s) `@rq`0x3f8c.cd12.9024.e088.a67c.c740.20bb.ea64) + (~(sub ^rq %n) `@rq`0x4000.921f.b544.42d1.8469.898c.c517.01b8 (~(mul ^rq %n) `@rq`0x4000.0000.0000.0000.0000.0000.0000.0000 (~(add ^rq %n) s w))) + =/ z (~(mul ^rq %n) (~(sub ^rq %n) `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000 x) `@rq`0x3ffe.0000.0000.0000.0000.0000.0000.0000) + =/ s (sqt z) + =/ df `@rq`(dis s 0xffff.ffff.ffff.ffff.ff00.0000.0000.0000) + =/ c (~(div ^rq %n) (~(sub ^rq %n) z (~(mul ^rq %n) df df)) (~(add ^rq %n) s df)) + =/ r (rr z) + =/ w (~(add ^rq %n) (~(mul ^rq %n) r s) c) + (~(mul ^rq %n) `@rq`0x4000.0000.0000.0000.0000.0000.0000.0000 (~(add ^rq %n) df w)) + -- + :: +acos: @rq -> @rq + :: + :: Returns the inverse cosine of a floating-point atom. + :: Examples + :: > (acos .~~~0) + :: .~~~1.5707963267948966192313216916397514 + :: > (acos .~~~1) + :: .~~~0 + :: > (acos .~~~0.7) + :: .~~~0.7953988301841435554899943710156033 + :: + :: +atan: @rq -> @rq + :: + :: Returns the inverse tangent of a floating-point atom. + :: Examples + :: > (atan .~~~1) + :: .~~~0.7853981633974483096146231179876219 + :: > (atan .~~~2) + :: .~~~1.1071487177940905030161167763325275 + :: > (atan pi) + :: .~~~1.2626272556789116834540013074115034 + :: + ++ atan + :: fdlibm breakpoint reduction + degree-30 minimax (f128); odd. |= x=@rq ^- @rq ?: !(~(equ ^rq %n) x x) `@rq`0x7fff.8000.0000.0000.0000.0000.0000.0000 + ?: =(x `@rq`0x7fff.0000.0000.0000.0000.0000.0000.0000) `@rq`0x3fff.921f.b544.42d1.8469.898c.c517.01b8 + ?: =(x `@rq`0xffff.0000.0000.0000.0000.0000.0000.0000) `@rq`0xbfff.921f.b544.42d1.8469.898c.c517.01b8 + ?: |(=(x `@rq`0x0) =(x `@rq`0x8000.0000.0000.0000.0000.0000.0000.0000)) x =/ neg (rsh [0 127] x) - =/ ax `@rq`(dis x 0x7fff.ffff.ffff.ffff.ffff.ffff.ffff.ffff) - ?: (~(gth ^rq %n) ax `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000) `@rq`0x7fff.8000.0000.0000.0000.0000.0000.0000 - ?: =(ax `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000) - ?: =(neg 0) `@rq`0x0 - (~(add ^rq %n) `@rq`0x4000.921f.b544.42d1.8469.898c.c517.01b8 (~(mul ^rq %n) `@rq`0x4000.0000.0000.0000.0000.0000.0000.0000 `@rq`0x3f8c.cd12.9024.e088.a67c.c740.20bb.ea64)) - ?: (~(lth ^rq %n) ax `@rq`0x3ffe.0000.0000.0000.0000.0000.0000.0000) - ?: (~(lth ^rq %n) ax `@rq`0x3f87.0000.0000.0000.0000.0000.0000.0000) `@rq`0x3fff.921f.b544.42d1.8469.898c.c517.01b8 - =/ z (~(mul ^rq %n) x x) - =/ r (rr z) - (~(sub ^rq %n) `@rq`0x3fff.921f.b544.42d1.8469.898c.c517.01b8 (~(sub ^rq %n) x (~(sub ^rq %n) `@rq`0x3f8c.cd12.9024.e088.a67c.c740.20bb.ea64 (~(mul ^rq %n) x r)))) - ?: =(neg 1) - =/ z (~(mul ^rq %n) (~(add ^rq %n) `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000 x) `@rq`0x3ffe.0000.0000.0000.0000.0000.0000.0000) - =/ s (sqt z) - =/ r (rr z) - =/ w (~(sub ^rq %n) (~(mul ^rq %n) r s) `@rq`0x3f8c.cd12.9024.e088.a67c.c740.20bb.ea64) - (~(sub ^rq %n) `@rq`0x4000.921f.b544.42d1.8469.898c.c517.01b8 (~(mul ^rq %n) `@rq`0x4000.0000.0000.0000.0000.0000.0000.0000 (~(add ^rq %n) s w))) - =/ z (~(mul ^rq %n) (~(sub ^rq %n) `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000 x) `@rq`0x3ffe.0000.0000.0000.0000.0000.0000.0000) - =/ s (sqt z) - =/ df `@rq`(dis s 0xffff.ffff.ffff.ffff.ff00.0000.0000.0000) - =/ c (~(div ^rq %n) (~(sub ^rq %n) z (~(mul ^rq %n) df df)) (~(add ^rq %n) s df)) - =/ r (rr z) - =/ w (~(add ^rq %n) (~(mul ^rq %n) r s) c) - (~(mul ^rq %n) `@rq`0x4000.0000.0000.0000.0000.0000.0000.0000 (~(add ^rq %n) df w)) + =/ r (ker:rq-atan `@rq`(dis x 0x7fff.ffff.ffff.ffff.ffff.ffff.ffff.ffff)) + ?:(=(neg 1) (~(sub ^rq %n) `@rq`0x0 r) r) + ++ rq-atan + |% + ++ at + ^- (list @rq) + :~ `@rq`0x3ffd.5555.5555.5555.5555.5555.5555.5555 `@rq`0xbffc.9999.9999.9999.9999.9999.9999.999a + `@rq`0x3ffc.2492.4924.9249.2492.4924.9249.2492 `@rq`0xbffb.c71c.71c7.1c71.c71c.71c7.1c71.c705 + `@rq`0x3ffb.745d.1745.d174.5d17.45d1.745c.f720 `@rq`0xbffb.3b13.b13b.13b1.3b13.b13b.1395.a0f6 + `@rq`0x3ffb.1111.1111.1111.1111.1111.010e.24e1 `@rq`0xbffa.e1e1.e1e1.e1e1.e1e1.e1d4.8fd7.bd0f + `@rq`0x3ffa.af28.6bca.1af2.86bc.9d8a.1266.1ce3 `@rq`0xbffa.8618.6186.1861.8617.62af.171f.46fb + `@rq`0x3ffa.642c.8590.b216.4297.f77f.1796.654a `@rq`0xbffa.47ae.147a.e147.a6ae.eb97.4d91.c763 + `@rq`0x3ffa.2f68.4bda.12f5.982c.8384.0df4.8c76 `@rq`0xbffa.1a7b.9611.a7a0.f241.3484.8b6f.9bc3 + `@rq`0x3ffa.0842.1084.1eed.46f1.272e.8718.edfe `@rq`0xbff9.f07c.1f07.73e1.dac4.76af.1946.ed1a + `@rq`0x3ff9.d41d.41cf.56a0.771b.4773.d1fd.bc46 `@rq`0xbff9.bacf.910c.a5ea.d9a2.c9f0.ffa2.8317 + `@rq`0x3ff9.a41a.3ed6.e709.5da3.c3e4.8cd5.5593 `@rq`0xbff9.8f9b.fe02.ad67.4d8a.c158.72fb.b51c + `@rq`0x3ff9.7d05.170d.1702.069f.17b9.5f6e.54f4 `@rq`0xbff9.6c10.bc42.d041.6ea0.5add.542a.f078 + `@rq`0x3ff9.5c74.e7f6.f412.eab1.21f2.0635.a41a `@rq`0xbff9.4dac.2e21.aa0e.283b.7552.8258.306b + `@rq`0x3ff9.3e57.3faa.c561.db9d.4b05.d70c.99cf `@rq`0xbff9.2af3.2cae.28f7.4f59.6690.8860.d11a + `@rq`0x3ff9.0c8b.03c5.5304.dec0.acdf.4b35.6e20 `@rq`0xbff8.b4ed.3a33.49ac.f7ad.9702.76c5.cf2b + `@rq`0x3ff8.261c.1a9e.da3a.d5dd.688f.198a.e3cb `@rq`0xbff7.1a7a.c449.b285.876f.4b57.d627.e71e + `@rq`0x3ff5.1a4e.a418.ebe8.1381.31c1.5128.032a + == + ++ atred + |= ax=@rq ^- [xr=@rq hi=@rq lo=@rq dir=?] + ?: (~(lth ^rq %n) ax `@rq`0x3ffd.c000.0000.0000.0000.0000.0000.0000) [ax `@rq`0x0 `@rq`0x0 %.y] + ?: (~(lth ^rq %n) ax `@rq`0x3ffe.6000.0000.0000.0000.0000.0000.0000) + :* (~(div ^rq %n) (~(sub ^rq %n) (~(add ^rq %n) ax ax) `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000) (~(add ^rq %n) `@rq`0x4000.0000.0000.0000.0000.0000.0000.0000 ax)) + `@rq`0x3ffd.dac6.7056.1bb4.f68a.dfc8.8bd9.7875 `@rq`0x3f89.a06d.c282.b0e4.c39b.e01c.59e2.dcdd %.n == + ?: (~(lth ^rq %n) ax `@rq`0x3fff.3000.0000.0000.0000.0000.0000.0000) + :* (~(div ^rq %n) (~(sub ^rq %n) ax `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000) (~(add ^rq %n) ax `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000)) + `@rq`0x3ffe.921f.b544.42d1.8469.898c.c517.01b8 `@rq`0x3f8b.cd12.9024.e088.a67c.c740.20bb.ea64 %.n == + ?: (~(lth ^rq %n) ax `@rq`0x4000.3800.0000.0000.0000.0000.0000.0000) + :* (~(div ^rq %n) (~(sub ^rq %n) ax `@rq`0x3fff.8000.0000.0000.0000.0000.0000.0000) (~(add ^rq %n) `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000 (~(mul ^rq %n) `@rq`0x3fff.8000.0000.0000.0000.0000.0000.0000 ax))) + `@rq`0x3ffe.f730.bd28.1f69.b200.f10f.5e19.7794 `@rq`0xbf8b.ebe5.66c9.9ada.9f23.1bcc.ae27.916c %.n == + :* (~(div ^rq %n) `@rq`0xbfff.0000.0000.0000.0000.0000.0000.0000 ax) `@rq`0x3fff.921f.b544.42d1.8469.898c.c517.01b8 `@rq`0x3f8c.cd12.9024.e088.a67c.c740.20bb.ea64 %.n == + ++ ker + |= ax=@rq ^- @rq + =/ q (atred ax) + =/ z (~(mul ^rq %n) xr.q xr.q) + =/ s (~(mul ^rq %n) z (roll (flop at) |=([c=@rq a=@rq] (~(add ^rq %n) (~(mul ^rq %n) a z) c)))) + ?: dir.q (~(sub ^rq %n) xr.q (~(mul ^rq %n) xr.q s)) + (~(sub ^rq %n) hi.q (~(sub ^rq %n) (~(sub ^rq %n) (~(mul ^rq %n) xr.q s) lo.q) xr.q)) + -- + :: +atan2: [@rq @rq] -> @rq + :: + :: Returns the inverse tangent of a floating-point coordinate. + :: Examples + :: > (atan2 .~~~0 .~~~1) + :: .~~~0 + :: > (atan2 .~~~-1 .~~~0) + :: .~~~-1.5707963267948966192313216916397514 + :: > (atan2 .~~~0.5 .~~~-0.5) + :: .~~~2.3561944901923449288480202652918806 + :: + ++ atan2 + |= [y=@rq x=@rq] ^- @rq + ?: (~(gth ^rq %n) x `@rq`0x0) (atan (~(div ^rq %n) y x)) + ?: &((~(lth ^rq %n) x `@rq`0x0) (~(gte ^rq %n) y `@rq`0x0)) (~(add ^rq %n) (atan (~(div ^rq %n) y x)) `@rq`0x4000.921f.b544.42d1.8469.898c.c517.01b8) + ?: &((~(lth ^rq %n) x `@rq`0x0) (~(lth ^rq %n) y `@rq`0x0)) (~(sub ^rq %n) (atan (~(div ^rq %n) y x)) `@rq`0x4000.921f.b544.42d1.8469.898c.c517.01b8) + ?: &(=(`@rq`0x0 x) (~(gth ^rq %n) y `@rq`0x0)) `@rq`0x3fff.921f.b544.42d1.8469.898c.c517.01b8 + ?: &(=(`@rq`0x0 x) (~(lth ^rq %n) y `@rq`0x0)) `@rq`0xbfff.921f.b544.42d1.8469.898c.c517.01b8 + `@rq`0x0 + + :: +pow-n: [@rq @rq] -> @rq + :: + :: Returns the power of a floating-point atom to a signed integer exponent. + :: Examples + :: > (pow-n .~~~2 .~~~2) + :: .~~~4 + :: > (pow-n .~~~2 .~~~-2) + :: .~~~0.25 + :: Source + ++ pow-n + |= [x=@rq n=@rq] ^- @rq + ?: =(n `@rq`0x0) `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000 + =/ i (need (~(toi ^rq %n) n)) + =/ p `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000 + |- ^- @rq + ?: =(i --0) p + $(i (dif:si i --1), p (~(mul ^rq %n) p x)) + :: +log: @rq -> @rq + :: + :: Returns the natural logarithm of a floating-point atom. + :: Examples + :: > (log .~~~1) + :: .~~~0 + :: > (log .~~~2) + :: .~~~0.6931471805599453094170735934298606 + :: > (~(log rq [%z .~~~1e-5]) .~~~2) + :: .~~~0.6931470737597852366942444674497712 + :: > (log .~~~inf) + :: .~~~inf + :: Source + ++ log + :: x = 2^e * m reduction + atanh series (fdlibm f - s*(f-R)); f128. + :: Round-nearest-even internally (matches tools/rq_check.c). + |= x=@rq ^- @rq + ?: !(~(equ ^rq %n) x x) `@rq`0x7fff.8000.0000.0000.0000.0000.0000.0000 + ?: =(x `@rq`0x7fff.0000.0000.0000.0000.0000.0000.0000) `@rq`0x7fff.0000.0000.0000.0000.0000.0000.0000 + ?: |(=(x `@rq`0x0) =(x `@rq`0x8000.0000.0000.0000.0000.0000.0000.0000)) `@rq`0xffff.0000.0000.0000.0000.0000.0000.0000 + ?: =(1 (rsh [0 127] x)) `@rq`0x7fff.8000.0000.0000.0000.0000.0000.0000 + =/ sub =(0 (dis 0x7fff (rsh [0 112] x))) + =/ xx ?:(sub (~(mul ^rq %n) x `@rq`0x4077.0000.0000.0000.0000.0000.0000.0000) x) + =/ ae ?:(sub -120 --0) + =/ b `@`xx + =/ e (dif:si (new:si %.y (dis 0x7fff (rsh [0 112] b))) --16.383) + =/ m `@rq`(con (dis b 0xffff.ffff.ffff.ffff.ffff.ffff.ffff) 0x3fff.0000.0000.0000.0000.0000.0000.0000) + =/ big (~(gte ^rq %n) m `@rq`0x3fff.6a09.e667.f3bc.c908.b2fb.1366.ea95) + =? m big (~(mul ^rq %n) m `@rq`0x3ffe.0000.0000.0000.0000.0000.0000.0000) + =? e big (sum:si e --1) + =. e (sum:si e ae) + =/ f (~(sub ^rq %n) m `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000) + =/ s (~(div ^rq %n) f (~(add ^rq %n) m `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000)) + =/ z (~(mul ^rq %n) s s) + =/ cs=(list @rq) + :~ `@rq`0x3ffd.5555.5555.5555.5555.5555.5555.5555 `@rq`0x3ffc.9999.9999.9999.9999.9999.9999.999a + `@rq`0x3ffc.2492.4924.9249.2492.4924.9249.2492 `@rq`0x3ffb.c71c.71c7.1c71.c71c.71c7.1c71.c71c + `@rq`0x3ffb.745d.1745.d174.5d17.45d1.745d.1746 `@rq`0x3ffb.3b13.b13b.13b1.3b13.b13b.13b1.3b14 + `@rq`0x3ffb.1111.1111.1111.1111.1111.1111.1111 `@rq`0x3ffa.e1e1.e1e1.e1e1.e1e1.e1e1.e1e1.e1e2 + `@rq`0x3ffa.af28.6bca.1af2.86bc.a1af.286b.ca1b `@rq`0x3ffa.8618.6186.1861.8618.6186.1861.8618 + `@rq`0x3ffa.642c.8590.b216.42c8.590b.2164.2c86 `@rq`0x3ffa.47ae.147a.e147.ae14.7ae1.47ae.147b + `@rq`0x3ffa.2f68.4bda.12f6.84bd.a12f.684b.da13 `@rq`0x3ffa.1a7b.9611.a7b9.611a.7b96.11a7.b961 + `@rq`0x3ffa.0842.1084.2108.4210.8421.0842.1084 `@rq`0x3ff9.f07c.1f07.c1f0.7c1f.07c1.f07c.1f08 + `@rq`0x3ff9.d41d.41d4.1d41.d41d.41d4.1d41.d41d `@rq`0x3ff9.bacf.914c.1bac.f914.c1ba.cf91.4c1c + `@rq`0x3ff9.a41a.41a4.1a41.a41a.41a4.1a41.a41a `@rq`0x3ff9.8f9c.18f9.c18f.9c18.f9c1.8f9c.18fa + `@rq`0x3ff9.7d05.f417.d05f.417d.05f4.17d0.5f41 `@rq`0x3ff9.6c16.c16c.16c1.6c16.c16c.16c1.6c17 + `@rq`0x3ff9.5c98.82b9.3105.7262.0ae4.c415.c988 + == + =/ p2 (roll (flop cs) |=([c=@rq acc=@rq] (~(add ^rq %n) (~(mul ^rq %n) acc z) c))) + =/ r (~(mul ^rq %n) (~(add ^rq %n) z z) p2) + =/ l1 (~(sub ^rq %n) f (~(mul ^rq %n) s (~(sub ^rq %n) f r))) + =/ efa (~(sun ^rq %n) (abs:si e)) + =/ ef ?:((syn:si e) efa (~(sub ^rq %n) `@rq`0x0 efa)) + =/ hi (~(mul ^rq %n) ef `@rq`0x3ffe.62e4.2fef.a39e.f357.93c8.0000.0000) + =/ lo (~(mul ^rq %n) ef `@rq`0xbfad.319f.f034.2542.fc32.f366.359d.274a) + (~(add ^rq %n) hi (~(add ^rq %n) l1 lo)) + :: +log-10: @rq -> @rq + :: + :: Returns the base-10 logarithm of a floating-point atom. + :: Examples + :: TODO + :: Source + ++ log-10 + |= x=@rq ^- @rq + ?: !(~(equ ^rq %n) x x) `@rq`0x7fff.8000.0000.0000.0000.0000.0000.0000 + ?: =(x `@rq`0x7fff.0000.0000.0000.0000.0000.0000.0000) `@rq`0x7fff.0000.0000.0000.0000.0000.0000.0000 + ?: |(=(x `@rq`0x0) =(x `@rq`0x8000.0000.0000.0000.0000.0000.0000.0000)) `@rq`0xffff.0000.0000.0000.0000.0000.0000.0000 + ?: =(1 (rsh [0 127] x)) `@rq`0x7fff.8000.0000.0000.0000.0000.0000.0000 + =/ el (lr x) + (~(add ^rq %n) (~(mul ^rq %n) ef.el `@rq`0x3ffd.3441.3509.f79f.ef31.1f12.b358.16f9) (~(mul ^rq %n) lm.el `@rq`0x3ffd.bcb7.b152.6e50.e32a.6ab7.555f.5a68)) + :: +log-2: @rq -> @rq + :: + :: Returns the base-2 logarithm of a floating-point atom. + :: Examples + :: TODO + :: Source + :: +lr: log reduction for finite positive @rq x -> [e (as @rq), log(mantissa)]. + ++ lr + |= x=@rq ^- [ef=@rq lm=@rq] + =/ sub =(0 (dis 0x7fff (rsh [0 112] x))) + =/ xx ?:(sub (~(mul ^rq %n) x `@rq`0x4077.0000.0000.0000.0000.0000.0000.0000) x) + =/ ae ?:(sub -120 --0) + =/ b `@`xx + =/ e (dif:si (new:si %.y (dis 0x7fff (rsh [0 112] b))) --16.383) + =/ m `@rq`(con (dis b 0xffff.ffff.ffff.ffff.ffff.ffff.ffff) 0x3fff.0000.0000.0000.0000.0000.0000.0000) + =/ big (~(gte ^rq %n) m `@rq`0x3fff.6a09.e667.f3bc.c908.b2fb.1366.ea95) + =? m big (~(mul ^rq %n) m `@rq`0x3ffe.0000.0000.0000.0000.0000.0000.0000) + =? e big (sum:si e --1) + =. e (sum:si e ae) + =/ f (~(sub ^rq %n) m `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000) + =/ s (~(div ^rq %n) f (~(add ^rq %n) m `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000)) + =/ z (~(mul ^rq %n) s s) + =/ cs=(list @rq) + :~ `@rq`0x3ffd.5555.5555.5555.5555.5555.5555.5555 `@rq`0x3ffc.9999.9999.9999.9999.9999.9999.999a + `@rq`0x3ffc.2492.4924.9249.2492.4924.9249.2492 `@rq`0x3ffb.c71c.71c7.1c71.c71c.71c7.1c71.c71c + `@rq`0x3ffb.745d.1745.d174.5d17.45d1.745d.1746 `@rq`0x3ffb.3b13.b13b.13b1.3b13.b13b.13b1.3b14 + `@rq`0x3ffb.1111.1111.1111.1111.1111.1111.1111 `@rq`0x3ffa.e1e1.e1e1.e1e1.e1e1.e1e1.e1e1.e1e2 + `@rq`0x3ffa.af28.6bca.1af2.86bc.a1af.286b.ca1b `@rq`0x3ffa.8618.6186.1861.8618.6186.1861.8618 + `@rq`0x3ffa.642c.8590.b216.42c8.590b.2164.2c86 `@rq`0x3ffa.47ae.147a.e147.ae14.7ae1.47ae.147b + `@rq`0x3ffa.2f68.4bda.12f6.84bd.a12f.684b.da13 `@rq`0x3ffa.1a7b.9611.a7b9.611a.7b96.11a7.b961 + `@rq`0x3ffa.0842.1084.2108.4210.8421.0842.1084 `@rq`0x3ff9.f07c.1f07.c1f0.7c1f.07c1.f07c.1f08 + `@rq`0x3ff9.d41d.41d4.1d41.d41d.41d4.1d41.d41d `@rq`0x3ff9.bacf.914c.1bac.f914.c1ba.cf91.4c1c + `@rq`0x3ff9.a41a.41a4.1a41.a41a.41a4.1a41.a41a `@rq`0x3ff9.8f9c.18f9.c18f.9c18.f9c1.8f9c.18fa + `@rq`0x3ff9.7d05.f417.d05f.417d.05f4.17d0.5f41 `@rq`0x3ff9.6c16.c16c.16c1.6c16.c16c.16c1.6c17 + `@rq`0x3ff9.5c98.82b9.3105.7262.0ae4.c415.c988 + == + =/ p2 (roll (flop cs) |=([c=@rq acc=@rq] (~(add ^rq %n) (~(mul ^rq %n) acc z) c))) + =/ r (~(mul ^rq %n) (~(add ^rq %n) z z) p2) + =/ l1 (~(sub ^rq %n) f (~(mul ^rq %n) s (~(sub ^rq %n) f r))) + =/ efa (~(sun ^rq %n) (abs:si e)) + [?:((syn:si e) efa (~(sub ^rq %n) `@rq`0x0 efa)) l1] + ++ log-2 + |= x=@rq ^- @rq + ?: !(~(equ ^rq %n) x x) `@rq`0x7fff.8000.0000.0000.0000.0000.0000.0000 + ?: =(x `@rq`0x7fff.0000.0000.0000.0000.0000.0000.0000) `@rq`0x7fff.0000.0000.0000.0000.0000.0000.0000 + ?: |(=(x `@rq`0x0) =(x `@rq`0x8000.0000.0000.0000.0000.0000.0000.0000)) `@rq`0xffff.0000.0000.0000.0000.0000.0000.0000 + ?: =(1 (rsh [0 127] x)) `@rq`0x7fff.8000.0000.0000.0000.0000.0000.0000 + =/ el (lr x) + (~(add ^rq %n) ef.el (~(mul ^rq %n) lm.el `@rq`0x3fff.7154.7652.b82f.e177.7d0f.fda0.d23a)) + :: +pow: [@rq @rq] -> @rq + :: + :: Returns the power of a floating-point atom to a floating-point exponent. + :: Examples + :: > (pow .~~~1 .~~~2) + :: .~~~1 + :: > (pow .~~~2 .~~~2) + :: .~~~4 + :: > (~(pow rq:math [%z .~~~1e-5]) .~~~2 .~~~3.5) + :: .~~~11.313703735926135014164384135726204 + :: Source + ++ pow + |= [x=@rq n=@rq] ^- @rq + ?: &(=(n (~(san ^rq %n) (need (~(toi ^rq %n) n)))) (~(gth ^rq %n) n `@rq`0x0)) + (pow-n x n) + (exp (~(mul ^rq %n) n (log x))) + :: +sqrt: @rq -> @rq + :: + :: Returns the square root of a floating-point atom. + :: Alias for +sqt. + :: Examples + :: > (sqrt .~~~1) + :: .~~~1 + :: > (sqrt .~~~2) + :: .~~~1.4142135623730950488015335862957159 + :: > (~(sqrt rq:math [%z .~~~1e-10]) .~~~2) + :: .~~~1.4142135623721439870165294373250435 + :: Source + ++ sqrt sqt + :: +sqt: @rq -> @rq + :: + :: Returns the square root of a floating-point atom. + :: Examples + :: > (sqt .~~~1) + :: .~~~1 + :: > (sqt .~~~2) + :: .~~~1.414213562373095048801688724209698 + :: > (sqt .~~~1e5) + :: .~~~316.2277660168379331998893544432718 + :: Source + ++ sqt + :: correctly-rounded f128 sqrt: stdlib seed + one Markstein FMA (matches + :: the SoftFloat f128_sqrt jet, tools/rq_check.c). + |= x=@rq ^- @rq + ?: !(~(equ ^rq %n) x x) `@rq`0x7fff.8000.0000.0000.0000.0000.0000.0000 + ?: =(x `@rq`0x7fff.0000.0000.0000.0000.0000.0000.0000) `@rq`0x7fff.0000.0000.0000.0000.0000.0000.0000 + ?: |(=(x `@rq`0x0) =(x `@rq`0x8000.0000.0000.0000.0000.0000.0000.0000)) x + ?: =(1 (rsh [0 127] x)) `@rq`0x7fff.8000.0000.0000.0000.0000.0000.0000 + =/ g (sqt:^rq x) + =/ h (~(div ^rq %n) `@rq`0x3ffe.0000.0000.0000.0000.0000.0000.0000 g) + =/ r (~(fma ^rq %n) (~(sub ^rq %n) `@rq`0x0 g) g x) + (~(fma ^rq %n) h r g) + :: +cbrt: @rq -> @rq + :: + :: Returns the cube root of a floating-point atom. + :: Alias for +cbt. + :: Examples + :: > (cbrt .~~~1) + :: .~~~1 + :: > (cbrt .~~~2) + :: .~~~1.2598919398737178526805575821133312 + :: > (~(cbrt rq:math [%z .~~~1e-10]) .~~~2) + :: .~~~1.2598919398731638759238176665172822 + :: Source + ++ cbrt cbt + :: +cbt: @rq -> @rq + :: + :: Returns the cube root of a floating-point atom. + :: Examples + :: > (cbt .~~~1) + :: .~~~1 + :: > (cbt .~~~2) + :: .~~~1.2598919398737178526805575821133312 + :: > (~(cbt rq:math [%z .~~~1e-10]) .~~~2) + :: .~~~1.2598919398731638759238176665172822 + :: Source + ++ cbt + |= x=@rq ^- @rq + ?: !(~(equ ^rq %n) x x) x + ?: |(=(x `@rq`0x0) =(x `@rq`0x8000.0000.0000.0000.0000.0000.0000.0000)) x + =/ ax `@rq`(dis x 0x7fff.ffff.ffff.ffff.ffff.ffff.ffff.ffff) + =/ r (exp (~(mul ^rq %n) (log ax) `@rq`0x3ffd.5555.5555.5555.5555.5555.5555.5555)) + ?:(=(1 (rsh [0 127] x)) (~(sub ^rq %n) `@rq`0x0 r) r) + + :: +arg: @rq -> @rq + :: + :: Returns the argument of a floating-point atom (real argument = absolute + :: value). + :: Examples + :: > (arg .~~~1) + :: .~~~1 + :: > (arg .~~~-1) + :: .~~~1 + :: Source + ++ arg abs -- - :: +acos: @rq -> @rq - :: - :: Returns the inverse cosine of a floating-point atom. - :: Examples - :: > (acos .~~~0) - :: .~~~1.5707963267948966192313216916397514 - :: > (acos .~~~1) - :: .~~~0 - :: > (acos .~~~0.7) - :: .~~~0.7953988301841435554899943710156033 - :: - :: +atan: @rq -> @rq - :: - :: Returns the inverse tangent of a floating-point atom. - :: Examples - :: > (atan .~~~1) - :: .~~~0.7853981633974483096146231179876219 - :: > (atan .~~~2) - :: .~~~1.1071487177940905030161167763325275 - :: > (atan pi) - :: .~~~1.2626272556789116834540013074115034 - :: - ++ atan - :: fdlibm breakpoint reduction + degree-30 minimax (f128); odd. - |= x=@rq ^- @rq - ?: !(~(equ ^rq %n) x x) `@rq`0x7fff.8000.0000.0000.0000.0000.0000.0000 - ?: =(x `@rq`0x7fff.0000.0000.0000.0000.0000.0000.0000) `@rq`0x3fff.921f.b544.42d1.8469.898c.c517.01b8 - ?: =(x `@rq`0xffff.0000.0000.0000.0000.0000.0000.0000) `@rq`0xbfff.921f.b544.42d1.8469.898c.c517.01b8 - ?: |(=(x `@rq`0x0) =(x `@rq`0x8000.0000.0000.0000.0000.0000.0000.0000)) x - =/ neg (rsh [0 127] x) - =/ r (ker:rq-atan `@rq`(dis x 0x7fff.ffff.ffff.ffff.ffff.ffff.ffff.ffff)) - ?:(=(neg 1) (~(sub ^rq %n) `@rq`0x0 r) r) - ++ rq-atan + :: reference values + ++ reference |% - ++ at - ^- (list @rq) - :~ `@rq`0x3ffd.5555.5555.5555.5555.5555.5555.5555 `@rq`0xbffc.9999.9999.9999.9999.9999.9999.999a - `@rq`0x3ffc.2492.4924.9249.2492.4924.9249.2492 `@rq`0xbffb.c71c.71c7.1c71.c71c.71c7.1c71.c705 - `@rq`0x3ffb.745d.1745.d174.5d17.45d1.745c.f720 `@rq`0xbffb.3b13.b13b.13b1.3b13.b13b.1395.a0f6 - `@rq`0x3ffb.1111.1111.1111.1111.1111.010e.24e1 `@rq`0xbffa.e1e1.e1e1.e1e1.e1e1.e1d4.8fd7.bd0f - `@rq`0x3ffa.af28.6bca.1af2.86bc.9d8a.1266.1ce3 `@rq`0xbffa.8618.6186.1861.8617.62af.171f.46fb - `@rq`0x3ffa.642c.8590.b216.4297.f77f.1796.654a `@rq`0xbffa.47ae.147a.e147.a6ae.eb97.4d91.c763 - `@rq`0x3ffa.2f68.4bda.12f5.982c.8384.0df4.8c76 `@rq`0xbffa.1a7b.9611.a7a0.f241.3484.8b6f.9bc3 - `@rq`0x3ffa.0842.1084.1eed.46f1.272e.8718.edfe `@rq`0xbff9.f07c.1f07.73e1.dac4.76af.1946.ed1a - `@rq`0x3ff9.d41d.41cf.56a0.771b.4773.d1fd.bc46 `@rq`0xbff9.bacf.910c.a5ea.d9a2.c9f0.ffa2.8317 - `@rq`0x3ff9.a41a.3ed6.e709.5da3.c3e4.8cd5.5593 `@rq`0xbff9.8f9b.fe02.ad67.4d8a.c158.72fb.b51c - `@rq`0x3ff9.7d05.170d.1702.069f.17b9.5f6e.54f4 `@rq`0xbff9.6c10.bc42.d041.6ea0.5add.542a.f078 - `@rq`0x3ff9.5c74.e7f6.f412.eab1.21f2.0635.a41a `@rq`0xbff9.4dac.2e21.aa0e.283b.7552.8258.306b - `@rq`0x3ff9.3e57.3faa.c561.db9d.4b05.d70c.99cf `@rq`0xbff9.2af3.2cae.28f7.4f59.6690.8860.d11a - `@rq`0x3ff9.0c8b.03c5.5304.dec0.acdf.4b35.6e20 `@rq`0xbff8.b4ed.3a33.49ac.f7ad.9702.76c5.cf2b - `@rq`0x3ff8.261c.1a9e.da3a.d5dd.688f.198a.e3cb `@rq`0xbff7.1a7a.c449.b285.876f.4b57.d627.e71e - `@rq`0x3ff5.1a4e.a418.ebe8.1381.31c1.5128.032a - == - ++ atred - |= ax=@rq ^- [xr=@rq hi=@rq lo=@rq dir=?] - ?: (~(lth ^rq %n) ax `@rq`0x3ffd.c000.0000.0000.0000.0000.0000.0000) [ax `@rq`0x0 `@rq`0x0 %.y] - ?: (~(lth ^rq %n) ax `@rq`0x3ffe.6000.0000.0000.0000.0000.0000.0000) - :* (~(div ^rq %n) (~(sub ^rq %n) (~(add ^rq %n) ax ax) `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000) (~(add ^rq %n) `@rq`0x4000.0000.0000.0000.0000.0000.0000.0000 ax)) - `@rq`0x3ffd.dac6.7056.1bb4.f68a.dfc8.8bd9.7875 `@rq`0x3f89.a06d.c282.b0e4.c39b.e01c.59e2.dcdd %.n == - ?: (~(lth ^rq %n) ax `@rq`0x3fff.3000.0000.0000.0000.0000.0000.0000) - :* (~(div ^rq %n) (~(sub ^rq %n) ax `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000) (~(add ^rq %n) ax `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000)) - `@rq`0x3ffe.921f.b544.42d1.8469.898c.c517.01b8 `@rq`0x3f8b.cd12.9024.e088.a67c.c740.20bb.ea64 %.n == - ?: (~(lth ^rq %n) ax `@rq`0x4000.3800.0000.0000.0000.0000.0000.0000) - :* (~(div ^rq %n) (~(sub ^rq %n) ax `@rq`0x3fff.8000.0000.0000.0000.0000.0000.0000) (~(add ^rq %n) `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000 (~(mul ^rq %n) `@rq`0x3fff.8000.0000.0000.0000.0000.0000.0000 ax))) - `@rq`0x3ffe.f730.bd28.1f69.b200.f10f.5e19.7794 `@rq`0xbf8b.ebe5.66c9.9ada.9f23.1bcc.ae27.916c %.n == - :* (~(div ^rq %n) `@rq`0xbfff.0000.0000.0000.0000.0000.0000.0000 ax) `@rq`0x3fff.921f.b544.42d1.8469.898c.c517.01b8 `@rq`0x3f8c.cd12.9024.e088.a67c.c740.20bb.ea64 %.n == - ++ ker - |= ax=@rq ^- @rq - =/ q (atred ax) - =/ z (~(mul ^rq %n) xr.q xr.q) - =/ s (~(mul ^rq %n) z (roll (flop at) |=([c=@rq a=@rq] (~(add ^rq %n) (~(mul ^rq %n) a z) c)))) - ?: dir.q (~(sub ^rq %n) xr.q (~(mul ^rq %n) xr.q s)) - (~(sub ^rq %n) hi.q (~(sub ^rq %n) (~(sub ^rq %n) (~(mul ^rq %n) xr.q s) lo.q) xr.q)) + :: hardcoded string constants for your viewing pleasure + :: OEIS A019692 + ++ tau '6.28318530717958647692528676655900576839433879875021164194988918461563281257241799625606965068423413596428' + :: OEIS A000796 + ++ pi '3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214' + :: OEIS A001113 + ++ e '2.71828182845904523536028747135266249775724709369995957496696762772407663035354759457138217852516642742746' + :: OEIS A001622 + ++ phi '1.61803398874989484820458683436563811772030917980576286213544862270526046281890244970720720418939113748475' + :: OEIS A002193 + ++ sqt2 '1.41421356237309504880168872420969807856967187537694807317667973799073247846210703885038753432764157273' + :: OEIS A010503 + ++ invsqt2 '0.70710678118654752440084436210484903928483593768847403658833986899536623923105351942519376716382086' + :: OEIS A002162 + ++ log2 '0.69314718055994530941723212145817656807550013436025525412068000949339362196969471560586332699641868754' + :: OEIS A002392 + ++ log10 '2.30258509299404568401799145468436420760110148862877297603332790096757260967735248023599726645985502929' -- - :: +atan2: [@rq @rq] -> @rq - :: - :: Returns the inverse tangent of a floating-point coordinate. - :: Examples - :: > (atan2 .~~~0 .~~~1) - :: .~~~0 - :: > (atan2 .~~~-1 .~~~0) - :: .~~~-1.5707963267948966192313216916397514 - :: > (atan2 .~~~0.5 .~~~-0.5) - :: .~~~2.3561944901923449288480202652918806 - :: - ++ atan2 - |= [y=@rq x=@rq] ^- @rq - ?: (~(gth ^rq %n) x `@rq`0x0) (atan (~(div ^rq %n) y x)) - ?: &((~(lth ^rq %n) x `@rq`0x0) (~(gte ^rq %n) y `@rq`0x0)) (~(add ^rq %n) (atan (~(div ^rq %n) y x)) `@rq`0x4000.921f.b544.42d1.8469.898c.c517.01b8) - ?: &((~(lth ^rq %n) x `@rq`0x0) (~(lth ^rq %n) y `@rq`0x0)) (~(sub ^rq %n) (atan (~(div ^rq %n) y x)) `@rq`0x4000.921f.b544.42d1.8469.898c.c517.01b8) - ?: &(=(`@rq`0x0 x) (~(gth ^rq %n) y `@rq`0x0)) `@rq`0x3fff.921f.b544.42d1.8469.898c.c517.01b8 - ?: &(=(`@rq`0x0 x) (~(lth ^rq %n) y `@rq`0x0)) `@rq`0xbfff.921f.b544.42d1.8469.898c.c517.01b8 - `@rq`0x0 - - :: +pow-n: [@rq @rq] -> @rq - :: - :: Returns the power of a floating-point atom to a signed integer exponent. - :: Examples - :: > (pow-n .~~~2 .~~~2) - :: .~~~4 - :: > (pow-n .~~~2 .~~~-2) - :: .~~~0.25 - :: Source - ++ pow-n - |= [x=@rq n=@rq] ^- @rq - ?: =(n `@rq`0x0) `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000 - =/ i (need (~(toi ^rq %n) n)) - =/ p `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000 - |- ^- @rq - ?: =(i --0) p - $(i (dif:si i --1), p (~(mul ^rq %n) p x)) - :: +log: @rq -> @rq - :: - :: Returns the natural logarithm of a floating-point atom. - :: Examples - :: > (log .~~~1) - :: .~~~0 - :: > (log .~~~2) - :: .~~~0.6931471805599453094170735934298606 - :: > (~(log rq [%z .~~~1e-5]) .~~~2) - :: .~~~0.6931470737597852366942444674497712 - :: > (log .~~~inf) - :: .~~~inf - :: Source - ++ log - :: x = 2^e * m reduction + atanh series (fdlibm f - s*(f-R)); f128. - :: Round-nearest-even internally (matches tools/rq_check.c). - |= x=@rq ^- @rq - ?: !(~(equ ^rq %n) x x) `@rq`0x7fff.8000.0000.0000.0000.0000.0000.0000 - ?: =(x `@rq`0x7fff.0000.0000.0000.0000.0000.0000.0000) `@rq`0x7fff.0000.0000.0000.0000.0000.0000.0000 - ?: |(=(x `@rq`0x0) =(x `@rq`0x8000.0000.0000.0000.0000.0000.0000.0000)) `@rq`0xffff.0000.0000.0000.0000.0000.0000.0000 - ?: =(1 (rsh [0 127] x)) `@rq`0x7fff.8000.0000.0000.0000.0000.0000.0000 - =/ sub =(0 (dis 0x7fff (rsh [0 112] x))) - =/ xx ?:(sub (~(mul ^rq %n) x `@rq`0x4077.0000.0000.0000.0000.0000.0000.0000) x) - =/ ae ?:(sub -120 --0) - =/ b `@`xx - =/ e (dif:si (new:si %.y (dis 0x7fff (rsh [0 112] b))) --16.383) - =/ m `@rq`(con (dis b 0xffff.ffff.ffff.ffff.ffff.ffff.ffff) 0x3fff.0000.0000.0000.0000.0000.0000.0000) - =/ big (~(gte ^rq %n) m `@rq`0x3fff.6a09.e667.f3bc.c908.b2fb.1366.ea95) - =? m big (~(mul ^rq %n) m `@rq`0x3ffe.0000.0000.0000.0000.0000.0000.0000) - =? e big (sum:si e --1) - =. e (sum:si e ae) - =/ f (~(sub ^rq %n) m `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000) - =/ s (~(div ^rq %n) f (~(add ^rq %n) m `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000)) - =/ z (~(mul ^rq %n) s s) - =/ cs=(list @rq) - :~ `@rq`0x3ffd.5555.5555.5555.5555.5555.5555.5555 `@rq`0x3ffc.9999.9999.9999.9999.9999.9999.999a - `@rq`0x3ffc.2492.4924.9249.2492.4924.9249.2492 `@rq`0x3ffb.c71c.71c7.1c71.c71c.71c7.1c71.c71c - `@rq`0x3ffb.745d.1745.d174.5d17.45d1.745d.1746 `@rq`0x3ffb.3b13.b13b.13b1.3b13.b13b.13b1.3b14 - `@rq`0x3ffb.1111.1111.1111.1111.1111.1111.1111 `@rq`0x3ffa.e1e1.e1e1.e1e1.e1e1.e1e1.e1e1.e1e2 - `@rq`0x3ffa.af28.6bca.1af2.86bc.a1af.286b.ca1b `@rq`0x3ffa.8618.6186.1861.8618.6186.1861.8618 - `@rq`0x3ffa.642c.8590.b216.42c8.590b.2164.2c86 `@rq`0x3ffa.47ae.147a.e147.ae14.7ae1.47ae.147b - `@rq`0x3ffa.2f68.4bda.12f6.84bd.a12f.684b.da13 `@rq`0x3ffa.1a7b.9611.a7b9.611a.7b96.11a7.b961 - `@rq`0x3ffa.0842.1084.2108.4210.8421.0842.1084 `@rq`0x3ff9.f07c.1f07.c1f0.7c1f.07c1.f07c.1f08 - `@rq`0x3ff9.d41d.41d4.1d41.d41d.41d4.1d41.d41d `@rq`0x3ff9.bacf.914c.1bac.f914.c1ba.cf91.4c1c - `@rq`0x3ff9.a41a.41a4.1a41.a41a.41a4.1a41.a41a `@rq`0x3ff9.8f9c.18f9.c18f.9c18.f9c1.8f9c.18fa - `@rq`0x3ff9.7d05.f417.d05f.417d.05f4.17d0.5f41 `@rq`0x3ff9.6c16.c16c.16c1.6c16.c16c.16c1.6c17 - `@rq`0x3ff9.5c98.82b9.3105.7262.0ae4.c415.c988 - == - =/ p2 (roll (flop cs) |=([c=@rq acc=@rq] (~(add ^rq %n) (~(mul ^rq %n) acc z) c))) - =/ r (~(mul ^rq %n) (~(add ^rq %n) z z) p2) - =/ l1 (~(sub ^rq %n) f (~(mul ^rq %n) s (~(sub ^rq %n) f r))) - =/ efa (~(sun ^rq %n) (abs:si e)) - =/ ef ?:((syn:si e) efa (~(sub ^rq %n) `@rq`0x0 efa)) - =/ hi (~(mul ^rq %n) ef `@rq`0x3ffe.62e4.2fef.a39e.f357.93c8.0000.0000) - =/ lo (~(mul ^rq %n) ef `@rq`0xbfad.319f.f034.2542.fc32.f366.359d.274a) - (~(add ^rq %n) hi (~(add ^rq %n) l1 lo)) - :: +log-10: @rq -> @rq - :: - :: Returns the base-10 logarithm of a floating-point atom. - :: Examples - :: TODO - :: Source - ++ log-10 - |= x=@rq ^- @rq - ?: !(~(equ ^rq %n) x x) `@rq`0x7fff.8000.0000.0000.0000.0000.0000.0000 - ?: =(x `@rq`0x7fff.0000.0000.0000.0000.0000.0000.0000) `@rq`0x7fff.0000.0000.0000.0000.0000.0000.0000 - ?: |(=(x `@rq`0x0) =(x `@rq`0x8000.0000.0000.0000.0000.0000.0000.0000)) `@rq`0xffff.0000.0000.0000.0000.0000.0000.0000 - ?: =(1 (rsh [0 127] x)) `@rq`0x7fff.8000.0000.0000.0000.0000.0000.0000 - =/ el (lr x) - (~(add ^rq %n) (~(mul ^rq %n) ef.el `@rq`0x3ffd.3441.3509.f79f.ef31.1f12.b358.16f9) (~(mul ^rq %n) lm.el `@rq`0x3ffd.bcb7.b152.6e50.e32a.6ab7.555f.5a68)) - :: +log-2: @rq -> @rq - :: - :: Returns the base-2 logarithm of a floating-point atom. - :: Examples - :: TODO - :: Source - :: +lr: log reduction for finite positive @rq x -> [e (as @rq), log(mantissa)]. - ++ lr - |= x=@rq ^- [ef=@rq lm=@rq] - =/ sub =(0 (dis 0x7fff (rsh [0 112] x))) - =/ xx ?:(sub (~(mul ^rq %n) x `@rq`0x4077.0000.0000.0000.0000.0000.0000.0000) x) - =/ ae ?:(sub -120 --0) - =/ b `@`xx - =/ e (dif:si (new:si %.y (dis 0x7fff (rsh [0 112] b))) --16.383) - =/ m `@rq`(con (dis b 0xffff.ffff.ffff.ffff.ffff.ffff.ffff) 0x3fff.0000.0000.0000.0000.0000.0000.0000) - =/ big (~(gte ^rq %n) m `@rq`0x3fff.6a09.e667.f3bc.c908.b2fb.1366.ea95) - =? m big (~(mul ^rq %n) m `@rq`0x3ffe.0000.0000.0000.0000.0000.0000.0000) - =? e big (sum:si e --1) - =. e (sum:si e ae) - =/ f (~(sub ^rq %n) m `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000) - =/ s (~(div ^rq %n) f (~(add ^rq %n) m `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000)) - =/ z (~(mul ^rq %n) s s) - =/ cs=(list @rq) - :~ `@rq`0x3ffd.5555.5555.5555.5555.5555.5555.5555 `@rq`0x3ffc.9999.9999.9999.9999.9999.9999.999a - `@rq`0x3ffc.2492.4924.9249.2492.4924.9249.2492 `@rq`0x3ffb.c71c.71c7.1c71.c71c.71c7.1c71.c71c - `@rq`0x3ffb.745d.1745.d174.5d17.45d1.745d.1746 `@rq`0x3ffb.3b13.b13b.13b1.3b13.b13b.13b1.3b14 - `@rq`0x3ffb.1111.1111.1111.1111.1111.1111.1111 `@rq`0x3ffa.e1e1.e1e1.e1e1.e1e1.e1e1.e1e1.e1e2 - `@rq`0x3ffa.af28.6bca.1af2.86bc.a1af.286b.ca1b `@rq`0x3ffa.8618.6186.1861.8618.6186.1861.8618 - `@rq`0x3ffa.642c.8590.b216.42c8.590b.2164.2c86 `@rq`0x3ffa.47ae.147a.e147.ae14.7ae1.47ae.147b - `@rq`0x3ffa.2f68.4bda.12f6.84bd.a12f.684b.da13 `@rq`0x3ffa.1a7b.9611.a7b9.611a.7b96.11a7.b961 - `@rq`0x3ffa.0842.1084.2108.4210.8421.0842.1084 `@rq`0x3ff9.f07c.1f07.c1f0.7c1f.07c1.f07c.1f08 - `@rq`0x3ff9.d41d.41d4.1d41.d41d.41d4.1d41.d41d `@rq`0x3ff9.bacf.914c.1bac.f914.c1ba.cf91.4c1c - `@rq`0x3ff9.a41a.41a4.1a41.a41a.41a4.1a41.a41a `@rq`0x3ff9.8f9c.18f9.c18f.9c18.f9c1.8f9c.18fa - `@rq`0x3ff9.7d05.f417.d05f.417d.05f4.17d0.5f41 `@rq`0x3ff9.6c16.c16c.16c1.6c16.c16c.16c1.6c17 - `@rq`0x3ff9.5c98.82b9.3105.7262.0ae4.c415.c988 - == - =/ p2 (roll (flop cs) |=([c=@rq acc=@rq] (~(add ^rq %n) (~(mul ^rq %n) acc z) c))) - =/ r (~(mul ^rq %n) (~(add ^rq %n) z z) p2) - =/ l1 (~(sub ^rq %n) f (~(mul ^rq %n) s (~(sub ^rq %n) f r))) - =/ efa (~(sun ^rq %n) (abs:si e)) - [?:((syn:si e) efa (~(sub ^rq %n) `@rq`0x0 efa)) l1] - ++ log-2 - |= x=@rq ^- @rq - ?: !(~(equ ^rq %n) x x) `@rq`0x7fff.8000.0000.0000.0000.0000.0000.0000 - ?: =(x `@rq`0x7fff.0000.0000.0000.0000.0000.0000.0000) `@rq`0x7fff.0000.0000.0000.0000.0000.0000.0000 - ?: |(=(x `@rq`0x0) =(x `@rq`0x8000.0000.0000.0000.0000.0000.0000.0000)) `@rq`0xffff.0000.0000.0000.0000.0000.0000.0000 - ?: =(1 (rsh [0 127] x)) `@rq`0x7fff.8000.0000.0000.0000.0000.0000.0000 - =/ el (lr x) - (~(add ^rq %n) ef.el (~(mul ^rq %n) lm.el `@rq`0x3fff.7154.7652.b82f.e177.7d0f.fda0.d23a)) - :: +pow: [@rq @rq] -> @rq - :: - :: Returns the power of a floating-point atom to a floating-point exponent. - :: Examples - :: > (pow .~~~1 .~~~2) - :: .~~~1 - :: > (pow .~~~2 .~~~2) - :: .~~~4 - :: > (~(pow rq:math [%z .~~~1e-5]) .~~~2 .~~~3.5) - :: .~~~11.313703735926135014164384135726204 - :: Source - ++ pow - |= [x=@rq n=@rq] ^- @rq - ?: &(=(n (~(san ^rq %n) (need (~(toi ^rq %n) n)))) (~(gth ^rq %n) n `@rq`0x0)) - (pow-n x n) - (exp (~(mul ^rq %n) n (log x))) - :: +sqrt: @rq -> @rq - :: - :: Returns the square root of a floating-point atom. - :: Alias for +sqt. - :: Examples - :: > (sqrt .~~~1) - :: .~~~1 - :: > (sqrt .~~~2) - :: .~~~1.4142135623730950488015335862957159 - :: > (~(sqrt rq:math [%z .~~~1e-10]) .~~~2) - :: .~~~1.4142135623721439870165294373250435 - :: Source - ++ sqrt sqt - :: +sqt: @rq -> @rq - :: - :: Returns the square root of a floating-point atom. - :: Examples - :: > (sqt .~~~1) - :: .~~~1 - :: > (sqt .~~~2) - :: .~~~1.414213562373095048801688724209698 - :: > (sqt .~~~1e5) - :: .~~~316.2277660168379331998893544432718 - :: Source - ++ sqt - :: correctly-rounded f128 sqrt: stdlib seed + one Markstein FMA (matches - :: the SoftFloat f128_sqrt jet, tools/rq_check.c). - |= x=@rq ^- @rq - ?: !(~(equ ^rq %n) x x) `@rq`0x7fff.8000.0000.0000.0000.0000.0000.0000 - ?: =(x `@rq`0x7fff.0000.0000.0000.0000.0000.0000.0000) `@rq`0x7fff.0000.0000.0000.0000.0000.0000.0000 - ?: |(=(x `@rq`0x0) =(x `@rq`0x8000.0000.0000.0000.0000.0000.0000.0000)) x - ?: =(1 (rsh [0 127] x)) `@rq`0x7fff.8000.0000.0000.0000.0000.0000.0000 - =/ g (sqt:^rq x) - =/ h (~(div ^rq %n) `@rq`0x3ffe.0000.0000.0000.0000.0000.0000.0000 g) - =/ r (~(fma ^rq %n) (~(sub ^rq %n) `@rq`0x0 g) g x) - (~(fma ^rq %n) h r g) - :: +cbrt: @rq -> @rq - :: - :: Returns the cube root of a floating-point atom. - :: Alias for +cbt. - :: Examples - :: > (cbrt .~~~1) - :: .~~~1 - :: > (cbrt .~~~2) - :: .~~~1.2598919398737178526805575821133312 - :: > (~(cbrt rq:math [%z .~~~1e-10]) .~~~2) - :: .~~~1.2598919398731638759238176665172822 - :: Source - ++ cbrt cbt - :: +cbt: @rq -> @rq - :: - :: Returns the cube root of a floating-point atom. - :: Examples - :: > (cbt .~~~1) - :: .~~~1 - :: > (cbt .~~~2) - :: .~~~1.2598919398737178526805575821133312 - :: > (~(cbt rq:math [%z .~~~1e-10]) .~~~2) - :: .~~~1.2598919398731638759238176665172822 - :: Source - ++ cbt - |= x=@rq ^- @rq - ?: !(~(equ ^rq %n) x x) x - ?: |(=(x `@rq`0x0) =(x `@rq`0x8000.0000.0000.0000.0000.0000.0000.0000)) x - =/ ax `@rq`(dis x 0x7fff.ffff.ffff.ffff.ffff.ffff.ffff.ffff) - =/ r (exp (~(mul ^rq %n) (log ax) `@rq`0x3ffd.5555.5555.5555.5555.5555.5555.5555)) - ?:(=(1 (rsh [0 127] x)) (~(sub ^rq %n) `@rq`0x0 r) r) - - :: +arg: @rq -> @rq - :: - :: Returns the argument of a floating-point atom (real argument = absolute - :: value). - :: Examples - :: > (arg .~~~1) - :: .~~~1 - :: > (arg .~~~-1) - :: .~~~1 - :: Source - ++ arg abs - -- -:: reference values -++ reference - |% - :: hardcoded string constants for your viewing pleasure - :: OEIS A019692 - ++ tau '6.28318530717958647692528676655900576839433879875021164194988918461563281257241799625606965068423413596428' - :: OEIS A000796 - ++ pi '3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214' - :: OEIS A001113 - ++ e '2.71828182845904523536028747135266249775724709369995957496696762772407663035354759457138217852516642742746' - :: OEIS A001622 - ++ phi '1.61803398874989484820458683436563811772030917980576286213544862270526046281890244970720720418939113748475' - :: OEIS A002193 - ++ sqt2 '1.41421356237309504880168872420969807856967187537694807317667973799073247846210703885038753432764157273' - :: OEIS A010503 - ++ invsqt2 '0.70710678118654752440084436210484903928483593768847403658833986899536623923105351942519376716382086' - :: OEIS A002162 - ++ log2 '0.69314718055994530941723212145817656807550013436025525412068000949339362196969471560586332699641868754' - :: OEIS A002392 - ++ log10 '2.30258509299404568401799145468436420760110148862877297603332790096757260967735248023599726645985502929' -- -- diff --git a/libmath/tools/rd_exp_check.c b/libmath/tools/rd_exp_check.c new file mode 100644 index 0000000..f0efe12 --- /dev/null +++ b/libmath/tools/rd_exp_check.c @@ -0,0 +1,76 @@ +// rd_exp_check.c -- SoftFloat-f64 reference for @rd exp (the jet body). +// Transcribed line-for-line from libmath/desk/lib/math.hoon ++rd ++exp +// (Cody-Waite reduction + degree-11 minimax Horner + scale2 ldexp). +// SoftFloat f64 round-near-even == the Hoon stdlib @rd ops, so this should be +// BIT-EXACT to (exp:rd:math x). Prints " " per input. +// +// Build: re-archive the zig softfloat .a (not 8-byte aligned for Apple ld): +// ar x && libtool -static -o /tmp/libsoftfloat.a *.o +// cc -I rd_exp_check.c /tmp/libsoftfloat.a -o /tmp/rd_exp_check +#include +#include +#include +#include +#include "softfloat.h" + +typedef float64_t d; +static inline d D(uint64_t b){ d r; r.v = b; return r; } +static inline d mul(d a, d b){ return f64_mul(a,b); } +static inline d sub(d a, d b){ return f64_sub(a,b); } +static inline d add(d a, d b){ return f64_add(a,b); } + +// pow2(j) = (j+1023)<<52 as f64 bits = 2^j (normal range j in [-1022,1023]) +static inline d pow2(int64_t j){ return D(((uint64_t)(j + 1023)) << 52); } + +// scale2: correctly-rounded ldexp with overflow/subnormal tails (math.hoon:1519) +static d scale2(d p, int64_t k){ + if ( k - 1024 >= 0 ) // k>=1024 + return mul(mul(p, pow2(1023)), pow2(k - 1023)); + if ( !(k + 1022 >= 0) ) // k<-1022 (i.e. k<=-1023) + return mul(mul(p, pow2(k + 54)), pow2(-54)); + return mul(p, pow2(k)); +} + +static d expd(d x){ + const uint64_t QNAN = 0x7ff8000000000000ULL, PINF = 0x7ff0000000000000ULL, + NINF = 0xfff0000000000000ULL; + if ( !f64_eq(x, x) ) return D(QNAN); // NaN + if ( x.v == PINF ) return D(PINF); // +inf + if ( x.v == NINF ) return D(0); // -inf -> 0 + d log2e = D(0x3ff71547652b82feULL); + d ln2hi = D(0x3fe62e42fee00000ULL); + d ln2lo = D(0x3dea39ef35793c76ULL); + int64_t k = f64_to_i64(mul(x, log2e), softfloat_round_near_even, false); + if ( k - 1025 >= 0 ) return D(PINF); // overflow -> inf + if ( !(k + 1075 >= 0) ) return D(0); // underflow -> 0 + d ka = ui64_to_f64( (uint64_t)(k < 0 ? -k : k) ); // |k| as f64 (sun abs) + d kf = (k >= 0) ? ka : sub(D(0), ka); + d r = sub( sub(x, mul(kf, ln2hi)), mul(kf, ln2lo) ); + // degree-11 minimax coeffs c0..c11 (math.hoon:1542-1547) + static const uint64_t cs[12] = { + 0x3ff0000000000000ULL, 0x3ff0000000000000ULL, 0x3fe0000000000011ULL, + 0x3fc555555555555aULL, 0x3fa555555554f0cfULL, 0x3f8111111110f225ULL, + 0x3f56c16c187fbe02ULL, 0x3f2a01a01b14378fULL, 0x3efa01991ac8730aULL, + 0x3ec71ddf5749d126ULL, 0x3e928b4057f44145ULL, 0x3e5af631d0059becULL + }; + // Horner: acc=0; for c in flop(cs) [c11..c0]: acc = acc*r + c (math.hoon:1549) + d p = D(0); + for ( int i = 11; i >= 0; i-- ) p = add(mul(p, r), D(cs[i])); + return scale2(p, k); +} + +int main(int argc, char** argv){ + softfloat_roundingMode = softfloat_round_near_even; + // inputs as native doubles (native == IEEE f64 bit patterns here) + double xs[] = { 0.0, 0.5, 1.0, 2.0, 3.0, -1.0, -2.0, 5.0, 10.0, -10.0, + 0.1, -0.1, 3.141592653589793, 100.0, -100.0, + 700.0, -700.0, 709.0, -740.0 }; + int n = (int)(sizeof xs / sizeof xs[0]); + for ( int i = 0; i < n; i++ ){ + union { double f; uint64_t b; } u; u.f = xs[i]; + d out = expd(D(u.b)); + printf("0x%016llx 0x%016llx (x=%g)\n", + (unsigned long long)u.b, (unsigned long long)out.v, xs[i]); + } + return 0; +} diff --git a/libmath/vere/README.md b/libmath/vere/README.md new file mode 100644 index 0000000..208323a --- /dev/null +++ b/libmath/vere/README.md @@ -0,0 +1,59 @@ +# libmath C jets (vere mirror) + +C jet implementations for the `math.hoon` transcendental library, **vendored +from the vere runtime** (`pkg/noun`). The jets do not live in this repo's build +— this directory is a maintained mirror so the C and the Hoon evolve together. +There is no automatic cross-repo sync; apply changes to vere by hand. + +## What's here +- `jets/i/math.c` — the jet bodies. Each runs the IDENTICAL algorithm as its + Hoon arm in Berkeley SoftFloat, so jet output is **bit-exact** to the pure-Hoon + reference (not merely faithful). Marshalling is chub-based (word-size-agnostic; + the divergence that broke the @rq sub jet). Currently: `@rd exp`. +- `jets/tree-registration.snippet.c` — the `tree.c` registration block to add to + each per-kelvin jet tree, plus the q.h/w.h/build.zig one-liners. + +## How to apply to vere (`pkg/noun`) +1. Copy `jets/i/math.c` → `pkg/noun/jets/i/math.c`. +2. Add the registration block from `jets/tree-registration.snippet.c` to + **each** of `pkg/noun/jets/13{5,6,7}/tree.c` (the active tree is picked by the + ship's `hoon-version`; numerics ships are 136, stock test ships 135). `math` + registers under the `non` chapter as a sibling of `lagoon`. +3. Declare in `pkg/noun/jets/q.h` (`u3qi_rd_exp`) and `w.h` (`u3wi_rd_exp`). +4. Add `"jets/i/math.c"` to the jet source list in `pkg/noun/build.zig`. +5. Rebuild; on a 64-bit build use `-Dvere64=true`. + +## CRITICAL: the Hoon jet structure (the gotcha that cost a day) +`math.hoon` must mirror `/lib/lagoon`'s jet structure exactly: + +``` +=< math :: export the engine so `/+ math` + `rd:math` work +~% %non ..part ~ :: file |% anchored to the shared %non chapter +|% +++ math + ^| + =+ [rnd=*?(%n %u %d %z)] :: <-- REQUIRED: the engine must be a DOOR + ~/ %math :: (sample-bearing), not a bare |% + |% + ++ rd + ~/ %rd + ^| + |_ [r=... rtol=...] + ++ exp ~/ %exp |=(x=@rd ...) +``` + +A **sample-less `~/`-hinted core anchors its parent to the dashboard ROOT**, so +`%math` (and everything under it) misses the hot dashboard — the core SPOTs in +`_cj_mile` but `_cj_hot_mean` returns `jax=0` and no C jet ever attaches. The +`^| =+ [rnd]` sample makes `~/` resolve the parent to `%non`, exactly as +lagoon's `++ la ^| =+ [rnd] ~/ %lagoon |%` does. Verified via a `_cj_hot_mean` +trace: `math par=0 MISS` (bare |%) -> `math par=non FOUND` (door). + +The chapter chain is `pen -> hex -> non -> math -> -> `, e.g. +`non/math/rd/exp`. + +## Verifying a jet fires +`~>(%bout (exp:rd:math .~1))` should report a few µs (jetted) vs hundreds of µs +(interpreted), and `` `@ux`(exp:rd:math .~1) `` must equal `0x4005.bf0a.8b14.576a` +(bit-exact). Use `tmux` for the ship so the dojo stays interactive; jet +registration only warms on first computation of each core (not at boot). diff --git a/libmath/vere/jets/i/math.c b/libmath/vere/jets/i/math.c new file mode 100644 index 0000000..55d0826 --- /dev/null +++ b/libmath/vere/jets/i/math.c @@ -0,0 +1,108 @@ +/// @file +/// +/// Jets for the numerics `math.hoon` library (userspace, registered under the +/// `non` chapter alongside `lagoon`). Each body runs the IDENTICAL algorithm +/// as its Hoon arm (same reduction, coefficients, Horner order) in Berkeley +/// SoftFloat, so jet output is BIT-EXACT to the pure-Hoon reference -- not +/// merely faithful. Transcendentals force round-nearest-even internally (they +/// take no rounding-mode axis), matching the Hoon. +/// +/// Marshalling uses chub (64-bit) reads/writes so it is word-size-agnostic +/// across the 32-bit and 64-bit runtimes (the divergence that broke @rq sub). + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" +#include "softfloat.h" + + union doub { + float64_t d; + c3_d c; + }; + +/* @rd exp -- math.hoon ++rd ++exp +** x = k*ln2 + r (Cody-Waite), exp(x) = 2^k * P(r), P a degree-11 minimax +** polynomial; +scale2 is a correctly-rounded ldexp. +*/ + // pow2(j) = (j+1023)<<52 as f64 bits = 2^j (normal range j in [-1022,1023]) + static inline float64_t + _rd_pow2(c3_ds j) + { + union doub u; + u.c = ((c3_d)(j + 1023)) << 52; + return u.d; + } + + // scale2: ldexp with overflow/subnormal tails (math.hoon:1519) + static inline float64_t + _rd_scale2(float64_t p, c3_ds k) + { + if ( (k - 1024) >= 0 ) { // k>=1024 + return f64_mul(f64_mul(p, _rd_pow2(1023)), _rd_pow2(k - 1023)); + } + if ( !((k + 1022) >= 0) ) { // k<-1022 + return f64_mul(f64_mul(p, _rd_pow2(k + 54)), _rd_pow2(-54)); + } + return f64_mul(p, _rd_pow2(k)); + } + + static float64_t + _rd_exp(float64_t x) + { + union doub r0; + // degree-11 minimax coeffs c0..c11 (math.hoon:1542-1547) + static const c3_d cs[12] = { + 0x3ff0000000000000ULL, 0x3ff0000000000000ULL, 0x3fe0000000000011ULL, + 0x3fc555555555555aULL, 0x3fa555555554f0cfULL, 0x3f8111111110f225ULL, + 0x3f56c16c187fbe02ULL, 0x3f2a01a01b14378fULL, 0x3efa01991ac8730aULL, + 0x3ec71ddf5749d126ULL, 0x3e928b4057f44145ULL, 0x3e5af631d0059becULL + }; + union doub log2e, ln2hi, ln2lo, ka, kf, rr, p, c, zero; + + zero.c = 0; + r0.d = x; + if ( !f64_eq(x, x) ) { r0.c = 0x7ff8000000000000ULL; return r0.d; } // NaN + if ( r0.c == 0x7ff0000000000000ULL ) { return x; } // +inf + if ( r0.c == 0xfff0000000000000ULL ) { r0.c = 0; return r0.d; } // -inf -> 0 + + log2e.c = 0x3ff71547652b82feULL; + ln2hi.c = 0x3fe62e42fee00000ULL; + ln2lo.c = 0x3dea39ef35793c76ULL; + + c3_ds k = (c3_ds)f64_to_i64(f64_mul(x, log2e.d), softfloat_round_near_even, 0); + if ( (k - 1025) >= 0 ) { r0.c = 0x7ff0000000000000ULL; return r0.d; } // overflow -> inf + if ( !((k + 1075) >= 0) ) { r0.c = 0; return r0.d; } // underflow -> 0 + + ka.d = ui64_to_f64( (c3_d)(k < 0 ? -k : k) ); + kf.d = (k >= 0) ? ka.d : f64_sub((union doub){.c=0}.d, ka.d); + rr.d = f64_sub( f64_sub(x, f64_mul(kf.d, ln2hi.d)), f64_mul(kf.d, ln2lo.d) ); + + p.c = 0; + for ( c3_w i = 12; i-- != 0; ) { // Horner over flop(cs): c11..c0 + c.c = cs[i]; + p.d = f64_add(f64_mul(p.d, rr.d), c.d); + } + return _rd_scale2(p.d, k); + } + + u3_noun + u3qi_rd_exp(u3_atom a) + { + union doub c, e; + softfloat_roundingMode = softfloat_round_near_even; + c.c = u3r_chub(0, a); + e.d = _rd_exp(c.d); + return u3i_chubs(1, &e.c); + } + + u3_noun + u3wi_rd_exp(u3_noun cor) + { + u3_noun x = u3r_at(u3x_sam, cor); + + if ( u3_none == x || c3n == u3ud(x) ) { + return u3m_bail(c3__exit); + } + return u3qi_rd_exp(x); + } diff --git a/libmath/vere/jets/tree-registration.snippet.c b/libmath/vere/jets/tree-registration.snippet.c new file mode 100644 index 0000000..f62af3d --- /dev/null +++ b/libmath/vere/jets/tree-registration.snippet.c @@ -0,0 +1,35 @@ +// math.hoon transcendental jets -- tree.c registration. +// +// Add this block to EACH per-hoon-kelvin tree in the vere runtime: +// pkg/noun/jets/135/tree.c, .../136/tree.c, .../137/tree.c +// (the active tree is chosen by the ship's `hoon-version`; numerics ships are +// 136, the stock urbit/urbit ships used for testing are 135). +// +// Place the three static decls just BEFORE `static u3j_core _13X_non_d[]` +// (next to the lagoon `_13X_non__la_core_d` block), then add the "math" entry +// to `_13X_non_d[]` as a sibling of "lagoon". Replace 13X with 135/136/137. + +// --- decls (before _13X_non_d) ------------------------------------------ +static u3j_harm _13X_non__math_rd_exp_a[] = {{".2", u3wi_rd_exp}, {}}; +static u3j_core _13X_non__math_rd_d[] = + { { "exp", 7, _13X_non__math_rd_exp_a, 0, no_hashes }, + {} + }; +static u3j_core _13X_non__math_d[] = + { { "rd", 7, 0, _13X_non__math_rd_d, no_hashes }, + {} + }; + +// --- entry (inside _13X_non_d[], next to "lagoon") ---------------------- +// { "lagoon", 7, 0, _13X_non__la_core_d, no_hashes }, + { "math", 7, 0, _13X_non__math_d, no_hashes }, +// { "mice", 7, _13X_non__mice_a, 0, no_hashes }, // (136/135 only) +// {} +// }; + +// --- header decls (pkg/noun/jets/q.h and w.h) --------------------------- +// q.h: u3_noun u3qi_rd_exp(u3_atom); +// w.h: u3_noun u3wi_rd_exp(u3_noun); + +// --- build (pkg/noun/build.zig, in the jet .c source list) -------------- +// "jets/i/math.c", From 4bc24bbcf1328e726798e9cd9d288323d1552370 Mon Sep 17 00:00:00 2001 From: Sigilante Date: Thu, 11 Jun 2026 10:56:28 -0500 Subject: [PATCH 02/28] math: @rd log jet + shared-source harness Add @rd log as the second jetted transcendental, and refactor the vere master (libmath/vere/jets/i/math.c) so the SoftFloat algorithm cores (_rd_exp, _rd_log) are shared between the runtime jet and a standalone bit-exact harness (libmath/vere/test/, via -DMATH_JET_HARNESS) -- the C the test runs is byte-for-byte the C the jet runs, so they can't drift. log transcribes math.hoon ++rd ++log (2^e*m reduction + degree-9 atanh Horner); ~/ %log hint added. Verified bit-exact to the Hoon incl the subnormal and sqrt(2)-boundary branches, and jetted on-ship (log:rd:math .~2 = 0x3fe6.2e42.fefa.39ef). Co-Authored-By: Claude Opus 4.8 --- libmath/desk/lib/math.hoon | 1 + libmath/vere/jets/i/math.c | 133 +++++++++++++++--- libmath/vere/jets/tree-registration.snippet.c | 3 + libmath/vere/test/build.sh | 23 +++ libmath/vere/test/rd_check.c | 40 ++++++ 5 files changed, 182 insertions(+), 18 deletions(-) create mode 100755 libmath/vere/test/build.sh create mode 100644 libmath/vere/test/rd_check.c diff --git a/libmath/desk/lib/math.hoon b/libmath/desk/lib/math.hoon index 7608f11..c2a1cb1 100644 --- a/libmath/desk/lib/math.hoon +++ b/libmath/desk/lib/math.hoon @@ -1961,6 +1961,7 @@ :: .~inf :: Source ++ log + ~/ %log |= x=@rd ^- @rd :: Reduce x = 2^e * m with m in [sqrt(1/2), sqrt(2)); then :: log(x) = e*ln2 + log(1+f), f = m-1, s = f/(2+f), diff --git a/libmath/vere/jets/i/math.c b/libmath/vere/jets/i/math.c index 55d0826..e4cecb7 100644 --- a/libmath/vere/jets/i/math.c +++ b/libmath/vere/jets/i/math.c @@ -9,18 +9,37 @@ /// /// Marshalling uses chub (64-bit) reads/writes so it is word-size-agnostic /// across the 32-bit and 64-bit runtimes (the divergence that broke @rq sub). +/// +/// MASTER COPY lives in urbit/numerics libmath/vere/; applied by hand to the +/// vere runtime (pkg/noun/jets/i/math.c) -- see libmath/vere/README.md. The +/// `_rd_*` algorithm cores below are shared with the bit-exact harness +/// (libmath/vere/test/) via -DMATH_JET_HARNESS, so the jet and its test can +/// never drift. +#ifndef MATH_JET_HARNESS #include "jets/q.h" #include "jets/w.h" - #include "noun.h" +#endif #include "softfloat.h" +#ifdef MATH_JET_HARNESS +#include +typedef uint64_t c3_d; +typedef int64_t c3_ds; +#endif + union doub { float64_t d; c3_d c; }; + static const c3_d _RD_QNAN = 0x7ff8000000000000ULL; + static const c3_d _RD_PINF = 0x7ff0000000000000ULL; + static const c3_d _RD_NINF = 0xfff0000000000000ULL; + + static inline union doub _rd_bits(c3_d b) { union doub u; u.c = b; return u; } + /* @rd exp -- math.hoon ++rd ++exp ** x = k*ln2 + r (Cody-Waite), exp(x) = 2^k * P(r), P a degree-11 minimax ** polynomial; +scale2 is a correctly-rounded ldexp. @@ -62,32 +81,108 @@ zero.c = 0; r0.d = x; - if ( !f64_eq(x, x) ) { r0.c = 0x7ff8000000000000ULL; return r0.d; } // NaN - if ( r0.c == 0x7ff0000000000000ULL ) { return x; } // +inf - if ( r0.c == 0xfff0000000000000ULL ) { r0.c = 0; return r0.d; } // -inf -> 0 + if ( !f64_eq(x, x) ) { r0.c = _RD_QNAN; return r0.d; } // NaN + if ( r0.c == _RD_PINF ) { return x; } // +inf + if ( r0.c == _RD_NINF ) { r0.c = 0; return r0.d; } // -inf -> 0 log2e.c = 0x3ff71547652b82feULL; ln2hi.c = 0x3fe62e42fee00000ULL; ln2lo.c = 0x3dea39ef35793c76ULL; c3_ds k = (c3_ds)f64_to_i64(f64_mul(x, log2e.d), softfloat_round_near_even, 0); - if ( (k - 1025) >= 0 ) { r0.c = 0x7ff0000000000000ULL; return r0.d; } // overflow -> inf - if ( !((k + 1075) >= 0) ) { r0.c = 0; return r0.d; } // underflow -> 0 + if ( (k - 1025) >= 0 ) { r0.c = _RD_PINF; return r0.d; } // overflow -> inf + if ( !((k + 1075) >= 0) ) { r0.c = 0; return r0.d; } // underflow -> 0 ka.d = ui64_to_f64( (c3_d)(k < 0 ? -k : k) ); - kf.d = (k >= 0) ? ka.d : f64_sub((union doub){.c=0}.d, ka.d); + kf.d = (k >= 0) ? ka.d : f64_sub(zero.d, ka.d); rr.d = f64_sub( f64_sub(x, f64_mul(kf.d, ln2hi.d)), f64_mul(kf.d, ln2lo.d) ); p.c = 0; - for ( c3_w i = 12; i-- != 0; ) { // Horner over flop(cs): c11..c0 + for ( int i = 12; i-- != 0; ) { // Horner over flop(cs): c11..c0 c.c = cs[i]; p.d = f64_add(f64_mul(p.d, rr.d), c.d); } return _rd_scale2(p.d, k); } - u3_noun - u3qi_rd_exp(u3_atom a) +/* @rd log -- math.hoon ++rd ++log +** x = 2^e * m, m in [sqrt(1/2),sqrt(2)); log(x) = e*ln2 + log(1+f), +** f = m-1, s = f/(2+f), log(1+f) = f - s*(f - 2z*P2(z)), z=s*s, P2 the +** atanh series 1/3 + z/5 + z^2/7 + ... +*/ + static float64_t + _rd_log(float64_t x) + { + static const c3_d cs[10] = { // atanh-series coeffs (math.hoon:1988) + 0x3fd5555555555555ULL, 0x3fc999999999999aULL, 0x3fc2492492492492ULL, + 0x3fbc71c71c71c71cULL, 0x3fb745d1745d1746ULL, 0x3fb3b13b13b13b14ULL, + 0x3fb1111111111111ULL, 0x3fae1e1e1e1e1e1eULL, 0x3faaf286bca1af28ULL, + 0x3fa8618618618618ULL + }; + union doub r0, xx, m, f, s, z, p, c, rr, l1, efd, hi, lo, one, zero; + + zero.c = 0; + r0.d = x; + if ( !f64_eq(x, x) ) { r0.c = _RD_QNAN; return r0.d; } // NaN + if ( r0.c == _RD_PINF ) { return x; } // +inf + if ( (r0.c == 0) || (r0.c == 0x8000000000000000ULL) ) { r0.c = _RD_NINF; return r0.d; } // +-0 -> -inf + if ( (r0.c >> 63) == 1 ) { r0.c = _RD_QNAN; return r0.d; } // x<0 -> NaN + + int sub = ( ((r0.c >> 52) & 0x7ffULL) == 0 ); + xx = r0; + if ( sub ) xx.d = f64_mul(x, _rd_bits(0x4350000000000000ULL).d); // x * 2^54 + c3_ds ae = sub ? -54 : 0; + c3_d b = xx.c; + c3_ds ef = (c3_ds)((b >> 52) & 0x7ffULL) - 1023; + m.c = (b & 0xfffffffffffffULL) | 0x3ff0000000000000ULL; // m in [1,2) + + int big = f64_le(_rd_bits(0x3ff6a09e667f3bcdULL).d, m.d); // m >= sqrt(2) + if ( big ) { m.d = f64_mul(m.d, _rd_bits(0x3fe0000000000000ULL).d); ef = ef + 1; } + ef = ef + ae; + + one.c = 0x3ff0000000000000ULL; + f.d = f64_sub(m.d, one.d); + s.d = f64_div(f.d, f64_add(m.d, one.d)); + z.d = f64_mul(s.d, s.d); + + p.c = 0; + for ( int i = 10; i-- != 0; ) { // Horner over flop(cs): c9..c0 + c.c = cs[i]; + p.d = f64_add(f64_mul(p.d, z.d), c.d); + } + rr.d = f64_mul(f64_add(z.d, z.d), p.d); // 2z * P2 + l1.d = f64_sub(f.d, f64_mul(s.d, f64_sub(f.d, rr.d))); // f - s*(f - r) + + efd.d = ui64_to_f64( (c3_d)(ef < 0 ? -ef : ef) ); + if ( ef < 0 ) efd.d = f64_sub(zero.d, efd.d); // e as @rd + hi.d = f64_mul(efd.d, _rd_bits(0x3fe62e42fee00000ULL).d); // e*ln2hi + lo.d = f64_mul(efd.d, _rd_bits(0x3dea39ef35793c76ULL).d); // e*ln2lo + return f64_add(hi.d, f64_add(l1.d, lo.d)); + } + +#ifndef MATH_JET_HARNESS + +/* u3 ABI wrappers. Each transcendental forces round-near-even; the @rd door's +** rounding axis is ignored (the Hoon does the same). Sample is the single @rd +** at u3x_sam. +*/ + static u3_noun + _rd_jet(u3_noun cor, float64_t (*fun)(float64_t)) + { + u3_noun x = u3r_at(u3x_sam, cor); + if ( u3_none == x || c3n == u3ud(x) ) { + return u3m_bail(c3__exit); + } + { + union doub c, e; + softfloat_roundingMode = softfloat_round_near_even; + c.c = u3r_chub(0, x); + e.d = fun(c.d); + return u3i_chubs(1, &e.c); + } + } + + u3_noun u3qi_rd_exp(u3_atom a) { union doub c, e; softfloat_roundingMode = softfloat_round_near_even; @@ -95,14 +190,16 @@ e.d = _rd_exp(c.d); return u3i_chubs(1, &e.c); } + u3_noun u3wi_rd_exp(u3_noun cor) { return _rd_jet(cor, _rd_exp); } - u3_noun - u3wi_rd_exp(u3_noun cor) + u3_noun u3qi_rd_log(u3_atom a) { - u3_noun x = u3r_at(u3x_sam, cor); - - if ( u3_none == x || c3n == u3ud(x) ) { - return u3m_bail(c3__exit); - } - return u3qi_rd_exp(x); + union doub c, e; + softfloat_roundingMode = softfloat_round_near_even; + c.c = u3r_chub(0, a); + e.d = _rd_log(c.d); + return u3i_chubs(1, &e.c); } + u3_noun u3wi_rd_log(u3_noun cor) { return _rd_jet(cor, _rd_log); } + +#endif diff --git a/libmath/vere/jets/tree-registration.snippet.c b/libmath/vere/jets/tree-registration.snippet.c index f62af3d..082c5b5 100644 --- a/libmath/vere/jets/tree-registration.snippet.c +++ b/libmath/vere/jets/tree-registration.snippet.c @@ -10,9 +10,12 @@ // to `_13X_non_d[]` as a sibling of "lagoon". Replace 13X with 135/136/137. // --- decls (before _13X_non_d) ------------------------------------------ +// One harm per arm of the rd door; add a line here per jetted @rd fn. static u3j_harm _13X_non__math_rd_exp_a[] = {{".2", u3wi_rd_exp}, {}}; +static u3j_harm _13X_non__math_rd_log_a[] = {{".2", u3wi_rd_log}, {}}; static u3j_core _13X_non__math_rd_d[] = { { "exp", 7, _13X_non__math_rd_exp_a, 0, no_hashes }, + { "log", 7, _13X_non__math_rd_log_a, 0, no_hashes }, {} }; static u3j_core _13X_non__math_d[] = diff --git a/libmath/vere/test/build.sh b/libmath/vere/test/build.sh new file mode 100755 index 0000000..97f50e4 --- /dev/null +++ b/libmath/vere/test/build.sh @@ -0,0 +1,23 @@ +#!/bin/sh +# Build + run the @rd bit-exact harness. Uses the SAME Berkeley SoftFloat the +# vere jets use. The zig-archived .a is not 8-byte aligned for Apple ld, so we +# re-archive it with libtool (chmod the extracted .o's; they come out read-only). +set -e + +SFINC="$(dirname "$(find "$HOME/urbit" -name softfloat.h 2>/dev/null | grep -i softfloat/source/include | head -1)")" +SFLIB="$(find "$HOME/urbit/vere-ml64" -name libsoftfloat.a 2>/dev/null | head -1)" +[ -n "$SFINC" ] && [ -n "$SFLIB" ] || { echo "softfloat not found (build vere-ml64 first)"; exit 1; } + +WORK="$(mktemp -d)" +( cd "$WORK" && ar x "$SFLIB" && chmod u+rw ./*.o && libtool -static -o ./libsoftfloat.a ./*.o ) +cc -O2 -I"$SFINC" "$(dirname "$0")/rd_check.c" "$WORK/libsoftfloat.a" -o "$WORK/rd_check" +"$WORK/rd_check" +rm -rf "$WORK" + +cat <<'EOF' + +# To compare against the Hoon (on a ship with /+ math), the dojo expression is: +# =rd rd:math +# :: then for each input X above, check `@ux`(exp:rd:math X) / (log:rd:math X) +# matches the harness bit-for-bit. +EOF diff --git a/libmath/vere/test/rd_check.c b/libmath/vere/test/rd_check.c new file mode 100644 index 0000000..d91affc --- /dev/null +++ b/libmath/vere/test/rd_check.c @@ -0,0 +1,40 @@ +// rd_check.c -- bit-exact harness for the @rd math jets. +// +// Includes the MASTER jet algorithms (jets/i/math.c) with -DMATH_JET_HARNESS, +// so the C tested here is byte-for-byte the C the runtime jet runs. Prints +// ` 0x 0x` per case; compare each against the Hoon +// `(:rd:math )` (see build.sh for the generated dojo expression). +// +// Build/run: ./build.sh (re-archives the zig softfloat .a for Apple ld). + +#define MATH_JET_HARNESS +#include "../jets/i/math.c" + +#include + +static void emit(const char* nm, double x, float64_t (*fun)(float64_t)) { + union { double f; uint64_t b; } u; u.f = x; + union doub in, out; + in.c = u.b; + out.d = fun(in.d); + printf("%-4s 0x%016llx 0x%016llx (%g)\n", + nm, (unsigned long long)in.c, (unsigned long long)out.c, x); +} + +int main(void) { + softfloat_roundingMode = softfloat_round_near_even; + + // exp: full range incl overflow/subnormal tails + static const double ex[] = { 0.0, 0.5, 1.0, 2.0, 3.0, -1.0, -2.0, 5.0, 10.0, + -10.0, 0.1, -0.1, 3.141592653589793, 100.0, -100.0, 700.0, -700.0, 709.0, + -740.0 }; + for (unsigned i = 0; i < sizeof ex/sizeof ex[0]; i++) emit("exp", ex[i], _rd_exp); + + // log: positive domain, incl <1, large, small, subnormal-ish + static const double lg[] = { 1.0, 2.0, 0.5, 10.0, 0.1, 2.718281828459045, + 100.0, 0.001, 1.0e10, 1.0e-10, 1.4142135623730951, 1.5, 3.0, 7.0, + 1.0e300, 5.0e-324 }; + for (unsigned i = 0; i < sizeof lg/sizeof lg[0]; i++) emit("log", lg[i], _rd_log); + + return 0; +} From e5d3f2423f6cba16415fd850dadf0e21444425ee Mon Sep 17 00:00:00 2001 From: Sigilante Date: Thu, 11 Jun 2026 21:34:26 -0500 Subject: [PATCH 03/28] math: complete all 15 @rd transcendental jets (bit-exact, verified on-ship) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Finish the @rd jet port begun with exp/log: add faithful softfloat cores + u3 wrappers for sin/cos/tan/atan/atan2/asin/acos/sqt/cbt/pow/pow-n/log-2/log-10, each transcribing its Hoon arm's exact reduction/coefficients/Horner order so jet output is bit-identical to the pure-Hoon reference, not merely faithful. - math.hoon: ~/ hints on all 15 @rd arms under the %math door anchor. - jets/i/math.c: 15 algorithm cores shared with the harness via -DMATH_JET_HARNESS, plus u3 ABI wrappers. Fix the 2-arg wrappers (atan2/pow/pow-n) to use brace-enclosed u3r_mean pairs {axis,&ptr} — the flat form failed -Werror=missing-braces and never compiled. - test/rd_check.c: add emit2() + atan2/pow/pow-n vectors. - test/verify_clean.sh: one-query-at-a-time on-ship diff, NO C-c. (SIGINT mid-event corrupts the loom; the old verify.sh's C-c spam was crashing the serf and masquerading as a jet bug.) Verified bit-exact on a fresh fakeship: 234/234 vectors, 0 DIFF (198 single-arg via verify_clean.sh, 36 two-arg via gen/m2.hoon in one event). sin x 200k under %bout = 431ms (~2.1us/call) confirms jetting. Co-Authored-By: Claude Opus 4.8 --- libmath/desk/lib/math.hoon | 13 + libmath/vere/jets/i/math.c | 560 +++++++++++++++++++++++++++--- libmath/vere/test/rd_check.c | 63 ++++ libmath/vere/test/verify.sh | 44 +++ libmath/vere/test/verify_clean.sh | 34 ++ 5 files changed, 675 insertions(+), 39 deletions(-) create mode 100755 libmath/vere/test/verify.sh create mode 100755 libmath/vere/test/verify_clean.sh diff --git a/libmath/desk/lib/math.hoon b/libmath/desk/lib/math.hoon index c2a1cb1..06aff7c 100644 --- a/libmath/desk/lib/math.hoon +++ b/libmath/desk/lib/math.hoon @@ -1577,6 +1577,7 @@ :: .~-1.698287706085482e-13 :: Source ++ sin + ~/ %sin |= x=@rd ^- @rd :: Reduce x = q*(pi/2) + (rhi+rlo) (2-part pi/2), then fdlibm sin/cos :: kernels picked by q&3. Faithful to <=1 ULP for |x| <~ 2^22. @@ -1598,6 +1599,7 @@ :: .~-1.0000000000013558 :: Source ++ cos + ~/ %cos |= x=@rd ^- @rd ?: !(~(equ ^rd %n) x x) `@rd`0x7ff8.0000.0000.0000 ?: |(=(x `@rd`0x7ff0.0000.0000.0000) =(x `@rd`0xfff0.0000.0000.0000)) `@rd`0x7ff8.0000.0000.0000 @@ -1668,6 +1670,7 @@ :: .~-2.6535896228476087e-6 :: Source ++ tan + ~/ %tan :: Dedicated fdlibm __kernel_tan (faithful <=1 ULP); the sin/cos ratio is :: ~2 ULP. q*pi/2 reduction, odd q uses the -cot path. See +rd-tan. |= x=@rd ^- @rd @@ -1751,6 +1754,7 @@ :: .~0.7753974965943197 :: ++ asin + ~/ %asin :: fdlibm rational kernel; see +rd-ainv. Faithful to <=1 ULP; |x|>1 -> NaN. |= x=@rd ^- @rd (asn:rd-ainv x) @@ -1766,6 +1770,7 @@ :: .~0.7953988301652518 :: ++ acos + ~/ %acos |= x=@rd ^- @rd (acs:rd-ainv x) :: +rd-ainv: shared asin/acos engine for the @rd door (rational P/Q kernel), @@ -1851,6 +1856,7 @@ :: .~1.2626272558398273 :: ++ atan + ~/ %atan :: fdlibm breakpoint reduction + minimax poly; odd. Round-nearest-even :: internally (the SoftFloat jet matches). |= x=@rd ^- @rd @@ -1915,6 +1921,7 @@ :: .~2.3561944902107888 :: ++ atan2 + ~/ %atan2 |= [y=@rd x=@rd] ^- @rd ?: (gth x .~0) (atan (div y x)) @@ -1939,6 +1946,7 @@ :: .8 :: Source ++ pow-n + ~/ %pow-n |= [x=@rd n=@rd] ^- @rd ?: =(n .~0) .~1 ?> &((gth n .~0) (is-int n)) @@ -2012,6 +2020,7 @@ :: .~0.30102999562024696 :: Source ++ log-10 + ~/ %log-10 :: e*log10(2) + log(m)/ln10, reusing +lr so the integer part is added with :: no division rounding (more accurate than log(x)/ln10). |= x=@rd ^- @rd @@ -2031,6 +2040,7 @@ :: .~-3.321928094887362 :: Source ++ log-2 + ~/ %log-2 :: e + log(m)/ln2 (integer part exact); see +lr. |= x=@rd ^- @rd ?: !(~(equ ^rd %n) x x) `@rd`0x7ff8.0000.0000.0000 @@ -2082,6 +2092,7 @@ :: .~11.313708498984685 :: Source ++ pow + ~/ %pow |= [x=@rd n=@rd] ^- @rd :: fall through on positive integers (faster) ?: &(=(n (san (need (toi n)))) (gth n .~0)) (pow-n x (san (need (toi n)))) @@ -2111,6 +2122,7 @@ :: .~316.2277660168379 :: Source ++ sqt + ~/ %sqt :: Correctly-rounded f64 square root. The stdlib f64 root is only :: faithful (off by up to 1 ULP), so seed with it and apply one Markstein :: correction (r = x - g*g via fma; g + (0.5/g)*r), which lands on the @@ -2149,6 +2161,7 @@ :: .~1.2599210498948716 :: Source ++ cbt + ~/ %cbt :: cbrt(x) = sign(x) * exp(log|x| / 3); defined for all reals (unlike pow). |= x=@rd ^- @rd ?: !(~(equ ^rd %n) x x) x :: NaN -> NaN diff --git a/libmath/vere/jets/i/math.c b/libmath/vere/jets/i/math.c index e4cecb7..5315671 100644 --- a/libmath/vere/jets/i/math.c +++ b/libmath/vere/jets/i/math.c @@ -105,59 +105,417 @@ typedef int64_t c3_ds; return _rd_scale2(p.d, k); } -/* @rd log -- math.hoon ++rd ++log -** x = 2^e * m, m in [sqrt(1/2),sqrt(2)); log(x) = e*ln2 + log(1+f), -** f = m-1, s = f/(2+f), log(1+f) = f - s*(f - 2z*P2(z)), z=s*s, P2 the -** atanh series 1/3 + z/5 + z^2/7 + ... +/* @rd log/log-2/log-10 -- math.hoon ++rd ++log/++log-2/++log-10/++lr +** lr: x = 2^e * m, m in [sqrt(1/2),sqrt(2)); returns [e-as-rd, log(1+f)] with +** f=m-1, s=f/(2+f), log(1+f) = f - s*(f - 2z*P2(z)), z=s*s, P2 the atanh +** series 1/3 + z/5 + ... log/log-2/log-10 recombine the integer part. */ - static float64_t - _rd_log(float64_t x) - { - static const c3_d cs[10] = { // atanh-series coeffs (math.hoon:1988) + // +lr (math.hoon:2043): for finite positive x, -> *ef = e as @rd, *lm = log(m) + static void _rd_lr(float64_t x, float64_t* ef, float64_t* lm) { + static const c3_d cs[10] = { 0x3fd5555555555555ULL, 0x3fc999999999999aULL, 0x3fc2492492492492ULL, 0x3fbc71c71c71c71cULL, 0x3fb745d1745d1746ULL, 0x3fb3b13b13b13b14ULL, 0x3fb1111111111111ULL, 0x3fae1e1e1e1e1e1eULL, 0x3faaf286bca1af28ULL, - 0x3fa8618618618618ULL - }; - union doub r0, xx, m, f, s, z, p, c, rr, l1, efd, hi, lo, one, zero; - - zero.c = 0; + 0x3fa8618618618618ULL }; + union doub r0, xx, m, f, s, z, p, c, rr, l1, efd, one, zero; + zero.c = 0; one.c = 0x3ff0000000000000ULL; r0.d = x; - if ( !f64_eq(x, x) ) { r0.c = _RD_QNAN; return r0.d; } // NaN - if ( r0.c == _RD_PINF ) { return x; } // +inf - if ( (r0.c == 0) || (r0.c == 0x8000000000000000ULL) ) { r0.c = _RD_NINF; return r0.d; } // +-0 -> -inf - if ( (r0.c >> 63) == 1 ) { r0.c = _RD_QNAN; return r0.d; } // x<0 -> NaN - - int sub = ( ((r0.c >> 52) & 0x7ffULL) == 0 ); + int sub = ( ((r0.c >> 52) & 0x7ffULL) == 0 ); xx = r0; if ( sub ) xx.d = f64_mul(x, _rd_bits(0x4350000000000000ULL).d); // x * 2^54 - c3_ds ae = sub ? -54 : 0; - c3_d b = xx.c; - c3_ds ef = (c3_ds)((b >> 52) & 0x7ffULL) - 1023; + c3_ds ae = sub ? -54 : 0; + c3_d b = xx.c; + c3_ds e = (c3_ds)((b >> 52) & 0x7ffULL) - 1023; m.c = (b & 0xfffffffffffffULL) | 0x3ff0000000000000ULL; // m in [1,2) - - int big = f64_le(_rd_bits(0x3ff6a09e667f3bcdULL).d, m.d); // m >= sqrt(2) - if ( big ) { m.d = f64_mul(m.d, _rd_bits(0x3fe0000000000000ULL).d); ef = ef + 1; } - ef = ef + ae; - - one.c = 0x3ff0000000000000ULL; + if ( f64_le(_rd_bits(0x3ff6a09e667f3bcdULL).d, m.d) ) { // m >= sqrt(2) + m.d = f64_mul(m.d, _rd_bits(0x3fe0000000000000ULL).d); e = e + 1; + } + e = e + ae; f.d = f64_sub(m.d, one.d); s.d = f64_div(f.d, f64_add(m.d, one.d)); z.d = f64_mul(s.d, s.d); - p.c = 0; - for ( int i = 10; i-- != 0; ) { // Horner over flop(cs): c9..c0 - c.c = cs[i]; - p.d = f64_add(f64_mul(p.d, z.d), c.d); + for ( int i = 10; i-- != 0; ) { c.c = cs[i]; p.d = f64_add(f64_mul(p.d, z.d), c.d); } + rr.d = f64_mul(f64_add(z.d, z.d), p.d); + l1.d = f64_sub(f.d, f64_mul(s.d, f64_sub(f.d, rr.d))); + efd.d = ui64_to_f64( (c3_d)(e < 0 ? -e : e) ); + if ( e < 0 ) efd.d = f64_sub(zero.d, efd.d); + *ef = efd.d; *lm = l1.d; + } + // shared guard: 0 on NaN/+inf/+-0/x<0 returned via *out + static int _rd_log_guard(float64_t x, float64_t* out) { + union doub r0; r0.d = x; + if ( !f64_eq(x, x) ) { r0.c = _RD_QNAN; *out = r0.d; return 1; } + if ( r0.c == _RD_PINF ) { *out = x; return 1; } + if ( (r0.c == 0)||(r0.c == 0x8000000000000000ULL) ) { r0.c = _RD_NINF; *out = r0.d; return 1; } + if ( (r0.c >> 63) == 1 ) { r0.c = _RD_QNAN; *out = r0.d; return 1; } + return 0; + } + static float64_t _rd_log(float64_t x) { + float64_t g, ef, lm; union doub hi, lo; + if ( _rd_log_guard(x, &g) ) return g; + _rd_lr(x, &ef, &lm); + hi.d = f64_mul(ef, _rd_bits(0x3fe62e42fee00000ULL).d); // e*ln2hi + lo.d = f64_mul(ef, _rd_bits(0x3dea39ef35793c76ULL).d); // e*ln2lo + return f64_add(hi.d, f64_add(lm, lo.d)); + } + static float64_t _rd_log2(float64_t x) { + float64_t g, ef, lm; + if ( _rd_log_guard(x, &g) ) return g; + _rd_lr(x, &ef, &lm); // e + lm/ln2 + return f64_add(ef, f64_mul(lm, _rd_bits(0x3ff71547652b82feULL).d)); + } + static float64_t _rd_log10(float64_t x) { + float64_t g, ef, lm; + if ( _rd_log_guard(x, &g) ) return g; + _rd_lr(x, &ef, &lm); // e*log10(2) + lm/ln10 + return f64_add(f64_mul(ef, _rd_bits(0x3fd34413509f79ffULL).d), + f64_mul(lm, _rd_bits(0x3fdbcb7b1526e50eULL).d)); + } + + static inline float64_t _rd_neg(float64_t a) { union doub z; z.c=0; return f64_sub(z.d, a); } + +/* @rd sin/cos -- math.hoon ++rd ++sin/++cos/++rd-trig +** x = q*(pi/2) + (rhi+rlo) (2-part pi/2), fdlibm sin/cos kernels by q&3. +*/ + static const c3_d _RD_SC[8] = { // sin kernel coeffs (math.hoon:1611) + 0xbfc5555555555555ULL, 0x3f81111111111111ULL, 0xbf2a01a01a01a01aULL, + 0x3ec71de3a556c734ULL, 0xbe5ae64567f544e4ULL, 0x3de6124613a86d09ULL, + 0xbd6ae7f3e733b81fULL, 0x3ce952c77030ad4aULL + }; + static const c3_d _RD_CC[8] = { // cos kernel coeffs (math.hoon:1618) + 0x3fa5555555555555ULL, 0xbf56c16c16c16c17ULL, 0x3efa01a01a01a01aULL, + 0xbe927e4fb7789f5cULL, 0x3e21eed8eff8d898ULL, 0xbda93974a8c07c9dULL, + 0x3d2ae7f3e733b81fULL, 0xbca6827863b97d97ULL + }; + + static float64_t _rd_ksin(float64_t xx, float64_t yy) { + union doub z, r, v, aa, bb, dd, c, half; + half.c = 0x3fe0000000000000ULL; + z.d = f64_mul(xx, xx); + r.c = 0; // Horner over flop(tail sc): sc[7..1] + for ( int i = 8; i-- != 1; ) { c.c = _RD_SC[i]; r.d = f64_add(f64_mul(r.d, z.d), c.d); } + v.d = f64_mul(z.d, xx); + aa.d = f64_sub(f64_mul(half.d, yy), f64_mul(v.d, r.d)); + bb.d = f64_sub(f64_mul(z.d, aa.d), yy); + dd.d = f64_sub(bb.d, f64_mul(v.d, _rd_bits(_RD_SC[0]).d)); + return f64_sub(xx, dd.d); + } + static float64_t _rd_kcos(float64_t xx, float64_t yy) { + union doub z, rc, hz, w2, aa, bb, c, half, one; + half.c = 0x3fe0000000000000ULL; one.c = 0x3ff0000000000000ULL; + z.d = f64_mul(xx, xx); + rc.c = 0; // Horner over flop(cc): cc[7..0] + for ( int i = 8; i-- != 0; ) { c.c = _RD_CC[i]; rc.d = f64_add(f64_mul(rc.d, z.d), c.d); } + hz.d = f64_mul(half.d, z.d); + w2.d = f64_sub(one.d, hz.d); + aa.d = f64_sub(f64_sub(one.d, w2.d), hz.d); + bb.d = f64_sub(f64_mul(f64_mul(z.d, z.d), rc.d), f64_mul(xx, yy)); + return f64_add(w2.d, f64_add(aa.d, bb.d)); + } + // trig-fin: is_sin ? sin(x) : cos(x); ax=|x|, sb=sign bit (math.hoon:1643) + static float64_t _rd_trigfin(int is_sin, float64_t ax, c3_d sb) { + union doub qf, t, w, rhi, rlo, ks, kc, v; + c3_ds q = (c3_ds)f64_to_i64(f64_mul(ax, _rd_bits(0x3fe45f306dc9c883ULL).d), + softfloat_round_near_even, 0); // round(ax*2/pi) + c3_d aq = (c3_d)(q < 0 ? -q : q); + qf.d = ui64_to_f64(aq); + t.d = f64_sub(ax, f64_mul(qf.d, _rd_bits(0x3ff921fb54400000ULL).d)); // ax - qf*pi/2_hi + w.d = f64_mul(qf.d, _rd_bits(0x3dd0b4611a626331ULL).d); // qf*pi/2_lo + rhi.d = f64_sub(t.d, w.d); + rlo.d = f64_sub(f64_sub(t.d, rhi.d), w.d); + int m = (int)(aq & 3); + ks.d = _rd_ksin(rhi.d, rlo.d); + kc.d = _rd_kcos(rhi.d, rlo.d); + if ( is_sin ) { + v.d = (m==0) ? ks.d : (m==1) ? kc.d : (m==2) ? _rd_neg(ks.d) : _rd_neg(kc.d); + return (sb == 1) ? _rd_neg(v.d) : v.d; + } + return (m==0) ? kc.d : (m==1) ? _rd_neg(ks.d) : (m==2) ? _rd_neg(kc.d) : ks.d; + } + static float64_t _rd_sin(float64_t x) { + union doub r0, ax; + r0.d = x; + if ( !f64_eq(x, x) ) { r0.c = _RD_QNAN; return r0.d; } // NaN + if ( (r0.c == _RD_PINF)||(r0.c == _RD_NINF) ) { r0.c = _RD_QNAN; return r0.d; } // +-inf -> NaN + if ( (r0.c == 0)||(r0.c == 0x8000000000000000ULL) ) { return x; } // +-0 -> +-0 + ax.c = r0.c & 0x7fffffffffffffffULL; + return _rd_trigfin(1, ax.d, r0.c >> 63); + } + static float64_t _rd_cos(float64_t x) { + union doub r0, ax; + r0.d = x; + if ( !f64_eq(x, x) ) { r0.c = _RD_QNAN; return r0.d; } // NaN + if ( (r0.c == _RD_PINF)||(r0.c == _RD_NINF) ) { r0.c = _RD_QNAN; return r0.d; } // +-inf -> NaN + ax.c = r0.c & 0x7fffffffffffffffULL; + return _rd_trigfin(0, ax.d, 0); + } + +/* @rd tan -- math.hoon ++rd ++tan/++rd-tan (fdlibm __kernel_tan) +** q*pi/2 reduction; big |x|~pi/4 reduced; odd q -> -cot path. +*/ + static float64_t _rd_ktan(float64_t x, float64_t y, c3_ds iy) { + static const c3_d rl[6] = { // math.hoon:1700 + 0x3fc111111110fe7aULL, 0x3f9664f48406d637ULL, 0x3f6d6d22c9560328ULL, + 0x3f4344d8f2f26501ULL, 0x3f147e88a03792a6ULL, 0xbef375cbdb605373ULL }; + static const c3_d vl[6] = { // math.hoon:1705 + 0x3faba1ba1bb341feULL, 0x3f8226e3e96e8493ULL, 0x3f57dbc8fee08315ULL, + 0x3f3026f71a8d1068ULL, 0x3f12b80f32f0a7e9ULL, 0x3efb2a7074bf7ad4ULL }; + union doub xb, ax, xa, ya, xr, yr, z, w, c, rr, vp, vv, s, r, w2; + union doub one, mone, two, third; + one.c=0x3ff0000000000000ULL; mone.c=0xbff0000000000000ULL; + two.c=0x4000000000000000ULL; third.c=0x3fd5555555555563ULL; + xb.d = x; + c3_d hxneg = xb.c >> 63; + ax.c = xb.c & 0x7fffffffffffffffULL; + int big = f64_le(_rd_bits(0x3fe5942800000000ULL).d, ax.d); // |x| >= ~0.674 + xa.d = (hxneg == 1) ? _rd_neg(x) : x; + ya.d = (hxneg == 1) ? _rd_neg(y) : y; + if ( big ) { // pio4_hi - xa + (pio4_lo - ya) + xr.d = f64_add(f64_sub(_rd_bits(0x3fe921fb54442d18ULL).d, xa.d), + f64_sub(_rd_bits(0x3c81a62633145c07ULL).d, ya.d)); + yr.c = 0; + } else { xr.d = x; yr.d = y; } + z.d = f64_mul(xr.d, xr.d); + w.d = f64_mul(z.d, z.d); + rr.c = 0; + for ( int i = 6; i-- != 0; ) { c.c = rl[i]; rr.d = f64_add(f64_mul(rr.d, w.d), c.d); } + vp.c = 0; + for ( int i = 6; i-- != 0; ) { c.c = vl[i]; vp.d = f64_add(f64_mul(vp.d, w.d), c.d); } + vv.d = f64_mul(z.d, vp.d); + s.d = f64_mul(z.d, xr.d); + r.d = f64_add(yr.d, f64_mul(z.d, f64_add(f64_mul(s.d, f64_add(rr.d, vv.d)), yr.d))); + r.d = f64_add(r.d, f64_mul(third.d, s.d)); + w2.d = f64_add(xr.d, r.d); + if ( big ) { + union doub fac, v, t1; + fac.d = (hxneg == 1) ? mone.d : one.d; + v.d = (iy == 1) ? one.d : mone.d; + t1.d = f64_sub(f64_div(f64_mul(w2.d, w2.d), f64_add(w2.d, v.d)), r.d); + t1.d = f64_mul(two.d, f64_sub(xr.d, t1.d)); + return f64_mul(fac.d, f64_sub(v.d, t1.d)); + } + if ( iy == 1 ) return w2.d; + { union doub zz, vv2, a, tt, ss; // -cot path + zz.c = w2.c & 0xffffffff00000000ULL; + vv2.d = f64_sub(r.d, f64_sub(zz.d, xr.d)); + a.d = f64_div(mone.d, w2.d); + tt.c = a.c & 0xffffffff00000000ULL; + ss.d = f64_add(one.d, f64_mul(tt.d, zz.d)); + return f64_add(tt.d, f64_mul(a.d, f64_add(ss.d, f64_mul(tt.d, vv2.d)))); + } + } + static float64_t _rd_tan(float64_t x) { + union doub r0, ax, qf, t, w, rhi, rlo, res; + r0.d = x; + if ( !f64_eq(x, x) ) { r0.c = _RD_QNAN; return r0.d; } + if ( (r0.c == _RD_PINF)||(r0.c == _RD_NINF) ) { r0.c = _RD_QNAN; return r0.d; } + if ( (r0.c == 0)||(r0.c == 0x8000000000000000ULL) ) { return x; } + c3_d neg = r0.c >> 63; + ax.c = r0.c & 0x7fffffffffffffffULL; + c3_ds q = (c3_ds)f64_to_i64(f64_mul(ax.d, _rd_bits(0x3fe45f306dc9c883ULL).d), + softfloat_round_near_even, 0); + c3_d aq = (c3_d)(q < 0 ? -q : q); + qf.d = ui64_to_f64(aq); + t.d = f64_sub(ax.d, f64_mul(qf.d, _rd_bits(0x3ff921fb54400000ULL).d)); + w.d = f64_mul(qf.d, _rd_bits(0x3dd0b4611a626331ULL).d); + rhi.d = f64_sub(t.d, w.d); + rlo.d = f64_sub(f64_sub(t.d, rhi.d), w.d); + c3_ds iy = ((aq & 1) == 0) ? 1 : -1; + res.d = _rd_ktan(rhi.d, rlo.d, iy); + return (neg == 1) ? _rd_neg(res.d) : res.d; + } + +/* @rd atan/atan2 -- math.hoon ++rd ++atan/++rd-atan/++atan2 +** fdlibm breakpoint reduction (7/16,11/16,19/16,39/16) + degree-10 minimax. +*/ + static float64_t _rd_atan(float64_t x) { + static const c3_d at[11] = { // fdlibm aT[] (math.hoon:1869) + 0x3fd555555555550dULL, 0xbfc999999998ebc4ULL, 0x3fc24924920083ffULL, + 0xbfbc71c6fe231671ULL, 0x3fb745cdc54c206eULL, 0xbfb3b0f2af749a6dULL, + 0x3fb10d66a0d03d51ULL, 0xbfadde2d52defd9aULL, 0x3fa97b4b24760debULL, + 0xbfa2b4442c6a6c2fULL, 0x3f90ad3ae322da11ULL }; + union doub r0, ax, xr, hi, lo, z, sp, s, c, res, one, two, ohf; + r0.d = x; + if ( !f64_eq(x, x) ) { r0.c = _RD_QNAN; return r0.d; } // NaN + if ( r0.c == _RD_PINF ) { r0.c = 0x3ff921fb54442d18ULL; return r0.d; } // +inf -> pi/2 + if ( r0.c == _RD_NINF ) { r0.c = 0xbff921fb54442d18ULL; return r0.d; } // -inf -> -pi/2 + if ( (r0.c == 0)||(r0.c == 0x8000000000000000ULL) ) { return x; } // +-0 + c3_d neg = r0.c >> 63; + ax.c = r0.c & 0x7fffffffffffffffULL; + one.c=0x3ff0000000000000ULL; two.c=0x4000000000000000ULL; ohf.c=0x3ff8000000000000ULL; + int dir = 0; + if ( f64_lt(ax.d, _rd_bits(0x3fdc000000000000ULL).d) ) { // |x| < 7/16 + xr.d = ax.d; hi.c = 0; lo.c = 0; dir = 1; + } else if ( f64_lt(ax.d, _rd_bits(0x3fe6000000000000ULL).d) ) { // < 11/16 + xr.d = f64_div(f64_sub(f64_add(ax.d, ax.d), one.d), f64_add(two.d, ax.d)); + hi.c = 0x3fddac670561bb4fULL; lo.c = 0x3c7a2b7f222f65e2ULL; // atan(0.5) + } else if ( f64_lt(ax.d, _rd_bits(0x3ff3000000000000ULL).d) ) { // < 19/16 + xr.d = f64_div(f64_sub(ax.d, one.d), f64_add(ax.d, one.d)); + hi.c = 0x3fe921fb54442d18ULL; lo.c = 0x3c81a62633145c07ULL; // atan(1)=pi/4 + } else if ( f64_lt(ax.d, _rd_bits(0x4003800000000000ULL).d) ) { // < 39/16 + xr.d = f64_div(f64_sub(ax.d, ohf.d), f64_add(one.d, f64_mul(ohf.d, ax.d))); + hi.c = 0x3fef730bd281f69bULL; lo.c = 0x3c7007887af0cbbdULL; // atan(1.5) + } else { // -1/x + xr.d = f64_div(_rd_bits(0xbff0000000000000ULL).d, ax.d); + hi.c = 0x3ff921fb54442d18ULL; lo.c = 0x3c91a62633145c07ULL; // pi/2 + } + z.d = f64_mul(xr.d, xr.d); + sp.c = 0; + for ( int i = 11; i-- != 0; ) { c.c = at[i]; sp.d = f64_add(f64_mul(sp.d, z.d), c.d); } + s.d = f64_mul(z.d, sp.d); + if ( dir ) res.d = f64_sub(xr.d, f64_mul(xr.d, s.d)); + else res.d = f64_sub(hi.d, f64_sub(f64_sub(f64_mul(xr.d, s.d), lo.d), xr.d)); + return (neg == 1) ? _rd_neg(res.d) : res.d; + } + static float64_t _rd_atan2(float64_t y, float64_t x) { + union doub xb, pi, pi2, mpi2, zero; + zero.c = 0; pi.c = 0x400921fb54442d18ULL; + pi2.c = 0x3ff921fb54442d18ULL; mpi2.c = 0xbff921fb54442d18ULL; + xb.d = x; + if ( f64_lt(zero.d, x) ) return _rd_atan(f64_div(y, x)); // x>0 + if ( f64_lt(x, zero.d) && f64_le(zero.d, y) ) // x<0,y>=0 + return f64_add(_rd_atan(f64_div(y, x)), pi.d); + if ( f64_lt(x, zero.d) && f64_lt(y, zero.d) ) // x<0,y<0 + return f64_sub(_rd_atan(f64_div(y, x)), pi.d); + if ( (xb.c == 0) && f64_lt(zero.d, y) ) return pi2.d; // x==+0,y>0 + if ( (xb.c == 0) && f64_lt(y, zero.d) ) return mpi2.d; // x==+0,y<0 + return zero.d; + } + +/* @rd asin/acos -- math.hoon ++rd ++asin/++acos/++rd-ainv +** fdlibm rational P/Q kernel; sqt is correctly-rounded (= f64_sqrt). +*/ + static float64_t _rd_ainv_rr(float64_t t) { // R(t) = P(t)/Q(t) (math.hoon:1775) + static const c3_d ps[6] = { + 0x3fc5555555555555ULL, 0xbfd4d61203eb6f7dULL, 0x3fc9c1550e884455ULL, + 0xbfa48228b5688f3bULL, 0x3f49efe07501b288ULL, 0x3f023de10dfdf709ULL }; + static const c3_d qs[4] = { + 0xc0033a271c8a2d4bULL, 0x40002ae59c598ac8ULL, 0xbfe6066c1b8d0159ULL, + 0x3fb3b8c5b12e9282ULL }; + union doub pp, qq, c, one; + one.c = 0x3ff0000000000000ULL; + pp.c = 0; + for ( int i = 6; i-- != 0; ) { c.c = ps[i]; pp.d = f64_add(f64_mul(pp.d, t), c.d); } + qq.c = 0; + for ( int i = 4; i-- != 0; ) { c.c = qs[i]; qq.d = f64_add(f64_mul(qq.d, t), c.d); } + return f64_div(f64_mul(t, pp.d), f64_add(one.d, f64_mul(t, qq.d))); + } + static float64_t _rd_asin(float64_t x) { + union doub r0, ax, t, w, r, s, res, half, one, two, pio2h, pio2l, pio4; + half.c=0x3fe0000000000000ULL; one.c=0x3ff0000000000000ULL; two.c=0x4000000000000000ULL; + pio2h.c=0x3ff921fb54442d18ULL; pio2l.c=0x3c91a62633145c07ULL; pio4.c=0x3fe921fb54442d18ULL; + r0.d = x; + if ( !f64_eq(x, x) ) { r0.c = _RD_QNAN; return r0.d; } // NaN + c3_d sgn = r0.c >> 63; + ax.c = r0.c & 0x7fffffffffffffffULL; + if ( f64_lt(one.d, ax.d) ) { r0.c = _RD_QNAN; return r0.d; } // |x|>1 -> NaN + if ( ax.c == one.c ) // |x|==1 + return f64_add(f64_mul(x, pio2h.d), f64_mul(x, pio2l.d)); + if ( f64_lt(ax.d, half.d) ) { // |x|<0.5 + if ( f64_lt(ax.d, _rd_bits(0x3e50000000000000ULL).d) ) return x; // tiny + t.d = f64_mul(x, x); + return f64_add(x, f64_mul(x, _rd_ainv_rr(t.d))); + } + w.d = f64_sub(one.d, ax.d); + t.d = f64_mul(w.d, half.d); + r.d = _rd_ainv_rr(t.d); + s.d = f64_sqrt(t.d); + if ( f64_le(_rd_bits(0x3fef333300000000ULL).d, ax.d) ) { // near 1 + res.d = f64_sub(pio2h.d, f64_sub(f64_mul(two.d, f64_add(s.d, f64_mul(s.d, r.d))), pio2l.d)); + return (sgn == 1) ? _rd_neg(res.d) : res.d; + } + { union doub df, cc, p2, q2; // head/tail + df.c = s.c & 0xffffffff00000000ULL; + cc.d = f64_div(f64_sub(t.d, f64_mul(df.d, df.d)), f64_add(s.d, df.d)); + p2.d = f64_sub(f64_mul(two.d, f64_mul(s.d, r.d)), f64_sub(pio2l.d, f64_mul(two.d, cc.d))); + q2.d = f64_sub(pio4.d, f64_mul(two.d, df.d)); + res.d = f64_sub(pio4.d, f64_sub(p2.d, q2.d)); + return (sgn == 1) ? _rd_neg(res.d) : res.d; + } + } + static float64_t _rd_acos(float64_t x) { + union doub r0, ax, z, s, r, w, half, one, two, pi, pio2h, pio2l; + half.c=0x3fe0000000000000ULL; one.c=0x3ff0000000000000ULL; two.c=0x4000000000000000ULL; + pi.c=0x400921fb54442d18ULL; pio2h.c=0x3ff921fb54442d18ULL; pio2l.c=0x3c91a62633145c07ULL; + r0.d = x; + if ( !f64_eq(x, x) ) { r0.c = _RD_QNAN; return r0.d; } // NaN + c3_d neg = r0.c >> 63; + ax.c = r0.c & 0x7fffffffffffffffULL; + if ( f64_lt(one.d, ax.d) ) { r0.c = _RD_QNAN; return r0.d; } // |x|>1 -> NaN + if ( ax.c == one.c ) { // |x|==1 + if ( neg == 0 ) { union doub z0; z0.c = 0; return z0.d; } // 1 -> 0 + return f64_add(pi.d, f64_mul(two.d, pio2l.d)); // -1 -> pi + } + if ( f64_lt(ax.d, half.d) ) { // |x|<0.5 + if ( f64_lt(ax.d, _rd_bits(0x3c60000000000000ULL).d) ) return pio2h.d; // tiny -> pi/2 + z.d = f64_mul(x, x); + r.d = _rd_ainv_rr(z.d); + return f64_sub(pio2h.d, f64_sub(x, f64_sub(pio2l.d, f64_mul(x, r.d)))); + } + if ( neg == 1 ) { // x <= -0.5 + z.d = f64_mul(f64_add(one.d, x), half.d); + s.d = f64_sqrt(z.d); + r.d = _rd_ainv_rr(z.d); + w.d = f64_sub(f64_mul(r.d, s.d), pio2l.d); + return f64_sub(pi.d, f64_mul(two.d, f64_add(s.d, w.d))); + } + { union doub df, cc; // x >= 0.5 + z.d = f64_mul(f64_sub(one.d, x), half.d); + s.d = f64_sqrt(z.d); + df.c = s.c & 0xffffffff00000000ULL; + cc.d = f64_div(f64_sub(z.d, f64_mul(df.d, df.d)), f64_add(s.d, df.d)); + r.d = _rd_ainv_rr(z.d); + w.d = f64_add(f64_mul(r.d, s.d), cc.d); + return f64_mul(two.d, f64_add(df.d, w.d)); } - rr.d = f64_mul(f64_add(z.d, z.d), p.d); // 2z * P2 - l1.d = f64_sub(f.d, f64_mul(s.d, f64_sub(f.d, rr.d))); // f - s*(f - r) + } + +/* @rd sqt/cbt -- math.hoon ++rd ++sqt/++cbt +** sqt: correctly-rounded f64 sqrt (the Markstein-corrected Hoon == f64_sqrt). +** cbt: sign(x) * exp(log|x| / 3). +*/ + static float64_t _rd_sqt(float64_t x) { + union doub r0; r0.d = x; + if ( !f64_eq(x, x) ) { r0.c = _RD_QNAN; return r0.d; } // NaN + if ( r0.c == _RD_PINF ) { return x; } // +inf + if ( (r0.c == 0)||(r0.c == 0x8000000000000000ULL) ) { return x; } // +-0 + if ( (r0.c >> 63) == 1 ) { r0.c = _RD_QNAN; return r0.d; } // x<0 -> NaN + return f64_sqrt(x); + } + static float64_t _rd_cbt(float64_t x) { + union doub r0, ax, r; + r0.d = x; + if ( !f64_eq(x, x) ) { return x; } // NaN -> NaN + if ( (r0.c == 0)||(r0.c == 0x8000000000000000ULL) ) { return x; } // +-0 + ax.c = r0.c & 0x7fffffffffffffffULL; + r.d = _rd_exp(f64_mul(_rd_log(ax.d), _rd_bits(0x3fd5555555555555ULL).d)); // exp(log|x|/3) + return ((r0.c >> 63) == 1) ? _rd_neg(r.d) : r.d; + } - efd.d = ui64_to_f64( (c3_d)(ef < 0 ? -ef : ef) ); - if ( ef < 0 ) efd.d = f64_sub(zero.d, efd.d); // e as @rd - hi.d = f64_mul(efd.d, _rd_bits(0x3fe62e42fee00000ULL).d); // e*ln2hi - lo.d = f64_mul(efd.d, _rd_bits(0x3dea39ef35793c76ULL).d); // e*ln2lo - return f64_add(hi.d, f64_add(l1.d, lo.d)); +/* @rd pow/pow-n -- math.hoon ++rd ++pow/++pow-n +** pow-n: x^n by repeated mul (n a positive integer as @rd). +** pow: positive-integer fast path -> pow-n, else exp(n*log x). +*/ + static float64_t _rd_pow_n(float64_t x, float64_t n) { + union doub nn, p, one, two; + one.c = 0x3ff0000000000000ULL; two.c = 0x4000000000000000ULL; + nn.d = n; + if ( nn.c == 0 ) return one.d; // n == +0 -> 1 + p.d = x; + while ( !f64_lt(n, two.d) ) { // while n >= 2: p *= x; n -= 1 + p.d = f64_mul(p.d, x); + n = f64_sub(n, one.d); + } + return p.d; + } + static float64_t _rd_pow(float64_t x, float64_t n) { + union doub nn, ni, zero; + zero.c = 0; nn.d = n; + ni.d = i64_to_f64(f64_to_i64(n, softfloat_round_near_even, 0)); // san (need (toi n)) + if ( (nn.c == ni.c) && f64_lt(zero.d, n) ) // positive integer + return _rd_pow_n(x, ni.d); + return _rd_exp(f64_mul(n, _rd_log(x))); // exp(n*log x) } #ifndef MATH_JET_HARNESS @@ -202,4 +560,128 @@ typedef int64_t c3_ds; } u3_noun u3wi_rd_log(u3_noun cor) { return _rd_jet(cor, _rd_log); } + u3_noun u3qi_rd_sin(u3_atom a) + { + union doub c, e; + softfloat_roundingMode = softfloat_round_near_even; + c.c = u3r_chub(0, a); + e.d = _rd_sin(c.d); + return u3i_chubs(1, &e.c); + } + u3_noun u3wi_rd_sin(u3_noun cor) { return _rd_jet(cor, _rd_sin); } + + u3_noun u3qi_rd_cos(u3_atom a) + { + union doub c, e; + softfloat_roundingMode = softfloat_round_near_even; + c.c = u3r_chub(0, a); + e.d = _rd_cos(c.d); + return u3i_chubs(1, &e.c); + } + u3_noun u3wi_rd_cos(u3_noun cor) { return _rd_jet(cor, _rd_cos); } + + u3_noun u3qi_rd_tan(u3_atom a) + { + union doub c, e; + softfloat_roundingMode = softfloat_round_near_even; + c.c = u3r_chub(0, a); + e.d = _rd_tan(c.d); + return u3i_chubs(1, &e.c); + } + u3_noun u3wi_rd_tan(u3_noun cor) { return _rd_jet(cor, _rd_tan); } + + u3_noun u3qi_rd_atan(u3_atom a) + { + union doub c, e; + softfloat_roundingMode = softfloat_round_near_even; + c.c = u3r_chub(0, a); + e.d = _rd_atan(c.d); + return u3i_chubs(1, &e.c); + } + u3_noun u3wi_rd_atan(u3_noun cor) { return _rd_jet(cor, _rd_atan); } + + u3_noun u3qi_rd_atan2(u3_atom y, u3_atom x) + { + union doub yy, xx, e; + softfloat_roundingMode = softfloat_round_near_even; + yy.c = u3r_chub(0, y); + xx.c = u3r_chub(0, x); + e.d = _rd_atan2(yy.d, xx.d); + return u3i_chubs(1, &e.c); + } + u3_noun u3wi_rd_atan2(u3_noun cor) + { + u3_noun y, x; + if ( c3n == u3r_mean(cor, {u3x_sam_2, &y}, {u3x_sam_3, &x}) || + c3n == u3ud(y) || c3n == u3ud(x) ) { + return u3m_bail(c3__exit); + } + return u3qi_rd_atan2(y, x); + } + + u3_noun u3qi_rd_asin(u3_atom a) + { + union doub c, e; + softfloat_roundingMode = softfloat_round_near_even; + c.c = u3r_chub(0, a); + e.d = _rd_asin(c.d); + return u3i_chubs(1, &e.c); + } + u3_noun u3wi_rd_asin(u3_noun cor) { return _rd_jet(cor, _rd_asin); } + + u3_noun u3qi_rd_acos(u3_atom a) + { + union doub c, e; + softfloat_roundingMode = softfloat_round_near_even; + c.c = u3r_chub(0, a); + e.d = _rd_acos(c.d); + return u3i_chubs(1, &e.c); + } + u3_noun u3wi_rd_acos(u3_noun cor) { return _rd_jet(cor, _rd_acos); } + + u3_noun u3qi_rd_log2(u3_atom a) + { union doub c,e; softfloat_roundingMode=softfloat_round_near_even; + c.c=u3r_chub(0,a); e.d=_rd_log2(c.d); return u3i_chubs(1,&e.c); } + u3_noun u3wi_rd_log2(u3_noun cor) { return _rd_jet(cor, _rd_log2); } + + u3_noun u3qi_rd_log10(u3_atom a) + { union doub c,e; softfloat_roundingMode=softfloat_round_near_even; + c.c=u3r_chub(0,a); e.d=_rd_log10(c.d); return u3i_chubs(1,&e.c); } + u3_noun u3wi_rd_log10(u3_noun cor) { return _rd_jet(cor, _rd_log10); } + + u3_noun u3qi_rd_sqt(u3_atom a) + { union doub c,e; softfloat_roundingMode=softfloat_round_near_even; + c.c=u3r_chub(0,a); e.d=_rd_sqt(c.d); return u3i_chubs(1,&e.c); } + u3_noun u3wi_rd_sqt(u3_noun cor) { return _rd_jet(cor, _rd_sqt); } + + u3_noun u3qi_rd_cbt(u3_atom a) + { union doub c,e; softfloat_roundingMode=softfloat_round_near_even; + c.c=u3r_chub(0,a); e.d=_rd_cbt(c.d); return u3i_chubs(1,&e.c); } + u3_noun u3wi_rd_cbt(u3_noun cor) { return _rd_jet(cor, _rd_cbt); } + + // pow / pow-n: sample is [x=@rd n=@rd] + static u3_noun _rd_jet2(u3_noun cor, float64_t (*fun)(float64_t, float64_t)) + { + u3_noun x, n; + if ( c3n == u3r_mean(cor, {u3x_sam_2, &x}, {u3x_sam_3, &n}) || + c3n == u3ud(x) || c3n == u3ud(n) ) { + return u3m_bail(c3__exit); + } + { union doub xx, nn, e; + softfloat_roundingMode = softfloat_round_near_even; + xx.c = u3r_chub(0, x); nn.c = u3r_chub(0, n); + e.d = fun(xx.d, nn.d); + return u3i_chubs(1, &e.c); + } + } + u3_noun u3qi_rd_pow(u3_atom x, u3_atom n) + { union doub xx,nn,e; softfloat_roundingMode=softfloat_round_near_even; + xx.c=u3r_chub(0,x); nn.c=u3r_chub(0,n); e.d=_rd_pow(xx.d,nn.d); return u3i_chubs(1,&e.c); } + u3_noun u3wi_rd_pow(u3_noun cor) { return _rd_jet2(cor, _rd_pow); } + + u3_noun u3qi_rd_pow_n(u3_atom x, u3_atom n) + { union doub xx,nn,e; softfloat_roundingMode=softfloat_round_near_even; + xx.c=u3r_chub(0,x); nn.c=u3r_chub(0,n); e.d=_rd_pow_n(xx.d,nn.d); return u3i_chubs(1,&e.c); } + u3_noun u3wi_rd_pow_n(u3_noun cor) { return _rd_jet2(cor, _rd_pow_n); } + #endif diff --git a/libmath/vere/test/rd_check.c b/libmath/vere/test/rd_check.c index d91affc..9b7e363 100644 --- a/libmath/vere/test/rd_check.c +++ b/libmath/vere/test/rd_check.c @@ -21,6 +21,18 @@ static void emit(const char* nm, double x, float64_t (*fun)(float64_t)) { nm, (unsigned long long)in.c, (unsigned long long)out.c, x); } +// two-arg: prints ` 0x 0x 0x` (the verifier reads cols 2,3,4) +static void emit2(const char* nm, double a, double b, + float64_t (*fun)(float64_t, float64_t)) { + union { double f; uint64_t b; } ua, ub; ua.f = a; ub.f = b; + union doub xa, xb, out; + xa.c = ua.b; xb.c = ub.b; + out.d = fun(xa.d, xb.d); + printf("%-6s 0x%016llx 0x%016llx 0x%016llx (%g,%g)\n", + nm, (unsigned long long)xa.c, (unsigned long long)xb.c, + (unsigned long long)out.c, a, b); +} + int main(void) { softfloat_roundingMode = softfloat_round_near_even; @@ -36,5 +48,56 @@ int main(void) { 1.0e300, 5.0e-324 }; for (unsigned i = 0; i < sizeof lg/sizeof lg[0]; i++) emit("log", lg[i], _rd_log); + // trig: span several pi/2 quadrants + negatives + near-zero + static const double tr[] = { 0.0, 0.5, 1.0, 1.5707963267948966, 2.0, 3.0, + 3.141592653589793, 4.0, 5.0, 6.283185307179586, 10.0, 100.0, 1000.0, + -1.0, -2.0, -0.5, 0.1, -0.1, 1.0e6 }; + for (unsigned i = 0; i < sizeof tr/sizeof tr[0]; i++) emit("sin", tr[i], _rd_sin); + for (unsigned i = 0; i < sizeof tr/sizeof tr[0]; i++) emit("cos", tr[i], _rd_cos); + // tan: incl near-poles (close to pi/2), small, large, negatives + static const double tn[] = { 0.0, 0.5, 1.0, 1.5, 1.5707963267948966, 2.0, 3.0, + 3.141592653589793, 4.0, 0.7, -1.0, -2.0, 0.1, -0.1, 10.0, 100.0, 0.674 }; + for (unsigned i = 0; i < sizeof tn/sizeof tn[0]; i++) emit("tan", tn[i], _rd_tan); + // atan: spans all breakpoints (7/16,11/16,19/16,39/16) + large + negatives + static const double at[] = { 0.0, 0.1, 0.4, 0.5, 0.6, 0.7, 1.0, 1.1, 1.5, 2.0, + 2.4, 3.0, 10.0, 100.0, 1.0e10, -0.5, -1.0, -2.0, -10.0 }; + for (unsigned i = 0; i < sizeof at/sizeof at[0]; i++) emit("atan", at[i], _rd_atan); + // asin/acos: domain [-1,1], spanning <0.5, [0.5,0.975), near-1, +-1, tiny, OOB + static const double iv[] = { 0.0, 0.1, 0.3, 0.5, 0.6, 0.7, 0.9, 0.975, 0.99, + 1.0, -1.0, -0.5, -0.7, -0.9, 0.25, -0.25, 2.0 }; + for (unsigned i = 0; i < sizeof iv/sizeof iv[0]; i++) emit("asin", iv[i], _rd_asin); + for (unsigned i = 0; i < sizeof iv/sizeof iv[0]; i++) emit("acos", iv[i], _rd_acos); + // log-2 / log-10: positive domain (reuse lg) + for (unsigned i = 0; i < sizeof lg/sizeof lg[0]; i++) emit("log-2", lg[i], _rd_log2); + for (unsigned i = 0; i < sizeof lg/sizeof lg[0]; i++) emit("log-10", lg[i], _rd_log10); + // sqt: non-negative; cbt: all reals + static const double sq[] = { 0.0, 1.0, 2.0, 4.0, 0.25, 1.0e5, 1.0e-5, 3.0, + 100.0, 1.0e300, 1.0e-300 }; + for (unsigned i = 0; i < sizeof sq/sizeof sq[0]; i++) emit("sqt", sq[i], _rd_sqt); + static const double cb[] = { 0.0, 1.0, 2.0, 8.0, 27.0, -8.0, -2.0, 0.125, + 1.0e9, -1.0e9, 0.5, -0.5 }; + for (unsigned i = 0; i < sizeof cb/sizeof cb[0]; i++) emit("cbt", cb[i], _rd_cbt); + + // --- two-arg functions ------------------------------------------------ + // atan2(y,x): all quadrants + axes + zero cases + static const double a2[][2] = { + {1.0,1.0}, {1.0,-1.0}, {-1.0,1.0}, {-1.0,-1.0}, {0.0,1.0}, {0.0,-1.0}, + {1.0,0.0}, {-1.0,0.0}, {3.0,4.0}, {-3.0,4.0}, {2.0,0.5}, {0.1,100.0}, + {100.0,0.1}, {0.0,0.0} }; + for (unsigned i = 0; i < sizeof a2/sizeof a2[0]; i++) + emit2("atan2", a2[i][0], a2[i][1], _rd_atan2); + // pow(x,n): integer + fractional exponents, negatives, fast-path + exp/log + static const double pw[][2] = { + {2.0,10.0}, {2.0,0.5}, {2.0,-1.0}, {3.0,3.0}, {10.0,2.0}, {0.5,2.0}, + {2.0,3.0}, {5.0,0.0}, {9.0,0.5}, {2.0,0.1}, {1.5,4.0}, {7.0,2.0} }; + for (unsigned i = 0; i < sizeof pw/sizeof pw[0]; i++) + emit2("pow", pw[i][0], pw[i][1], _rd_pow); + // pow-n(x,n): positive-integer exponents (repeated mul) + static const double pn[][2] = { + {2.0,3.0}, {2.0,10.0}, {3.0,4.0}, {10.0,2.0}, {1.5,2.0}, {2.0,1.0}, + {5.0,3.0}, {7.0,2.0}, {0.5,4.0}, {2.0,8.0} }; + for (unsigned i = 0; i < sizeof pn/sizeof pn[0]; i++) + emit2("pow-n", pn[i][0], pn[i][1], _rd_pow_n); + return 0; } diff --git a/libmath/vere/test/verify.sh b/libmath/vere/test/verify.sh new file mode 100755 index 0000000..0393c94 --- /dev/null +++ b/libmath/vere/test/verify.sh @@ -0,0 +1,44 @@ +#!/bin/sh +# verify.sh [fn2 ...] -- diff harness outputs against the live Hoon +# (:rd:math) in the tmux 'dev' ship, bit-for-bit. Run ./build.sh first to +# refresh /tmp/rd_harness.txt; this script reuses it. +# +# ./build.sh > /tmp/rd_harness.txt 2>/dev/null +# ./verify.sh exp log sin cos +norm() { printf '%s' "$1" | tr -d '0xX.' | sed 's/^0*//'; } # canonical hex (no 0x/dots/leading-0) +# minimal dot-grouped @rd literal: strip leading 0s, group every 4 from the right +# (so 0x0000000000000000 -> 0x0, not a wrapping 0x0000.0000.0000.0000) +dotg() { + h=$(printf '%s' "$1" | sed 's/^0x//;s/^0*//'); [ -z "$h" ] && h=0 + printf '0x%s' "$(printf '%s' "$h" | rev | sed 's/.\{4\}/&./g;s/\.$//' | rev)" +} +# warmup: wait until the dojo answers a known query (clears stale pane state) +tmux clear-history -t dev 2>/dev/null +i=0 +while [ $i -lt 20 ]; do + tmux send-keys -t dev C-c 2>/dev/null; sleep 0.3; tmux send-keys -t dev C-u 2>/dev/null; sleep 0.3 + tmux send-keys -t dev -l '`@ux`(exp:rd:math `@rd`0x3ff0.0000.0000.0000)' 2>/dev/null; sleep 0.2 + tmux send-keys -t dev Enter 2>/dev/null; sleep 1.5 + tmux capture-pane -t dev -p 2>/dev/null | grep -qE '^0x4005.bf0a' && break + i=$((i+1)) +done + +for FN in "$@"; do + ok=0; bad=0 + grep "^$FN " /tmp/rd_harness.txt | while read -r f in out _; do + din=$(dotg "$in") + tmux send-keys -t dev C-c 2>/dev/null; sleep 0.4 + tmux send-keys -t dev C-u 2>/dev/null; sleep 0.4 + tmux send-keys -t dev -l "\`@ux\`($FN:rd:math \`@rd\`$din)" 2>/dev/null; sleep 0.3 + tmux send-keys -t dev Enter 2>/dev/null; sleep 1.6 + got=$(tmux capture-pane -t dev -p 2>/dev/null | grep -E '^0x[0-9a-f]' | tail -1) + if [ "$(norm "$got")" = "$(norm "$out")" ]; then + ok=$((ok+1)) + else + bad=$((bad+1)); printf 'DIFF %s %s hoon=%s C=%s\n' "$FN" "$in" "$got" "$out" + fi + printf '%s\n' "$ok $bad" > /tmp/rd_tally.$FN + done + read o b < /tmp/rd_tally.$FN 2>/dev/null + printf '== %s: %s OK, %s DIFF ==\n' "$FN" "${o:-0}" "${b:-0}" +done diff --git a/libmath/vere/test/verify_clean.sh b/libmath/vere/test/verify_clean.sh new file mode 100755 index 0000000..b5bc040 --- /dev/null +++ b/libmath/vere/test/verify_clean.sh @@ -0,0 +1,34 @@ +#!/bin/sh +# verify_clean.sh [fn2 ...] +# One-at-a-time, NO C-c (SIGINT corrupts the loom mid-event). Clears the dojo +# line with C-u only, generous spacing, checks ship liveness after every query. +# Compares harness /tmp/rd_harness.txt outputs against live (:rd:math) bit- +# for-bit. Aborts immediately and names the killer input if the serf dies. +SES="$1"; shift +norm() { printf '%s' "$1" | tr -d '0xX.' | sed 's/^0*//'; } +dotg() { + h=$(printf '%s' "$1" | sed 's/^0x//;s/^0*//'); [ -z "$h" ] && h=0 + printf '0x%s' "$(printf '%s' "$h" | rev | sed 's/.\{4\}/&./g;s/\.$//' | rev)" +} +alive() { pgrep -fq "urbit -F $SES" && return 0 || return 1; } +ask() { # $1 = dojo expression; echoes first 0x line of the response + tmux send-keys -t "$SES" C-u 2>/dev/null; sleep 0.3 + tmux send-keys -t "$SES" -l "$1" 2>/dev/null; sleep 0.3 + tmux send-keys -t "$SES" Enter 2>/dev/null; sleep 1.6 + tmux capture-pane -t "$SES" -p 2>/dev/null | grep -E '^0x[0-9a-f]' | tail -1 +} + +for FN in "$@"; do + ok=0; bad=0; dead=0 + while read -r f in out _; do + [ "$f" = "$FN" ] || continue + alive || { echo "ABORT: ship dead before $FN $in"; dead=1; break; } + din=$(dotg "$in") + got=$(ask "\`@ux\`($FN:rd:math \`@rd\`$din)") + if ! alive; then echo "KILLER: $FN $din (ship died on this input)"; dead=1; break; fi + if [ "$(norm "$got")" = "$(norm "$out")" ]; then ok=$((ok+1)) + else bad=$((bad+1)); printf 'DIFF %s %s hoon=%s C=%s\n' "$FN" "$din" "$got" "$out"; fi + done < /tmp/rd_harness.txt + printf '== %s: %s OK, %s DIFF%s ==\n' "$FN" "$ok" "$bad" "$([ $dead = 1 ] && echo ' (ABORTED)')" + [ $dead = 1 ] && break +done From 2423ef1fd954326ca20b210f499ee99a7063e4da Mon Sep 17 00:00:00 2001 From: Sigilante Date: Thu, 11 Jun 2026 22:31:59 -0500 Subject: [PATCH 04/28] math: split vere jet mirror into vere/ (32-bit) + vere64/ (64-bit) Mirror /lib/lagoon's layout: maintain both runtimes' vendored jet files under libmath/, in noun/jets/ form. The two math.c copies differ by exactly two lines -- the two-arg u3r_mean form (brace-pair {axis,&p} on 64-bit vere-ml64 vs flat varargs on 32-bit vere), because that macro's API diverged between the runtimes. Everything else (15 algorithm cores, 12 single-arg wrappers, helpers) is byte-identical: marshalling is chub-based and word-size-agnostic. - libmath/vere/ noun/jets/{i/math.c,135/tree.c,q.h,w.h} -- 32-bit - libmath/vere64/ noun/jets/{i/math.c,135/tree.c,q.h,w.h} -- 64-bit (+ test/) Both built and verified bit-exact: full -test suite (math-exp/log/sqrt/ainv/ atan/tan/trig/derived) passes ok=%.y on a jetted 32-bit AND 64-bit fakeship, plus the standalone harness's 234 single+two-arg vectors. Vendor 135 only (the stock test ships' hoon-version; apply to 136/137 only if a target needs them). Drop the now-redundant tree-registration.snippet.c (the full vendored tree.c plus the rewritten README supersede it). README documents the 2-line divergence, per-word-size apply steps, the door-anchor gotcha, -test verification, and the SIGINT-corrupts-the-loom warning. Co-Authored-By: Claude Opus 4.8 --- libmath/vere/README.md | 63 +- libmath/vere/jets/tree-registration.snippet.c | 38 - libmath/vere/noun/jets/135/tree.c | 1310 +++++++++++++++++ libmath/vere/noun/jets/i/math.c | 687 +++++++++ libmath/vere/noun/jets/q.h | 322 ++++ libmath/vere/noun/jets/w.h | 449 ++++++ libmath/vere64/README.md | 106 ++ libmath/vere64/noun/jets/135/tree.c | 1309 ++++++++++++++++ libmath/{vere => vere64/noun}/jets/i/math.c | 0 libmath/vere64/noun/jets/q.h | 322 ++++ libmath/vere64/noun/jets/w.h | 449 ++++++ libmath/{vere => vere64}/test/build.sh | 0 libmath/{vere => vere64}/test/rd_check.c | 12 +- libmath/{vere => vere64}/test/verify.sh | 0 libmath/{vere => vere64}/test/verify_clean.sh | 0 15 files changed, 4966 insertions(+), 101 deletions(-) delete mode 100644 libmath/vere/jets/tree-registration.snippet.c create mode 100644 libmath/vere/noun/jets/135/tree.c create mode 100644 libmath/vere/noun/jets/i/math.c create mode 100644 libmath/vere/noun/jets/q.h create mode 100644 libmath/vere/noun/jets/w.h create mode 100644 libmath/vere64/README.md create mode 100644 libmath/vere64/noun/jets/135/tree.c rename libmath/{vere => vere64/noun}/jets/i/math.c (100%) create mode 100644 libmath/vere64/noun/jets/q.h create mode 100644 libmath/vere64/noun/jets/w.h rename libmath/{vere => vere64}/test/build.sh (100%) rename libmath/{vere => vere64}/test/rd_check.c (91%) rename libmath/{vere => vere64}/test/verify.sh (100%) rename libmath/{vere => vere64}/test/verify_clean.sh (100%) diff --git a/libmath/vere/README.md b/libmath/vere/README.md index 208323a..6298380 100644 --- a/libmath/vere/README.md +++ b/libmath/vere/README.md @@ -1,59 +1,6 @@ -# libmath C jets (vere mirror) +# libmath C jets — 32-bit vere mirror -C jet implementations for the `math.hoon` transcendental library, **vendored -from the vere runtime** (`pkg/noun`). The jets do not live in this repo's build -— this directory is a maintained mirror so the C and the Hoon evolve together. -There is no automatic cross-repo sync; apply changes to vere by hand. - -## What's here -- `jets/i/math.c` — the jet bodies. Each runs the IDENTICAL algorithm as its - Hoon arm in Berkeley SoftFloat, so jet output is **bit-exact** to the pure-Hoon - reference (not merely faithful). Marshalling is chub-based (word-size-agnostic; - the divergence that broke the @rq sub jet). Currently: `@rd exp`. -- `jets/tree-registration.snippet.c` — the `tree.c` registration block to add to - each per-kelvin jet tree, plus the q.h/w.h/build.zig one-liners. - -## How to apply to vere (`pkg/noun`) -1. Copy `jets/i/math.c` → `pkg/noun/jets/i/math.c`. -2. Add the registration block from `jets/tree-registration.snippet.c` to - **each** of `pkg/noun/jets/13{5,6,7}/tree.c` (the active tree is picked by the - ship's `hoon-version`; numerics ships are 136, stock test ships 135). `math` - registers under the `non` chapter as a sibling of `lagoon`. -3. Declare in `pkg/noun/jets/q.h` (`u3qi_rd_exp`) and `w.h` (`u3wi_rd_exp`). -4. Add `"jets/i/math.c"` to the jet source list in `pkg/noun/build.zig`. -5. Rebuild; on a 64-bit build use `-Dvere64=true`. - -## CRITICAL: the Hoon jet structure (the gotcha that cost a day) -`math.hoon` must mirror `/lib/lagoon`'s jet structure exactly: - -``` -=< math :: export the engine so `/+ math` + `rd:math` work -~% %non ..part ~ :: file |% anchored to the shared %non chapter -|% -++ math - ^| - =+ [rnd=*?(%n %u %d %z)] :: <-- REQUIRED: the engine must be a DOOR - ~/ %math :: (sample-bearing), not a bare |% - |% - ++ rd - ~/ %rd - ^| - |_ [r=... rtol=...] - ++ exp ~/ %exp |=(x=@rd ...) -``` - -A **sample-less `~/`-hinted core anchors its parent to the dashboard ROOT**, so -`%math` (and everything under it) misses the hot dashboard — the core SPOTs in -`_cj_mile` but `_cj_hot_mean` returns `jax=0` and no C jet ever attaches. The -`^| =+ [rnd]` sample makes `~/` resolve the parent to `%non`, exactly as -lagoon's `++ la ^| =+ [rnd] ~/ %lagoon |%` does. Verified via a `_cj_hot_mean` -trace: `math par=0 MISS` (bare |%) -> `math par=non FOUND` (door). - -The chapter chain is `pen -> hex -> non -> math -> -> `, e.g. -`non/math/rd/exp`. - -## Verifying a jet fires -`~>(%bout (exp:rd:math .~1))` should report a few µs (jetted) vs hundreds of µs -(interpreted), and `` `@ux`(exp:rd:math .~1) `` must equal `0x4005.bf0a.8b14.576a` -(bit-exact). Use `tmux` for the ship so the dojo stays interactive; jet -registration only warms on first computation of each core (not at boot). +Vendored from the 32-bit `urbit/vere` runtime (`pkg/noun/jets`). This is the +32-bit twin of `libmath/vere64/`; the two `math.c` copies differ by exactly two +lines (the `u3r_mean` two-arg form). See **`../vere64/README.md`** for the full +documentation, apply steps, the Hoon jet-structure gotcha, and verification. diff --git a/libmath/vere/jets/tree-registration.snippet.c b/libmath/vere/jets/tree-registration.snippet.c deleted file mode 100644 index 082c5b5..0000000 --- a/libmath/vere/jets/tree-registration.snippet.c +++ /dev/null @@ -1,38 +0,0 @@ -// math.hoon transcendental jets -- tree.c registration. -// -// Add this block to EACH per-hoon-kelvin tree in the vere runtime: -// pkg/noun/jets/135/tree.c, .../136/tree.c, .../137/tree.c -// (the active tree is chosen by the ship's `hoon-version`; numerics ships are -// 136, the stock urbit/urbit ships used for testing are 135). -// -// Place the three static decls just BEFORE `static u3j_core _13X_non_d[]` -// (next to the lagoon `_13X_non__la_core_d` block), then add the "math" entry -// to `_13X_non_d[]` as a sibling of "lagoon". Replace 13X with 135/136/137. - -// --- decls (before _13X_non_d) ------------------------------------------ -// One harm per arm of the rd door; add a line here per jetted @rd fn. -static u3j_harm _13X_non__math_rd_exp_a[] = {{".2", u3wi_rd_exp}, {}}; -static u3j_harm _13X_non__math_rd_log_a[] = {{".2", u3wi_rd_log}, {}}; -static u3j_core _13X_non__math_rd_d[] = - { { "exp", 7, _13X_non__math_rd_exp_a, 0, no_hashes }, - { "log", 7, _13X_non__math_rd_log_a, 0, no_hashes }, - {} - }; -static u3j_core _13X_non__math_d[] = - { { "rd", 7, 0, _13X_non__math_rd_d, no_hashes }, - {} - }; - -// --- entry (inside _13X_non_d[], next to "lagoon") ---------------------- -// { "lagoon", 7, 0, _13X_non__la_core_d, no_hashes }, - { "math", 7, 0, _13X_non__math_d, no_hashes }, -// { "mice", 7, _13X_non__mice_a, 0, no_hashes }, // (136/135 only) -// {} -// }; - -// --- header decls (pkg/noun/jets/q.h and w.h) --------------------------- -// q.h: u3_noun u3qi_rd_exp(u3_atom); -// w.h: u3_noun u3wi_rd_exp(u3_noun); - -// --- build (pkg/noun/build.zig, in the jet .c source list) -------------- -// "jets/i/math.c", diff --git a/libmath/vere/noun/jets/135/tree.c b/libmath/vere/noun/jets/135/tree.c new file mode 100644 index 0000000..4ee583e --- /dev/null +++ b/libmath/vere/noun/jets/135/tree.c @@ -0,0 +1,1310 @@ +#include "c3/c3.h" +#include "jets.h" +#include "jets/w.h" + + +static c3_c* no_hashes[] = { 0 }; + +static u3j_harm _135_hex_mimes_base16_en_a[] = {{".2", u3we_en_base16}, {}}; +static u3j_harm _135_hex_mimes_base16_de_a[] = {{".2", u3we_de_base16}, {}}; +static u3j_core _135_hex_mimes_base16_d[] = + { { "en", 7, _135_hex_mimes_base16_en_a, 0, no_hashes }, + { "de", 7, _135_hex_mimes_base16_de_a, 0, no_hashes }, + {} + }; +static u3j_core _135_hex_mimes_d[] = + { { "base16", 3, 0, _135_hex_mimes_base16_d, no_hashes }, + {} + }; + +static u3j_harm _135_hex_aes_ecba_en_a[] = {{".2", u3wea_ecba_en}, {}}; +static u3j_harm _135_hex_aes_ecba_de_a[] = {{".2", u3wea_ecba_de}, {}}; +static u3j_core _135_hex_aes_ecba_d[] = + { { "en", 7, _135_hex_aes_ecba_en_a, 0, no_hashes }, + { "de", 7, _135_hex_aes_ecba_de_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_hex_aes_ecbb_en_a[] = {{".2", u3wea_ecbb_en}, {}}; +static u3j_harm _135_hex_aes_ecbb_de_a[] = {{".2", u3wea_ecbb_de}, {}}; +static u3j_core _135_hex_aes_ecbb_d[] = + { { "en", 7, _135_hex_aes_ecbb_en_a, 0, no_hashes }, + { "de", 7, _135_hex_aes_ecbb_de_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_hex_aes_ecbc_en_a[] = {{".2", u3wea_ecbc_en}, {}}; +static u3j_harm _135_hex_aes_ecbc_de_a[] = {{".2", u3wea_ecbc_de}, {}}; +static u3j_core _135_hex_aes_ecbc_d[] = + { { "en", 7, _135_hex_aes_ecbc_en_a, 0, no_hashes }, + { "de", 7, _135_hex_aes_ecbc_de_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_hex_aes_cbca_en_a[] = {{".2", u3wea_cbca_en}, {}}; +static u3j_harm _135_hex_aes_cbca_de_a[] = {{".2", u3wea_cbca_de}, {}}; +static u3j_core _135_hex_aes_cbca_d[] = + { { "en", 7, _135_hex_aes_cbca_en_a, 0, no_hashes }, + { "de", 7, _135_hex_aes_cbca_de_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_hex_aes_cbcb_en_a[] = {{".2", u3wea_cbcb_en}, {}}; +static u3j_harm _135_hex_aes_cbcb_de_a[] = {{".2", u3wea_cbcb_de}, {}}; +static u3j_core _135_hex_aes_cbcb_d[] = + { { "en", 7, _135_hex_aes_cbcb_en_a, 0, no_hashes }, + { "de", 7, _135_hex_aes_cbcb_de_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_hex_aes_cbcc_en_a[] = {{".2", u3wea_cbcc_en}, {}}; +static u3j_harm _135_hex_aes_cbcc_de_a[] = {{".2", u3wea_cbcc_de}, {}}; +static u3j_core _135_hex_aes_cbcc_d[] = + { { "en", 7, _135_hex_aes_cbcc_en_a, 0, no_hashes }, + { "de", 7, _135_hex_aes_cbcc_de_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_hex_aes_siva_en_a[] = {{".2", u3wea_siva_en}, {}}; +static u3j_harm _135_hex_aes_siva_de_a[] = {{".2", u3wea_siva_de}, {}}; +static u3j_core _135_hex_aes_siva_d[] = + { { "en", 7, _135_hex_aes_siva_en_a, 0, no_hashes }, + { "de", 7, _135_hex_aes_siva_de_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_hex_aes_sivb_en_a[] = {{".2", u3wea_sivb_en}, {}}; +static u3j_harm _135_hex_aes_sivb_de_a[] = {{".2", u3wea_sivb_de}, {}}; +static u3j_core _135_hex_aes_sivb_d[] = + { { "en", 7, _135_hex_aes_sivb_en_a, 0, no_hashes }, + { "de", 7, _135_hex_aes_sivb_de_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_hex_aes_sivc_en_a[] = {{".2", u3wea_sivc_en}, {}}; +static u3j_harm _135_hex_aes_sivc_de_a[] = {{".2", u3wea_sivc_de}, {}}; +static u3j_core _135_hex_aes_sivc_d[] = + { { "en", 7, _135_hex_aes_sivc_en_a, 0, no_hashes }, + { "de", 7, _135_hex_aes_sivc_de_a, 0, no_hashes }, + {} + }; +static u3j_core _135_hex_aes_d[] = + { { "ecba", 7, 0, _135_hex_aes_ecba_d, no_hashes }, + { "ecbb", 7, 0, _135_hex_aes_ecbb_d, no_hashes }, + { "ecbc", 7, 0, _135_hex_aes_ecbc_d, no_hashes }, + { "cbca", 7, 0, _135_hex_aes_cbca_d, no_hashes }, + { "cbcb", 7, 0, _135_hex_aes_cbcb_d, no_hashes }, + { "cbcc", 7, 0, _135_hex_aes_cbcc_d, no_hashes }, + { "siva", 7, 0, _135_hex_aes_siva_d, no_hashes }, + { "sivb", 7, 0, _135_hex_aes_sivb_d, no_hashes }, + { "sivc", 7, 0, _135_hex_aes_sivc_d, no_hashes }, + {} + }; + +static u3j_harm _135_hex_leer_a[] = {{".2", u3we_leer}, {}}; +static u3j_harm _135_hex_lore_a[] = {{".2", u3we_lore}, {}}; +static u3j_harm _135_hex_loss_a[] = {{".2", u3we_loss}, {}}; +static u3j_harm _135_hex_lune_a[] = {{".2", u3we_lune}, {}}; + + +static u3j_harm _135_hex__adler32_a[] = {{".2", u3we_adler32, c3y}, {}}; +static u3j_core _135_hex__adler_d[] = + { { "adler32", 7, _135_hex__adler32_a, 0, no_hashes }, + {} + }; +static u3j_harm _135_hex__crc32_a[] = {{".2", u3we_crc32}, {}}; +static u3j_core _135_hex__crc_d[] = + { {"crc32", 7, _135_hex__crc32_a, 0, no_hashes }, + {} + }; + +static u3j_core _135_hex_checksum_d[] = + { { "adler", 3, 0, _135_hex__adler_d, no_hashes }, + { "crc", 3, 0, _135_hex__crc_d, no_hashes}, + {} + }; + + +static u3j_harm _135_hex__decompress_zlib_a[] = {{".2", u3we_decompress_zlib}, {}}; +static u3j_harm _135_hex__decompress_gzip_a[] = {{".2", u3we_decompress_gzip}, {}}; +static u3j_core _135_hex__zlib_d[] = { + {"decompress-zlib", 7, _135_hex__decompress_zlib_a, 0, no_hashes }, + {"decompress-gzip", 7, _135_hex__decompress_gzip_a, 0, no_hashes }, + {}}; + + +static u3j_harm _135_hex_coed__ed_scad_a[] = {{".2", u3wee_scad}, {}}; +static u3j_harm _135_hex_coed__ed_scas_a[] = {{".2", u3wee_scas}, {}}; +static u3j_harm _135_hex_coed__ed_scap_a[] = {{".2", u3wee_scap}, {}}; + +static u3j_harm _135_hex_coed__ed_puck_a[] = {{".2", u3wee_puck}, {}}; +static u3j_harm _135_hex_coed__ed_luck_a[] = {{".2", u3wee_luck}, {}}; +static u3j_harm _135_hex_coed__ed_sign_a[] = {{".2", u3wee_sign}, {}}; +static u3j_harm _135_hex_coed__ed_sign_raw_a[] = {{".2", u3wee_sign_raw}, {}}; +static u3j_harm _135_hex_coed__ed_sign_octs_a[] = {{".2", u3wee_sign_octs}, {}}; +static u3j_harm _135_hex_coed__ed_sign_octs_raw_a[] = {{".2", u3wee_sign_octs_raw}, {}}; +static u3j_harm _135_hex_coed__ed_veri_octs_a[] = {{".2", u3wee_veri_octs}, {}}; +static u3j_harm _135_hex_coed__ed_veri_a[] = {{".2", u3wee_veri}, {}}; +static u3j_harm _135_hex_coed__ed_shar_a[] = {{".2", u3wee_shar}, {}}; +static u3j_harm _135_hex_coed__ed_slar_a[] = {{".2", u3wee_slar}, {}}; + +static u3j_harm _135_hex_coed__ed_smac_a[] = + {{".2", u3wee_smac}, {}}; + +static u3j_harm _135_hex_coed__ed_recs_a[] = + {{".2", u3wee_recs}, {}}; + +static u3j_harm _135_hex_coed__ed_point_neg_a[] = + {{".2", u3wee_point_neg}, {}}; + +static u3j_harm _135_hex_coed__ed_point_add_a[] = + {{".2", u3wee_point_add}, {}}; + +static u3j_harm _135_hex_coed__ed_scalarmult_a[] = + {{".2", u3wee_scalarmult}, {}}; + +static u3j_harm _135_hex_coed__ed_scalarmult_base_a[] = + {{".2", u3wee_scalarmult_base}, {}}; + +static u3j_harm _135_hex_coed__ed_add_scalarmult_scalarmult_base_a[] = + {{".2", u3wee_add_scalarmult_scalarmult_base}, {}}; + +static u3j_harm _135_hex_coed__ed_add_double_scalarmult_a[] = + {{".2", u3wee_add_double_scalarmult}, {}}; + +static u3j_core _135_hex_coed__ed_d[] = + { { "sign", 7, _135_hex_coed__ed_sign_a, 0, no_hashes }, + { "sign-raw", 7, _135_hex_coed__ed_sign_raw_a, 0, no_hashes }, + { "sign-octs", 7, _135_hex_coed__ed_sign_octs_a, 0, no_hashes }, + { "sign-octs-raw", 7, _135_hex_coed__ed_sign_octs_raw_a, 0, no_hashes }, + { "puck", 7, _135_hex_coed__ed_puck_a, 0, no_hashes }, + { "luck", 7, _135_hex_coed__ed_luck_a, 0, no_hashes }, + { "scad", 7, _135_hex_coed__ed_scad_a, 0, no_hashes }, + { "scas", 7, _135_hex_coed__ed_scas_a, 0, no_hashes }, + { "scap", 7, _135_hex_coed__ed_scap_a, 0, no_hashes }, + { "veri-octs", 7, _135_hex_coed__ed_veri_octs_a, 0, no_hashes }, + { "veri", 7, _135_hex_coed__ed_veri_a, 0, no_hashes }, + { "shar", 7, _135_hex_coed__ed_shar_a, 0, no_hashes }, + { "slar", 7, _135_hex_coed__ed_slar_a, 0, no_hashes }, + { "point-add", 7, _135_hex_coed__ed_point_add_a, 0, 0 }, + { "point-neg", 7, _135_hex_coed__ed_point_neg_a, 0, 0 }, + { "recs", 7, _135_hex_coed__ed_recs_a, 0, 0 }, + { "smac", 7, _135_hex_coed__ed_smac_a, 0, 0 }, + { "scalarmult", 7, _135_hex_coed__ed_scalarmult_a, 0, + no_hashes }, + { "scalarmult-base", 7, _135_hex_coed__ed_scalarmult_base_a, 0, + no_hashes }, + { "add-scalarmult-scalarmult-base", 7, + _135_hex_coed__ed_add_scalarmult_scalarmult_base_a, 0, + no_hashes }, + { "add-double-scalarmult", 7, + _135_hex_coed__ed_add_double_scalarmult_a, 0, + no_hashes }, + {} + }; + +static u3j_core _135_hex_coed_d[] = + { { "ed", 3, 0, _135_hex_coed__ed_d, no_hashes }, + {} + }; + +static u3j_harm _135_hex_hmac_hmac_a[] = {{".2", u3we_hmac}, {}}; +static u3j_core _135_hex_hmac_d[] = + { { "hmac", 7, _135_hex_hmac_hmac_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_hex_argon2_a[] = {{".2", u3we_argon2}, {}}; +static u3j_core _135_hex_argon_d[] = + { { "argon2", 511, _135_hex_argon2_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_hex_scr_pbk_a[] = {{".2", u3wes_pbk, c3y}, {}}; +static u3j_harm _135_hex_scr_pbl_a[] = {{".2", u3wes_pbl, c3y}, {}}; +static u3j_harm _135_hex_scr_hsh_a[] = {{".2", u3wes_hsh, c3y}, {}}; +static u3j_harm _135_hex_scr_hsl_a[] = {{".2", u3wes_hsl, c3y}, {}}; +static u3j_core _135_hex_scr_d[] = + { { "pbk", 7, _135_hex_scr_pbk_a, 0, no_hashes }, + { "pbl", 7, _135_hex_scr_pbl_a, 0, no_hashes }, + { "hsh", 7, _135_hex_scr_hsh_a, 0, no_hashes }, + { "hsl", 7, _135_hex_scr_hsl_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_hex_secp_secp256k1_make_a[] = {{".2", u3we_make, c3y}, {}}; +static u3j_harm _135_hex_secp_secp256k1_sign_a[] = {{".2", u3we_sign, c3y}, {}}; +static u3j_harm _135_hex_secp_secp256k1_reco_a[] = {{".2", u3we_reco, c3y}, {}}; + +static u3j_harm _135_hex_secp_secp256k1_schnorr_sosi_a[] = + {{".2", u3we_sosi}, {}}; +static u3j_harm _135_hex_secp_secp256k1_schnorr_sove_a[] = + {{".2", u3we_sove}, {}}; +static u3j_core _135_hex_secp_secp256k1_schnorr_d[] = + { { "sosi", 7, + _135_hex_secp_secp256k1_schnorr_sosi_a, 0, + no_hashes }, + { "sove", 7, + _135_hex_secp_secp256k1_schnorr_sove_a, 0, + no_hashes }, + {} + }; + +static u3j_core _135_hex_secp_secp256k1_d[] = + { { "make", 7, _135_hex_secp_secp256k1_make_a, 0, no_hashes }, + { "sign", 7, _135_hex_secp_secp256k1_sign_a, 0, no_hashes }, + { "reco", 7, _135_hex_secp_secp256k1_reco_a, 0, no_hashes }, + { "schnorr", 7, 0, + _135_hex_secp_secp256k1_schnorr_d, + no_hashes }, + {} + }; +static u3j_core _135_hex_secp_d[] = + { { "secp256k1", 3, 0, _135_hex_secp_secp256k1_d, no_hashes }, + {} + }; + + +static u3j_harm _135_hex_kecc_k224_a[] = + {{".2", u3we_kecc224, c3y, c3y, c3y}, {}}; +static u3j_harm _135_hex_kecc_k256_a[] = + {{".2", u3we_kecc256, c3y, c3y, c3y}, {}}; +static u3j_harm _135_hex_kecc_k384_a[] = + {{".2", u3we_kecc384, c3y, c3y, c3y}, {}}; +static u3j_harm _135_hex_kecc_k512_a[] = + {{".2", u3we_kecc512, c3y, c3y, c3y}, {}}; +static u3j_core _135_hex_kecc_d[] = + { { "k224", 7, _135_hex_kecc_k224_a, 0, no_hashes }, + { "k256", 7, _135_hex_kecc_k256_a, 0, no_hashes }, + { "k384", 7, _135_hex_kecc_k384_a, 0, no_hashes }, + { "k512", 7, _135_hex_kecc_k512_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_hex_ripemd_160_a[] = {{".2", u3we_ripe, c3y}, {}}; +static u3j_core _135_hex_ripe_d[] = + { { "ripemd160", 7, _135_hex_ripemd_160_a, 0, no_hashes }, + {} + }; + + + +/* layer five + */ +static u3j_harm _135_pen_cell_a[] = {{".2", u3wf_cell}, {}}; +static u3j_harm _135_pen_comb_a[] = {{".2", u3wf_comb}, {}}; +static u3j_harm _135_pen_cons_a[] = {{".2", u3wf_cons}, {}}; +static u3j_harm _135_pen_core_a[] = {{".2", u3wf_core}, {}}; +static u3j_harm _135_pen_face_a[] = {{".2", u3wf_face}, {}}; +static u3j_harm _135_pen_fitz_a[] = {{".2", u3wf_fitz}, {}}; +static u3j_harm _135_pen_fork_a[] = {{".2", u3wf_fork}, {}}; + +static u3j_harm _135_pen_look_a[] = {{".2", u3wf_look}, {}}; +static u3j_harm _135_pen_loot_a[] = {{".2", u3wf_loot}, {}}; + +static u3j_harm _135_pen__ut_crop_a[] = {{".2", u3wfu_crop}, {}}; +static u3j_harm _135_pen__ut_fish_a[] = {{".2", u3wfu_fish}, {}}; +static u3j_harm _135_pen__ut_fuse_a[] = {{".2", u3wfu_fuse}, {}}; +static u3j_harm _135_pen__ut_redo_a[] = {{".2", u3wfu_redo}, {}}; +static u3j_harm _135_pen__ut_mint_a[] = {{".2", u3wfu_mint}, {}}; +static u3j_harm _135_pen__ut_mull_a[] = {{".2", u3wfu_mull}, {}}; + +static u3j_harm _135_pen__ut_nest_dext_a[] = {{".2", u3wfu_nest_dext}, {}}; +static u3j_core _135_pen__ut_nest_in_d[] = + { + { "nest-dext", 3, _135_pen__ut_nest_dext_a, 0, no_hashes }, + {} + }; +static u3j_core _135_pen__ut_nest_d[] = + { + { "nest-in", 7, 0, _135_pen__ut_nest_in_d, no_hashes }, + {} + }; + +static u3j_harm _135_pen__ut_rest_a[] = {{".2", u3wfu_rest}, {}}; + +static u3j_core _135_pen__ut_d[] = + { + { "crop", 7, _135_pen__ut_crop_a, 0, no_hashes }, + { "fish", 7, _135_pen__ut_fish_a, 0, no_hashes }, + { "fuse", 7, _135_pen__ut_fuse_a, 0, no_hashes }, + { "redo", 7, _135_pen__ut_redo_a, 0, no_hashes }, + { "mint", 7, _135_pen__ut_mint_a, 0, no_hashes }, + { "mull", 7, _135_pen__ut_mull_a, 0, no_hashes }, + { "nest", 7, 0, _135_pen__ut_nest_d, no_hashes }, + { "rest", 7, _135_pen__ut_rest_a, 0, no_hashes }, + {} + }; + +static u3j_hood _135_pen__ut_ho[] = + { { "ar", 12282 }, + { "fan", 28, c3n }, + { "rib", 58, c3n }, + { "vet", 59, c3n }, + + { "blow", 6015 }, + { "burp", 342 }, + { "busk", 1353 }, + { "buss", 374 }, + { "crop", 1494 }, + { "duck", 1524 }, + { "dune", 2991 }, + { "dunk", 3066 }, + { "epla", 12206 }, + { "emin", 1534 }, + { "emul", 6134 }, + { "feel", 1502 }, + { "felt", 94 }, + { "fine", 49086 }, + { "fire", 4 }, + { "fish", 6006 }, + { "fond", 12283 }, + { "fund", 6014 }, + // XX +funk is not part of +ut, and this hook appears to be unused + // remove from here and the +ut hint + // + { "funk", 0xbefafa, c3y, 31 }, + { "fuse", 24021 }, + { "gain", 380 }, + { "lose", 0x2fefe }, + { "mile", 382 }, + { "mine", 372 }, + { "mint", 49083 }, + { "moot", 0x2feff }, + { "mull", 24020 }, + { "nest", 92 }, + { "peel", 1526 }, + { "play", 3006 }, + { "peek", 1532 }, + { "repo", 22 }, + { "rest", 6102 }, + { "tack", 6007 }, + { "toss", 24540 }, + { "wrap", 6135 }, + {}, + }; + + +static u3j_hood _135_pen_ho[] = { + { "ap", 22 }, + { "ut", 86 }, + {}, +}; + + +/* layer four + */ +static u3j_harm _135_qua_trip_a[] = {{".2", u3we_trip}, {}}; + +static u3j_harm _135_qua_slaw_a[] = {{".2", u3we_slaw}, {}}; +static u3j_harm _135_qua_scot_a[] = {{".2", u3we_scot}, {}}; +static u3j_harm _135_qua_scow_a[] = {{".2", u3we_scow}, {}}; + +static u3j_harm _135_qua__po_ind_a[] = {{".2", u3wcp_ind}, {}}; +static u3j_harm _135_qua__po_ins_a[] = {{".2", u3wcp_ins}, {}}; +static u3j_harm _135_qua__po_tod_a[] = {{".2", u3wcp_tod}, {}}; +static u3j_harm _135_qua__po_tos_a[] = {{".2", u3wcp_tos}, {}}; +static u3j_core _135_qua__po_d[] = + { { "ind", 7, _135_qua__po_ind_a, 0, no_hashes }, + { "ins", 7, _135_qua__po_ins_a, 0, no_hashes }, + { "tod", 7, _135_qua__po_tod_a, 0, no_hashes }, + { "tos", 7, _135_qua__po_tos_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_qua__bend_fun_a[] = {{".2", u3we_bend_fun}, {}}; +static u3j_core _135_qua__bend_d[] = + { { "fun", 7, _135_qua__bend_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_qua__cold_fun_a[] = {{".2", u3we_cold_fun}, {}}; +static u3j_core _135_qua__cold_d[] = + { { "fun", 7, _135_qua__cold_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_qua__cook_fun_a[] = {{".2", u3we_cook_fun}, {}}; +static u3j_core _135_qua__cook_d[] = + { { "fun", 7, _135_qua__cook_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_qua__comp_fun_a[] = {{".2", u3we_comp_fun}, {}}; +static u3j_core _135_qua__comp_d[] = + { { "fun", 7, _135_qua__comp_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_qua__easy_fun_a[] = {{".2", u3we_easy_fun}, {}}; +static u3j_core _135_qua__easy_d[] = + { { "fun", 7, _135_qua__easy_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_qua__glue_fun_a[] = {{".2", u3we_glue_fun}, {}}; +static u3j_core _135_qua__glue_d[] = + { { "fun", 7, _135_qua__glue_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_qua__here_fun_a[] = {{".2", u3we_here_fun}, {}}; +static u3j_core _135_qua__here_d[] = + { { "fun", 7, _135_qua__here_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_qua__just_fun_a[] = {{".2", u3we_just_fun}, {}}; +static u3j_core _135_qua__just_d[] = + { { "fun", 7, _135_qua__just_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_qua__mask_fun_a[] = {{".2", u3we_mask_fun}, {}}; +static u3j_core _135_qua__mask_d[] = + { { "fun", 7, _135_qua__mask_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_qua__shim_fun_a[] = {{".2", u3we_shim_fun}, {}}; +static u3j_core _135_qua__shim_d[] = + { { "fun", 7, _135_qua__shim_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_qua__stag_fun_a[] = {{".2", u3we_stag_fun}, {}}; +static u3j_core _135_qua__stag_d[] = + { { "fun", 7, _135_qua__stag_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_qua__stew_fun_a[] = {{".2", u3we_stew_fun}, {}}; +static u3j_core _135_qua__stew_d[] = + { { "fun", 31, _135_qua__stew_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_qua__stir_fun_a[] = {{".2", u3we_stir_fun}, {}}; +static u3j_core _135_qua__stir_d[] = + { { "fun", 7, _135_qua__stir_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_qua_pfix_a[] = {{".2", u3we_pfix}, {}}; + +static u3j_harm _135_qua_plug_a[] = {{".2", u3we_plug}, {}}; +static u3j_harm _135_qua_pose_a[] = {{".2", u3we_pose}, {}}; + +static u3j_harm _135_qua_sfix_a[] = {{".2", u3we_sfix}, {}}; + +static u3j_harm _135_qua_mink_a[] = {{".2", u3we_mink}, {}}; +static u3j_harm _135_qua_mole_a[] = {{".2", u3we_mole}, {}}; +static u3j_harm _135_qua_mule_a[] = {{".2", u3we_mule}, {}}; + + +static u3j_hood _135_qua_ho[] = { + { "show", 188 }, + {}, +}; + + +/* layer three + */ +static u3j_harm _135_tri__cofl__drg_a[] = {{".2", u3wef_drg}, {}}; +static u3j_harm _135_tri__cofl__lug_a[] = {{".2", u3wef_lug}, {}}; +static u3j_core _135_tri__cofl_d[] = + { { "drg", 7, _135_tri__cofl__drg_a, 0, no_hashes }, + { "lug", 7, _135_tri__cofl__lug_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_tri__rd_add_a[] = {{".2", u3wer_add}, {}}; +static u3j_harm _135_tri__rd_sub_a[] = {{".2", u3wer_sub}, {}}; +static u3j_harm _135_tri__rd_mul_a[] = {{".2", u3wer_mul}, {}}; +static u3j_harm _135_tri__rd_div_a[] = {{".2", u3wer_div}, {}}; +static u3j_harm _135_tri__rd_sqt_a[] = {{".2", u3wer_sqt}, {}}; +static u3j_harm _135_tri__rd_fma_a[] = {{".2", u3wer_fma}, {}}; +static u3j_harm _135_tri__rd_lth_a[] = {{".2", u3wer_lth}, {}}; +static u3j_harm _135_tri__rd_lte_a[] = {{".2", u3wer_lte}, {}}; +static u3j_harm _135_tri__rd_equ_a[] = {{".2", u3wer_equ}, {}}; +static u3j_harm _135_tri__rd_gte_a[] = {{".2", u3wer_gte}, {}}; +static u3j_harm _135_tri__rd_gth_a[] = {{".2", u3wer_gth}, {}}; +static u3j_core _135_tri__rd_d[] = + { { "add", 7, _135_tri__rd_add_a, 0, no_hashes }, + { "sub", 7, _135_tri__rd_sub_a, 0, no_hashes }, + { "mul", 7, _135_tri__rd_mul_a, 0, no_hashes }, + { "div", 7, _135_tri__rd_div_a, 0, no_hashes }, + { "sqt", 7, _135_tri__rd_sqt_a, 0, no_hashes }, + { "fma", 7, _135_tri__rd_fma_a, 0, no_hashes }, + { "lth", 7, _135_tri__rd_lth_a, 0, no_hashes }, + { "lte", 7, _135_tri__rd_lte_a, 0, no_hashes }, + { "equ", 7, _135_tri__rd_equ_a, 0, no_hashes }, + { "gte", 7, _135_tri__rd_gte_a, 0, no_hashes }, + { "gth", 7, _135_tri__rd_gth_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_tri__rs_add_a[] = {{".2", u3wet_add}, {}}; +static u3j_harm _135_tri__rs_sub_a[] = {{".2", u3wet_sub}, {}}; +static u3j_harm _135_tri__rs_mul_a[] = {{".2", u3wet_mul}, {}}; +static u3j_harm _135_tri__rs_div_a[] = {{".2", u3wet_div}, {}}; +static u3j_harm _135_tri__rs_sqt_a[] = {{".2", u3wet_sqt}, {}}; +static u3j_harm _135_tri__rs_fma_a[] = {{".2", u3wet_fma}, {}}; +static u3j_harm _135_tri__rs_lth_a[] = {{".2", u3wet_lth}, {}}; +static u3j_harm _135_tri__rs_lte_a[] = {{".2", u3wet_lte}, {}}; +static u3j_harm _135_tri__rs_equ_a[] = {{".2", u3wet_equ}, {}}; +static u3j_harm _135_tri__rs_gte_a[] = {{".2", u3wet_gte}, {}}; +static u3j_harm _135_tri__rs_gth_a[] = {{".2", u3wet_gth}, {}}; +static u3j_core _135_tri__rs_d[] = + { { "add", 7, _135_tri__rs_add_a, 0, no_hashes }, + { "sub", 7, _135_tri__rs_sub_a, 0, no_hashes }, + { "mul", 7, _135_tri__rs_mul_a, 0, no_hashes }, + { "div", 7, _135_tri__rs_div_a, 0, no_hashes }, + { "sqt", 7, _135_tri__rs_sqt_a, 0, no_hashes }, + { "fma", 7, _135_tri__rs_fma_a, 0, no_hashes }, + { "lth", 7, _135_tri__rs_lth_a, 0, no_hashes }, + { "lte", 7, _135_tri__rs_lte_a, 0, no_hashes }, + { "equ", 7, _135_tri__rs_equ_a, 0, no_hashes }, + { "gte", 7, _135_tri__rs_gte_a, 0, no_hashes }, + { "gth", 7, _135_tri__rs_gth_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_tri__rq_add_a[] = {{".2", u3weq_add}, {}}; +static u3j_harm _135_tri__rq_sub_a[] = {{".2", u3weq_sub}, {}}; +static u3j_harm _135_tri__rq_mul_a[] = {{".2", u3weq_mul}, {}}; +static u3j_harm _135_tri__rq_div_a[] = {{".2", u3weq_div}, {}}; +static u3j_harm _135_tri__rq_sqt_a[] = {{".2", u3weq_sqt}, {}}; +static u3j_harm _135_tri__rq_fma_a[] = {{".2", u3weq_fma}, {}}; +static u3j_harm _135_tri__rq_lth_a[] = {{".2", u3weq_lth}, {}}; +static u3j_harm _135_tri__rq_lte_a[] = {{".2", u3weq_lte}, {}}; +static u3j_harm _135_tri__rq_equ_a[] = {{".2", u3weq_equ}, {}}; +static u3j_harm _135_tri__rq_gte_a[] = {{".2", u3weq_gte}, {}}; +static u3j_harm _135_tri__rq_gth_a[] = {{".2", u3weq_gth}, {}}; +static u3j_core _135_tri__rq_d[] = + { { "add", 7, _135_tri__rq_add_a, 0, no_hashes }, + { "sub", 7, _135_tri__rq_sub_a, 0, no_hashes }, + { "mul", 7, _135_tri__rq_mul_a, 0, no_hashes }, + { "div", 7, _135_tri__rq_div_a, 0, no_hashes }, + { "sqt", 7, _135_tri__rq_sqt_a, 0, no_hashes }, + { "fma", 7, _135_tri__rq_fma_a, 0, no_hashes }, + { "lth", 7, _135_tri__rq_lth_a, 0, no_hashes }, + { "lte", 7, _135_tri__rq_lte_a, 0, no_hashes }, + { "equ", 7, _135_tri__rq_equ_a, 0, no_hashes }, + { "gte", 7, _135_tri__rq_gte_a, 0, no_hashes }, + { "gth", 7, _135_tri__rq_gth_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_tri__rh_add_a[] = {{".2", u3wes_add}, {}}; +static u3j_harm _135_tri__rh_sub_a[] = {{".2", u3wes_sub}, {}}; +static u3j_harm _135_tri__rh_mul_a[] = {{".2", u3wes_mul}, {}}; +static u3j_harm _135_tri__rh_div_a[] = {{".2", u3wes_div}, {}}; +static u3j_harm _135_tri__rh_sqt_a[] = {{".2", u3wes_sqt}, {}}; +static u3j_harm _135_tri__rh_fma_a[] = {{".2", u3wes_fma}, {}}; +static u3j_harm _135_tri__rh_lth_a[] = {{".2", u3wes_lth}, {}}; +static u3j_harm _135_tri__rh_lte_a[] = {{".2", u3wes_lte}, {}}; +static u3j_harm _135_tri__rh_equ_a[] = {{".2", u3wes_equ}, {}}; +static u3j_harm _135_tri__rh_gte_a[] = {{".2", u3wes_gte}, {}}; +static u3j_harm _135_tri__rh_gth_a[] = {{".2", u3wes_gth}, {}}; +static u3j_core _135_tri__rh_d[] = + { { "add", 7, _135_tri__rh_add_a, 0, no_hashes }, + { "sub", 7, _135_tri__rh_sub_a, 0, no_hashes }, + { "mul", 7, _135_tri__rh_mul_a, 0, no_hashes }, + { "div", 7, _135_tri__rh_div_a, 0, no_hashes }, + { "sqt", 7, _135_tri__rh_sqt_a, 0, no_hashes }, + { "fma", 7, _135_tri__rh_fma_a, 0, no_hashes }, + { "lth", 7, _135_tri__rh_lth_a, 0, no_hashes }, + { "lte", 7, _135_tri__rh_lte_a, 0, no_hashes }, + { "equ", 7, _135_tri__rh_equ_a, 0, no_hashes }, + { "gte", 7, _135_tri__rh_gte_a, 0, no_hashes }, + { "gth", 7, _135_tri__rh_gth_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_tri__og_raw_a[] = {{".2", u3weo_raw}, {}}; +static u3j_core _135_tri__og_d[] = + { { "raw", 7, _135_tri__og_raw_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_tri__sha_sha1_a[] = {{".2", u3we_sha1}, {}}; +static u3j_core _135_tri__sha_d[] = + { { "sha1", 7, _135_tri__sha_sha1_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_tri_shax_a[] = {{".2", u3we_shax}, {}}; +static u3j_harm _135_tri_shay_a[] = {{".2", u3we_shay}, {}}; +static u3j_harm _135_tri_shas_a[] = {{".2", u3we_shas}, {}}; +static u3j_harm _135_tri_shal_a[] = {{".2", u3we_shal}, {}}; + +static u3j_harm _135_ob_fynd_a[] = {{".2", u3we_fynd_ob}, {}}; +static u3j_harm _135_ob_fein_a[] = {{".2", u3we_fein_ob}, {}}; +static u3j_core _135_ob_d[] = { + { "fein", 7, _135_ob_fein_a, 0, no_hashes }, + { "fynd", 7, _135_ob_fynd_a, 0, no_hashes }, + {} +}; +static u3j_hood _135_ob_ho[] = { + { "fein", 42 }, + { "fynd", 20 }, + {}, +}; + + +static u3j_hood _135_tri_ho[] = { + { "ob", 20 }, + { "yore", 5462 }, + { "year", 44975 }, + {}, +}; + + +/* layer two + */ +static u3j_harm _135_two_find_a[] = {{".2", u3wb_find, c3y}, {}}; +static u3j_harm _135_two_flop_a[] = {{".2", u3wb_flop, c3y}, {}}; +static u3j_harm _135_two_lent_a[] = {{".2", u3wb_lent, c3y}, {}}; +static u3j_harm _135_two_levy_a[] = {{".2", u3wb_levy, c3y}, {}}; +static u3j_harm _135_two_lien_a[] = {{".2", u3wb_lien, c3y}, {}}; +static u3j_harm _135_two_murn_a[] = {{".2", u3wb_murn, c3y}, {}}; +static u3j_harm _135_two_need_a[] = {{".2", u3wb_need, c3y}, {}}; +static u3j_harm _135_two_reap_a[] = {{".2", u3wb_reap, c3y}, {}}; +static u3j_harm _135_two_reel_a[] = {{".2", u3wb_reel, c3y}, {}}; +static u3j_harm _135_two_roll_a[] = {{".2", u3wb_roll, c3y}, {}}; +static u3j_harm _135_two_skid_a[] = {{".2", u3wb_skid, c3y}, {}}; +static u3j_harm _135_two_skim_a[] = {{".2", u3wb_skim, c3y}, {}}; +static u3j_harm _135_two_skip_a[] = {{".2", u3wb_skip, c3y}, {}}; +static u3j_harm _135_two_scag_a[] = {{".2", u3wb_scag, c3y}, {}}; +static u3j_harm _135_two_slag_a[] = {{".2", u3wb_slag, c3y}, {}}; +static u3j_harm _135_two_snag_a[] = {{".2", u3wb_snag, c3y}, {}}; +static u3j_harm _135_two_sort_a[] = {{".2", u3wb_sort, c3y}, {}}; +static u3j_harm _135_two_turn_a[] = {{".2", u3wb_turn, c3y}, {}}; +static u3j_harm _135_two_weld_a[] = {{".2", u3wb_weld, c3y}, {}}; +static u3j_harm _135_two_welp_a[] = {{".2", u3wb_welp, c3y}, {}}; +static u3j_harm _135_two_zing_a[] = {{".2", u3wb_zing, c3y}, {}}; + +static u3j_harm _135_two_bex_a[] = {{".2", u3wc_bex, c3y}, {}}; +static u3j_harm _135_two_can_a[] = {{".2", u3wc_can, c3y}, {}}; +static u3j_harm _135_two_cat_a[] = {{".2", u3wc_cat, c3y}, {}}; +static u3j_harm _135_two_con_a[] = {{".2", u3wc_con, c3y}, {}}; +static u3j_harm _135_two_cut_a[] = {{".2", u3wc_cut, c3y}, {}}; +static u3j_harm _135_two_dis_a[] = {{".2", u3wc_dis, c3y}, {}}; +static u3j_harm _135_two_dor_a[] = {{".2", u3wc_dor, c3y}, {}}; +static u3j_harm _135_two_end_a[] = {{".2", u3wc_end, c3y}, {}}; +static u3j_harm _135_two_gor_a[] = {{".2", u3wc_gor, c3y}, {}}; +static u3j_harm _135_two_lsh_a[] = {{".2", u3wc_lsh, c3y}, {}}; +static u3j_harm _135_two_met_a[] = {{".2", u3wc_met, c3y}, {}}; +static u3j_harm _135_two_mix_a[] = {{".2", u3wc_mix, c3y}, {}}; +static u3j_harm _135_two_mor_a[] = {{".2", u3wc_mor, c3y}, {}}; +static u3j_harm _135_two_mug_a[] = {{".2", u3wc_mug, c3y}, {}}; +static u3j_harm _135_two_muk_a[] = {{".2", u3wc_muk, c3y}, {}}; +static u3j_harm _135_two_pow_a[] = {{".2", u3wc_pow, c3y}, {}}; +static u3j_harm _135_two_rap_a[] = {{".2", u3wc_rap, c3y}, {}}; +static u3j_harm _135_two_rep_a[] = {{".2", u3wc_rep, c3y}, {}}; +static u3j_harm _135_two_rev_a[] = {{".2", u3wc_rev, c3y}, {}}; +static u3j_harm _135_two_rip_a[] = {{".2", u3wc_rip, c3y}, {}}; +static u3j_harm _135_two_rsh_a[] = {{".2", u3wc_rsh, c3y}, {}}; +static u3j_harm _135_two_swp_a[] = {{".2", u3wc_swp, c3y}, {}}; +static u3j_harm _135_two_sqt_a[] = {{".2", u3wc_sqt, c3y}, {}}; +static u3j_harm _135_two_xeb_a[] = {{".2", u3wc_xeb, c3y}, {}}; + +static u3j_harm _135_two__in_bif_a[] = {{".2", u3wdi_bif}, {}}; +static u3j_harm _135_two__in_del_a[] = {{".2", u3wdi_del}, {}}; +static u3j_harm _135_two__in_dif_a[] = {{".2", u3wdi_dif}, {}}; +static u3j_harm _135_two__in_gas_a[] = {{".2", u3wdi_gas}, {}}; +static u3j_harm _135_two__in_has_a[] = {{".2", u3wdi_has}, {}}; +static u3j_harm _135_two__in_int_a[] = {{".2", u3wdi_int}, {}}; +static u3j_harm _135_two__in_put_a[] = {{".2", u3wdi_put}, {}}; +static u3j_harm _135_two__in_rep_a[] = {{".2", u3wdi_rep}, {}}; +static u3j_harm _135_two__in_run_a[] = {{".2", u3wdi_run}, {}}; +static u3j_harm _135_two__in_tap_a[] = {{".2", u3wdi_tap}, {}}; +static u3j_harm _135_two__in_wyt_a[] = {{".2", u3wdi_wyt}, {}}; +static u3j_harm _135_two__in_uni_a[] = {{".2", u3wdi_uni}, {}}; + +static u3j_harm _135_two__by_all_a[] = {{".2", u3wdb_all, c3y}, {}}; +static u3j_harm _135_two__by_any_a[] = {{".2", u3wdb_any, c3y}, {}}; +static u3j_harm _135_two__by_apt_a[] = {{".2", u3wdb_apt, c3y}, {}}; + +static u3j_harm _135_two__by_del_a[] = {{".2", u3wdb_del, c3y}, {}}; +static u3j_harm _135_two__by_dif_a[] = {{".2", u3wdb_dif, c3y}, {}}; +static u3j_harm _135_two__by_gas_a[] = {{".2", u3wdb_gas, c3y}, {}}; +static u3j_harm _135_two__by_get_a[] = {{".2", u3wdb_get, c3y}, {}}; +static u3j_harm _135_two__by_has_a[] = {{".2", u3wdb_has, c3y}, {}}; +static u3j_harm _135_two__by_int_a[] = {{".2", u3wdb_int, c3y}, {}}; +static u3j_harm _135_two__by_jab_a[] = {{".2", u3wdb_jab, c3y}, {}}; +static u3j_harm _135_two__by_key_a[] = {{".2", u3wdb_key, c3y}, {}}; +static u3j_harm _135_two__by_put_a[] = {{".2", u3wdb_put, c3y}, {}}; +static u3j_harm _135_two__by_rep_a[] = {{".2", u3wdb_rep, c3y}, {}}; +static u3j_harm _135_two__by_run_a[] = {{".2", u3wdb_run, c3y}, {}}; +static u3j_harm _135_two__by_tap_a[] = {{".2", u3wdb_tap, c3y}, {}}; +static u3j_harm _135_two__by_uni_a[] = {{".2", u3wdb_uni, c3y}, {}}; +static u3j_harm _135_two__by_urn_a[] = {{".2", u3wdb_urn, c3y}, {}}; +static u3j_harm _135_two__by_wyt_a[] = {{".2", u3wdb_wyt, c3y}, {}}; + +static u3j_harm _135_two_cue_a[] = {{".2", u3we_cue}, {}}; +static u3j_harm _135_two_jam_a[] = {{".2", u3we_jam}, {}}; +static u3j_harm _135_two_mat_a[] = {{".2", u3we_mat}, {}}; +static u3j_harm _135_two_rub_a[] = {{".2", u3we_rub}, {}}; + + + +/* layer one + */ +static u3j_harm _135_one_add_a[] = {{".2", u3wa_add, c3y}, {}}; +static u3j_harm _135_one_dec_a[] = {{".2", u3wa_dec, c3y}, {}}; +static u3j_harm _135_one_div_a[] = {{".2", u3wa_div, c3y}, {}}; +static u3j_harm _135_one_dvr_a[] = {{".2", u3wc_dvr, c3y}, {}}; +static u3j_harm _135_one_gte_a[] = {{".2", u3wa_gte, c3y}, {}}; +static u3j_harm _135_one_gth_a[] = {{".2", u3wa_gth, c3y}, {}}; +static u3j_harm _135_one_lte_a[] = {{".2", u3wa_lte, c3y}, {}}; +static u3j_harm _135_one_lth_a[] = {{".2", u3wa_lth, c3y}, {}}; +static u3j_harm _135_one_max_a[] = {{".2", u3wa_max, c3y}, {}}; +static u3j_harm _135_one_min_a[] = {{".2", u3wa_min, c3y}, {}}; +static u3j_harm _135_one_mod_a[] = {{".2", u3wa_mod, c3y}, {}}; +static u3j_harm _135_one_mul_a[] = {{".2", u3wa_mul, c3y}, {}}; +static u3j_harm _135_one_sub_a[] = {{".2", u3wa_sub, c3y}, {}}; + +static u3j_harm _135_one_cap_a[] = {{".2", u3wc_cap, c3y}, {}}; +static u3j_harm _135_one_peg_a[] = {{".2", u3wc_peg, c3y}, {}}; +static u3j_harm _135_one_mas_a[] = {{".2", u3wc_mas, c3y}, {}}; + +static u3j_harm _135_lull_plot_fax_a[] = {{".2", u3wg_plot_fax, c3y}, {}}; +static u3j_harm _135_lull_plot_met_a[] = {{".2", u3wg_plot_met, c3y}, {}}; + +static u3j_core _135_lull_plot_d[] = + { { "fax", 7, _135_lull_plot_fax_a, 0, no_hashes }, + { "met", 7, _135_lull_plot_met_a, 0, no_hashes }, + {} + }; + +static u3j_core _135_lull_d[] = + { { "plot", 31, 0, _135_lull_plot_d, no_hashes }, + {} + }; + +static u3j_harm _135_hex_blake3_hash_a[] = {{".2", u3we_blake3_hash, c3y}, {}}; +static u3j_harm _135_hex_blake3_compress_a[] = {{".2", u3we_blake3_compress, c3y}, {}}; +static u3j_harm _135_hex_blake3_chunk_output_a[] = {{".2", u3we_blake3_chunk_output, c3y}, {}}; + +static u3j_core _135_hex_blake3_d[] = + { { "hash", 7, _135_hex_blake3_hash_a, 0, no_hashes }, + { "chunk-output", 7, _135_hex_blake3_chunk_output_a, 0, no_hashes }, + {} + }; + + +static u3j_core _135_hex_blake3_impl_d[] = + { { "compress", 7, _135_hex_blake3_compress_a, 0, no_hashes }, + { "blake3", 7, 0, _135_hex_blake3_d, no_hashes }, + {} + }; + +static u3j_harm _135_hex_blake2b_a[] = {{".2", u3we_blake2b, c3y}, {}}; + +static u3j_core _135_hex_blake_d[] = + { { "blake2b", 7, _135_hex_blake2b_a, 0, no_hashes }, + { "blake3-impl", 7, 0, _135_hex_blake3_impl_d, no_hashes }, + {} + }; + + +static u3j_harm _135_hex_chacha_crypt_a[] = {{".2", u3we_chacha_crypt, c3y}, {}}; +static u3j_harm _135_hex_chacha_xchacha_a[] = {{".2", u3we_chacha_xchacha, c3y}, {}}; +static u3j_core _135_hex_chacha_d[] = + { { "crypt", 7, _135_hex_chacha_crypt_a, 0, no_hashes }, + { "xchacha", 7, _135_hex_chacha_xchacha_a, 0, no_hashes }, + {} + }; + + +//+| %utilities +static u3j_harm _135_hex_bytestream_rip_octs_a[] = {{".2", u3we_bytestream_rip_octs, c3y}, {}}; +static u3j_harm _135_hex_bytestream_cat_octs_a[] = {{".2", u3we_bytestream_cat_octs, c3y}, {}}; +static u3j_harm _135_hex_bytestream_can_octs_a[] = {{".2", u3we_bytestream_can_octs, c3y}, {}}; +//+| %read-byte +static u3j_harm _135_hex_bytestream_read_byte_a[] = {{".2", u3we_bytestream_read_byte, c3y}, {}}; +//+| %read-octs +static u3j_harm _135_hex_bytestream_read_octs_a[] = {{".2", u3we_bytestream_read_octs, c3y}, {}}; +//+| %navigation +static u3j_harm _135_hex_bytestream_skip_line_a[] = {{".2", u3we_bytestream_skip_line, c3y}, {}}; +static u3j_harm _135_hex_bytestream_find_byte_a[] = {{".2", u3we_bytestream_find_byte, c3y}, {}}; +static u3j_harm _135_hex_bytestream_seek_byte_a[] = {{".2", u3we_bytestream_seek_byte, c3y}, {}}; +//+| %transformation +static u3j_harm _135_hex_bytestream_chunk_a[] = {{".2", u3we_bytestream_chunk}, {}}; +static u3j_harm _135_hex_bytestream_extract_a[] = {{".2", u3we_bytestream_extract}, {}}; +static u3j_harm _135_hex_bytestream_fuse_extract_a[] = {{".2", u3we_bytestream_fuse_extract}, {}}; +//+| %bitstream +static u3j_harm _135_hex_bytestream_need_bits_a[] = {{".2", u3we_bytestream_need_bits}, {}}; +static u3j_harm _135_hex_bytestream_drop_bits_a[] = {{".2", u3we_bytestream_drop_bits}, {}}; +// static u3j_harm _135_hex_bytestream_skip_bits_a[] = {{".2", u3we_bytestream_skip_bits}, {}}; +static u3j_harm _135_hex_bytestream_peek_bits_a[] = {{".2", u3we_bytestream_peek_bits}, {}}; +static u3j_harm _135_hex_bytestream_read_bits_a[] = {{".2", u3we_bytestream_read_bits}, {}}; +// static u3j_harm _135_hex_bytestream_read_need_bits_a[] = {{".2", u3we_bytestream_read_need_bits}, {}}; +static u3j_harm _135_hex_bytestream_byte_bits_a[] = {{".2", u3we_bytestream_byte_bits}, {}}; + +static u3j_core _135_hex_bytestream_d[] = + { //+| %utilities + {"rip-octs", 7, _135_hex_bytestream_rip_octs_a, 0, no_hashes }, + {"cat-octs", 7, _135_hex_bytestream_cat_octs_a, 0, no_hashes }, + {"can-octs", 7, _135_hex_bytestream_can_octs_a, 0, no_hashes }, + //+| %navigation + {"skip-line", 7, _135_hex_bytestream_skip_line_a, 0, no_hashes }, + {"find-byte", 7, _135_hex_bytestream_find_byte_a, 0, no_hashes }, + {"seek-byte", 7, _135_hex_bytestream_seek_byte_a, 0, no_hashes }, + //+| %read-byte + {"read-byte", 7, _135_hex_bytestream_read_byte_a, 0, no_hashes }, + //+| %read-octs + {"read-octs", 7, _135_hex_bytestream_read_octs_a, 0, no_hashes }, + //+| %transformation + {"chunk", 7, _135_hex_bytestream_chunk_a, 0, no_hashes }, + {"extract", 7, _135_hex_bytestream_extract_a, 0, no_hashes }, + {"fuse-extract", 7, _135_hex_bytestream_fuse_extract_a, 0, no_hashes }, + //+| %bitstream + {"need-bits", 7, _135_hex_bytestream_need_bits_a, 0, no_hashes }, + {"drop-bits", 7, _135_hex_bytestream_drop_bits_a, 0, no_hashes }, + // {"skip-bits", 7, _135_hex_bytestream_skip_bits_a, 0, no_hashes }, + {"peek-bits", 7, _135_hex_bytestream_peek_bits_a, 0, no_hashes }, + {"read-bits", 7, _135_hex_bytestream_read_bits_a, 0, no_hashes }, + // {"read-need-bits", 7, _135_hex_bytestream_read_need_bits_a, 0, no_hashes }, + {"byte-bits", 7, _135_hex_bytestream_byte_bits_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_hex_json_de_a[] = {{".2", u3we_json_de}, {}}; +static u3j_harm _135_hex_json_en_a[] = {{".2", u3we_json_en}, {}}; +static u3j_core _135_hex_json_d[] = + { { "de", 15, _135_hex_json_de_a, 0, no_hashes }, + { "en", 15, _135_hex_json_en_a, 0, no_hashes }, + {} + }; + +/* /lib jets in non core +*/ +static u3j_harm _135_non__lagoon_add_a[] = {{".2", u3wi_la_add}, {}}; +static u3j_harm _135_non__lagoon_sub_a[] = {{".2", u3wi_la_sub}, {}}; +static u3j_harm _135_non__lagoon_mul_a[] = {{".2", u3wi_la_mul}, {}}; +static u3j_harm _135_non__lagoon_div_a[] = {{".2", u3wi_la_div}, {}}; +static u3j_harm _135_non__lagoon_mod_a[] = {{".2", u3wi_la_mod}, {}}; +static u3j_harm _135_non__lagoon_adds_a[] = {{".2", u3wi_la_adds}, {}}; +static u3j_harm _135_non__lagoon_subs_a[] = {{".2", u3wi_la_subs}, {}}; +static u3j_harm _135_non__lagoon_muls_a[] = {{".2", u3wi_la_muls}, {}}; +static u3j_harm _135_non__lagoon_divs_a[] = {{".2", u3wi_la_divs}, {}}; +static u3j_harm _135_non__lagoon_mods_a[] = {{".2", u3wi_la_mods}, {}}; +static u3j_harm _135_non__lagoon_dot_a[] = {{".2", u3wi_la_dot}, {}}; +static u3j_harm _135_non__lagoon_trans_a[] ={{".2", u3wi_la_transpose}, {}}; +static u3j_harm _135_non__lagoon_cumsum_a[]={{".2", u3wi_la_cumsum}, {}}; +static u3j_harm _135_non__lagoon_argmin_a[]={{".2", u3wi_la_argmin}, {}}; +static u3j_harm _135_non__lagoon_argmax_a[]={{".2", u3wi_la_argmax}, {}}; +static u3j_harm _135_non__lagoon_ravel_a[]={{".2", u3wi_la_ravel}, {}}; +static u3j_harm _135_non__lagoon_min_a[] = {{".2", u3wi_la_min}, {}}; +static u3j_harm _135_non__lagoon_max_a[] = {{".2", u3wi_la_max}, {}}; +static u3j_harm _135_non__lagoon_linspace_a[]={{".2", u3wi_la_linspace}, {}}; +static u3j_harm _135_non__lagoon_range_a[]= {{".2", u3wi_la_range}, {}}; +static u3j_harm _135_non__lagoon_abs_a[] = {{".2", u3wi_la_abs}, {}}; +static u3j_harm _135_non__lagoon_gth_a[] = {{".2", u3wi_la_gth}, {}}; +static u3j_harm _135_non__lagoon_gte_a[] = {{".2", u3wi_la_gte}, {}}; +static u3j_harm _135_non__lagoon_lth_a[] = {{".2", u3wi_la_lth}, {}}; +static u3j_harm _135_non__lagoon_lte_a[] = {{".2", u3wi_la_lte}, {}}; +static u3j_harm _135_non__lagoon_diag_a[] = {{".2", u3wi_la_diag}, {}}; +static u3j_harm _135_non__lagoon_trace_a[]= {{".2", u3wi_la_trace}, {}}; +static u3j_harm _135_non__lagoon_mmul_a[] = {{".2", u3wi_la_mmul}, {}}; +static u3j_harm _135_non__mice_a[] = {{".2", u3we_mice}, {}}; + +static u3j_core _135_non__la_core_d[] = + { { "add-rays", 7, _135_non__lagoon_add_a, 0, no_hashes }, + { "sub-rays", 7, _135_non__lagoon_sub_a, 0, no_hashes }, + { "mul-rays", 7, _135_non__lagoon_mul_a, 0, no_hashes }, + { "div-rays", 7, _135_non__lagoon_div_a, 0, no_hashes }, + { "mod-rays", 7, _135_non__lagoon_mod_a, 0, no_hashes }, + { "add-scal", 7, _135_non__lagoon_adds_a, 0, no_hashes }, + { "sub-scal", 7, _135_non__lagoon_subs_a, 0, no_hashes }, + { "mul-scal", 7, _135_non__lagoon_muls_a, 0, no_hashes }, + { "div-scal", 7, _135_non__lagoon_divs_a, 0, no_hashes }, + { "mod-scal", 7, _135_non__lagoon_mods_a, 0, no_hashes }, + { "dot", 7, _135_non__lagoon_dot_a, 0, no_hashes }, + { "transpose",7, _135_non__lagoon_trans_a, 0, no_hashes }, + { "cumsum", 7, _135_non__lagoon_cumsum_a, 0, no_hashes }, + { "argmin", 7, _135_non__lagoon_argmin_a, 0, no_hashes }, + { "argmax", 7, _135_non__lagoon_argmax_a, 0, no_hashes }, + { "ravel", 7, _135_non__lagoon_ravel_a, 0, no_hashes }, + { "min", 7, _135_non__lagoon_min_a, 0, no_hashes }, + { "max", 7, _135_non__lagoon_max_a, 0, no_hashes }, + { "linspace", 7, _135_non__lagoon_linspace_a, 0, no_hashes }, + { "range", 7, _135_non__lagoon_range_a, 0, no_hashes }, + { "abs", 7, _135_non__lagoon_abs_a, 0, no_hashes }, + { "gth", 7, _135_non__lagoon_gth_a, 0, no_hashes }, + { "gte", 7, _135_non__lagoon_gte_a, 0, no_hashes }, + { "lth", 7, _135_non__lagoon_lth_a, 0, no_hashes }, + { "lte", 7, _135_non__lagoon_lte_a, 0, no_hashes }, + { "diag", 7, _135_non__lagoon_diag_a, 0, no_hashes }, + { "trace", 7, _135_non__lagoon_trace_a,0, no_hashes }, + { "mmul", 7, _135_non__lagoon_mmul_a, 0, no_hashes }, + {} + }; + +// numerics math.hoon transcendentals: non -> math -> rd -> +static u3j_harm _135_non__math_rd_exp_a[] = {{".2", u3wi_rd_exp}, {}}; +static u3j_harm _135_non__math_rd_log_a[] = {{".2", u3wi_rd_log}, {}}; +static u3j_harm _135_non__math_rd_sin_a[] = {{".2", u3wi_rd_sin}, {}}; +static u3j_harm _135_non__math_rd_cos_a[] = {{".2", u3wi_rd_cos}, {}}; +static u3j_harm _135_non__math_rd_tan_a[] = {{".2", u3wi_rd_tan}, {}}; +static u3j_harm _135_non__math_rd_atan_a[] = {{".2", u3wi_rd_atan}, {}}; +static u3j_harm _135_non__math_rd_atan2_a[] = {{".2", u3wi_rd_atan2}, {}}; +static u3j_harm _135_non__math_rd_asin_a[] = {{".2", u3wi_rd_asin}, {}}; +static u3j_harm _135_non__math_rd_acos_a[] = {{".2", u3wi_rd_acos}, {}}; +static u3j_harm _135_non__math_rd_sqt_a[] = {{".2", u3wi_rd_sqt}, {}}; +static u3j_harm _135_non__math_rd_cbt_a[] = {{".2", u3wi_rd_cbt}, {}}; +static u3j_harm _135_non__math_rd_pow_a[] = {{".2", u3wi_rd_pow}, {}}; +static u3j_harm _135_non__math_rd_pow_n_a[] = {{".2", u3wi_rd_pow_n}, {}}; +static u3j_harm _135_non__math_rd_log2_a[] = {{".2", u3wi_rd_log2}, {}}; +static u3j_harm _135_non__math_rd_log10_a[] = {{".2", u3wi_rd_log10}, {}}; +static u3j_core _135_non__math_rd_d[] = + { + { "exp", 7, _135_non__math_rd_exp_a, 0, no_hashes }, + { "log", 7, _135_non__math_rd_log_a, 0, no_hashes }, + { "sin", 7, _135_non__math_rd_sin_a, 0, no_hashes }, + { "cos", 7, _135_non__math_rd_cos_a, 0, no_hashes }, + { "tan", 7, _135_non__math_rd_tan_a, 0, no_hashes }, + { "atan", 7, _135_non__math_rd_atan_a, 0, no_hashes }, + { "atan2", 7, _135_non__math_rd_atan2_a, 0, no_hashes }, + { "asin", 7, _135_non__math_rd_asin_a, 0, no_hashes }, + { "acos", 7, _135_non__math_rd_acos_a, 0, no_hashes }, + { "sqt", 7, _135_non__math_rd_sqt_a, 0, no_hashes }, + { "cbt", 7, _135_non__math_rd_cbt_a, 0, no_hashes }, + { "pow", 7, _135_non__math_rd_pow_a, 0, no_hashes }, + { "pow-n", 7, _135_non__math_rd_pow_n_a, 0, no_hashes }, + { "log-2", 7, _135_non__math_rd_log2_a, 0, no_hashes }, + { "log-10", 7, _135_non__math_rd_log10_a, 0, no_hashes }, + {} + }; +static u3j_core _135_non__math_d[] = + { { "rd", 7, 0, _135_non__math_rd_d, no_hashes }, + {} + }; + + +static u3j_core _135_non_d[] = + { { "lagoon", 7, 0, _135_non__la_core_d, no_hashes }, + { "math", 7, 0, _135_non__math_d, no_hashes }, + { "mice", 7, _135_non__mice_a, 0, no_hashes }, + {} + }; + + +static u3j_harm _135_hex_lia_run_v1_a[] = {{".2", u3we_lia_run_v1, c3y}, {}}; + +static u3j_harm _135_hex_lia_run_once_inner_a[] = {{".2", u3we_lia_run_once, c3y}, {}}; + +static u3j_core _135_hex_lia_run_once_d[] = { + { "run-once-inner-v0", 15, _135_hex_lia_run_once_inner_a, 0, no_hashes }, + {} +}; + +static u3j_core _135_hex_lia_monad_d[] = { + { "run-v1", 7, _135_hex_lia_run_v1_a, 0, no_hashes }, + { "run-once-v0", 7, 0, _135_hex_lia_run_once_d, no_hashes }, + {} +}; + +static u3j_core _135_hex_wasm_engine_d[] = { + { "monad-v0", 3, 0, _135_hex_lia_monad_d, no_hashes }, + {} +}; + +static u3j_core _135_hex_wasm_op_def_d[] = { + { "wasm-engine-v0", 3, 0, _135_hex_wasm_engine_d, no_hashes }, + {} +}; + +static u3j_core _135_hex_wasm_validator_d[] = { + { "wasm-op-def-v0", 3, 0, _135_hex_wasm_op_def_d, no_hashes }, + {} +}; + +static u3j_core _135_hex_wasm_parser_d[] = { + { "validator-v0", 3, 0, _135_hex_wasm_validator_d, no_hashes }, + {} +}; + +static u3j_core _135_hex_lia_sur_d[] = { + { "wasm-parser-v0", 3, 0, _135_hex_wasm_parser_d, no_hashes }, + {} +}; + +static u3j_core _135_hex_wasm_engine_sur_d[] = { + { "monad-sur-v1", 3, 0, _135_hex_lia_sur_d, no_hashes }, + {} +}; + +static u3j_core _135_hex_wasm_sur_d[] = { + { "engine-sur-v0", 3, 0, _135_hex_wasm_engine_sur_d, no_hashes }, + {} +}; + +static u3j_core _135_hex_d[] = + { { "non", 7, 0, _135_non_d, no_hashes }, + + { "lull", 3, 0, _135_lull_d, no_hashes }, + + { "lore", 63, _135_hex_lore_a, 0, no_hashes }, + + { "leer", 63, _135_hex_leer_a, 0, no_hashes }, + { "loss", 63, _135_hex_loss_a, 0, no_hashes }, + { "lune", 127, _135_hex_lune_a, 0, no_hashes }, + + { "crc", 31, 0, _135_hex__crc_d, no_hashes }, + + { "coed", 63, 0, _135_hex_coed_d, no_hashes }, + { "aes", 31, 0, _135_hex_aes_d, no_hashes }, + + { "hmac", 63, 0, _135_hex_hmac_d, no_hashes }, + { "argon", 31, 0, _135_hex_argon_d, no_hashes }, + { "blake", 31, 0, _135_hex_blake_d, no_hashes }, + { "chacha", 31, 0, _135_hex_chacha_d, no_hashes }, + { "kecc", 31, 0, _135_hex_kecc_d, no_hashes }, + { "ripemd", 31, 0, _135_hex_ripe_d, no_hashes }, + { "scr", 31, 0, _135_hex_scr_d, no_hashes }, + { "secp", 6, 0, _135_hex_secp_d, no_hashes }, + { "mimes", 31, 0, _135_hex_mimes_d, no_hashes }, + { "json", 31, 0, _135_hex_json_d, no_hashes }, + { "checksum", 15, 0, _135_hex_checksum_d, no_hashes}, + { "wasm-sur-v0", 3, 0, _135_hex_wasm_sur_d, no_hashes }, + { "bytestream-v0", 31, 0, _135_hex_bytestream_d, no_hashes}, + { "zlib-v0", 31, 0, _135_hex__zlib_d, no_hashes }, + {} + }; + +static u3j_core _135_pen_d[] = + { { "hex", 7, 0, _135_hex_d, no_hashes }, + + { "cell", 7, _135_pen_cell_a, 0, no_hashes }, + { "comb", 7, _135_pen_comb_a, 0, no_hashes }, + { "cons", 7, _135_pen_cons_a, 0, no_hashes }, + { "core", 7, _135_pen_core_a, 0, no_hashes }, + { "face", 7, _135_pen_face_a, 0, no_hashes }, + { "fitz", 7, _135_pen_fitz_a, 0, no_hashes }, + { "fork", 7, _135_pen_fork_a, 0, no_hashes }, + { "look", 7, _135_pen_look_a, 0, no_hashes }, + { "loot", 7, _135_pen_loot_a, 0, no_hashes }, + { "ut", 15, 0, _135_pen__ut_d, no_hashes, _135_pen__ut_ho }, + {} + }; + +static u3j_core _135_qua__vi_d[] = + { + { "mole", 7, _135_qua_mole_a, 0, no_hashes }, + { "mule", 7, _135_qua_mule_a, 0, no_hashes }, + {} + }; + +static u3j_core _135_qua_d[] = + { { "pen", 3, 0, _135_pen_d, no_hashes, _135_pen_ho }, + + { "po", 7, 0, _135_qua__po_d, no_hashes }, + + { "trip", 7, _135_qua_trip_a, 0, no_hashes }, + + { "bend", 7, 0, _135_qua__bend_d, no_hashes }, + { "cold", 7, 0, _135_qua__cold_d, no_hashes }, + { "comp", 7, 0, _135_qua__comp_d, no_hashes }, + { "cook", 7, 0, _135_qua__cook_d, no_hashes }, + { "easy", 7, 0, _135_qua__easy_d, no_hashes }, + { "glue", 7, 0, _135_qua__glue_d, no_hashes }, + { "here", 7, 0, _135_qua__here_d, no_hashes }, + { "just", 7, 0, _135_qua__just_d, no_hashes }, + { "mask", 7, 0, _135_qua__mask_d, no_hashes }, + { "shim", 7, 0, _135_qua__shim_d, no_hashes }, + { "stag", 7, 0, _135_qua__stag_d, no_hashes }, + { "stew", 7, 0, _135_qua__stew_d, no_hashes }, + { "stir", 7, 0, _135_qua__stir_d, no_hashes }, + + { "pfix", 7, _135_qua_pfix_a, 0, no_hashes }, + { "plug", 7, _135_qua_plug_a, 0, no_hashes }, + { "pose", 7, _135_qua_pose_a, 0, no_hashes }, + { "sfix", 7, _135_qua_sfix_a, 0, no_hashes }, + + { "mink", 7, _135_qua_mink_a, 0, no_hashes }, + { "vi", 7, 0, _135_qua__vi_d, no_hashes }, + + { "scot", 7, _135_qua_scot_a, 0, no_hashes }, + { "scow", 7, _135_qua_scow_a, 0, no_hashes }, + { "slaw", 7, _135_qua_slaw_a, 0, no_hashes }, + {} + }; + +static u3j_core _135_tri_d[] = + { { "qua", 3, 0, _135_qua_d, no_hashes, _135_qua_ho }, + + { "cofl", 7, 0, _135_tri__cofl_d, no_hashes }, + { "rd", 7, 0, _135_tri__rd_d, no_hashes }, + { "rs", 7, 0, _135_tri__rs_d, no_hashes }, + { "rq", 7, 0, _135_tri__rq_d, no_hashes }, + { "rh", 7, 0, _135_tri__rh_d, no_hashes }, + { "og", 7, 0, _135_tri__og_d, no_hashes }, + + { "sha", 7, 0, _135_tri__sha_d, no_hashes }, + { "shax", 7, _135_tri_shax_a, 0, no_hashes }, + { "shay", 7, _135_tri_shay_a, 0, no_hashes }, + { "shas", 7, _135_tri_shas_a, 0, no_hashes }, + { "shal", 7, _135_tri_shal_a, 0, no_hashes }, + + { "ob", 3, 0, _135_ob_d, no_hashes, _135_ob_ho }, + {} + }; + +static u3j_harm _135_two_clz_a[] = {{".2", u3wc_clz, c3n}, {}}; +static u3j_harm _135_two_ctz_a[] = {{".2", u3wc_ctz, c3n}, {}}; +static u3j_harm _135_two_ham_a[] = {{".2", u3wc_ham, c3n}, {}}; + +static u3j_harm _135_two__hew_fun_a[] = {{".2", u3wc_hew, c3n}, {}}; +static u3j_core _135_two__hew_d[] = + { { "fun", 15, _135_two__hew_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_two__by_bif_a[] = {{".2", u3wdb_bif, c3y}, {}}; + +static u3j_core _135_two__by_d[] = + { { "all", 7, _135_two__by_all_a, 0, no_hashes }, + { "any", 7, _135_two__by_any_a, 0, no_hashes }, + { "apt", 7, _135_two__by_apt_a, 0, no_hashes }, + { "bif", 7, _135_two__by_bif_a, 0, no_hashes }, + { "del", 7, _135_two__by_del_a, 0, no_hashes }, + { "dif", 7, _135_two__by_dif_a, 0, no_hashes }, + { "gas", 7, _135_two__by_gas_a, 0, no_hashes }, + { "get", 7, _135_two__by_get_a, 0, no_hashes }, + { "has", 7, _135_two__by_has_a, 0, no_hashes }, + { "int", 7, _135_two__by_int_a, 0, no_hashes }, + { "jab", 7, _135_two__by_jab_a, 0, no_hashes }, + { "key", 7, _135_two__by_key_a, 0, no_hashes }, + { "put", 7, _135_two__by_put_a, 0, no_hashes }, + { "rep", 7, _135_two__by_rep_a, 0, no_hashes }, + { "run", 7, _135_two__by_run_a, 0, no_hashes }, + { "tap", 7, _135_two__by_tap_a, 0, no_hashes }, + { "uni", 7, _135_two__by_uni_a, 0, no_hashes }, + { "urn", 7, _135_two__by_urn_a, 0, no_hashes }, + { "wyt", 3, _135_two__by_wyt_a, 0, no_hashes }, + {} + }; + + +static u3j_harm _135_two__in_apt_a[] = {{".2", u3wdi_apt}, {}}; + +static u3j_core _135_two__in_d[] = + { { "apt", 7, _135_two__in_apt_a, 0, no_hashes }, + { "bif", 7, _135_two__in_bif_a, 0, no_hashes }, + { "del", 7, _135_two__in_del_a, 0, no_hashes }, + { "dif", 7, _135_two__in_dif_a, 0, no_hashes }, + { "gas", 7, _135_two__in_gas_a, 0, no_hashes }, + { "has", 7, _135_two__in_has_a, 0, no_hashes }, + { "int", 7, _135_two__in_int_a, 0, no_hashes }, + { "put", 7, _135_two__in_put_a, 0, no_hashes }, + { "rep", 7, _135_two__in_rep_a, 0, no_hashes }, + { "run", 7, _135_two__in_run_a, 0, no_hashes }, + { "tap", 7, _135_two__in_tap_a, 0, no_hashes }, + { "uni", 7, _135_two__in_uni_a, 0, no_hashes }, + { "wyt", 3, _135_two__in_wyt_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_two_rig_a[] = {{".2", u3wc_rig, c3n}, {}}; + +static u3j_harm _135_two_mate_a[] = {{".2", u3wb_mate, c3y}, {}}; +static u3j_harm _135_two_sew_a[] = {{".2", u3wc_sew, c3y}, {}}; + +static u3j_core _135_two_d[] = + { { "tri", 3, 0, _135_tri_d, no_hashes, _135_tri_ho }, + + { "find", 7, _135_two_find_a, 0, no_hashes }, + { "flop", 7, _135_two_flop_a, 0, no_hashes }, + { "lent", 7, _135_two_lent_a, 0, no_hashes }, + { "levy", 7, _135_two_levy_a, 0, no_hashes }, + { "lien", 7, _135_two_lien_a, 0, no_hashes }, + { "murn", 7, _135_two_murn_a, 0, no_hashes }, + { "need", 7, _135_two_need_a, 0, no_hashes }, + { "mate", 7, _135_two_mate_a, 0, no_hashes }, + { "reap", 7, _135_two_reap_a, 0, no_hashes }, + { "reel", 7, _135_two_reel_a, 0, no_hashes }, + { "roll", 7, _135_two_roll_a, 0, no_hashes }, + { "skid", 7, _135_two_skid_a, 0, no_hashes }, + { "skim", 7, _135_two_skim_a, 0, no_hashes }, + { "skip", 7, _135_two_skip_a, 0, no_hashes }, + { "scag", 7, _135_two_scag_a, 0, no_hashes }, + { "slag", 7, _135_two_slag_a, 0, no_hashes }, + { "snag", 7, _135_two_snag_a, 0, no_hashes }, + { "sort", 7, _135_two_sort_a, 0, no_hashes }, + { "turn", 7, _135_two_turn_a, 0, no_hashes }, + { "weld", 7, _135_two_weld_a, 0, no_hashes }, + { "welp", 7, _135_two_welp_a, 0, no_hashes }, + { "zing", 7, _135_two_zing_a, 0, no_hashes }, + + { "bex", 7, _135_two_bex_a, 0, no_hashes }, + { "cat", 7, _135_two_cat_a, 0, no_hashes }, + { "can", 7, _135_two_can_a, 0, no_hashes }, + { "clz", 7, _135_two_clz_a, 0, no_hashes }, + { "con", 7, _135_two_con_a, 0, no_hashes }, + { "ctz", 7, _135_two_ctz_a, 0, no_hashes }, + { "cue", 7, _135_two_cue_a, 0, no_hashes }, + { "cut", 7, _135_two_cut_a, 0, no_hashes }, + { "dis", 7, _135_two_dis_a, 0, no_hashes }, + { "dor", 7, _135_two_dor_a, 0, no_hashes }, + { "end", 7, _135_two_end_a, 0, no_hashes }, + { "gor", 7, _135_two_gor_a, 0, no_hashes }, + { "ham", 7, _135_two_ham_a, 0, no_hashes }, + { "hew", 7, 0, _135_two__hew_d, no_hashes }, + { "jam", 7, _135_two_jam_a, 0, no_hashes }, + { "lsh", 7, _135_two_lsh_a, 0, no_hashes }, + { "mat", 7, _135_two_mat_a, 0, no_hashes }, + { "met", 7, _135_two_met_a, 0, no_hashes }, + { "mix", 7, _135_two_mix_a, 0, no_hashes }, + { "mor", 7, _135_two_mor_a, 0, no_hashes }, + { "mug", 7, _135_two_mug_a, 0, no_hashes }, + { "muk", 7, _135_two_muk_a, 0, no_hashes }, + { "rap", 7, _135_two_rap_a, 0, no_hashes }, + { "rep", 7, _135_two_rep_a, 0, no_hashes }, + { "rev", 7, _135_two_rev_a, 0, no_hashes }, + { "rig", 7, _135_two_rig_a, 0, no_hashes }, + { "rip", 7, _135_two_rip_a, 0, no_hashes }, + { "rsh", 7, _135_two_rsh_a, 0, no_hashes }, + { "swp", 7, _135_two_swp_a, 0, no_hashes }, + { "rub", 7, _135_two_rub_a, 0, no_hashes }, + { "pow", 7, _135_two_pow_a, 0, no_hashes }, + { "sew", 7, _135_two_sew_a, 0, no_hashes }, + { "sqt", 7, _135_two_sqt_a, 0, no_hashes }, + { "xeb", 7, _135_two_xeb_a, 0, no_hashes }, + + { "by", 7, 0, _135_two__by_d, no_hashes }, + { "in", 7, 0, _135_two__in_d, no_hashes }, + {} + }; + +static u3j_core _135_one_d[] = + { { "two", 3, 0, _135_two_d, no_hashes }, + + { "add", 7, _135_one_add_a, 0, no_hashes }, + { "dec", 7, _135_one_dec_a, 0, no_hashes }, + { "div", 7, _135_one_div_a, 0, no_hashes }, + { "dvr", 7, _135_one_dvr_a, 0, no_hashes }, + { "gte", 7, _135_one_gte_a, 0, no_hashes }, + { "gth", 7, _135_one_gth_a, 0, no_hashes }, + { "lte", 7, _135_one_lte_a, 0, no_hashes }, + { "lth", 7, _135_one_lth_a, 0, no_hashes }, + { "max", 7, _135_one_max_a, 0, no_hashes }, + { "min", 7, _135_one_min_a, 0, no_hashes }, + { "mod", 7, _135_one_mod_a, 0, no_hashes }, + { "mul", 7, _135_one_mul_a, 0, no_hashes }, + { "sub", 7, _135_one_sub_a, 0, no_hashes }, + + { "cap", 7, _135_one_cap_a, 0, no_hashes }, + { "mas", 7, _135_one_mas_a, 0, no_hashes }, + { "peg", 7, _135_one_peg_a, 0, no_hashes }, + {} + }; + +u3j_core _k135_d[] = + { { "one", 3, 0, _135_one_d, no_hashes }, + {} + }; + diff --git a/libmath/vere/noun/jets/i/math.c b/libmath/vere/noun/jets/i/math.c new file mode 100644 index 0000000..87bca72 --- /dev/null +++ b/libmath/vere/noun/jets/i/math.c @@ -0,0 +1,687 @@ +/// @file +/// +/// Jets for the numerics `math.hoon` library (userspace, registered under the +/// `non` chapter alongside `lagoon`). Each body runs the IDENTICAL algorithm +/// as its Hoon arm (same reduction, coefficients, Horner order) in Berkeley +/// SoftFloat, so jet output is BIT-EXACT to the pure-Hoon reference -- not +/// merely faithful. Transcendentals force round-nearest-even internally (they +/// take no rounding-mode axis), matching the Hoon. +/// +/// Marshalling uses chub (64-bit) reads/writes so it is word-size-agnostic +/// across the 32-bit and 64-bit runtimes (the divergence that broke @rq sub). +/// +/// MASTER COPY lives in urbit/numerics libmath/vere/; applied by hand to the +/// vere runtime (pkg/noun/jets/i/math.c) -- see libmath/vere/README.md. The +/// `_rd_*` algorithm cores below are shared with the bit-exact harness +/// (libmath/vere/test/) via -DMATH_JET_HARNESS, so the jet and its test can +/// never drift. + +#ifndef MATH_JET_HARNESS +#include "jets/q.h" +#include "jets/w.h" +#include "noun.h" +#endif +#include "softfloat.h" + +#ifdef MATH_JET_HARNESS +#include +typedef uint64_t c3_d; +typedef int64_t c3_ds; +#endif + + union doub { + float64_t d; + c3_d c; + }; + + static const c3_d _RD_QNAN = 0x7ff8000000000000ULL; + static const c3_d _RD_PINF = 0x7ff0000000000000ULL; + static const c3_d _RD_NINF = 0xfff0000000000000ULL; + + static inline union doub _rd_bits(c3_d b) { union doub u; u.c = b; return u; } + +/* @rd exp -- math.hoon ++rd ++exp +** x = k*ln2 + r (Cody-Waite), exp(x) = 2^k * P(r), P a degree-11 minimax +** polynomial; +scale2 is a correctly-rounded ldexp. +*/ + // pow2(j) = (j+1023)<<52 as f64 bits = 2^j (normal range j in [-1022,1023]) + static inline float64_t + _rd_pow2(c3_ds j) + { + union doub u; + u.c = ((c3_d)(j + 1023)) << 52; + return u.d; + } + + // scale2: ldexp with overflow/subnormal tails (math.hoon:1519) + static inline float64_t + _rd_scale2(float64_t p, c3_ds k) + { + if ( (k - 1024) >= 0 ) { // k>=1024 + return f64_mul(f64_mul(p, _rd_pow2(1023)), _rd_pow2(k - 1023)); + } + if ( !((k + 1022) >= 0) ) { // k<-1022 + return f64_mul(f64_mul(p, _rd_pow2(k + 54)), _rd_pow2(-54)); + } + return f64_mul(p, _rd_pow2(k)); + } + + static float64_t + _rd_exp(float64_t x) + { + union doub r0; + // degree-11 minimax coeffs c0..c11 (math.hoon:1542-1547) + static const c3_d cs[12] = { + 0x3ff0000000000000ULL, 0x3ff0000000000000ULL, 0x3fe0000000000011ULL, + 0x3fc555555555555aULL, 0x3fa555555554f0cfULL, 0x3f8111111110f225ULL, + 0x3f56c16c187fbe02ULL, 0x3f2a01a01b14378fULL, 0x3efa01991ac8730aULL, + 0x3ec71ddf5749d126ULL, 0x3e928b4057f44145ULL, 0x3e5af631d0059becULL + }; + union doub log2e, ln2hi, ln2lo, ka, kf, rr, p, c, zero; + + zero.c = 0; + r0.d = x; + if ( !f64_eq(x, x) ) { r0.c = _RD_QNAN; return r0.d; } // NaN + if ( r0.c == _RD_PINF ) { return x; } // +inf + if ( r0.c == _RD_NINF ) { r0.c = 0; return r0.d; } // -inf -> 0 + + log2e.c = 0x3ff71547652b82feULL; + ln2hi.c = 0x3fe62e42fee00000ULL; + ln2lo.c = 0x3dea39ef35793c76ULL; + + c3_ds k = (c3_ds)f64_to_i64(f64_mul(x, log2e.d), softfloat_round_near_even, 0); + if ( (k - 1025) >= 0 ) { r0.c = _RD_PINF; return r0.d; } // overflow -> inf + if ( !((k + 1075) >= 0) ) { r0.c = 0; return r0.d; } // underflow -> 0 + + ka.d = ui64_to_f64( (c3_d)(k < 0 ? -k : k) ); + kf.d = (k >= 0) ? ka.d : f64_sub(zero.d, ka.d); + rr.d = f64_sub( f64_sub(x, f64_mul(kf.d, ln2hi.d)), f64_mul(kf.d, ln2lo.d) ); + + p.c = 0; + for ( int i = 12; i-- != 0; ) { // Horner over flop(cs): c11..c0 + c.c = cs[i]; + p.d = f64_add(f64_mul(p.d, rr.d), c.d); + } + return _rd_scale2(p.d, k); + } + +/* @rd log/log-2/log-10 -- math.hoon ++rd ++log/++log-2/++log-10/++lr +** lr: x = 2^e * m, m in [sqrt(1/2),sqrt(2)); returns [e-as-rd, log(1+f)] with +** f=m-1, s=f/(2+f), log(1+f) = f - s*(f - 2z*P2(z)), z=s*s, P2 the atanh +** series 1/3 + z/5 + ... log/log-2/log-10 recombine the integer part. +*/ + // +lr (math.hoon:2043): for finite positive x, -> *ef = e as @rd, *lm = log(m) + static void _rd_lr(float64_t x, float64_t* ef, float64_t* lm) { + static const c3_d cs[10] = { + 0x3fd5555555555555ULL, 0x3fc999999999999aULL, 0x3fc2492492492492ULL, + 0x3fbc71c71c71c71cULL, 0x3fb745d1745d1746ULL, 0x3fb3b13b13b13b14ULL, + 0x3fb1111111111111ULL, 0x3fae1e1e1e1e1e1eULL, 0x3faaf286bca1af28ULL, + 0x3fa8618618618618ULL }; + union doub r0, xx, m, f, s, z, p, c, rr, l1, efd, one, zero; + zero.c = 0; one.c = 0x3ff0000000000000ULL; + r0.d = x; + int sub = ( ((r0.c >> 52) & 0x7ffULL) == 0 ); + xx = r0; + if ( sub ) xx.d = f64_mul(x, _rd_bits(0x4350000000000000ULL).d); // x * 2^54 + c3_ds ae = sub ? -54 : 0; + c3_d b = xx.c; + c3_ds e = (c3_ds)((b >> 52) & 0x7ffULL) - 1023; + m.c = (b & 0xfffffffffffffULL) | 0x3ff0000000000000ULL; // m in [1,2) + if ( f64_le(_rd_bits(0x3ff6a09e667f3bcdULL).d, m.d) ) { // m >= sqrt(2) + m.d = f64_mul(m.d, _rd_bits(0x3fe0000000000000ULL).d); e = e + 1; + } + e = e + ae; + f.d = f64_sub(m.d, one.d); + s.d = f64_div(f.d, f64_add(m.d, one.d)); + z.d = f64_mul(s.d, s.d); + p.c = 0; + for ( int i = 10; i-- != 0; ) { c.c = cs[i]; p.d = f64_add(f64_mul(p.d, z.d), c.d); } + rr.d = f64_mul(f64_add(z.d, z.d), p.d); + l1.d = f64_sub(f.d, f64_mul(s.d, f64_sub(f.d, rr.d))); + efd.d = ui64_to_f64( (c3_d)(e < 0 ? -e : e) ); + if ( e < 0 ) efd.d = f64_sub(zero.d, efd.d); + *ef = efd.d; *lm = l1.d; + } + // shared guard: 0 on NaN/+inf/+-0/x<0 returned via *out + static int _rd_log_guard(float64_t x, float64_t* out) { + union doub r0; r0.d = x; + if ( !f64_eq(x, x) ) { r0.c = _RD_QNAN; *out = r0.d; return 1; } + if ( r0.c == _RD_PINF ) { *out = x; return 1; } + if ( (r0.c == 0)||(r0.c == 0x8000000000000000ULL) ) { r0.c = _RD_NINF; *out = r0.d; return 1; } + if ( (r0.c >> 63) == 1 ) { r0.c = _RD_QNAN; *out = r0.d; return 1; } + return 0; + } + static float64_t _rd_log(float64_t x) { + float64_t g, ef, lm; union doub hi, lo; + if ( _rd_log_guard(x, &g) ) return g; + _rd_lr(x, &ef, &lm); + hi.d = f64_mul(ef, _rd_bits(0x3fe62e42fee00000ULL).d); // e*ln2hi + lo.d = f64_mul(ef, _rd_bits(0x3dea39ef35793c76ULL).d); // e*ln2lo + return f64_add(hi.d, f64_add(lm, lo.d)); + } + static float64_t _rd_log2(float64_t x) { + float64_t g, ef, lm; + if ( _rd_log_guard(x, &g) ) return g; + _rd_lr(x, &ef, &lm); // e + lm/ln2 + return f64_add(ef, f64_mul(lm, _rd_bits(0x3ff71547652b82feULL).d)); + } + static float64_t _rd_log10(float64_t x) { + float64_t g, ef, lm; + if ( _rd_log_guard(x, &g) ) return g; + _rd_lr(x, &ef, &lm); // e*log10(2) + lm/ln10 + return f64_add(f64_mul(ef, _rd_bits(0x3fd34413509f79ffULL).d), + f64_mul(lm, _rd_bits(0x3fdbcb7b1526e50eULL).d)); + } + + static inline float64_t _rd_neg(float64_t a) { union doub z; z.c=0; return f64_sub(z.d, a); } + +/* @rd sin/cos -- math.hoon ++rd ++sin/++cos/++rd-trig +** x = q*(pi/2) + (rhi+rlo) (2-part pi/2), fdlibm sin/cos kernels by q&3. +*/ + static const c3_d _RD_SC[8] = { // sin kernel coeffs (math.hoon:1611) + 0xbfc5555555555555ULL, 0x3f81111111111111ULL, 0xbf2a01a01a01a01aULL, + 0x3ec71de3a556c734ULL, 0xbe5ae64567f544e4ULL, 0x3de6124613a86d09ULL, + 0xbd6ae7f3e733b81fULL, 0x3ce952c77030ad4aULL + }; + static const c3_d _RD_CC[8] = { // cos kernel coeffs (math.hoon:1618) + 0x3fa5555555555555ULL, 0xbf56c16c16c16c17ULL, 0x3efa01a01a01a01aULL, + 0xbe927e4fb7789f5cULL, 0x3e21eed8eff8d898ULL, 0xbda93974a8c07c9dULL, + 0x3d2ae7f3e733b81fULL, 0xbca6827863b97d97ULL + }; + + static float64_t _rd_ksin(float64_t xx, float64_t yy) { + union doub z, r, v, aa, bb, dd, c, half; + half.c = 0x3fe0000000000000ULL; + z.d = f64_mul(xx, xx); + r.c = 0; // Horner over flop(tail sc): sc[7..1] + for ( int i = 8; i-- != 1; ) { c.c = _RD_SC[i]; r.d = f64_add(f64_mul(r.d, z.d), c.d); } + v.d = f64_mul(z.d, xx); + aa.d = f64_sub(f64_mul(half.d, yy), f64_mul(v.d, r.d)); + bb.d = f64_sub(f64_mul(z.d, aa.d), yy); + dd.d = f64_sub(bb.d, f64_mul(v.d, _rd_bits(_RD_SC[0]).d)); + return f64_sub(xx, dd.d); + } + static float64_t _rd_kcos(float64_t xx, float64_t yy) { + union doub z, rc, hz, w2, aa, bb, c, half, one; + half.c = 0x3fe0000000000000ULL; one.c = 0x3ff0000000000000ULL; + z.d = f64_mul(xx, xx); + rc.c = 0; // Horner over flop(cc): cc[7..0] + for ( int i = 8; i-- != 0; ) { c.c = _RD_CC[i]; rc.d = f64_add(f64_mul(rc.d, z.d), c.d); } + hz.d = f64_mul(half.d, z.d); + w2.d = f64_sub(one.d, hz.d); + aa.d = f64_sub(f64_sub(one.d, w2.d), hz.d); + bb.d = f64_sub(f64_mul(f64_mul(z.d, z.d), rc.d), f64_mul(xx, yy)); + return f64_add(w2.d, f64_add(aa.d, bb.d)); + } + // trig-fin: is_sin ? sin(x) : cos(x); ax=|x|, sb=sign bit (math.hoon:1643) + static float64_t _rd_trigfin(int is_sin, float64_t ax, c3_d sb) { + union doub qf, t, w, rhi, rlo, ks, kc, v; + c3_ds q = (c3_ds)f64_to_i64(f64_mul(ax, _rd_bits(0x3fe45f306dc9c883ULL).d), + softfloat_round_near_even, 0); // round(ax*2/pi) + c3_d aq = (c3_d)(q < 0 ? -q : q); + qf.d = ui64_to_f64(aq); + t.d = f64_sub(ax, f64_mul(qf.d, _rd_bits(0x3ff921fb54400000ULL).d)); // ax - qf*pi/2_hi + w.d = f64_mul(qf.d, _rd_bits(0x3dd0b4611a626331ULL).d); // qf*pi/2_lo + rhi.d = f64_sub(t.d, w.d); + rlo.d = f64_sub(f64_sub(t.d, rhi.d), w.d); + int m = (int)(aq & 3); + ks.d = _rd_ksin(rhi.d, rlo.d); + kc.d = _rd_kcos(rhi.d, rlo.d); + if ( is_sin ) { + v.d = (m==0) ? ks.d : (m==1) ? kc.d : (m==2) ? _rd_neg(ks.d) : _rd_neg(kc.d); + return (sb == 1) ? _rd_neg(v.d) : v.d; + } + return (m==0) ? kc.d : (m==1) ? _rd_neg(ks.d) : (m==2) ? _rd_neg(kc.d) : ks.d; + } + static float64_t _rd_sin(float64_t x) { + union doub r0, ax; + r0.d = x; + if ( !f64_eq(x, x) ) { r0.c = _RD_QNAN; return r0.d; } // NaN + if ( (r0.c == _RD_PINF)||(r0.c == _RD_NINF) ) { r0.c = _RD_QNAN; return r0.d; } // +-inf -> NaN + if ( (r0.c == 0)||(r0.c == 0x8000000000000000ULL) ) { return x; } // +-0 -> +-0 + ax.c = r0.c & 0x7fffffffffffffffULL; + return _rd_trigfin(1, ax.d, r0.c >> 63); + } + static float64_t _rd_cos(float64_t x) { + union doub r0, ax; + r0.d = x; + if ( !f64_eq(x, x) ) { r0.c = _RD_QNAN; return r0.d; } // NaN + if ( (r0.c == _RD_PINF)||(r0.c == _RD_NINF) ) { r0.c = _RD_QNAN; return r0.d; } // +-inf -> NaN + ax.c = r0.c & 0x7fffffffffffffffULL; + return _rd_trigfin(0, ax.d, 0); + } + +/* @rd tan -- math.hoon ++rd ++tan/++rd-tan (fdlibm __kernel_tan) +** q*pi/2 reduction; big |x|~pi/4 reduced; odd q -> -cot path. +*/ + static float64_t _rd_ktan(float64_t x, float64_t y, c3_ds iy) { + static const c3_d rl[6] = { // math.hoon:1700 + 0x3fc111111110fe7aULL, 0x3f9664f48406d637ULL, 0x3f6d6d22c9560328ULL, + 0x3f4344d8f2f26501ULL, 0x3f147e88a03792a6ULL, 0xbef375cbdb605373ULL }; + static const c3_d vl[6] = { // math.hoon:1705 + 0x3faba1ba1bb341feULL, 0x3f8226e3e96e8493ULL, 0x3f57dbc8fee08315ULL, + 0x3f3026f71a8d1068ULL, 0x3f12b80f32f0a7e9ULL, 0x3efb2a7074bf7ad4ULL }; + union doub xb, ax, xa, ya, xr, yr, z, w, c, rr, vp, vv, s, r, w2; + union doub one, mone, two, third; + one.c=0x3ff0000000000000ULL; mone.c=0xbff0000000000000ULL; + two.c=0x4000000000000000ULL; third.c=0x3fd5555555555563ULL; + xb.d = x; + c3_d hxneg = xb.c >> 63; + ax.c = xb.c & 0x7fffffffffffffffULL; + int big = f64_le(_rd_bits(0x3fe5942800000000ULL).d, ax.d); // |x| >= ~0.674 + xa.d = (hxneg == 1) ? _rd_neg(x) : x; + ya.d = (hxneg == 1) ? _rd_neg(y) : y; + if ( big ) { // pio4_hi - xa + (pio4_lo - ya) + xr.d = f64_add(f64_sub(_rd_bits(0x3fe921fb54442d18ULL).d, xa.d), + f64_sub(_rd_bits(0x3c81a62633145c07ULL).d, ya.d)); + yr.c = 0; + } else { xr.d = x; yr.d = y; } + z.d = f64_mul(xr.d, xr.d); + w.d = f64_mul(z.d, z.d); + rr.c = 0; + for ( int i = 6; i-- != 0; ) { c.c = rl[i]; rr.d = f64_add(f64_mul(rr.d, w.d), c.d); } + vp.c = 0; + for ( int i = 6; i-- != 0; ) { c.c = vl[i]; vp.d = f64_add(f64_mul(vp.d, w.d), c.d); } + vv.d = f64_mul(z.d, vp.d); + s.d = f64_mul(z.d, xr.d); + r.d = f64_add(yr.d, f64_mul(z.d, f64_add(f64_mul(s.d, f64_add(rr.d, vv.d)), yr.d))); + r.d = f64_add(r.d, f64_mul(third.d, s.d)); + w2.d = f64_add(xr.d, r.d); + if ( big ) { + union doub fac, v, t1; + fac.d = (hxneg == 1) ? mone.d : one.d; + v.d = (iy == 1) ? one.d : mone.d; + t1.d = f64_sub(f64_div(f64_mul(w2.d, w2.d), f64_add(w2.d, v.d)), r.d); + t1.d = f64_mul(two.d, f64_sub(xr.d, t1.d)); + return f64_mul(fac.d, f64_sub(v.d, t1.d)); + } + if ( iy == 1 ) return w2.d; + { union doub zz, vv2, a, tt, ss; // -cot path + zz.c = w2.c & 0xffffffff00000000ULL; + vv2.d = f64_sub(r.d, f64_sub(zz.d, xr.d)); + a.d = f64_div(mone.d, w2.d); + tt.c = a.c & 0xffffffff00000000ULL; + ss.d = f64_add(one.d, f64_mul(tt.d, zz.d)); + return f64_add(tt.d, f64_mul(a.d, f64_add(ss.d, f64_mul(tt.d, vv2.d)))); + } + } + static float64_t _rd_tan(float64_t x) { + union doub r0, ax, qf, t, w, rhi, rlo, res; + r0.d = x; + if ( !f64_eq(x, x) ) { r0.c = _RD_QNAN; return r0.d; } + if ( (r0.c == _RD_PINF)||(r0.c == _RD_NINF) ) { r0.c = _RD_QNAN; return r0.d; } + if ( (r0.c == 0)||(r0.c == 0x8000000000000000ULL) ) { return x; } + c3_d neg = r0.c >> 63; + ax.c = r0.c & 0x7fffffffffffffffULL; + c3_ds q = (c3_ds)f64_to_i64(f64_mul(ax.d, _rd_bits(0x3fe45f306dc9c883ULL).d), + softfloat_round_near_even, 0); + c3_d aq = (c3_d)(q < 0 ? -q : q); + qf.d = ui64_to_f64(aq); + t.d = f64_sub(ax.d, f64_mul(qf.d, _rd_bits(0x3ff921fb54400000ULL).d)); + w.d = f64_mul(qf.d, _rd_bits(0x3dd0b4611a626331ULL).d); + rhi.d = f64_sub(t.d, w.d); + rlo.d = f64_sub(f64_sub(t.d, rhi.d), w.d); + c3_ds iy = ((aq & 1) == 0) ? 1 : -1; + res.d = _rd_ktan(rhi.d, rlo.d, iy); + return (neg == 1) ? _rd_neg(res.d) : res.d; + } + +/* @rd atan/atan2 -- math.hoon ++rd ++atan/++rd-atan/++atan2 +** fdlibm breakpoint reduction (7/16,11/16,19/16,39/16) + degree-10 minimax. +*/ + static float64_t _rd_atan(float64_t x) { + static const c3_d at[11] = { // fdlibm aT[] (math.hoon:1869) + 0x3fd555555555550dULL, 0xbfc999999998ebc4ULL, 0x3fc24924920083ffULL, + 0xbfbc71c6fe231671ULL, 0x3fb745cdc54c206eULL, 0xbfb3b0f2af749a6dULL, + 0x3fb10d66a0d03d51ULL, 0xbfadde2d52defd9aULL, 0x3fa97b4b24760debULL, + 0xbfa2b4442c6a6c2fULL, 0x3f90ad3ae322da11ULL }; + union doub r0, ax, xr, hi, lo, z, sp, s, c, res, one, two, ohf; + r0.d = x; + if ( !f64_eq(x, x) ) { r0.c = _RD_QNAN; return r0.d; } // NaN + if ( r0.c == _RD_PINF ) { r0.c = 0x3ff921fb54442d18ULL; return r0.d; } // +inf -> pi/2 + if ( r0.c == _RD_NINF ) { r0.c = 0xbff921fb54442d18ULL; return r0.d; } // -inf -> -pi/2 + if ( (r0.c == 0)||(r0.c == 0x8000000000000000ULL) ) { return x; } // +-0 + c3_d neg = r0.c >> 63; + ax.c = r0.c & 0x7fffffffffffffffULL; + one.c=0x3ff0000000000000ULL; two.c=0x4000000000000000ULL; ohf.c=0x3ff8000000000000ULL; + int dir = 0; + if ( f64_lt(ax.d, _rd_bits(0x3fdc000000000000ULL).d) ) { // |x| < 7/16 + xr.d = ax.d; hi.c = 0; lo.c = 0; dir = 1; + } else if ( f64_lt(ax.d, _rd_bits(0x3fe6000000000000ULL).d) ) { // < 11/16 + xr.d = f64_div(f64_sub(f64_add(ax.d, ax.d), one.d), f64_add(two.d, ax.d)); + hi.c = 0x3fddac670561bb4fULL; lo.c = 0x3c7a2b7f222f65e2ULL; // atan(0.5) + } else if ( f64_lt(ax.d, _rd_bits(0x3ff3000000000000ULL).d) ) { // < 19/16 + xr.d = f64_div(f64_sub(ax.d, one.d), f64_add(ax.d, one.d)); + hi.c = 0x3fe921fb54442d18ULL; lo.c = 0x3c81a62633145c07ULL; // atan(1)=pi/4 + } else if ( f64_lt(ax.d, _rd_bits(0x4003800000000000ULL).d) ) { // < 39/16 + xr.d = f64_div(f64_sub(ax.d, ohf.d), f64_add(one.d, f64_mul(ohf.d, ax.d))); + hi.c = 0x3fef730bd281f69bULL; lo.c = 0x3c7007887af0cbbdULL; // atan(1.5) + } else { // -1/x + xr.d = f64_div(_rd_bits(0xbff0000000000000ULL).d, ax.d); + hi.c = 0x3ff921fb54442d18ULL; lo.c = 0x3c91a62633145c07ULL; // pi/2 + } + z.d = f64_mul(xr.d, xr.d); + sp.c = 0; + for ( int i = 11; i-- != 0; ) { c.c = at[i]; sp.d = f64_add(f64_mul(sp.d, z.d), c.d); } + s.d = f64_mul(z.d, sp.d); + if ( dir ) res.d = f64_sub(xr.d, f64_mul(xr.d, s.d)); + else res.d = f64_sub(hi.d, f64_sub(f64_sub(f64_mul(xr.d, s.d), lo.d), xr.d)); + return (neg == 1) ? _rd_neg(res.d) : res.d; + } + static float64_t _rd_atan2(float64_t y, float64_t x) { + union doub xb, pi, pi2, mpi2, zero; + zero.c = 0; pi.c = 0x400921fb54442d18ULL; + pi2.c = 0x3ff921fb54442d18ULL; mpi2.c = 0xbff921fb54442d18ULL; + xb.d = x; + if ( f64_lt(zero.d, x) ) return _rd_atan(f64_div(y, x)); // x>0 + if ( f64_lt(x, zero.d) && f64_le(zero.d, y) ) // x<0,y>=0 + return f64_add(_rd_atan(f64_div(y, x)), pi.d); + if ( f64_lt(x, zero.d) && f64_lt(y, zero.d) ) // x<0,y<0 + return f64_sub(_rd_atan(f64_div(y, x)), pi.d); + if ( (xb.c == 0) && f64_lt(zero.d, y) ) return pi2.d; // x==+0,y>0 + if ( (xb.c == 0) && f64_lt(y, zero.d) ) return mpi2.d; // x==+0,y<0 + return zero.d; + } + +/* @rd asin/acos -- math.hoon ++rd ++asin/++acos/++rd-ainv +** fdlibm rational P/Q kernel; sqt is correctly-rounded (= f64_sqrt). +*/ + static float64_t _rd_ainv_rr(float64_t t) { // R(t) = P(t)/Q(t) (math.hoon:1775) + static const c3_d ps[6] = { + 0x3fc5555555555555ULL, 0xbfd4d61203eb6f7dULL, 0x3fc9c1550e884455ULL, + 0xbfa48228b5688f3bULL, 0x3f49efe07501b288ULL, 0x3f023de10dfdf709ULL }; + static const c3_d qs[4] = { + 0xc0033a271c8a2d4bULL, 0x40002ae59c598ac8ULL, 0xbfe6066c1b8d0159ULL, + 0x3fb3b8c5b12e9282ULL }; + union doub pp, qq, c, one; + one.c = 0x3ff0000000000000ULL; + pp.c = 0; + for ( int i = 6; i-- != 0; ) { c.c = ps[i]; pp.d = f64_add(f64_mul(pp.d, t), c.d); } + qq.c = 0; + for ( int i = 4; i-- != 0; ) { c.c = qs[i]; qq.d = f64_add(f64_mul(qq.d, t), c.d); } + return f64_div(f64_mul(t, pp.d), f64_add(one.d, f64_mul(t, qq.d))); + } + static float64_t _rd_asin(float64_t x) { + union doub r0, ax, t, w, r, s, res, half, one, two, pio2h, pio2l, pio4; + half.c=0x3fe0000000000000ULL; one.c=0x3ff0000000000000ULL; two.c=0x4000000000000000ULL; + pio2h.c=0x3ff921fb54442d18ULL; pio2l.c=0x3c91a62633145c07ULL; pio4.c=0x3fe921fb54442d18ULL; + r0.d = x; + if ( !f64_eq(x, x) ) { r0.c = _RD_QNAN; return r0.d; } // NaN + c3_d sgn = r0.c >> 63; + ax.c = r0.c & 0x7fffffffffffffffULL; + if ( f64_lt(one.d, ax.d) ) { r0.c = _RD_QNAN; return r0.d; } // |x|>1 -> NaN + if ( ax.c == one.c ) // |x|==1 + return f64_add(f64_mul(x, pio2h.d), f64_mul(x, pio2l.d)); + if ( f64_lt(ax.d, half.d) ) { // |x|<0.5 + if ( f64_lt(ax.d, _rd_bits(0x3e50000000000000ULL).d) ) return x; // tiny + t.d = f64_mul(x, x); + return f64_add(x, f64_mul(x, _rd_ainv_rr(t.d))); + } + w.d = f64_sub(one.d, ax.d); + t.d = f64_mul(w.d, half.d); + r.d = _rd_ainv_rr(t.d); + s.d = f64_sqrt(t.d); + if ( f64_le(_rd_bits(0x3fef333300000000ULL).d, ax.d) ) { // near 1 + res.d = f64_sub(pio2h.d, f64_sub(f64_mul(two.d, f64_add(s.d, f64_mul(s.d, r.d))), pio2l.d)); + return (sgn == 1) ? _rd_neg(res.d) : res.d; + } + { union doub df, cc, p2, q2; // head/tail + df.c = s.c & 0xffffffff00000000ULL; + cc.d = f64_div(f64_sub(t.d, f64_mul(df.d, df.d)), f64_add(s.d, df.d)); + p2.d = f64_sub(f64_mul(two.d, f64_mul(s.d, r.d)), f64_sub(pio2l.d, f64_mul(two.d, cc.d))); + q2.d = f64_sub(pio4.d, f64_mul(two.d, df.d)); + res.d = f64_sub(pio4.d, f64_sub(p2.d, q2.d)); + return (sgn == 1) ? _rd_neg(res.d) : res.d; + } + } + static float64_t _rd_acos(float64_t x) { + union doub r0, ax, z, s, r, w, half, one, two, pi, pio2h, pio2l; + half.c=0x3fe0000000000000ULL; one.c=0x3ff0000000000000ULL; two.c=0x4000000000000000ULL; + pi.c=0x400921fb54442d18ULL; pio2h.c=0x3ff921fb54442d18ULL; pio2l.c=0x3c91a62633145c07ULL; + r0.d = x; + if ( !f64_eq(x, x) ) { r0.c = _RD_QNAN; return r0.d; } // NaN + c3_d neg = r0.c >> 63; + ax.c = r0.c & 0x7fffffffffffffffULL; + if ( f64_lt(one.d, ax.d) ) { r0.c = _RD_QNAN; return r0.d; } // |x|>1 -> NaN + if ( ax.c == one.c ) { // |x|==1 + if ( neg == 0 ) { union doub z0; z0.c = 0; return z0.d; } // 1 -> 0 + return f64_add(pi.d, f64_mul(two.d, pio2l.d)); // -1 -> pi + } + if ( f64_lt(ax.d, half.d) ) { // |x|<0.5 + if ( f64_lt(ax.d, _rd_bits(0x3c60000000000000ULL).d) ) return pio2h.d; // tiny -> pi/2 + z.d = f64_mul(x, x); + r.d = _rd_ainv_rr(z.d); + return f64_sub(pio2h.d, f64_sub(x, f64_sub(pio2l.d, f64_mul(x, r.d)))); + } + if ( neg == 1 ) { // x <= -0.5 + z.d = f64_mul(f64_add(one.d, x), half.d); + s.d = f64_sqrt(z.d); + r.d = _rd_ainv_rr(z.d); + w.d = f64_sub(f64_mul(r.d, s.d), pio2l.d); + return f64_sub(pi.d, f64_mul(two.d, f64_add(s.d, w.d))); + } + { union doub df, cc; // x >= 0.5 + z.d = f64_mul(f64_sub(one.d, x), half.d); + s.d = f64_sqrt(z.d); + df.c = s.c & 0xffffffff00000000ULL; + cc.d = f64_div(f64_sub(z.d, f64_mul(df.d, df.d)), f64_add(s.d, df.d)); + r.d = _rd_ainv_rr(z.d); + w.d = f64_add(f64_mul(r.d, s.d), cc.d); + return f64_mul(two.d, f64_add(df.d, w.d)); + } + } + +/* @rd sqt/cbt -- math.hoon ++rd ++sqt/++cbt +** sqt: correctly-rounded f64 sqrt (the Markstein-corrected Hoon == f64_sqrt). +** cbt: sign(x) * exp(log|x| / 3). +*/ + static float64_t _rd_sqt(float64_t x) { + union doub r0; r0.d = x; + if ( !f64_eq(x, x) ) { r0.c = _RD_QNAN; return r0.d; } // NaN + if ( r0.c == _RD_PINF ) { return x; } // +inf + if ( (r0.c == 0)||(r0.c == 0x8000000000000000ULL) ) { return x; } // +-0 + if ( (r0.c >> 63) == 1 ) { r0.c = _RD_QNAN; return r0.d; } // x<0 -> NaN + return f64_sqrt(x); + } + static float64_t _rd_cbt(float64_t x) { + union doub r0, ax, r; + r0.d = x; + if ( !f64_eq(x, x) ) { return x; } // NaN -> NaN + if ( (r0.c == 0)||(r0.c == 0x8000000000000000ULL) ) { return x; } // +-0 + ax.c = r0.c & 0x7fffffffffffffffULL; + r.d = _rd_exp(f64_mul(_rd_log(ax.d), _rd_bits(0x3fd5555555555555ULL).d)); // exp(log|x|/3) + return ((r0.c >> 63) == 1) ? _rd_neg(r.d) : r.d; + } + +/* @rd pow/pow-n -- math.hoon ++rd ++pow/++pow-n +** pow-n: x^n by repeated mul (n a positive integer as @rd). +** pow: positive-integer fast path -> pow-n, else exp(n*log x). +*/ + static float64_t _rd_pow_n(float64_t x, float64_t n) { + union doub nn, p, one, two; + one.c = 0x3ff0000000000000ULL; two.c = 0x4000000000000000ULL; + nn.d = n; + if ( nn.c == 0 ) return one.d; // n == +0 -> 1 + p.d = x; + while ( !f64_lt(n, two.d) ) { // while n >= 2: p *= x; n -= 1 + p.d = f64_mul(p.d, x); + n = f64_sub(n, one.d); + } + return p.d; + } + static float64_t _rd_pow(float64_t x, float64_t n) { + union doub nn, ni, zero; + zero.c = 0; nn.d = n; + ni.d = i64_to_f64(f64_to_i64(n, softfloat_round_near_even, 0)); // san (need (toi n)) + if ( (nn.c == ni.c) && f64_lt(zero.d, n) ) // positive integer + return _rd_pow_n(x, ni.d); + return _rd_exp(f64_mul(n, _rd_log(x))); // exp(n*log x) + } + +#ifndef MATH_JET_HARNESS + +/* u3 ABI wrappers. Each transcendental forces round-near-even; the @rd door's +** rounding axis is ignored (the Hoon does the same). Sample is the single @rd +** at u3x_sam. +*/ + static u3_noun + _rd_jet(u3_noun cor, float64_t (*fun)(float64_t)) + { + u3_noun x = u3r_at(u3x_sam, cor); + if ( u3_none == x || c3n == u3ud(x) ) { + return u3m_bail(c3__exit); + } + { + union doub c, e; + softfloat_roundingMode = softfloat_round_near_even; + c.c = u3r_chub(0, x); + e.d = fun(c.d); + return u3i_chubs(1, &e.c); + } + } + + u3_noun u3qi_rd_exp(u3_atom a) + { + union doub c, e; + softfloat_roundingMode = softfloat_round_near_even; + c.c = u3r_chub(0, a); + e.d = _rd_exp(c.d); + return u3i_chubs(1, &e.c); + } + u3_noun u3wi_rd_exp(u3_noun cor) { return _rd_jet(cor, _rd_exp); } + + u3_noun u3qi_rd_log(u3_atom a) + { + union doub c, e; + softfloat_roundingMode = softfloat_round_near_even; + c.c = u3r_chub(0, a); + e.d = _rd_log(c.d); + return u3i_chubs(1, &e.c); + } + u3_noun u3wi_rd_log(u3_noun cor) { return _rd_jet(cor, _rd_log); } + + u3_noun u3qi_rd_sin(u3_atom a) + { + union doub c, e; + softfloat_roundingMode = softfloat_round_near_even; + c.c = u3r_chub(0, a); + e.d = _rd_sin(c.d); + return u3i_chubs(1, &e.c); + } + u3_noun u3wi_rd_sin(u3_noun cor) { return _rd_jet(cor, _rd_sin); } + + u3_noun u3qi_rd_cos(u3_atom a) + { + union doub c, e; + softfloat_roundingMode = softfloat_round_near_even; + c.c = u3r_chub(0, a); + e.d = _rd_cos(c.d); + return u3i_chubs(1, &e.c); + } + u3_noun u3wi_rd_cos(u3_noun cor) { return _rd_jet(cor, _rd_cos); } + + u3_noun u3qi_rd_tan(u3_atom a) + { + union doub c, e; + softfloat_roundingMode = softfloat_round_near_even; + c.c = u3r_chub(0, a); + e.d = _rd_tan(c.d); + return u3i_chubs(1, &e.c); + } + u3_noun u3wi_rd_tan(u3_noun cor) { return _rd_jet(cor, _rd_tan); } + + u3_noun u3qi_rd_atan(u3_atom a) + { + union doub c, e; + softfloat_roundingMode = softfloat_round_near_even; + c.c = u3r_chub(0, a); + e.d = _rd_atan(c.d); + return u3i_chubs(1, &e.c); + } + u3_noun u3wi_rd_atan(u3_noun cor) { return _rd_jet(cor, _rd_atan); } + + u3_noun u3qi_rd_atan2(u3_atom y, u3_atom x) + { + union doub yy, xx, e; + softfloat_roundingMode = softfloat_round_near_even; + yy.c = u3r_chub(0, y); + xx.c = u3r_chub(0, x); + e.d = _rd_atan2(yy.d, xx.d); + return u3i_chubs(1, &e.c); + } + u3_noun u3wi_rd_atan2(u3_noun cor) + { + u3_noun y, x; + if ( c3n == u3r_mean(cor, u3x_sam_2, &y, u3x_sam_3, &x, 0) || + c3n == u3ud(y) || c3n == u3ud(x) ) { + return u3m_bail(c3__exit); + } + return u3qi_rd_atan2(y, x); + } + + u3_noun u3qi_rd_asin(u3_atom a) + { + union doub c, e; + softfloat_roundingMode = softfloat_round_near_even; + c.c = u3r_chub(0, a); + e.d = _rd_asin(c.d); + return u3i_chubs(1, &e.c); + } + u3_noun u3wi_rd_asin(u3_noun cor) { return _rd_jet(cor, _rd_asin); } + + u3_noun u3qi_rd_acos(u3_atom a) + { + union doub c, e; + softfloat_roundingMode = softfloat_round_near_even; + c.c = u3r_chub(0, a); + e.d = _rd_acos(c.d); + return u3i_chubs(1, &e.c); + } + u3_noun u3wi_rd_acos(u3_noun cor) { return _rd_jet(cor, _rd_acos); } + + u3_noun u3qi_rd_log2(u3_atom a) + { union doub c,e; softfloat_roundingMode=softfloat_round_near_even; + c.c=u3r_chub(0,a); e.d=_rd_log2(c.d); return u3i_chubs(1,&e.c); } + u3_noun u3wi_rd_log2(u3_noun cor) { return _rd_jet(cor, _rd_log2); } + + u3_noun u3qi_rd_log10(u3_atom a) + { union doub c,e; softfloat_roundingMode=softfloat_round_near_even; + c.c=u3r_chub(0,a); e.d=_rd_log10(c.d); return u3i_chubs(1,&e.c); } + u3_noun u3wi_rd_log10(u3_noun cor) { return _rd_jet(cor, _rd_log10); } + + u3_noun u3qi_rd_sqt(u3_atom a) + { union doub c,e; softfloat_roundingMode=softfloat_round_near_even; + c.c=u3r_chub(0,a); e.d=_rd_sqt(c.d); return u3i_chubs(1,&e.c); } + u3_noun u3wi_rd_sqt(u3_noun cor) { return _rd_jet(cor, _rd_sqt); } + + u3_noun u3qi_rd_cbt(u3_atom a) + { union doub c,e; softfloat_roundingMode=softfloat_round_near_even; + c.c=u3r_chub(0,a); e.d=_rd_cbt(c.d); return u3i_chubs(1,&e.c); } + u3_noun u3wi_rd_cbt(u3_noun cor) { return _rd_jet(cor, _rd_cbt); } + + // pow / pow-n: sample is [x=@rd n=@rd] + static u3_noun _rd_jet2(u3_noun cor, float64_t (*fun)(float64_t, float64_t)) + { + u3_noun x, n; + if ( c3n == u3r_mean(cor, u3x_sam_2, &x, u3x_sam_3, &n, 0) || + c3n == u3ud(x) || c3n == u3ud(n) ) { + return u3m_bail(c3__exit); + } + { union doub xx, nn, e; + softfloat_roundingMode = softfloat_round_near_even; + xx.c = u3r_chub(0, x); nn.c = u3r_chub(0, n); + e.d = fun(xx.d, nn.d); + return u3i_chubs(1, &e.c); + } + } + u3_noun u3qi_rd_pow(u3_atom x, u3_atom n) + { union doub xx,nn,e; softfloat_roundingMode=softfloat_round_near_even; + xx.c=u3r_chub(0,x); nn.c=u3r_chub(0,n); e.d=_rd_pow(xx.d,nn.d); return u3i_chubs(1,&e.c); } + u3_noun u3wi_rd_pow(u3_noun cor) { return _rd_jet2(cor, _rd_pow); } + + u3_noun u3qi_rd_pow_n(u3_atom x, u3_atom n) + { union doub xx,nn,e; softfloat_roundingMode=softfloat_round_near_even; + xx.c=u3r_chub(0,x); nn.c=u3r_chub(0,n); e.d=_rd_pow_n(xx.d,nn.d); return u3i_chubs(1,&e.c); } + u3_noun u3wi_rd_pow_n(u3_noun cor) { return _rd_jet2(cor, _rd_pow_n); } + +#endif diff --git a/libmath/vere/noun/jets/q.h b/libmath/vere/noun/jets/q.h new file mode 100644 index 0000000..95c9b07 --- /dev/null +++ b/libmath/vere/noun/jets/q.h @@ -0,0 +1,322 @@ +/// @file + +#ifndef U3_JETS_Q_H +#define U3_JETS_Q_H + +#include "types.h" + + /** Tier 1. + **/ + u3_noun u3qa_add(u3_atom, u3_atom); + u3_noun u3qa_dec(u3_atom); + u3_noun u3qa_div(u3_atom, u3_atom); + u3_noun u3qa_gte(u3_atom, u3_atom); + u3_noun u3qa_gth(u3_atom, u3_atom); + u3_noun u3qa_inc(u3_atom); + u3_noun u3qa_lte(u3_atom, u3_atom); + u3_noun u3qa_lth(u3_atom, u3_atom); + u3_noun u3qa_max(u3_atom, u3_atom); + u3_noun u3qa_min(u3_atom, u3_atom); + u3_noun u3qa_mod(u3_atom, u3_atom); + u3_noun u3qa_mul(u3_atom, u3_atom); + u3_noun u3qa_sub(u3_atom, u3_atom); + + /** Tier 2. + **/ + u3_noun u3qb_bind(u3_noun, u3_noun); + u3_noun u3qb_clap(u3_noun, u3_noun, u3_noun); + u3_noun u3qb_drop(u3_noun); + u3_noun u3qb_flop(u3_noun); + u3_noun u3qb_lent(u3_noun); + u3_noun u3qb_levy(u3_noun, u3_noun); + u3_noun u3qb_lien(u3_noun, u3_noun); + u3_noun u3qb_murn(u3_noun, u3_noun); + u3_noun u3qb_need(u3_noun); + u3_noun u3qb_mate(u3_noun, u3_noun); + u3_noun u3qb_reap(u3_atom, u3_noun); + u3_noun u3qb_reel(u3_noun, u3_noun); + u3_noun u3qb_roll(u3_noun, u3_noun); + u3_noun u3qb_skid(u3_noun, u3_noun); + u3_noun u3qb_skim(u3_noun, u3_noun); + u3_noun u3qb_skip(u3_noun, u3_noun); + u3_noun u3qb_scag(u3_atom, u3_noun); + u3_noun u3qb_slag(u3_atom, u3_noun); + u3_noun u3qb_snag(u3_atom, u3_noun); + u3_noun u3qb_sort(u3_noun, u3_noun); + u3_noun u3qb_turn(u3_noun, u3_noun); + u3_noun u3qb_weld(u3_noun, u3_noun); + + /** Tier 3. + **/ + u3_noun u3qc_aor(u3_atom, u3_atom); + u3_noun u3qc_bex(u3_atom); + u3_noun u3qc_xeb(u3_atom); + u3_noun u3qc_can(u3_atom, u3_noun); + u3_noun u3qc_cap(u3_atom); + u3_noun u3qc_cat(u3_atom, u3_atom, u3_atom); + u3_noun u3qc_clz(u3_atom, u3_atom, u3_atom); + u3_noun u3qc_con(u3_atom, u3_atom); + u3_noun u3qc_ctz(u3_atom); + u3_noun u3qc_cut(u3_atom, u3_atom, u3_atom, u3_atom); + u3_noun u3qc_dis(u3_atom, u3_atom); + u3_noun u3qc_dor(u3_atom, u3_atom); + u3_noun u3qc_dvr(u3_atom, u3_atom); + u3_noun u3qc_end(u3_atom, u3_atom, u3_atom); + u3_noun u3qc_gor(u3_atom, u3_atom); + u3_noun u3qc_ham(u3_atom); + u3_noun u3qc_hew(u3_atom, u3_atom, u3_atom, u3_noun); + u3_noun u3qc_lsh(u3_atom, u3_atom, u3_atom); + u3_noun u3qc_mas(u3_atom); + u3_noun u3qc_met(u3_atom, u3_atom); + u3_noun u3qc_mix(u3_atom, u3_atom); + u3_noun u3qc_mor(u3_atom, u3_atom); + u3_noun u3qc_muk(u3_atom, u3_atom, u3_atom); + u3_noun u3qc_peg(u3_atom, u3_atom); + u3_noun u3qc_pow(u3_atom, u3_atom); + u3_noun u3qc_rap(u3_atom, u3_noun); + u3_noun u3qc_rep(u3_atom, u3_atom, u3_noun); + u3_noun u3qc_rev(u3_atom, u3_atom, u3_atom); + u3_noun u3qc_rig(u3_atom, u3_atom, u3_atom); + u3_noun u3qc_rip(u3_atom, u3_atom, u3_atom); + u3_noun u3qc_rsh(u3_atom, u3_atom, u3_atom); + u3_noun u3qc_sew(u3_atom, u3_atom, u3_atom, u3_atom, u3_atom); + u3_noun u3qc_swp(u3_atom, u3_atom); + u3_noun u3qc_sqt(u3_atom); + + c3_d u3qc_rig_s(c3_g, c3_w, c3_g); + + u3_noun u3_po_find_prefix(c3_y one, c3_y two, c3_y three); + u3_noun u3_po_find_suffix(c3_y one, c3_y two, c3_y three); + void u3_po_to_prefix(u3_noun id, c3_y* a, c3_y* b, c3_y* c); + void u3_po_to_suffix(u3_noun id, c3_y* a, c3_y* b, c3_y* c); + + /** Tier 4. + **/ + u3_noun u3qdb_all(u3_noun, u3_noun); + u3_noun u3qdb_any(u3_noun, u3_noun); + u3_noun u3qdb_apt(u3_noun); + u3_noun u3qdb_bif(u3_noun, u3_noun); + u3_noun u3qdb_del(u3_noun, u3_noun); + u3_noun u3qdb_dif(u3_noun, u3_noun); + u3_noun u3qdb_gas(u3_noun, u3_noun); + u3_noun u3qdb_get(u3_noun, u3_noun); + u3_noun u3qdb_has(u3_noun, u3_noun); + u3_noun u3qdb_int(u3_noun, u3_noun); + u3_noun u3qdb_key(u3_noun); + u3_noun u3qdb_put(u3_noun, u3_noun, u3_noun); + u3_noun u3qdb_run(u3_noun, u3_noun); +# define u3qdb_tap u3qdi_tap + u3_noun u3qdb_uni(u3_noun, u3_noun); + u3_noun u3qdb_urn(u3_noun, u3_noun); +# define u3qdb_wyt u3qdi_wyt + + u3_noun u3qdi_apt(u3_noun); + u3_noun u3qdi_bif(u3_noun, u3_noun); + u3_noun u3qdi_del(u3_noun, u3_noun); + u3_noun u3qdi_dif(u3_noun, u3_noun); + u3_noun u3qdi_gas(u3_noun, u3_noun); + u3_noun u3qdi_has(u3_noun, u3_noun); + u3_noun u3qdi_int(u3_noun, u3_noun); + u3_noun u3qdi_put(u3_noun, u3_noun); + u3_noun u3qdi_rep(u3_noun, u3_noun); + u3_noun u3qdi_run(u3_noun, u3_noun); + u3_noun u3qdi_tap(u3_noun); + u3_noun u3qdi_uni(u3_noun, u3_noun); + u3_noun u3qdi_wyt(u3_noun); + + /** Tier 5. + **/ + u3_noun u3qe_cue(u3_atom); + u3_noun u3qe_jam(u3_atom); + u3_noun u3qe_mat(u3_atom); + u3_noun u3qe_rub(u3_atom, u3_atom); + u3_noun u3qe_leer(u3_atom); + u3_noun u3qe_lore(u3_atom); + u3_noun u3qe_loss(u3_noun, u3_noun); + u3_noun u3qe_lune(u3_atom); + u3_noun u3qe_repg(u3_noun, u3_noun, u3_noun); + u3_noun u3qe_rexp(u3_noun, u3_noun); + u3_noun u3qe_trip(u3_atom); + + u3_atom u3qe_scot(u3_atom, u3_atom); + u3_atom u3qe_scow(u3_atom, u3_atom); + + u3_noun u3qea_ecba_en(u3_atom, u3_atom); + u3_noun u3qea_ecba_de(u3_atom, u3_atom); + u3_noun u3qea_ecbb_en(u3_atom, u3_atom); + u3_noun u3qea_ecbb_de(u3_atom, u3_atom); + u3_noun u3qea_ecbc_en(u3_atom, u3_atom); + u3_noun u3qea_ecbc_de(u3_atom, u3_atom); + + u3_noun u3qea_cbca_en(u3_atom, u3_atom, u3_atom); + u3_noun u3qea_cbca_de(u3_atom, u3_atom, u3_atom); + u3_noun u3qea_cbcb_en(u3_atom, u3_atom, u3_atom); + u3_noun u3qea_cbcb_de(u3_atom, u3_atom, u3_atom); + u3_noun u3qea_cbcc_en(u3_atom, u3_atom, u3_atom); + u3_noun u3qea_cbcc_de(u3_atom, u3_atom, u3_atom); + + u3_noun u3qea_de(u3_atom, u3_atom); + u3_noun u3qea_en(u3_atom, u3_atom); + + u3_noun u3qee_recs(u3_atom); + + u3_atom u3qe_fein_ob(u3_atom pyn); + u3_atom u3qe_fynd_ob(u3_atom pyn); + + u3_noun u3qe_hmac(u3_noun, u3_atom, u3_atom, + u3_atom, u3_atom, u3_atom, u3_atom); + + u3_noun u3qe_en_base16(u3_atom len, u3_atom dat); + u3_noun u3qe_de_base16(u3_atom inp); + + u3_noun u3qe_json_de(u3_atom); + u3_atom u3qe_json_en(u3_noun); + + u3_noun u3qeo_raw(u3_atom, u3_atom); + + u3_noun u3qef_drg(u3_noun, u3_atom); + u3_noun u3qef_lug(u3_noun, u3_noun, u3_atom, u3_atom); + + u3_noun u3qer_add(u3_atom, u3_atom, u3_atom); + u3_noun u3qer_sub(u3_atom, u3_atom, u3_atom); + u3_noun u3qer_mul(u3_atom, u3_atom, u3_atom); + u3_noun u3qer_div(u3_atom, u3_atom, u3_atom); + u3_noun u3qer_sqt(u3_atom, u3_atom); + u3_noun u3qer_fma(u3_atom, u3_atom, u3_atom, u3_atom); + u3_noun u3qer_lth(u3_atom, u3_atom); + u3_noun u3qer_lte(u3_atom, u3_atom); + u3_noun u3qer_equ(u3_atom, u3_atom); + u3_noun u3qer_gte(u3_atom, u3_atom); + u3_noun u3qer_gth(u3_atom, u3_atom); + + u3_noun u3qet_add(u3_atom, u3_atom, u3_atom); + u3_noun u3qet_sub(u3_atom, u3_atom, u3_atom); + u3_noun u3qet_mul(u3_atom, u3_atom, u3_atom); + u3_noun u3qet_div(u3_atom, u3_atom, u3_atom); + u3_noun u3qet_sqt(u3_atom, u3_atom); + u3_noun u3qet_fma(u3_atom, u3_atom, u3_atom, u3_atom); + u3_noun u3qet_lth(u3_atom, u3_atom); + u3_noun u3qet_lte(u3_atom, u3_atom); + u3_noun u3qet_equ(u3_atom, u3_atom); + u3_noun u3qet_gte(u3_atom, u3_atom); + u3_noun u3qet_gth(u3_atom, u3_atom); + + u3_noun u3qeq_add(u3_atom, u3_atom, u3_atom); + u3_noun u3qeq_sub(u3_atom, u3_atom, u3_atom); + u3_noun u3qeq_mul(u3_atom, u3_atom, u3_atom); + u3_noun u3qeq_div(u3_atom, u3_atom, u3_atom); + u3_noun u3qeq_sqt(u3_atom, u3_atom); + u3_noun u3qeq_fma(u3_atom, u3_atom, u3_atom, u3_atom); + u3_noun u3qeq_lth(u3_atom, u3_atom); + u3_noun u3qeq_lte(u3_atom, u3_atom); + u3_noun u3qeq_equ(u3_atom, u3_atom); + u3_noun u3qeq_gte(u3_atom, u3_atom); + u3_noun u3qeq_gth(u3_atom, u3_atom); + + u3_noun u3qes_add(u3_atom, u3_atom, u3_atom); + u3_noun u3qes_sub(u3_atom, u3_atom, u3_atom); + u3_noun u3qes_mul(u3_atom, u3_atom, u3_atom); + u3_noun u3qes_div(u3_atom, u3_atom, u3_atom); + u3_noun u3qes_sqt(u3_atom, u3_atom); + u3_noun u3qes_fma(u3_atom, u3_atom, u3_atom, u3_atom); + u3_noun u3qes_lth(u3_atom, u3_atom); + u3_noun u3qes_lte(u3_atom, u3_atom); + u3_noun u3qes_equ(u3_atom, u3_atom); + u3_noun u3qes_gte(u3_atom, u3_atom); + u3_noun u3qes_gth(u3_atom, u3_atom); + + u3_noun u3qe_decompress_zlib(u3_atom, u3_noun); + u3_noun u3qe_decompress_gzip(u3_atom, u3_noun); + + /** Tier 6. + **/ + u3_noun u3qf_bull(u3_noun, u3_noun); + u3_noun u3qf_cell(u3_noun, u3_noun); + u3_noun u3qf_comb(u3_noun, u3_noun); + u3_noun u3qf_cons(u3_noun, u3_noun); + u3_noun u3qf_core(u3_noun, u3_noun); + u3_noun u3qf_cube(u3_noun, u3_noun); + u3_noun u3qf_face(u3_noun, u3_noun); + u3_noun u3qf_fine(u3_noun, u3_noun, u3_noun); + u3_noun u3qf_fitz(u3_noun, u3_noun); + u3_noun u3qf_flay(u3_noun); + u3_noun u3qf_forq(u3_noun, u3_noun); + u3_noun u3qf_fork(u3_noun); + u3_noun u3qf_grof(u3_noun); + u3_noun u3qf_hint(u3_noun, u3_noun); + u3_noun u3qf_hike(u3_noun, u3_noun); + u3_noun u3qf_look(u3_noun, u3_noun); + u3_noun u3qf_loot(u3_noun, u3_noun); + u3_noun u3qf_slot(u3_atom, u3_noun); + u3_noun u3qf_type(u3_noun); + + u3_noun u3qfl_bunt(u3_noun, u3_noun); + u3_noun u3qfl_whip(u3_noun, u3_noun, u3_noun); + + u3_noun u3qfr_fish(u3_noun, u3_noun, u3_noun, u3_noun); + + u3_noun u3qfp_hack(u3_noun, u3_noun); + u3_noun u3qfp_late(u3_noun); + u3_noun u3qfp_open(u3_noun, u3_noun, u3_noun); + u3_noun u3qfp_nepo(u3_noun, u3_noun); + u3_noun u3qfp_rake(u3_noun); + + u3_noun u3qi_la_add_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_sub_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_mul_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_div_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_mod_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_adds_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_subs_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_muls_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_divs_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_mods_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_dot_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_diag(u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_transpose(u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_cumsum_i754(u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_argmin_i754(u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_argmax_i754(u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_ravel_i754(u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_min_i754(u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_max_i754(u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_linspace_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_range_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_abs_i754(u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_gth_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_gte_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_lth_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_lte_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_trace_i754(u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_mmul_i754(u3_noun, u3_noun, u3_noun, u3_noun, u3_noun); + + u3_noun u3qi_rd_exp(u3_noun); + u3_noun u3qi_rd_log(u3_noun); + u3_noun u3qi_rd_sin(u3_atom); + u3_noun u3qi_rd_cos(u3_atom); + u3_noun u3qi_rd_tan(u3_atom); + u3_noun u3qi_rd_atan(u3_atom); + u3_noun u3qi_rd_atan2(u3_atom, u3_atom); + u3_noun u3qi_rd_asin(u3_atom); + u3_noun u3qi_rd_acos(u3_atom); + u3_noun u3qi_rd_sqt(u3_atom); + u3_noun u3qi_rd_cbt(u3_atom); + u3_noun u3qi_rd_pow(u3_atom, u3_atom); + u3_noun u3qi_rd_pow_n(u3_atom, u3_atom); + u3_noun u3qi_rd_log2(u3_atom); + u3_noun u3qi_rd_log10(u3_atom); + +# define u3qfu_van_fan 28 +# define u3qfu_van_rib 58 +# define u3qfu_van_vet 59 + + void u3qf_test(const c3_c*, u3_noun); + + + /** Tier 6. + **/ + u3_noun u3qg_plot_fax(u3_noun, u3_noun); + u3_noun u3qg_plot_met(u3_noun, u3_noun); + +#endif /* ifndef U3_JETS_Q_H */ + diff --git a/libmath/vere/noun/jets/w.h b/libmath/vere/noun/jets/w.h new file mode 100644 index 0000000..effc85a --- /dev/null +++ b/libmath/vere/noun/jets/w.h @@ -0,0 +1,449 @@ +/// @file + +#ifndef U3_JETS_W_H +#define U3_JETS_W_H + +#include "types.h" + + /** Tier 1. + **/ + u3_noun u3wa_add(u3_noun); + u3_noun u3wa_dec(u3_noun); + u3_noun u3wa_div(u3_noun); + u3_noun u3wa_gte(u3_noun); + u3_noun u3wa_gth(u3_noun); + u3_noun u3wa_lte(u3_noun); + u3_noun u3wa_lth(u3_noun); + u3_noun u3wa_max(u3_noun); + u3_noun u3wa_min(u3_noun); + u3_noun u3wa_mod(u3_noun); + u3_noun u3wa_mul(u3_noun); + u3_noun u3wa_sub(u3_noun); + + /** Tier 2. + **/ + u3_noun u3wb_bind(u3_noun); + u3_noun u3wb_clap(u3_noun); + u3_noun u3wb_drop(u3_noun); + u3_noun u3wb_find(u3_noun); + u3_noun u3wb_flop(u3_noun); + u3_noun u3wb_lent(u3_noun); + u3_noun u3wb_levy(u3_noun); + u3_noun u3wb_lien(u3_noun); + u3_noun u3wb_murn(u3_noun); + u3_noun u3wb_need(u3_noun); + u3_noun u3wb_mate(u3_noun); + u3_noun u3wb_reap(u3_noun); + u3_noun u3wb_reel(u3_noun); + u3_noun u3wb_roll(u3_noun); + u3_noun u3wb_skid(u3_noun); + u3_noun u3wb_skim(u3_noun); + u3_noun u3wb_skip(u3_noun); + u3_noun u3wb_scag(u3_noun); + u3_noun u3wb_slag(u3_noun); + u3_noun u3wb_snag(u3_noun); + u3_noun u3wb_sort(u3_noun); + u3_noun u3wb_turn(u3_noun); + u3_noun u3wb_weld(u3_noun); +# define u3wb_welp u3wb_weld + u3_noun u3wb_zing(u3_noun); + + /** Tier 3. + **/ + u3_noun u3wc_aor(u3_noun); + u3_noun u3wc_bex(u3_noun); + u3_noun u3wc_xeb(u3_noun); + u3_noun u3wc_can(u3_noun); + u3_noun u3wc_cap(u3_noun); + u3_noun u3wc_cat(u3_noun); + u3_noun u3wc_clz(u3_noun); + u3_noun u3wc_con(u3_noun); + u3_noun u3wc_ctz(u3_noun); + u3_noun u3wc_cut(u3_noun); + u3_noun u3wc_dis(u3_noun); + u3_noun u3wc_dor(u3_noun); + u3_noun u3wc_dvr(u3_noun); + u3_noun u3wc_end(u3_noun); + u3_noun u3wc_gor(u3_noun); + u3_noun u3wc_ham(u3_noun); + u3_noun u3wc_hew(u3_noun); + u3_noun u3wc_lsh(u3_noun); + u3_noun u3wc_mas(u3_noun); + u3_noun u3wc_met(u3_noun); + u3_noun u3wc_mix(u3_noun); + u3_noun u3wc_mor(u3_noun); + u3_noun u3wc_mug(u3_noun); + u3_noun u3wc_muk(u3_noun); + u3_noun u3wc_peg(u3_noun); + u3_noun u3wc_pow(u3_noun); + u3_noun u3wc_rap(u3_noun); + u3_noun u3wc_rep(u3_noun); + u3_noun u3wc_rev(u3_noun); + u3_noun u3wc_rig(u3_noun); + u3_noun u3wc_rip(u3_noun); + u3_noun u3wc_rsh(u3_noun); + u3_noun u3wc_sew(u3_noun); + u3_noun u3wc_swp(u3_noun); + u3_noun u3wc_sqt(u3_noun); + + u3_noun u3wcp_ins(u3_noun); + u3_noun u3wcp_ind(u3_noun); + u3_noun u3wcp_tos(u3_noun); + u3_noun u3wcp_tod(u3_noun); + + /** Tier 4. + **/ + u3_noun u3wdb_all(u3_noun); + u3_noun u3wdb_any(u3_noun); + u3_noun u3wdb_apt(u3_noun); + u3_noun u3wdb_bif(u3_noun); + u3_noun u3wdb_del(u3_noun); + u3_noun u3wdb_dif(u3_noun); + u3_noun u3wdb_gas(u3_noun); + u3_noun u3wdb_get(u3_noun); + u3_noun u3wdb_has(u3_noun); + u3_noun u3wdb_int(u3_noun); + u3_noun u3wdb_jab(u3_noun); + u3_noun u3wdb_key(u3_noun); + u3_noun u3wdb_put(u3_noun); +# define u3wdb_tap u3wdi_tap + u3_noun u3wdb_uni(u3_noun); + u3_noun u3wdb_urn(u3_noun); +# define u3wdb_rep u3wdi_rep + u3_noun u3wdb_run(u3_noun); +# define u3wdb_wyt u3wdi_wyt + + u3_noun u3wdi_apt_140(u3_noun); + u3_noun u3wdi_apt(u3_noun); + u3_noun u3wdi_bif(u3_noun); + u3_noun u3wdi_del(u3_noun); + u3_noun u3wdi_dif(u3_noun); + u3_noun u3wdi_gas(u3_noun); + u3_noun u3wdi_has(u3_noun); + u3_noun u3wdi_int(u3_noun); + u3_noun u3wdi_put(u3_noun); + u3_noun u3wdi_rep(u3_noun); + u3_noun u3wdi_run(u3_noun); + u3_noun u3wdi_tap(u3_noun); + u3_noun u3wdi_uni(u3_noun); + u3_noun u3wdi_wyt(u3_noun); + + /** Tier 5. + **/ + u3_noun u3we_cue(u3_noun); + u3_noun u3we_jam(u3_noun); + u3_noun u3we_mat(u3_noun); + u3_noun u3we_rub(u3_noun); + u3_noun u3we_leer(u3_noun); + u3_noun u3we_lore(u3_noun); + u3_noun u3we_loss(u3_noun); + u3_noun u3we_lune(u3_noun); + u3_noun u3we_mice(u3_noun); + u3_noun u3we_mink(u3_noun); + u3_noun u3we_mole(u3_noun); + u3_noun u3we_mule(u3_noun); + u3_noun u3we_repg(u3_noun); + u3_noun u3we_rexp(u3_noun); + u3_noun u3we_trip(u3_noun); + + u3_noun u3we_scow(u3_noun); + u3_noun u3we_scot(u3_noun); + u3_noun u3we_slaw(u3_noun); + + u3_noun u3we_pfix(u3_noun); + u3_noun u3we_plug(u3_noun); + u3_noun u3we_pose(u3_noun); + u3_noun u3we_sfix(u3_noun); + + u3_noun u3wea_ecba_en(u3_noun); + u3_noun u3wea_ecba_de(u3_noun); + u3_noun u3wea_ecbb_en(u3_noun); + u3_noun u3wea_ecbb_de(u3_noun); + u3_noun u3wea_ecbc_en(u3_noun); + u3_noun u3wea_ecbc_de(u3_noun); + + u3_noun u3wea_cbca_en(u3_noun); + u3_noun u3wea_cbca_de(u3_noun); + u3_noun u3wea_cbcb_en(u3_noun); + u3_noun u3wea_cbcb_de(u3_noun); + u3_noun u3wea_cbcc_en(u3_noun); + u3_noun u3wea_cbcc_de(u3_noun); + + u3_noun u3wea_siva_en(u3_noun); + u3_noun u3wea_siva_de(u3_noun); + u3_noun u3wea_sivb_en(u3_noun); + u3_noun u3wea_sivb_de(u3_noun); + u3_noun u3wea_sivc_en(u3_noun); + u3_noun u3wea_sivc_de(u3_noun); + + u3_noun u3wea_de(u3_noun); + u3_noun u3wea_en(u3_noun); + + u3_noun u3wes_hsh(u3_noun); + u3_noun u3wes_hsl(u3_noun); + u3_noun u3wes_pbk(u3_noun); + u3_noun u3wes_pbl(u3_noun); + + u3_noun u3we_shax(u3_noun); + u3_noun u3we_shay(u3_noun); + u3_noun u3we_shas(u3_noun); + u3_noun u3we_shal(u3_noun); + u3_noun u3we_sha1(u3_noun); + + u3_noun u3we_fein_ob(u3_noun); + u3_noun u3we_fynd_ob(u3_noun); + + u3_noun u3weo_raw(u3_noun); + + u3_noun u3wee_scad(u3_noun); + u3_noun u3wee_scas(u3_noun); + u3_noun u3wee_scap(u3_noun); + + u3_noun u3wee_puck(u3_noun); + u3_noun u3wee_luck(u3_noun); + u3_noun u3wee_sign(u3_noun); + u3_noun u3wee_sign_raw(u3_noun); + u3_noun u3wee_veri(u3_noun); + u3_noun u3wee_sign_octs(u3_noun); + u3_noun u3wee_sign_octs_raw(u3_noun); + u3_noun u3wee_veri_octs(u3_noun); + u3_noun u3wee_shar(u3_noun); + u3_noun u3wee_slar(u3_noun); + u3_noun u3wee_recs(u3_noun); + u3_noun u3wee_smac(u3_noun); + u3_noun u3wee_point_neg(u3_noun); + u3_noun u3wee_point_add(u3_noun); + u3_noun u3wee_scalarmult(u3_noun); + u3_noun u3wee_scalarmult_base(u3_noun); + u3_noun u3wee_add_scalarmult_scalarmult_base(u3_noun); + u3_noun u3wee_add_double_scalarmult(u3_noun); + + u3_noun u3we_hmac(u3_noun); + + u3_noun u3we_kecc224(u3_noun); + u3_noun u3we_kecc256(u3_noun); + u3_noun u3we_kecc384(u3_noun); + u3_noun u3we_kecc512(u3_noun); + + u3_noun u3we_argon2(u3_noun); + + u3_noun u3we_blake2b(u3_noun); + u3_noun u3we_blake3_hash(u3_noun); + u3_noun u3we_blake3_chunk_output(u3_noun); + u3_noun u3we_blake3_compress(u3_noun); + + u3_noun u3we_chacha_crypt(u3_noun); + u3_noun u3we_chacha_xchacha(u3_noun); + + u3_noun u3we_adler32(u3_noun); + u3_noun u3we_crc32(u3_noun); + + u3_noun u3we_ripe(u3_noun); + + u3_noun u3we_make(u3_noun); + u3_noun u3we_sign(u3_noun); + u3_noun u3we_reco(u3_noun); + + u3_noun u3we_sosi(u3_noun); + u3_noun u3we_sove(u3_noun); + + u3_noun u3we_en_base16(u3_noun); + u3_noun u3we_de_base16(u3_noun); + + u3_noun u3we_json_de(u3_noun); + u3_atom u3we_json_en(u3_noun); + + u3_noun u3we_bend_fun(u3_noun); + u3_noun u3we_cold_fun(u3_noun); + u3_noun u3we_cook_fun(u3_noun); + u3_noun u3we_comp_fun(u3_noun); + u3_noun u3we_easy_fun(u3_noun); + u3_noun u3we_glue_fun(u3_noun); + u3_noun u3we_here_fun(u3_noun); + u3_noun u3we_just_fun(u3_noun); + u3_noun u3we_mask_fun(u3_noun); + u3_noun u3we_shim_fun(u3_noun); + u3_noun u3we_stag_fun(u3_noun); + u3_noun u3we_stew_fun(u3_noun); + u3_noun u3we_stir_fun(u3_noun); + + u3_noun u3wef_drg(u3_noun); + u3_noun u3wef_lug(u3_noun); + + u3_noun u3wer_add(u3_noun); + u3_noun u3wer_sub(u3_noun); + u3_noun u3wer_mul(u3_noun); + u3_noun u3wer_div(u3_noun); + u3_noun u3wer_sqt(u3_noun); + u3_noun u3wer_fma(u3_noun); + u3_noun u3wer_lth(u3_noun); + u3_noun u3wer_lte(u3_noun); + u3_noun u3wer_equ(u3_noun); + u3_noun u3wer_gte(u3_noun); + u3_noun u3wer_gth(u3_noun); + + u3_noun u3wet_add(u3_noun); + u3_noun u3wet_sub(u3_noun); + u3_noun u3wet_mul(u3_noun); + u3_noun u3wet_div(u3_noun); + u3_noun u3wet_sqt(u3_noun); + u3_noun u3wet_fma(u3_noun); + u3_noun u3wet_lth(u3_noun); + u3_noun u3wet_lte(u3_noun); + u3_noun u3wet_equ(u3_noun); + u3_noun u3wet_gte(u3_noun); + u3_noun u3wet_gth(u3_noun); + + u3_noun u3weq_add(u3_noun); + u3_noun u3weq_sub(u3_noun); + u3_noun u3weq_mul(u3_noun); + u3_noun u3weq_div(u3_noun); + u3_noun u3weq_sqt(u3_noun); + u3_noun u3weq_fma(u3_noun); + u3_noun u3weq_lth(u3_noun); + u3_noun u3weq_lte(u3_noun); + u3_noun u3weq_equ(u3_noun); + u3_noun u3weq_gte(u3_noun); + u3_noun u3weq_gth(u3_noun); + + u3_noun u3wes_add(u3_noun); + u3_noun u3wes_sub(u3_noun); + u3_noun u3wes_mul(u3_noun); + u3_noun u3wes_div(u3_noun); + u3_noun u3wes_sqt(u3_noun); + u3_noun u3wes_fma(u3_noun); + u3_noun u3wes_lth(u3_noun); + u3_noun u3wes_lte(u3_noun); + u3_noun u3wes_equ(u3_noun); + u3_noun u3wes_gte(u3_noun); + u3_noun u3wes_gth(u3_noun); + + u3_noun u3we_crc32(u3_noun); + u3_noun u3we_decompress_zlib(u3_noun); + u3_noun u3we_decompress_gzip(u3_noun); + + u3_noun u3we_lia_run_v1(u3_noun); + u3_noun u3we_lia_run_once(u3_noun); + + //+| %utilities + u3_noun u3we_bytestream_rip_octs(u3_noun); + u3_noun u3we_bytestream_cat_octs(u3_noun); + u3_noun u3we_bytestream_can_octs(u3_noun); + //+| %navigation + u3_noun u3we_bytestream_skip_line(u3_noun); + u3_noun u3we_bytestream_find_byte(u3_noun); + u3_noun u3we_bytestream_seek_byte(u3_noun); + //+| %read-byte + u3_noun u3we_bytestream_read_byte(u3_noun); + //+| %read-octs + u3_noun u3we_bytestream_read_octs(u3_noun); + //+| %transformation + u3_noun u3we_bytestream_chunk(u3_noun); + u3_noun u3we_bytestream_extract(u3_noun); + u3_noun u3we_bytestream_fuse_extract(u3_noun); + //+| %bitstream + u3_noun u3we_bytestream_need_bits(u3_noun); + u3_noun u3we_bytestream_drop_bits(u3_noun); + // u3_noun u3we_bytestream_skip_bits(u3_noun); + u3_noun u3we_bytestream_peek_bits(u3_noun); + u3_noun u3we_bytestream_read_bits(u3_noun); + // u3_noun u3we_bytestream_read_need_bits(u3_noun); + u3_noun u3we_bytestream_byte_bits(u3_noun); + + /** Tier 6. + **/ + u3_noun u3wf_bull(u3_noun); + u3_noun u3wf_cell(u3_noun); + u3_noun u3wf_comb(u3_noun); + u3_noun u3wf_cons(u3_noun); + u3_noun u3wf_core(u3_noun); + u3_noun u3wf_cube(u3_noun); + u3_noun u3wf_face(u3_noun); + u3_noun u3wf_fine(u3_noun); + u3_noun u3wf_fitz(u3_noun); + u3_noun u3wf_flan_139(u3_noun); + u3_noun u3wf_flay(u3_noun); + u3_noun u3wf_flip_139(u3_noun); + u3_noun u3wf_flor_139(u3_noun); + u3_noun u3wf_forq(u3_noun); + u3_noun u3wf_fork(u3_noun); + u3_noun u3wf_hint(u3_noun); + u3_noun u3wf_hike(u3_noun); + u3_noun u3wf_look(u3_noun); + u3_noun u3wf_loot(u3_noun); + + u3_noun u3wfl_bunt(u3_noun); + u3_noun u3wfl_whip(u3_noun); + + u3_noun u3wfp_hack(u3_noun); + u3_noun u3wfp_late(u3_noun); + u3_noun u3wfp_open(u3_noun); + u3_noun u3wfp_rake(u3_noun); + + u3_noun u3wfu_busk(u3_noun); + u3_noun u3wfu_crop(u3_noun); + u3_noun u3wfu_find(u3_noun); + u3_noun u3wfu_fond(u3_noun); + u3_noun u3wfu_fish(u3_noun); + u3_noun u3wfu_fuse(u3_noun); + u3_noun u3wfu_redo(u3_noun); + u3_noun u3wfu_mint(u3_noun); + u3_noun u3wfu_mull(u3_noun); + u3_noun u3wfu_nest_dext(u3_noun); + u3_noun u3wfu_peek(u3_noun); + u3_noun u3wfu_play(u3_noun); + u3_noun u3wfu_repo(u3_noun); + u3_noun u3wfu_rest(u3_noun); + + /** Tier 7. + **/ + u3_noun u3wg_plot_fax(u3_noun); + u3_noun u3wg_plot_met(u3_noun); + u3_noun u3wi_la_add(u3_noun); + u3_noun u3wi_la_sub(u3_noun); + u3_noun u3wi_la_mul(u3_noun); + u3_noun u3wi_la_div(u3_noun); + u3_noun u3wi_la_mod(u3_noun); + u3_noun u3wi_la_adds(u3_noun); + u3_noun u3wi_la_subs(u3_noun); + u3_noun u3wi_la_muls(u3_noun); + u3_noun u3wi_la_divs(u3_noun); + u3_noun u3wi_la_mods(u3_noun); + u3_noun u3wi_la_dot(u3_noun); + u3_noun u3wi_la_diag(u3_noun); + u3_noun u3wi_la_transpose(u3_noun); + u3_noun u3wi_la_cumsum(u3_noun); + u3_noun u3wi_la_argmin(u3_noun); + u3_noun u3wi_la_argmax(u3_noun); + u3_noun u3wi_la_ravel(u3_noun); + u3_noun u3wi_la_min(u3_noun); + u3_noun u3wi_la_max(u3_noun); + u3_noun u3wi_la_linspace(u3_noun); + u3_noun u3wi_la_range(u3_noun); + u3_noun u3wi_la_abs(u3_noun); + u3_noun u3wi_la_gth(u3_noun); + u3_noun u3wi_la_gte(u3_noun); + u3_noun u3wi_la_lth(u3_noun); + u3_noun u3wi_la_lte(u3_noun); + + u3_noun u3wi_la_trace(u3_noun); + u3_noun u3wi_la_mmul(u3_noun); + + u3_noun u3wi_rd_exp(u3_noun); + u3_noun u3wi_rd_log(u3_noun); + u3_noun u3wi_rd_sin(u3_noun); + u3_noun u3wi_rd_cos(u3_noun); + u3_noun u3wi_rd_tan(u3_noun); + u3_noun u3wi_rd_atan(u3_noun); + u3_noun u3wi_rd_atan2(u3_noun); + u3_noun u3wi_rd_asin(u3_noun); + u3_noun u3wi_rd_acos(u3_noun); + u3_noun u3wi_rd_sqt(u3_noun); + u3_noun u3wi_rd_cbt(u3_noun); + u3_noun u3wi_rd_pow(u3_noun); + u3_noun u3wi_rd_pow_n(u3_noun); + u3_noun u3wi_rd_log2(u3_noun); + u3_noun u3wi_rd_log10(u3_noun); + +#endif /* ifndef U3_JETS_W_H */ + diff --git a/libmath/vere64/README.md b/libmath/vere64/README.md new file mode 100644 index 0000000..a3d7218 --- /dev/null +++ b/libmath/vere64/README.md @@ -0,0 +1,106 @@ +# libmath C jets (vere mirror) + +C jet implementations for the `math.hoon` transcendental library, **vendored +from the vere runtime** (`pkg/noun`). The jets do not build in this repo — these +directories are a maintained mirror so the C and the Hoon evolve together. There +is no automatic cross-repo sync; apply changes to vere by hand. + +Two copies, one per runtime word size (mirroring `/lib/lagoon`): + +- `libmath/vere/` — the 32-bit runtime (`urbit/vere`) +- `libmath/vere64/` — the 64-bit runtime (`urbit/vere-ml64`, built `-Dvere64=true`) + +Each holds `noun/jets/{i/math.c, 135/tree.c, q.h, w.h}` — the full vendored files, +ready to diff/apply against the corresponding `pkg/noun/jets/…`. + +## The 32-bit and 64-bit `math.c` differ by exactly 2 lines +Marshalling is **chub-based** (`u3r_chub`/`u3i_chubs`), so it is word-size-agnostic +— the divergence that broke the `@rq sub` jet cannot recur, and all 15 algorithm +cores plus the 12 single-arg wrappers are byte-identical across the two copies. +The **only** difference is the two-arg sample extraction (atan2, pow/pow-n), +because the `u3r_mean` macro's API diverged between the runtimes: + +``` +64-bit (vere64): u3r_mean(cor, {u3x_sam_2, &y}, {u3x_sam_3, &x}) // brace pairs +32-bit (vere): u3r_mean(cor, u3x_sam_2, &y, u3x_sam_3, &x, 0) // flat varargs +``` + +Keep the two copies in sync **except** those two lines. + +## What's covered +All 15 `@rd` transcendentals, bit-exact to the Hoon `++ rd` door (same reduction, +coefficients, Horner order — not merely faithful): `exp log sin cos tan atan +atan2 asin acos sqt cbt pow pow-n log-2 log-10`. The other width doors +(`rs`/`rh`/`rq`) are not yet jetted. + +Only the **135** kelvin tree is vendored: the stock test ships (`~dev`, fresh +fakeships from `brass.pill`) are `hoon-version` 135, and that is where these jets +fire. Apply to 136/137 as well if a target ship runs those. + +## How to apply to a vere tree (`pkg/noun`) +1. Copy `noun/jets/i/math.c` → `pkg/noun/jets/i/math.c` (use the matching word-size + copy — the two-arg `u3r_mean` form must match that runtime's macro). +2. Add the math registration block to `pkg/noun/jets/135/tree.c`: the 15 + `_135_non__math_rd_*_a[]` harms, the `_135_non__math_rd_d[]` / `_135_non__math_d[]` + cores, and the `{ "math", 7, 0, _135_non__math_d, no_hashes }` entry in + `_135_non_d[]` as a sibling of `lagoon`. (`noun/jets/135/tree.c` here already + has it — diff it in.) +3. Declare the 15 `u3qi_rd_*` in `pkg/noun/jets/q.h` and `u3wi_rd_*` in `w.h` + (after the lagoon decls). `atan2`/`pow`/`pow_n` take two atoms. +4. Add `"jets/i/math.c"` to the jet source list in `pkg/noun/build.zig`. +5. Rebuild; on a 64-bit build pass `-Dvere64=true`. + +## CRITICAL: the Hoon jet structure (the gotcha that cost a day) +`math.hoon` must mirror `/lib/lagoon`'s jet structure exactly: + +``` +=< math :: export the engine so `/+ math` + `rd:math` work +~% %non ..part ~ :: file |% anchored to the shared %non chapter +|% +++ math + ^| + =+ [rnd=*?(%n %u %d %z)] :: <-- REQUIRED: the engine must be a DOOR + ~/ %math :: (sample-bearing), not a bare |% + |% + ++ rd + ~/ %rd + ^| + |_ [r=... rtol=...] + ++ exp ~/ %exp |=(x=@rd ...) +``` + +A **sample-less `~/`-hinted core anchors its parent to the dashboard ROOT**, so +`%math` (and everything under it) misses the hot dashboard — the core SPOTs in +`_cj_mile` but `_cj_hot_mean` returns `jax=0` and no C jet ever attaches. The +`^| =+ [rnd]` sample makes `~/` resolve the parent to `%non`, exactly as +lagoon's `++ la ^| =+ [rnd] ~/ %lagoon |%` does. Verified via a `_cj_hot_mean` +trace: `math par=0 MISS` (bare |%) -> `math par=non FOUND` (door). + +The chapter chain is `pen -> hex -> non -> math -> -> `, e.g. +`non/math/rd/exp`. + +## Verifying the jets +The idiomatic check is the desk's own `-test` suite — run on a **jetted** binary, +`expect-eq` compares the jet's output against the hardcoded bit pattern, so a +wrong jet fails the test: + +``` +-test %/tests/lib :: math-exp/log/sqrt/ainv/atan/tan/trig/derived... +``` + +All pass `ok=%.y` on both the 32-bit and 64-bit jetted runtimes (proving the +chub-ABI claim: identical bit-exact results at both word sizes). `test/` here +also has a standalone C harness (`build.sh` + `rd_check.c`, sharing the master +`math.c` via `-DMATH_JET_HARNESS`) and an on-ship differ. + +To confirm a jet actually fires: `~>(%bout (sin:rd:math .~1))` reports ~µs/call +(jetted) vs many ms (interpreted); `sin × 200k` under `%bout` was ~430ms. + +## WARNING: never `C-c` a running serf in a test loop +SIGINT mid-event makes the runtime longjmp out with the loom half-mutated (e.g. +inside a `u3i_chubs` alloc), producing a `palloc: double free` / `loom: corrupt` +that is **persisted into the snapshot** and re-detected on every later boot as a +"serf unexpectedly shut down" in `u3j_boot`. It looks exactly like a +non-deterministic jet memory bug but is purely the SIGINT. Drive the dojo with +`C-u` only (clears the line without signalling), one query at a time — or use a +generator / `-test` thread that computes everything in one event. diff --git a/libmath/vere64/noun/jets/135/tree.c b/libmath/vere64/noun/jets/135/tree.c new file mode 100644 index 0000000..e7419bc --- /dev/null +++ b/libmath/vere64/noun/jets/135/tree.c @@ -0,0 +1,1309 @@ +#include "c3/c3.h" +#include "jets.h" +#include "jets/w.h" + + +static c3_c* no_hashes[] = { 0 }; + +static u3j_harm _135_hex_mimes_base16_en_a[] = {{".2", u3we_en_base16}, {}}; +static u3j_harm _135_hex_mimes_base16_de_a[] = {{".2", u3we_de_base16}, {}}; +static u3j_core _135_hex_mimes_base16_d[] = + { { "en", 7, _135_hex_mimes_base16_en_a, 0, no_hashes }, + { "de", 7, _135_hex_mimes_base16_de_a, 0, no_hashes }, + {} + }; +static u3j_core _135_hex_mimes_d[] = + { { "base16", 3, 0, _135_hex_mimes_base16_d, no_hashes }, + {} + }; + +static u3j_harm _135_hex_aes_ecba_en_a[] = {{".2", u3wea_ecba_en}, {}}; +static u3j_harm _135_hex_aes_ecba_de_a[] = {{".2", u3wea_ecba_de}, {}}; +static u3j_core _135_hex_aes_ecba_d[] = + { { "en", 7, _135_hex_aes_ecba_en_a, 0, no_hashes }, + { "de", 7, _135_hex_aes_ecba_de_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_hex_aes_ecbb_en_a[] = {{".2", u3wea_ecbb_en}, {}}; +static u3j_harm _135_hex_aes_ecbb_de_a[] = {{".2", u3wea_ecbb_de}, {}}; +static u3j_core _135_hex_aes_ecbb_d[] = + { { "en", 7, _135_hex_aes_ecbb_en_a, 0, no_hashes }, + { "de", 7, _135_hex_aes_ecbb_de_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_hex_aes_ecbc_en_a[] = {{".2", u3wea_ecbc_en}, {}}; +static u3j_harm _135_hex_aes_ecbc_de_a[] = {{".2", u3wea_ecbc_de}, {}}; +static u3j_core _135_hex_aes_ecbc_d[] = + { { "en", 7, _135_hex_aes_ecbc_en_a, 0, no_hashes }, + { "de", 7, _135_hex_aes_ecbc_de_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_hex_aes_cbca_en_a[] = {{".2", u3wea_cbca_en}, {}}; +static u3j_harm _135_hex_aes_cbca_de_a[] = {{".2", u3wea_cbca_de}, {}}; +static u3j_core _135_hex_aes_cbca_d[] = + { { "en", 7, _135_hex_aes_cbca_en_a, 0, no_hashes }, + { "de", 7, _135_hex_aes_cbca_de_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_hex_aes_cbcb_en_a[] = {{".2", u3wea_cbcb_en}, {}}; +static u3j_harm _135_hex_aes_cbcb_de_a[] = {{".2", u3wea_cbcb_de}, {}}; +static u3j_core _135_hex_aes_cbcb_d[] = + { { "en", 7, _135_hex_aes_cbcb_en_a, 0, no_hashes }, + { "de", 7, _135_hex_aes_cbcb_de_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_hex_aes_cbcc_en_a[] = {{".2", u3wea_cbcc_en}, {}}; +static u3j_harm _135_hex_aes_cbcc_de_a[] = {{".2", u3wea_cbcc_de}, {}}; +static u3j_core _135_hex_aes_cbcc_d[] = + { { "en", 7, _135_hex_aes_cbcc_en_a, 0, no_hashes }, + { "de", 7, _135_hex_aes_cbcc_de_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_hex_aes_siva_en_a[] = {{".2", u3wea_siva_en}, {}}; +static u3j_harm _135_hex_aes_siva_de_a[] = {{".2", u3wea_siva_de}, {}}; +static u3j_core _135_hex_aes_siva_d[] = + { { "en", 7, _135_hex_aes_siva_en_a, 0, no_hashes }, + { "de", 7, _135_hex_aes_siva_de_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_hex_aes_sivb_en_a[] = {{".2", u3wea_sivb_en}, {}}; +static u3j_harm _135_hex_aes_sivb_de_a[] = {{".2", u3wea_sivb_de}, {}}; +static u3j_core _135_hex_aes_sivb_d[] = + { { "en", 7, _135_hex_aes_sivb_en_a, 0, no_hashes }, + { "de", 7, _135_hex_aes_sivb_de_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_hex_aes_sivc_en_a[] = {{".2", u3wea_sivc_en}, {}}; +static u3j_harm _135_hex_aes_sivc_de_a[] = {{".2", u3wea_sivc_de}, {}}; +static u3j_core _135_hex_aes_sivc_d[] = + { { "en", 7, _135_hex_aes_sivc_en_a, 0, no_hashes }, + { "de", 7, _135_hex_aes_sivc_de_a, 0, no_hashes }, + {} + }; +static u3j_core _135_hex_aes_d[] = + { { "ecba", 7, 0, _135_hex_aes_ecba_d, no_hashes }, + { "ecbb", 7, 0, _135_hex_aes_ecbb_d, no_hashes }, + { "ecbc", 7, 0, _135_hex_aes_ecbc_d, no_hashes }, + { "cbca", 7, 0, _135_hex_aes_cbca_d, no_hashes }, + { "cbcb", 7, 0, _135_hex_aes_cbcb_d, no_hashes }, + { "cbcc", 7, 0, _135_hex_aes_cbcc_d, no_hashes }, + { "siva", 7, 0, _135_hex_aes_siva_d, no_hashes }, + { "sivb", 7, 0, _135_hex_aes_sivb_d, no_hashes }, + { "sivc", 7, 0, _135_hex_aes_sivc_d, no_hashes }, + {} + }; + +static u3j_harm _135_hex_leer_a[] = {{".2", u3we_leer}, {}}; +static u3j_harm _135_hex_lore_a[] = {{".2", u3we_lore}, {}}; +static u3j_harm _135_hex_loss_a[] = {{".2", u3we_loss}, {}}; +static u3j_harm _135_hex_lune_a[] = {{".2", u3we_lune}, {}}; + + +static u3j_harm _135_hex__adler32_a[] = {{".2", u3we_adler32, c3y}, {}}; +static u3j_core _135_hex__adler_d[] = + { { "adler32", 7, _135_hex__adler32_a, 0, no_hashes }, + {} + }; +static u3j_harm _135_hex__crc32_a[] = {{".2", u3we_crc32}, {}}; +static u3j_core _135_hex__crc_d[] = + { {"crc32", 7, _135_hex__crc32_a, 0, no_hashes }, + {} + }; + +static u3j_core _135_hex_checksum_d[] = + { { "adler", 3, 0, _135_hex__adler_d, no_hashes }, + { "crc", 3, 0, _135_hex__crc_d, no_hashes}, + {} + }; + + +static u3j_harm _135_hex__decompress_zlib_a[] = {{".2", u3we_decompress_zlib}, {}}; +static u3j_harm _135_hex__decompress_gzip_a[] = {{".2", u3we_decompress_gzip}, {}}; +static u3j_core _135_hex__zlib_d[] = { + {"decompress-zlib", 7, _135_hex__decompress_zlib_a, 0, no_hashes }, + {"decompress-gzip", 7, _135_hex__decompress_gzip_a, 0, no_hashes }, + {}}; + + +static u3j_harm _135_hex_coed__ed_scad_a[] = {{".2", u3wee_scad}, {}}; +static u3j_harm _135_hex_coed__ed_scas_a[] = {{".2", u3wee_scas}, {}}; +static u3j_harm _135_hex_coed__ed_scap_a[] = {{".2", u3wee_scap}, {}}; + +static u3j_harm _135_hex_coed__ed_puck_a[] = {{".2", u3wee_puck}, {}}; +static u3j_harm _135_hex_coed__ed_luck_a[] = {{".2", u3wee_luck}, {}}; +static u3j_harm _135_hex_coed__ed_sign_a[] = {{".2", u3wee_sign}, {}}; +static u3j_harm _135_hex_coed__ed_sign_raw_a[] = {{".2", u3wee_sign_raw}, {}}; +static u3j_harm _135_hex_coed__ed_sign_octs_a[] = {{".2", u3wee_sign_octs}, {}}; +static u3j_harm _135_hex_coed__ed_sign_octs_raw_a[] = {{".2", u3wee_sign_octs_raw}, {}}; +static u3j_harm _135_hex_coed__ed_veri_octs_a[] = {{".2", u3wee_veri_octs}, {}}; +static u3j_harm _135_hex_coed__ed_veri_a[] = {{".2", u3wee_veri}, {}}; +static u3j_harm _135_hex_coed__ed_shar_a[] = {{".2", u3wee_shar}, {}}; +static u3j_harm _135_hex_coed__ed_slar_a[] = {{".2", u3wee_slar}, {}}; + +static u3j_harm _135_hex_coed__ed_smac_a[] = + {{".2", u3wee_smac}, {}}; + +static u3j_harm _135_hex_coed__ed_recs_a[] = + {{".2", u3wee_recs}, {}}; + +static u3j_harm _135_hex_coed__ed_point_neg_a[] = + {{".2", u3wee_point_neg}, {}}; + +static u3j_harm _135_hex_coed__ed_point_add_a[] = + {{".2", u3wee_point_add}, {}}; + +static u3j_harm _135_hex_coed__ed_scalarmult_a[] = + {{".2", u3wee_scalarmult}, {}}; + +static u3j_harm _135_hex_coed__ed_scalarmult_base_a[] = + {{".2", u3wee_scalarmult_base}, {}}; + +static u3j_harm _135_hex_coed__ed_add_scalarmult_scalarmult_base_a[] = + {{".2", u3wee_add_scalarmult_scalarmult_base}, {}}; + +static u3j_harm _135_hex_coed__ed_add_double_scalarmult_a[] = + {{".2", u3wee_add_double_scalarmult}, {}}; + +static u3j_core _135_hex_coed__ed_d[] = + { { "sign", 7, _135_hex_coed__ed_sign_a, 0, no_hashes }, + { "sign-raw", 7, _135_hex_coed__ed_sign_raw_a, 0, no_hashes }, + { "sign-octs", 7, _135_hex_coed__ed_sign_octs_a, 0, no_hashes }, + { "sign-octs-raw", 7, _135_hex_coed__ed_sign_octs_raw_a, 0, no_hashes }, + { "puck", 7, _135_hex_coed__ed_puck_a, 0, no_hashes }, + { "luck", 7, _135_hex_coed__ed_luck_a, 0, no_hashes }, + { "scad", 7, _135_hex_coed__ed_scad_a, 0, no_hashes }, + { "scas", 7, _135_hex_coed__ed_scas_a, 0, no_hashes }, + { "scap", 7, _135_hex_coed__ed_scap_a, 0, no_hashes }, + { "veri-octs", 7, _135_hex_coed__ed_veri_octs_a, 0, no_hashes }, + { "veri", 7, _135_hex_coed__ed_veri_a, 0, no_hashes }, + { "shar", 7, _135_hex_coed__ed_shar_a, 0, no_hashes }, + { "slar", 7, _135_hex_coed__ed_slar_a, 0, no_hashes }, + { "point-add", 7, _135_hex_coed__ed_point_add_a, 0, 0 }, + { "point-neg", 7, _135_hex_coed__ed_point_neg_a, 0, 0 }, + { "recs", 7, _135_hex_coed__ed_recs_a, 0, 0 }, + { "smac", 7, _135_hex_coed__ed_smac_a, 0, 0 }, + { "scalarmult", 7, _135_hex_coed__ed_scalarmult_a, 0, + no_hashes }, + { "scalarmult-base", 7, _135_hex_coed__ed_scalarmult_base_a, 0, + no_hashes }, + { "add-scalarmult-scalarmult-base", 7, + _135_hex_coed__ed_add_scalarmult_scalarmult_base_a, 0, + no_hashes }, + { "add-double-scalarmult", 7, + _135_hex_coed__ed_add_double_scalarmult_a, 0, + no_hashes }, + {} + }; + +static u3j_core _135_hex_coed_d[] = + { { "ed", 3, 0, _135_hex_coed__ed_d, no_hashes }, + {} + }; + +static u3j_harm _135_hex_hmac_hmac_a[] = {{".2", u3we_hmac}, {}}; +static u3j_core _135_hex_hmac_d[] = + { { "hmac", 7, _135_hex_hmac_hmac_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_hex_argon2_a[] = {{".2", u3we_argon2}, {}}; +static u3j_core _135_hex_argon_d[] = + { { "argon2", 511, _135_hex_argon2_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_hex_scr_pbk_a[] = {{".2", u3wes_pbk, c3y}, {}}; +static u3j_harm _135_hex_scr_pbl_a[] = {{".2", u3wes_pbl, c3y}, {}}; +static u3j_harm _135_hex_scr_hsh_a[] = {{".2", u3wes_hsh, c3y}, {}}; +static u3j_harm _135_hex_scr_hsl_a[] = {{".2", u3wes_hsl, c3y}, {}}; +static u3j_core _135_hex_scr_d[] = + { { "pbk", 7, _135_hex_scr_pbk_a, 0, no_hashes }, + { "pbl", 7, _135_hex_scr_pbl_a, 0, no_hashes }, + { "hsh", 7, _135_hex_scr_hsh_a, 0, no_hashes }, + { "hsl", 7, _135_hex_scr_hsl_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_hex_secp_secp256k1_make_a[] = {{".2", u3we_make, c3y}, {}}; +static u3j_harm _135_hex_secp_secp256k1_sign_a[] = {{".2", u3we_sign, c3y}, {}}; +static u3j_harm _135_hex_secp_secp256k1_reco_a[] = {{".2", u3we_reco, c3y}, {}}; + +static u3j_harm _135_hex_secp_secp256k1_schnorr_sosi_a[] = + {{".2", u3we_sosi}, {}}; +static u3j_harm _135_hex_secp_secp256k1_schnorr_sove_a[] = + {{".2", u3we_sove}, {}}; +static u3j_core _135_hex_secp_secp256k1_schnorr_d[] = + { { "sosi", 7, + _135_hex_secp_secp256k1_schnorr_sosi_a, 0, + no_hashes }, + { "sove", 7, + _135_hex_secp_secp256k1_schnorr_sove_a, 0, + no_hashes }, + {} + }; + +static u3j_core _135_hex_secp_secp256k1_d[] = + { { "make", 7, _135_hex_secp_secp256k1_make_a, 0, no_hashes }, + { "sign", 7, _135_hex_secp_secp256k1_sign_a, 0, no_hashes }, + { "reco", 7, _135_hex_secp_secp256k1_reco_a, 0, no_hashes }, + { "schnorr", 7, 0, + _135_hex_secp_secp256k1_schnorr_d, + no_hashes }, + {} + }; +static u3j_core _135_hex_secp_d[] = + { { "secp256k1", 3, 0, _135_hex_secp_secp256k1_d, no_hashes }, + {} + }; + + +static u3j_harm _135_hex_kecc_k224_a[] = + {{".2", u3we_kecc224, c3y, c3y, c3y}, {}}; +static u3j_harm _135_hex_kecc_k256_a[] = + {{".2", u3we_kecc256, c3y, c3y, c3y}, {}}; +static u3j_harm _135_hex_kecc_k384_a[] = + {{".2", u3we_kecc384, c3y, c3y, c3y}, {}}; +static u3j_harm _135_hex_kecc_k512_a[] = + {{".2", u3we_kecc512, c3y, c3y, c3y}, {}}; +static u3j_core _135_hex_kecc_d[] = + { { "k224", 7, _135_hex_kecc_k224_a, 0, no_hashes }, + { "k256", 7, _135_hex_kecc_k256_a, 0, no_hashes }, + { "k384", 7, _135_hex_kecc_k384_a, 0, no_hashes }, + { "k512", 7, _135_hex_kecc_k512_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_hex_ripemd_160_a[] = {{".2", u3we_ripe, c3y}, {}}; +static u3j_core _135_hex_ripe_d[] = + { { "ripemd160", 7, _135_hex_ripemd_160_a, 0, no_hashes }, + {} + }; + + + +/* layer five + */ +static u3j_harm _135_pen_cell_a[] = {{".2", u3wf_cell}, {}}; +static u3j_harm _135_pen_comb_a[] = {{".2", u3wf_comb}, {}}; +static u3j_harm _135_pen_cons_a[] = {{".2", u3wf_cons}, {}}; +static u3j_harm _135_pen_core_a[] = {{".2", u3wf_core}, {}}; +static u3j_harm _135_pen_face_a[] = {{".2", u3wf_face}, {}}; +static u3j_harm _135_pen_fitz_a[] = {{".2", u3wf_fitz}, {}}; +static u3j_harm _135_pen_fork_a[] = {{".2", u3wf_fork}, {}}; + +static u3j_harm _135_pen_look_a[] = {{".2", u3wf_look}, {}}; +static u3j_harm _135_pen_loot_a[] = {{".2", u3wf_loot}, {}}; + +static u3j_harm _135_pen__ut_crop_a[] = {{".2", u3wfu_crop}, {}}; +static u3j_harm _135_pen__ut_fish_a[] = {{".2", u3wfu_fish}, {}}; +static u3j_harm _135_pen__ut_fuse_a[] = {{".2", u3wfu_fuse}, {}}; +static u3j_harm _135_pen__ut_redo_a[] = {{".2", u3wfu_redo}, {}}; +static u3j_harm _135_pen__ut_mint_a[] = {{".2", u3wfu_mint}, {}}; +static u3j_harm _135_pen__ut_mull_a[] = {{".2", u3wfu_mull}, {}}; + +static u3j_harm _135_pen__ut_nest_dext_a[] = {{".2", u3wfu_nest_dext}, {}}; +static u3j_core _135_pen__ut_nest_in_d[] = + { + { "nest-dext", 3, _135_pen__ut_nest_dext_a, 0, no_hashes }, + {} + }; +static u3j_core _135_pen__ut_nest_d[] = + { + { "nest-in", 7, 0, _135_pen__ut_nest_in_d, no_hashes }, + {} + }; + +static u3j_harm _135_pen__ut_rest_a[] = {{".2", u3wfu_rest}, {}}; + +static u3j_core _135_pen__ut_d[] = + { + { "crop", 7, _135_pen__ut_crop_a, 0, no_hashes }, + { "fish", 7, _135_pen__ut_fish_a, 0, no_hashes }, + { "fuse", 7, _135_pen__ut_fuse_a, 0, no_hashes }, + { "redo", 7, _135_pen__ut_redo_a, 0, no_hashes }, + { "mint", 7, _135_pen__ut_mint_a, 0, no_hashes }, + { "mull", 7, _135_pen__ut_mull_a, 0, no_hashes }, + { "nest", 7, 0, _135_pen__ut_nest_d, no_hashes }, + { "rest", 7, _135_pen__ut_rest_a, 0, no_hashes }, + {} + }; + +static u3j_hood _135_pen__ut_ho[] = + { { "ar", 12282 }, + { "fan", 28, c3n }, + { "rib", 58, c3n }, + { "vet", 59, c3n }, + + { "blow", 6015 }, + { "burp", 342 }, + { "busk", 1353 }, + { "buss", 374 }, + { "crop", 1494 }, + { "duck", 1524 }, + { "dune", 2991 }, + { "dunk", 3066 }, + { "epla", 12206 }, + { "emin", 1534 }, + { "emul", 6134 }, + { "feel", 1502 }, + { "felt", 94 }, + { "fine", 49086 }, + { "fire", 4 }, + { "fish", 6006 }, + { "fond", 12283 }, + { "fund", 6014 }, + // XX +funk is not part of +ut, and this hook appears to be unused + // remove from here and the +ut hint + // + { "funk", 0xbefafa, c3y, 31 }, + { "fuse", 24021 }, + { "gain", 380 }, + { "lose", 0x2fefe }, + { "mile", 382 }, + { "mine", 372 }, + { "mint", 49083 }, + { "moot", 0x2feff }, + { "mull", 24020 }, + { "nest", 92 }, + { "peel", 1526 }, + { "play", 3006 }, + { "peek", 1532 }, + { "repo", 22 }, + { "rest", 6102 }, + { "tack", 6007 }, + { "toss", 24540 }, + { "wrap", 6135 }, + {}, + }; + + +static u3j_hood _135_pen_ho[] = { + { "ap", 22 }, + { "ut", 86 }, + {}, +}; + + +/* layer four + */ +static u3j_harm _135_qua_trip_a[] = {{".2", u3we_trip}, {}}; + +static u3j_harm _135_qua_slaw_a[] = {{".2", u3we_slaw}, {}}; +static u3j_harm _135_qua_scot_a[] = {{".2", u3we_scot}, {}}; +static u3j_harm _135_qua_scow_a[] = {{".2", u3we_scow}, {}}; + +static u3j_harm _135_qua__po_ind_a[] = {{".2", u3wcp_ind}, {}}; +static u3j_harm _135_qua__po_ins_a[] = {{".2", u3wcp_ins}, {}}; +static u3j_harm _135_qua__po_tod_a[] = {{".2", u3wcp_tod}, {}}; +static u3j_harm _135_qua__po_tos_a[] = {{".2", u3wcp_tos}, {}}; +static u3j_core _135_qua__po_d[] = + { { "ind", 7, _135_qua__po_ind_a, 0, no_hashes }, + { "ins", 7, _135_qua__po_ins_a, 0, no_hashes }, + { "tod", 7, _135_qua__po_tod_a, 0, no_hashes }, + { "tos", 7, _135_qua__po_tos_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_qua__bend_fun_a[] = {{".2", u3we_bend_fun}, {}}; +static u3j_core _135_qua__bend_d[] = + { { "fun", 7, _135_qua__bend_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_qua__cold_fun_a[] = {{".2", u3we_cold_fun}, {}}; +static u3j_core _135_qua__cold_d[] = + { { "fun", 7, _135_qua__cold_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_qua__cook_fun_a[] = {{".2", u3we_cook_fun}, {}}; +static u3j_core _135_qua__cook_d[] = + { { "fun", 7, _135_qua__cook_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_qua__comp_fun_a[] = {{".2", u3we_comp_fun}, {}}; +static u3j_core _135_qua__comp_d[] = + { { "fun", 7, _135_qua__comp_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_qua__easy_fun_a[] = {{".2", u3we_easy_fun}, {}}; +static u3j_core _135_qua__easy_d[] = + { { "fun", 7, _135_qua__easy_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_qua__glue_fun_a[] = {{".2", u3we_glue_fun}, {}}; +static u3j_core _135_qua__glue_d[] = + { { "fun", 7, _135_qua__glue_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_qua__here_fun_a[] = {{".2", u3we_here_fun}, {}}; +static u3j_core _135_qua__here_d[] = + { { "fun", 7, _135_qua__here_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_qua__just_fun_a[] = {{".2", u3we_just_fun}, {}}; +static u3j_core _135_qua__just_d[] = + { { "fun", 7, _135_qua__just_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_qua__mask_fun_a[] = {{".2", u3we_mask_fun}, {}}; +static u3j_core _135_qua__mask_d[] = + { { "fun", 7, _135_qua__mask_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_qua__shim_fun_a[] = {{".2", u3we_shim_fun}, {}}; +static u3j_core _135_qua__shim_d[] = + { { "fun", 7, _135_qua__shim_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_qua__stag_fun_a[] = {{".2", u3we_stag_fun}, {}}; +static u3j_core _135_qua__stag_d[] = + { { "fun", 7, _135_qua__stag_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_qua__stew_fun_a[] = {{".2", u3we_stew_fun}, {}}; +static u3j_core _135_qua__stew_d[] = + { { "fun", 31, _135_qua__stew_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_qua__stir_fun_a[] = {{".2", u3we_stir_fun}, {}}; +static u3j_core _135_qua__stir_d[] = + { { "fun", 7, _135_qua__stir_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_qua_pfix_a[] = {{".2", u3we_pfix}, {}}; + +static u3j_harm _135_qua_plug_a[] = {{".2", u3we_plug}, {}}; +static u3j_harm _135_qua_pose_a[] = {{".2", u3we_pose}, {}}; + +static u3j_harm _135_qua_sfix_a[] = {{".2", u3we_sfix}, {}}; + +static u3j_harm _135_qua_mink_a[] = {{".2", u3we_mink}, {}}; +static u3j_harm _135_qua_mole_a[] = {{".2", u3we_mole}, {}}; +static u3j_harm _135_qua_mule_a[] = {{".2", u3we_mule}, {}}; + + +static u3j_hood _135_qua_ho[] = { + { "show", 188 }, + {}, +}; + + +/* layer three + */ +static u3j_harm _135_tri__cofl__drg_a[] = {{".2", u3wef_drg}, {}}; +static u3j_harm _135_tri__cofl__lug_a[] = {{".2", u3wef_lug}, {}}; +static u3j_core _135_tri__cofl_d[] = + { { "drg", 7, _135_tri__cofl__drg_a, 0, no_hashes }, + { "lug", 7, _135_tri__cofl__lug_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_tri__rd_add_a[] = {{".2", u3wer_add}, {}}; +static u3j_harm _135_tri__rd_sub_a[] = {{".2", u3wer_sub}, {}}; +static u3j_harm _135_tri__rd_mul_a[] = {{".2", u3wer_mul}, {}}; +static u3j_harm _135_tri__rd_div_a[] = {{".2", u3wer_div}, {}}; +static u3j_harm _135_tri__rd_sqt_a[] = {{".2", u3wer_sqt}, {}}; +static u3j_harm _135_tri__rd_fma_a[] = {{".2", u3wer_fma}, {}}; +static u3j_harm _135_tri__rd_lth_a[] = {{".2", u3wer_lth}, {}}; +static u3j_harm _135_tri__rd_lte_a[] = {{".2", u3wer_lte}, {}}; +static u3j_harm _135_tri__rd_equ_a[] = {{".2", u3wer_equ}, {}}; +static u3j_harm _135_tri__rd_gte_a[] = {{".2", u3wer_gte}, {}}; +static u3j_harm _135_tri__rd_gth_a[] = {{".2", u3wer_gth}, {}}; +static u3j_core _135_tri__rd_d[] = + { { "add", 7, _135_tri__rd_add_a, 0, no_hashes }, + { "sub", 7, _135_tri__rd_sub_a, 0, no_hashes }, + { "mul", 7, _135_tri__rd_mul_a, 0, no_hashes }, + { "div", 7, _135_tri__rd_div_a, 0, no_hashes }, + { "sqt", 7, _135_tri__rd_sqt_a, 0, no_hashes }, + { "fma", 7, _135_tri__rd_fma_a, 0, no_hashes }, + { "lth", 7, _135_tri__rd_lth_a, 0, no_hashes }, + { "lte", 7, _135_tri__rd_lte_a, 0, no_hashes }, + { "equ", 7, _135_tri__rd_equ_a, 0, no_hashes }, + { "gte", 7, _135_tri__rd_gte_a, 0, no_hashes }, + { "gth", 7, _135_tri__rd_gth_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_tri__rs_add_a[] = {{".2", u3wet_add}, {}}; +static u3j_harm _135_tri__rs_sub_a[] = {{".2", u3wet_sub}, {}}; +static u3j_harm _135_tri__rs_mul_a[] = {{".2", u3wet_mul}, {}}; +static u3j_harm _135_tri__rs_div_a[] = {{".2", u3wet_div}, {}}; +static u3j_harm _135_tri__rs_sqt_a[] = {{".2", u3wet_sqt}, {}}; +static u3j_harm _135_tri__rs_fma_a[] = {{".2", u3wet_fma}, {}}; +static u3j_harm _135_tri__rs_lth_a[] = {{".2", u3wet_lth}, {}}; +static u3j_harm _135_tri__rs_lte_a[] = {{".2", u3wet_lte}, {}}; +static u3j_harm _135_tri__rs_equ_a[] = {{".2", u3wet_equ}, {}}; +static u3j_harm _135_tri__rs_gte_a[] = {{".2", u3wet_gte}, {}}; +static u3j_harm _135_tri__rs_gth_a[] = {{".2", u3wet_gth}, {}}; +static u3j_core _135_tri__rs_d[] = + { { "add", 7, _135_tri__rs_add_a, 0, no_hashes }, + { "sub", 7, _135_tri__rs_sub_a, 0, no_hashes }, + { "mul", 7, _135_tri__rs_mul_a, 0, no_hashes }, + { "div", 7, _135_tri__rs_div_a, 0, no_hashes }, + { "sqt", 7, _135_tri__rs_sqt_a, 0, no_hashes }, + { "fma", 7, _135_tri__rs_fma_a, 0, no_hashes }, + { "lth", 7, _135_tri__rs_lth_a, 0, no_hashes }, + { "lte", 7, _135_tri__rs_lte_a, 0, no_hashes }, + { "equ", 7, _135_tri__rs_equ_a, 0, no_hashes }, + { "gte", 7, _135_tri__rs_gte_a, 0, no_hashes }, + { "gth", 7, _135_tri__rs_gth_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_tri__rq_add_a[] = {{".2", u3weq_add}, {}}; +static u3j_harm _135_tri__rq_sub_a[] = {{".2", u3weq_sub}, {}}; +static u3j_harm _135_tri__rq_mul_a[] = {{".2", u3weq_mul}, {}}; +static u3j_harm _135_tri__rq_div_a[] = {{".2", u3weq_div}, {}}; +static u3j_harm _135_tri__rq_sqt_a[] = {{".2", u3weq_sqt}, {}}; +static u3j_harm _135_tri__rq_fma_a[] = {{".2", u3weq_fma}, {}}; +static u3j_harm _135_tri__rq_lth_a[] = {{".2", u3weq_lth}, {}}; +static u3j_harm _135_tri__rq_lte_a[] = {{".2", u3weq_lte}, {}}; +static u3j_harm _135_tri__rq_equ_a[] = {{".2", u3weq_equ}, {}}; +static u3j_harm _135_tri__rq_gte_a[] = {{".2", u3weq_gte}, {}}; +static u3j_harm _135_tri__rq_gth_a[] = {{".2", u3weq_gth}, {}}; +static u3j_core _135_tri__rq_d[] = + { { "add", 7, _135_tri__rq_add_a, 0, no_hashes }, + { "sub", 7, _135_tri__rq_sub_a, 0, no_hashes }, + { "mul", 7, _135_tri__rq_mul_a, 0, no_hashes }, + { "div", 7, _135_tri__rq_div_a, 0, no_hashes }, + { "sqt", 7, _135_tri__rq_sqt_a, 0, no_hashes }, + { "fma", 7, _135_tri__rq_fma_a, 0, no_hashes }, + { "lth", 7, _135_tri__rq_lth_a, 0, no_hashes }, + { "lte", 7, _135_tri__rq_lte_a, 0, no_hashes }, + { "equ", 7, _135_tri__rq_equ_a, 0, no_hashes }, + { "gte", 7, _135_tri__rq_gte_a, 0, no_hashes }, + { "gth", 7, _135_tri__rq_gth_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_tri__rh_add_a[] = {{".2", u3wes_add}, {}}; +static u3j_harm _135_tri__rh_sub_a[] = {{".2", u3wes_sub}, {}}; +static u3j_harm _135_tri__rh_mul_a[] = {{".2", u3wes_mul}, {}}; +static u3j_harm _135_tri__rh_div_a[] = {{".2", u3wes_div}, {}}; +static u3j_harm _135_tri__rh_sqt_a[] = {{".2", u3wes_sqt}, {}}; +static u3j_harm _135_tri__rh_fma_a[] = {{".2", u3wes_fma}, {}}; +static u3j_harm _135_tri__rh_lth_a[] = {{".2", u3wes_lth}, {}}; +static u3j_harm _135_tri__rh_lte_a[] = {{".2", u3wes_lte}, {}}; +static u3j_harm _135_tri__rh_equ_a[] = {{".2", u3wes_equ}, {}}; +static u3j_harm _135_tri__rh_gte_a[] = {{".2", u3wes_gte}, {}}; +static u3j_harm _135_tri__rh_gth_a[] = {{".2", u3wes_gth}, {}}; +static u3j_core _135_tri__rh_d[] = + { { "add", 7, _135_tri__rh_add_a, 0, no_hashes }, + { "sub", 7, _135_tri__rh_sub_a, 0, no_hashes }, + { "mul", 7, _135_tri__rh_mul_a, 0, no_hashes }, + { "div", 7, _135_tri__rh_div_a, 0, no_hashes }, + { "sqt", 7, _135_tri__rh_sqt_a, 0, no_hashes }, + { "fma", 7, _135_tri__rh_fma_a, 0, no_hashes }, + { "lth", 7, _135_tri__rh_lth_a, 0, no_hashes }, + { "lte", 7, _135_tri__rh_lte_a, 0, no_hashes }, + { "equ", 7, _135_tri__rh_equ_a, 0, no_hashes }, + { "gte", 7, _135_tri__rh_gte_a, 0, no_hashes }, + { "gth", 7, _135_tri__rh_gth_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_tri__og_raw_a[] = {{".2", u3weo_raw}, {}}; +static u3j_core _135_tri__og_d[] = + { { "raw", 7, _135_tri__og_raw_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_tri__sha_sha1_a[] = {{".2", u3we_sha1}, {}}; +static u3j_core _135_tri__sha_d[] = + { { "sha1", 7, _135_tri__sha_sha1_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_tri_shax_a[] = {{".2", u3we_shax}, {}}; +static u3j_harm _135_tri_shay_a[] = {{".2", u3we_shay}, {}}; +static u3j_harm _135_tri_shas_a[] = {{".2", u3we_shas}, {}}; +static u3j_harm _135_tri_shal_a[] = {{".2", u3we_shal}, {}}; + +static u3j_harm _135_ob_fynd_a[] = {{".2", u3we_fynd_ob}, {}}; +static u3j_harm _135_ob_fein_a[] = {{".2", u3we_fein_ob}, {}}; +static u3j_core _135_ob_d[] = { + { "fein", 7, _135_ob_fein_a, 0, no_hashes }, + { "fynd", 7, _135_ob_fynd_a, 0, no_hashes }, + {} +}; +static u3j_hood _135_ob_ho[] = { + { "fein", 42 }, + { "fynd", 20 }, + {}, +}; + + +static u3j_hood _135_tri_ho[] = { + { "ob", 20 }, + { "yore", 5462 }, + { "year", 44975 }, + {}, +}; + + +/* layer two + */ +static u3j_harm _135_two_find_a[] = {{".2", u3wb_find, c3y}, {}}; +static u3j_harm _135_two_flop_a[] = {{".2", u3wb_flop, c3y}, {}}; +static u3j_harm _135_two_lent_a[] = {{".2", u3wb_lent, c3y}, {}}; +static u3j_harm _135_two_levy_a[] = {{".2", u3wb_levy, c3y}, {}}; +static u3j_harm _135_two_lien_a[] = {{".2", u3wb_lien, c3y}, {}}; +static u3j_harm _135_two_murn_a[] = {{".2", u3wb_murn, c3y}, {}}; +static u3j_harm _135_two_need_a[] = {{".2", u3wb_need, c3y}, {}}; +static u3j_harm _135_two_reap_a[] = {{".2", u3wb_reap, c3y}, {}}; +static u3j_harm _135_two_reel_a[] = {{".2", u3wb_reel, c3y}, {}}; +static u3j_harm _135_two_roll_a[] = {{".2", u3wb_roll, c3y}, {}}; +static u3j_harm _135_two_skid_a[] = {{".2", u3wb_skid, c3y}, {}}; +static u3j_harm _135_two_skim_a[] = {{".2", u3wb_skim, c3y}, {}}; +static u3j_harm _135_two_skip_a[] = {{".2", u3wb_skip, c3y}, {}}; +static u3j_harm _135_two_scag_a[] = {{".2", u3wb_scag, c3y}, {}}; +static u3j_harm _135_two_slag_a[] = {{".2", u3wb_slag, c3y}, {}}; +static u3j_harm _135_two_snag_a[] = {{".2", u3wb_snag, c3y}, {}}; +static u3j_harm _135_two_sort_a[] = {{".2", u3wb_sort, c3y}, {}}; +static u3j_harm _135_two_turn_a[] = {{".2", u3wb_turn, c3y}, {}}; +static u3j_harm _135_two_weld_a[] = {{".2", u3wb_weld, c3y}, {}}; +static u3j_harm _135_two_welp_a[] = {{".2", u3wb_welp, c3y}, {}}; +static u3j_harm _135_two_zing_a[] = {{".2", u3wb_zing, c3y}, {}}; + +static u3j_harm _135_two_bex_a[] = {{".2", u3wc_bex, c3y}, {}}; +static u3j_harm _135_two_can_a[] = {{".2", u3wc_can, c3y}, {}}; +static u3j_harm _135_two_cat_a[] = {{".2", u3wc_cat, c3y}, {}}; +static u3j_harm _135_two_con_a[] = {{".2", u3wc_con, c3y}, {}}; +static u3j_harm _135_two_cut_a[] = {{".2", u3wc_cut, c3y}, {}}; +static u3j_harm _135_two_dis_a[] = {{".2", u3wc_dis, c3y}, {}}; +static u3j_harm _135_two_dor_a[] = {{".2", u3wc_dor, c3y}, {}}; +static u3j_harm _135_two_end_a[] = {{".2", u3wc_end, c3y}, {}}; +static u3j_harm _135_two_gor_a[] = {{".2", u3wc_gor, c3y}, {}}; +static u3j_harm _135_two_lsh_a[] = {{".2", u3wc_lsh, c3y}, {}}; +static u3j_harm _135_two_met_a[] = {{".2", u3wc_met, c3y}, {}}; +static u3j_harm _135_two_mix_a[] = {{".2", u3wc_mix, c3y}, {}}; +static u3j_harm _135_two_mor_a[] = {{".2", u3wc_mor, c3y}, {}}; +static u3j_harm _135_two_mug_a[] = {{".2", u3wc_mug, c3y}, {}}; +static u3j_harm _135_two_muk_a[] = {{".2", u3wc_muk, c3y}, {}}; +static u3j_harm _135_two_pow_a[] = {{".2", u3wc_pow, c3y}, {}}; +static u3j_harm _135_two_rap_a[] = {{".2", u3wc_rap, c3y}, {}}; +static u3j_harm _135_two_rep_a[] = {{".2", u3wc_rep, c3y}, {}}; +static u3j_harm _135_two_rev_a[] = {{".2", u3wc_rev, c3y}, {}}; +static u3j_harm _135_two_rip_a[] = {{".2", u3wc_rip, c3y}, {}}; +static u3j_harm _135_two_rsh_a[] = {{".2", u3wc_rsh, c3y}, {}}; +static u3j_harm _135_two_swp_a[] = {{".2", u3wc_swp, c3y}, {}}; +static u3j_harm _135_two_sqt_a[] = {{".2", u3wc_sqt, c3y}, {}}; +static u3j_harm _135_two_xeb_a[] = {{".2", u3wc_xeb, c3y}, {}}; + +static u3j_harm _135_two__in_bif_a[] = {{".2", u3wdi_bif}, {}}; +static u3j_harm _135_two__in_del_a[] = {{".2", u3wdi_del}, {}}; +static u3j_harm _135_two__in_dif_a[] = {{".2", u3wdi_dif}, {}}; +static u3j_harm _135_two__in_gas_a[] = {{".2", u3wdi_gas}, {}}; +static u3j_harm _135_two__in_has_a[] = {{".2", u3wdi_has}, {}}; +static u3j_harm _135_two__in_int_a[] = {{".2", u3wdi_int}, {}}; +static u3j_harm _135_two__in_put_a[] = {{".2", u3wdi_put}, {}}; +static u3j_harm _135_two__in_rep_a[] = {{".2", u3wdi_rep}, {}}; +static u3j_harm _135_two__in_run_a[] = {{".2", u3wdi_run}, {}}; +static u3j_harm _135_two__in_tap_a[] = {{".2", u3wdi_tap}, {}}; +static u3j_harm _135_two__in_wyt_a[] = {{".2", u3wdi_wyt}, {}}; +static u3j_harm _135_two__in_uni_a[] = {{".2", u3wdi_uni}, {}}; + +static u3j_harm _135_two__by_all_a[] = {{".2", u3wdb_all, c3y}, {}}; +static u3j_harm _135_two__by_any_a[] = {{".2", u3wdb_any, c3y}, {}}; +static u3j_harm _135_two__by_apt_a[] = {{".2", u3wdb_apt, c3y}, {}}; + +static u3j_harm _135_two__by_del_a[] = {{".2", u3wdb_del, c3y}, {}}; +static u3j_harm _135_two__by_dif_a[] = {{".2", u3wdb_dif, c3y}, {}}; +static u3j_harm _135_two__by_gas_a[] = {{".2", u3wdb_gas, c3y}, {}}; +static u3j_harm _135_two__by_get_a[] = {{".2", u3wdb_get, c3y}, {}}; +static u3j_harm _135_two__by_has_a[] = {{".2", u3wdb_has, c3y}, {}}; +static u3j_harm _135_two__by_int_a[] = {{".2", u3wdb_int, c3y}, {}}; +static u3j_harm _135_two__by_jab_a[] = {{".2", u3wdb_jab, c3y}, {}}; +static u3j_harm _135_two__by_key_a[] = {{".2", u3wdb_key, c3y}, {}}; +static u3j_harm _135_two__by_put_a[] = {{".2", u3wdb_put, c3y}, {}}; +static u3j_harm _135_two__by_rep_a[] = {{".2", u3wdb_rep, c3y}, {}}; +static u3j_harm _135_two__by_run_a[] = {{".2", u3wdb_run, c3y}, {}}; +static u3j_harm _135_two__by_tap_a[] = {{".2", u3wdb_tap, c3y}, {}}; +static u3j_harm _135_two__by_uni_a[] = {{".2", u3wdb_uni, c3y}, {}}; +static u3j_harm _135_two__by_urn_a[] = {{".2", u3wdb_urn, c3y}, {}}; +static u3j_harm _135_two__by_wyt_a[] = {{".2", u3wdb_wyt, c3y}, {}}; + +static u3j_harm _135_two_cue_a[] = {{".2", u3we_cue}, {}}; +static u3j_harm _135_two_jam_a[] = {{".2", u3we_jam}, {}}; +static u3j_harm _135_two_mat_a[] = {{".2", u3we_mat}, {}}; +static u3j_harm _135_two_rub_a[] = {{".2", u3we_rub}, {}}; + + + +/* layer one + */ +static u3j_harm _135_one_add_a[] = {{".2", u3wa_add, c3y}, {}}; +static u3j_harm _135_one_dec_a[] = {{".2", u3wa_dec, c3y}, {}}; +static u3j_harm _135_one_div_a[] = {{".2", u3wa_div, c3y}, {}}; +static u3j_harm _135_one_dvr_a[] = {{".2", u3wc_dvr, c3y}, {}}; +static u3j_harm _135_one_gte_a[] = {{".2", u3wa_gte, c3y}, {}}; +static u3j_harm _135_one_gth_a[] = {{".2", u3wa_gth, c3y}, {}}; +static u3j_harm _135_one_lte_a[] = {{".2", u3wa_lte, c3y}, {}}; +static u3j_harm _135_one_lth_a[] = {{".2", u3wa_lth, c3y}, {}}; +static u3j_harm _135_one_max_a[] = {{".2", u3wa_max, c3y}, {}}; +static u3j_harm _135_one_min_a[] = {{".2", u3wa_min, c3y}, {}}; +static u3j_harm _135_one_mod_a[] = {{".2", u3wa_mod, c3y}, {}}; +static u3j_harm _135_one_mul_a[] = {{".2", u3wa_mul, c3y}, {}}; +static u3j_harm _135_one_sub_a[] = {{".2", u3wa_sub, c3y}, {}}; + +static u3j_harm _135_one_cap_a[] = {{".2", u3wc_cap, c3y}, {}}; +static u3j_harm _135_one_peg_a[] = {{".2", u3wc_peg, c3y}, {}}; +static u3j_harm _135_one_mas_a[] = {{".2", u3wc_mas, c3y}, {}}; + +static u3j_harm _135_lull_plot_fax_a[] = {{".2", u3wg_plot_fax, c3y}, {}}; +static u3j_harm _135_lull_plot_met_a[] = {{".2", u3wg_plot_met, c3y}, {}}; + +static u3j_core _135_lull_plot_d[] = + { { "fax", 7, _135_lull_plot_fax_a, 0, no_hashes }, + { "met", 7, _135_lull_plot_met_a, 0, no_hashes }, + {} + }; + +static u3j_core _135_lull_d[] = + { { "plot", 31, 0, _135_lull_plot_d, no_hashes }, + {} + }; + +static u3j_harm _135_hex_blake3_hash_a[] = {{".2", u3we_blake3_hash, c3y}, {}}; +static u3j_harm _135_hex_blake3_compress_a[] = {{".2", u3we_blake3_compress, c3y}, {}}; +static u3j_harm _135_hex_blake3_chunk_output_a[] = {{".2", u3we_blake3_chunk_output, c3y}, {}}; + +static u3j_core _135_hex_blake3_d[] = + { { "hash", 7, _135_hex_blake3_hash_a, 0, no_hashes }, + { "chunk-output", 7, _135_hex_blake3_chunk_output_a, 0, no_hashes }, + {} + }; + + +static u3j_core _135_hex_blake3_impl_d[] = + { { "compress", 7, _135_hex_blake3_compress_a, 0, no_hashes }, + { "blake3", 7, 0, _135_hex_blake3_d, no_hashes }, + {} + }; + +static u3j_harm _135_hex_blake2b_a[] = {{".2", u3we_blake2b, c3y}, {}}; + +static u3j_core _135_hex_blake_d[] = + { { "blake2b", 7, _135_hex_blake2b_a, 0, no_hashes }, + { "blake3-impl", 7, 0, _135_hex_blake3_impl_d, no_hashes }, + {} + }; + + +static u3j_harm _135_hex_chacha_crypt_a[] = {{".2", u3we_chacha_crypt, c3y}, {}}; +static u3j_harm _135_hex_chacha_xchacha_a[] = {{".2", u3we_chacha_xchacha, c3y}, {}}; +static u3j_core _135_hex_chacha_d[] = + { { "crypt", 7, _135_hex_chacha_crypt_a, 0, no_hashes }, + { "xchacha", 7, _135_hex_chacha_xchacha_a, 0, no_hashes }, + {} + }; + + +//+| %utilities +static u3j_harm _135_hex_bytestream_rip_octs_a[] = {{".2", u3we_bytestream_rip_octs, c3y}, {}}; +static u3j_harm _135_hex_bytestream_cat_octs_a[] = {{".2", u3we_bytestream_cat_octs, c3y}, {}}; +static u3j_harm _135_hex_bytestream_can_octs_a[] = {{".2", u3we_bytestream_can_octs, c3y}, {}}; +//+| %read-byte +static u3j_harm _135_hex_bytestream_read_byte_a[] = {{".2", u3we_bytestream_read_byte, c3y}, {}}; +//+| %read-octs +static u3j_harm _135_hex_bytestream_read_octs_a[] = {{".2", u3we_bytestream_read_octs, c3y}, {}}; +//+| %navigation +static u3j_harm _135_hex_bytestream_skip_line_a[] = {{".2", u3we_bytestream_skip_line, c3y}, {}}; +static u3j_harm _135_hex_bytestream_find_byte_a[] = {{".2", u3we_bytestream_find_byte, c3y}, {}}; +static u3j_harm _135_hex_bytestream_seek_byte_a[] = {{".2", u3we_bytestream_seek_byte, c3y}, {}}; +//+| %transformation +static u3j_harm _135_hex_bytestream_chunk_a[] = {{".2", u3we_bytestream_chunk}, {}}; +static u3j_harm _135_hex_bytestream_extract_a[] = {{".2", u3we_bytestream_extract}, {}}; +static u3j_harm _135_hex_bytestream_fuse_extract_a[] = {{".2", u3we_bytestream_fuse_extract}, {}}; +//+| %bitstream +static u3j_harm _135_hex_bytestream_need_bits_a[] = {{".2", u3we_bytestream_need_bits}, {}}; +static u3j_harm _135_hex_bytestream_drop_bits_a[] = {{".2", u3we_bytestream_drop_bits}, {}}; +// static u3j_harm _135_hex_bytestream_skip_bits_a[] = {{".2", u3we_bytestream_skip_bits}, {}}; +static u3j_harm _135_hex_bytestream_peek_bits_a[] = {{".2", u3we_bytestream_peek_bits}, {}}; +static u3j_harm _135_hex_bytestream_read_bits_a[] = {{".2", u3we_bytestream_read_bits}, {}}; +// static u3j_harm _135_hex_bytestream_read_need_bits_a[] = {{".2", u3we_bytestream_read_need_bits}, {}}; +static u3j_harm _135_hex_bytestream_byte_bits_a[] = {{".2", u3we_bytestream_byte_bits}, {}}; + +static u3j_core _135_hex_bytestream_d[] = + { //+| %utilities + {"rip-octs", 7, _135_hex_bytestream_rip_octs_a, 0, no_hashes }, + {"cat-octs", 7, _135_hex_bytestream_cat_octs_a, 0, no_hashes }, + {"can-octs", 7, _135_hex_bytestream_can_octs_a, 0, no_hashes }, + //+| %navigation + {"skip-line", 7, _135_hex_bytestream_skip_line_a, 0, no_hashes }, + {"find-byte", 7, _135_hex_bytestream_find_byte_a, 0, no_hashes }, + {"seek-byte", 7, _135_hex_bytestream_seek_byte_a, 0, no_hashes }, + //+| %read-byte + {"read-byte", 7, _135_hex_bytestream_read_byte_a, 0, no_hashes }, + //+| %read-octs + {"read-octs", 7, _135_hex_bytestream_read_octs_a, 0, no_hashes }, + //+| %transformation + {"chunk", 7, _135_hex_bytestream_chunk_a, 0, no_hashes }, + {"extract", 7, _135_hex_bytestream_extract_a, 0, no_hashes }, + {"fuse-extract", 7, _135_hex_bytestream_fuse_extract_a, 0, no_hashes }, + //+| %bitstream + {"need-bits", 7, _135_hex_bytestream_need_bits_a, 0, no_hashes }, + {"drop-bits", 7, _135_hex_bytestream_drop_bits_a, 0, no_hashes }, + // {"skip-bits", 7, _135_hex_bytestream_skip_bits_a, 0, no_hashes }, + {"peek-bits", 7, _135_hex_bytestream_peek_bits_a, 0, no_hashes }, + {"read-bits", 7, _135_hex_bytestream_read_bits_a, 0, no_hashes }, + // {"read-need-bits", 7, _135_hex_bytestream_read_need_bits_a, 0, no_hashes }, + {"byte-bits", 7, _135_hex_bytestream_byte_bits_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_hex_json_de_a[] = {{".2", u3we_json_de}, {}}; +static u3j_harm _135_hex_json_en_a[] = {{".2", u3we_json_en}, {}}; +static u3j_core _135_hex_json_d[] = + { { "de", 15, _135_hex_json_de_a, 0, no_hashes }, + { "en", 15, _135_hex_json_en_a, 0, no_hashes }, + {} + }; + +/* /lib jets in non core +*/ +static u3j_harm _135_non__lagoon_add_a[] = {{".2", u3wi_la_add}, {}}; +static u3j_harm _135_non__lagoon_sub_a[] = {{".2", u3wi_la_sub}, {}}; +static u3j_harm _135_non__lagoon_mul_a[] = {{".2", u3wi_la_mul}, {}}; +static u3j_harm _135_non__lagoon_div_a[] = {{".2", u3wi_la_div}, {}}; +static u3j_harm _135_non__lagoon_mod_a[] = {{".2", u3wi_la_mod}, {}}; +static u3j_harm _135_non__lagoon_adds_a[] = {{".2", u3wi_la_adds}, {}}; +static u3j_harm _135_non__lagoon_subs_a[] = {{".2", u3wi_la_subs}, {}}; +static u3j_harm _135_non__lagoon_muls_a[] = {{".2", u3wi_la_muls}, {}}; +static u3j_harm _135_non__lagoon_divs_a[] = {{".2", u3wi_la_divs}, {}}; +static u3j_harm _135_non__lagoon_mods_a[] = {{".2", u3wi_la_mods}, {}}; +static u3j_harm _135_non__lagoon_dot_a[] = {{".2", u3wi_la_dot}, {}}; +static u3j_harm _135_non__lagoon_trans_a[] ={{".2", u3wi_la_transpose}, {}}; +static u3j_harm _135_non__lagoon_cumsum_a[]={{".2", u3wi_la_cumsum}, {}}; +static u3j_harm _135_non__lagoon_argmin_a[]={{".2", u3wi_la_argmin}, {}}; +static u3j_harm _135_non__lagoon_argmax_a[]={{".2", u3wi_la_argmax}, {}}; +static u3j_harm _135_non__lagoon_ravel_a[]={{".2", u3wi_la_ravel}, {}}; +static u3j_harm _135_non__lagoon_min_a[] = {{".2", u3wi_la_min}, {}}; +static u3j_harm _135_non__lagoon_max_a[] = {{".2", u3wi_la_max}, {}}; +static u3j_harm _135_non__lagoon_linspace_a[]={{".2", u3wi_la_linspace}, {}}; +static u3j_harm _135_non__lagoon_range_a[]= {{".2", u3wi_la_range}, {}}; +static u3j_harm _135_non__lagoon_abs_a[] = {{".2", u3wi_la_abs}, {}}; +static u3j_harm _135_non__lagoon_gth_a[] = {{".2", u3wi_la_gth}, {}}; +static u3j_harm _135_non__lagoon_gte_a[] = {{".2", u3wi_la_gte}, {}}; +static u3j_harm _135_non__lagoon_lth_a[] = {{".2", u3wi_la_lth}, {}}; +static u3j_harm _135_non__lagoon_lte_a[] = {{".2", u3wi_la_lte}, {}}; +static u3j_harm _135_non__lagoon_diag_a[] = {{".2", u3wi_la_diag}, {}}; +static u3j_harm _135_non__lagoon_trace_a[]= {{".2", u3wi_la_trace}, {}}; +static u3j_harm _135_non__lagoon_mmul_a[] = {{".2", u3wi_la_mmul}, {}}; +static u3j_harm _135_non__mice_a[] = {{".2", u3we_mice}, {}}; + +static u3j_core _135_non__la_core_d[] = + { { "add-rays", 7, _135_non__lagoon_add_a, 0, no_hashes }, + { "sub-rays", 7, _135_non__lagoon_sub_a, 0, no_hashes }, + { "mul-rays", 7, _135_non__lagoon_mul_a, 0, no_hashes }, + { "div-rays", 7, _135_non__lagoon_div_a, 0, no_hashes }, + { "mod-rays", 7, _135_non__lagoon_mod_a, 0, no_hashes }, + { "add-scal", 7, _135_non__lagoon_adds_a, 0, no_hashes }, + { "sub-scal", 7, _135_non__lagoon_subs_a, 0, no_hashes }, + { "mul-scal", 7, _135_non__lagoon_muls_a, 0, no_hashes }, + { "div-scal", 7, _135_non__lagoon_divs_a, 0, no_hashes }, + { "mod-scal", 7, _135_non__lagoon_mods_a, 0, no_hashes }, + { "dot", 7, _135_non__lagoon_dot_a, 0, no_hashes }, + { "transpose",7, _135_non__lagoon_trans_a, 0, no_hashes }, + { "cumsum", 7, _135_non__lagoon_cumsum_a, 0, no_hashes }, + { "argmin", 7, _135_non__lagoon_argmin_a, 0, no_hashes }, + { "argmax", 7, _135_non__lagoon_argmax_a, 0, no_hashes }, + { "ravel", 7, _135_non__lagoon_ravel_a, 0, no_hashes }, + { "min", 7, _135_non__lagoon_min_a, 0, no_hashes }, + { "max", 7, _135_non__lagoon_max_a, 0, no_hashes }, + { "linspace", 7, _135_non__lagoon_linspace_a, 0, no_hashes }, + { "range", 7, _135_non__lagoon_range_a, 0, no_hashes }, + { "abs", 7, _135_non__lagoon_abs_a, 0, no_hashes }, + { "gth", 7, _135_non__lagoon_gth_a, 0, no_hashes }, + { "gte", 7, _135_non__lagoon_gte_a, 0, no_hashes }, + { "lth", 7, _135_non__lagoon_lth_a, 0, no_hashes }, + { "lte", 7, _135_non__lagoon_lte_a, 0, no_hashes }, + { "diag", 7, _135_non__lagoon_diag_a, 0, no_hashes }, + { "trace", 7, _135_non__lagoon_trace_a,0, no_hashes }, + { "mmul", 7, _135_non__lagoon_mmul_a, 0, no_hashes }, + {} + }; + +// numerics math.hoon transcendentals: non -> math -> rd -> +static u3j_harm _135_non__math_rd_exp_a[] = {{".2", u3wi_rd_exp}, {}}; +static u3j_harm _135_non__math_rd_log_a[] = {{".2", u3wi_rd_log}, {}}; +static u3j_harm _135_non__math_rd_sin_a[] = {{".2", u3wi_rd_sin}, {}}; +static u3j_harm _135_non__math_rd_cos_a[] = {{".2", u3wi_rd_cos}, {}}; +static u3j_harm _135_non__math_rd_tan_a[] = {{".2", u3wi_rd_tan}, {}}; +static u3j_harm _135_non__math_rd_atan_a[] = {{".2", u3wi_rd_atan}, {}}; +static u3j_harm _135_non__math_rd_atan2_a[] = {{".2", u3wi_rd_atan2}, {}}; +static u3j_harm _135_non__math_rd_asin_a[] = {{".2", u3wi_rd_asin}, {}}; +static u3j_harm _135_non__math_rd_acos_a[] = {{".2", u3wi_rd_acos}, {}}; +static u3j_harm _135_non__math_rd_sqt_a[] = {{".2", u3wi_rd_sqt}, {}}; +static u3j_harm _135_non__math_rd_cbt_a[] = {{".2", u3wi_rd_cbt}, {}}; +static u3j_harm _135_non__math_rd_pow_a[] = {{".2", u3wi_rd_pow}, {}}; +static u3j_harm _135_non__math_rd_pow_n_a[] = {{".2", u3wi_rd_pow_n}, {}}; +static u3j_harm _135_non__math_rd_log2_a[] = {{".2", u3wi_rd_log2}, {}}; +static u3j_harm _135_non__math_rd_log10_a[] = {{".2", u3wi_rd_log10}, {}}; +static u3j_core _135_non__math_rd_d[] = + { + { "exp", 7, _135_non__math_rd_exp_a, 0, no_hashes }, + { "log", 7, _135_non__math_rd_log_a, 0, no_hashes }, + { "sin", 7, _135_non__math_rd_sin_a, 0, no_hashes }, + { "cos", 7, _135_non__math_rd_cos_a, 0, no_hashes }, + { "tan", 7, _135_non__math_rd_tan_a, 0, no_hashes }, + { "atan", 7, _135_non__math_rd_atan_a, 0, no_hashes }, + { "atan2", 7, _135_non__math_rd_atan2_a, 0, no_hashes }, + { "asin", 7, _135_non__math_rd_asin_a, 0, no_hashes }, + { "acos", 7, _135_non__math_rd_acos_a, 0, no_hashes }, + { "sqt", 7, _135_non__math_rd_sqt_a, 0, no_hashes }, + { "cbt", 7, _135_non__math_rd_cbt_a, 0, no_hashes }, + { "pow", 7, _135_non__math_rd_pow_a, 0, no_hashes }, + { "pow-n", 7, _135_non__math_rd_pow_n_a, 0, no_hashes }, + { "log-2", 7, _135_non__math_rd_log2_a, 0, no_hashes }, + { "log-10", 7, _135_non__math_rd_log10_a, 0, no_hashes }, + {} + }; +static u3j_core _135_non__math_d[] = + { { "rd", 7, 0, _135_non__math_rd_d, no_hashes }, + {} + }; + +static u3j_core _135_non_d[] = + { { "lagoon", 7, 0, _135_non__la_core_d, no_hashes }, + { "math", 7, 0, _135_non__math_d, no_hashes }, + { "mice", 7, _135_non__mice_a, 0, no_hashes }, + {} + }; + + +static u3j_harm _135_hex_lia_run_v1_a[] = {{".2", u3we_lia_run_v1, c3y}, {}}; + +static u3j_harm _135_hex_lia_run_once_inner_a[] = {{".2", u3we_lia_run_once, c3y}, {}}; + +static u3j_core _135_hex_lia_run_once_d[] = { + { "run-once-inner-v0", 15, _135_hex_lia_run_once_inner_a, 0, no_hashes }, + {} +}; + +static u3j_core _135_hex_lia_monad_d[] = { + { "run-v1", 7, _135_hex_lia_run_v1_a, 0, no_hashes }, + { "run-once-v0", 7, 0, _135_hex_lia_run_once_d, no_hashes }, + {} +}; + +static u3j_core _135_hex_wasm_engine_d[] = { + { "monad-v0", 3, 0, _135_hex_lia_monad_d, no_hashes }, + {} +}; + +static u3j_core _135_hex_wasm_op_def_d[] = { + { "wasm-engine-v0", 3, 0, _135_hex_wasm_engine_d, no_hashes }, + {} +}; + +static u3j_core _135_hex_wasm_validator_d[] = { + { "wasm-op-def-v0", 3, 0, _135_hex_wasm_op_def_d, no_hashes }, + {} +}; + +static u3j_core _135_hex_wasm_parser_d[] = { + { "validator-v0", 3, 0, _135_hex_wasm_validator_d, no_hashes }, + {} +}; + +static u3j_core _135_hex_lia_sur_d[] = { + { "wasm-parser-v0", 3, 0, _135_hex_wasm_parser_d, no_hashes }, + {} +}; + +static u3j_core _135_hex_wasm_engine_sur_d[] = { + { "monad-sur-v1", 3, 0, _135_hex_lia_sur_d, no_hashes }, + {} +}; + +static u3j_core _135_hex_wasm_sur_d[] = { + { "engine-sur-v0", 3, 0, _135_hex_wasm_engine_sur_d, no_hashes }, + {} +}; + +static u3j_core _135_hex_d[] = + { { "non", 7, 0, _135_non_d, no_hashes }, + + { "lull", 3, 0, _135_lull_d, no_hashes }, + + { "lore", 63, _135_hex_lore_a, 0, no_hashes }, + + { "leer", 63, _135_hex_leer_a, 0, no_hashes }, + { "loss", 63, _135_hex_loss_a, 0, no_hashes }, + { "lune", 127, _135_hex_lune_a, 0, no_hashes }, + + { "crc", 31, 0, _135_hex__crc_d, no_hashes }, + + { "coed", 63, 0, _135_hex_coed_d, no_hashes }, + { "aes", 31, 0, _135_hex_aes_d, no_hashes }, + + { "hmac", 63, 0, _135_hex_hmac_d, no_hashes }, + { "argon", 31, 0, _135_hex_argon_d, no_hashes }, + { "blake", 31, 0, _135_hex_blake_d, no_hashes }, + { "chacha", 31, 0, _135_hex_chacha_d, no_hashes }, + { "kecc", 31, 0, _135_hex_kecc_d, no_hashes }, + { "ripemd", 31, 0, _135_hex_ripe_d, no_hashes }, + { "scr", 31, 0, _135_hex_scr_d, no_hashes }, + { "secp", 6, 0, _135_hex_secp_d, no_hashes }, + { "mimes", 31, 0, _135_hex_mimes_d, no_hashes }, + { "json", 31, 0, _135_hex_json_d, no_hashes }, + { "checksum", 15, 0, _135_hex_checksum_d, no_hashes}, + { "wasm-sur-v0", 3, 0, _135_hex_wasm_sur_d, no_hashes }, + { "bytestream-v0", 31, 0, _135_hex_bytestream_d, no_hashes}, + { "zlib-v0", 31, 0, _135_hex__zlib_d, no_hashes }, + {} + }; + +static u3j_core _135_pen_d[] = + { { "hex", 7, 0, _135_hex_d, no_hashes }, + + { "cell", 7, _135_pen_cell_a, 0, no_hashes }, + { "comb", 7, _135_pen_comb_a, 0, no_hashes }, + { "cons", 7, _135_pen_cons_a, 0, no_hashes }, + { "core", 7, _135_pen_core_a, 0, no_hashes }, + { "face", 7, _135_pen_face_a, 0, no_hashes }, + { "fitz", 7, _135_pen_fitz_a, 0, no_hashes }, + { "fork", 7, _135_pen_fork_a, 0, no_hashes }, + { "look", 7, _135_pen_look_a, 0, no_hashes }, + { "loot", 7, _135_pen_loot_a, 0, no_hashes }, + { "ut", 15, 0, _135_pen__ut_d, no_hashes, _135_pen__ut_ho }, + {} + }; + +static u3j_core _135_qua__vi_d[] = + { + { "mole", 7, _135_qua_mole_a, 0, no_hashes }, + { "mule", 7, _135_qua_mule_a, 0, no_hashes }, + {} + }; + +static u3j_core _135_qua_d[] = + { { "pen", 3, 0, _135_pen_d, no_hashes, _135_pen_ho }, + + { "po", 7, 0, _135_qua__po_d, no_hashes }, + + { "trip", 7, _135_qua_trip_a, 0, no_hashes }, + + { "bend", 7, 0, _135_qua__bend_d, no_hashes }, + { "cold", 7, 0, _135_qua__cold_d, no_hashes }, + { "comp", 7, 0, _135_qua__comp_d, no_hashes }, + { "cook", 7, 0, _135_qua__cook_d, no_hashes }, + { "easy", 7, 0, _135_qua__easy_d, no_hashes }, + { "glue", 7, 0, _135_qua__glue_d, no_hashes }, + { "here", 7, 0, _135_qua__here_d, no_hashes }, + { "just", 7, 0, _135_qua__just_d, no_hashes }, + { "mask", 7, 0, _135_qua__mask_d, no_hashes }, + { "shim", 7, 0, _135_qua__shim_d, no_hashes }, + { "stag", 7, 0, _135_qua__stag_d, no_hashes }, + { "stew", 7, 0, _135_qua__stew_d, no_hashes }, + { "stir", 7, 0, _135_qua__stir_d, no_hashes }, + + { "pfix", 7, _135_qua_pfix_a, 0, no_hashes }, + { "plug", 7, _135_qua_plug_a, 0, no_hashes }, + { "pose", 7, _135_qua_pose_a, 0, no_hashes }, + { "sfix", 7, _135_qua_sfix_a, 0, no_hashes }, + + { "mink", 7, _135_qua_mink_a, 0, no_hashes }, + { "vi", 7, 0, _135_qua__vi_d, no_hashes }, + + { "scot", 7, _135_qua_scot_a, 0, no_hashes }, + { "scow", 7, _135_qua_scow_a, 0, no_hashes }, + { "slaw", 7, _135_qua_slaw_a, 0, no_hashes }, + {} + }; + +static u3j_core _135_tri_d[] = + { { "qua", 3, 0, _135_qua_d, no_hashes, _135_qua_ho }, + + { "cofl", 7, 0, _135_tri__cofl_d, no_hashes }, + { "rd", 7, 0, _135_tri__rd_d, no_hashes }, + { "rs", 7, 0, _135_tri__rs_d, no_hashes }, + { "rq", 7, 0, _135_tri__rq_d, no_hashes }, + { "rh", 7, 0, _135_tri__rh_d, no_hashes }, + { "og", 7, 0, _135_tri__og_d, no_hashes }, + + { "sha", 7, 0, _135_tri__sha_d, no_hashes }, + { "shax", 7, _135_tri_shax_a, 0, no_hashes }, + { "shay", 7, _135_tri_shay_a, 0, no_hashes }, + { "shas", 7, _135_tri_shas_a, 0, no_hashes }, + { "shal", 7, _135_tri_shal_a, 0, no_hashes }, + + { "ob", 3, 0, _135_ob_d, no_hashes, _135_ob_ho }, + {} + }; + +static u3j_harm _135_two_clz_a[] = {{".2", u3wc_clz, c3n}, {}}; +static u3j_harm _135_two_ctz_a[] = {{".2", u3wc_ctz, c3n}, {}}; +static u3j_harm _135_two_ham_a[] = {{".2", u3wc_ham, c3n}, {}}; + +static u3j_harm _135_two__hew_fun_a[] = {{".2", u3wc_hew, c3n}, {}}; +static u3j_core _135_two__hew_d[] = + { { "fun", 15, _135_two__hew_fun_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_two__by_bif_a[] = {{".2", u3wdb_bif, c3y}, {}}; + +static u3j_core _135_two__by_d[] = + { { "all", 7, _135_two__by_all_a, 0, no_hashes }, + { "any", 7, _135_two__by_any_a, 0, no_hashes }, + { "apt", 7, _135_two__by_apt_a, 0, no_hashes }, + { "bif", 7, _135_two__by_bif_a, 0, no_hashes }, + { "del", 7, _135_two__by_del_a, 0, no_hashes }, + { "dif", 7, _135_two__by_dif_a, 0, no_hashes }, + { "gas", 7, _135_two__by_gas_a, 0, no_hashes }, + { "get", 7, _135_two__by_get_a, 0, no_hashes }, + { "has", 7, _135_two__by_has_a, 0, no_hashes }, + { "int", 7, _135_two__by_int_a, 0, no_hashes }, + { "jab", 7, _135_two__by_jab_a, 0, no_hashes }, + { "key", 7, _135_two__by_key_a, 0, no_hashes }, + { "put", 7, _135_two__by_put_a, 0, no_hashes }, + { "rep", 7, _135_two__by_rep_a, 0, no_hashes }, + { "run", 7, _135_two__by_run_a, 0, no_hashes }, + { "tap", 7, _135_two__by_tap_a, 0, no_hashes }, + { "uni", 7, _135_two__by_uni_a, 0, no_hashes }, + { "urn", 7, _135_two__by_urn_a, 0, no_hashes }, + { "wyt", 3, _135_two__by_wyt_a, 0, no_hashes }, + {} + }; + + +static u3j_harm _135_two__in_apt_a[] = {{".2", u3wdi_apt}, {}}; + +static u3j_core _135_two__in_d[] = + { { "apt", 7, _135_two__in_apt_a, 0, no_hashes }, + { "bif", 7, _135_two__in_bif_a, 0, no_hashes }, + { "del", 7, _135_two__in_del_a, 0, no_hashes }, + { "dif", 7, _135_two__in_dif_a, 0, no_hashes }, + { "gas", 7, _135_two__in_gas_a, 0, no_hashes }, + { "has", 7, _135_two__in_has_a, 0, no_hashes }, + { "int", 7, _135_two__in_int_a, 0, no_hashes }, + { "put", 7, _135_two__in_put_a, 0, no_hashes }, + { "rep", 7, _135_two__in_rep_a, 0, no_hashes }, + { "run", 7, _135_two__in_run_a, 0, no_hashes }, + { "tap", 7, _135_two__in_tap_a, 0, no_hashes }, + { "uni", 7, _135_two__in_uni_a, 0, no_hashes }, + { "wyt", 3, _135_two__in_wyt_a, 0, no_hashes }, + {} + }; + +static u3j_harm _135_two_rig_a[] = {{".2", u3wc_rig, c3n}, {}}; + +static u3j_harm _135_two_mate_a[] = {{".2", u3wb_mate, c3y}, {}}; +static u3j_harm _135_two_sew_a[] = {{".2", u3wc_sew, c3y}, {}}; + +static u3j_core _135_two_d[] = + { { "tri", 3, 0, _135_tri_d, no_hashes, _135_tri_ho }, + + { "find", 7, _135_two_find_a, 0, no_hashes }, + { "flop", 7, _135_two_flop_a, 0, no_hashes }, + { "lent", 7, _135_two_lent_a, 0, no_hashes }, + { "levy", 7, _135_two_levy_a, 0, no_hashes }, + { "lien", 7, _135_two_lien_a, 0, no_hashes }, + { "murn", 7, _135_two_murn_a, 0, no_hashes }, + { "need", 7, _135_two_need_a, 0, no_hashes }, + { "mate", 7, _135_two_mate_a, 0, no_hashes }, + { "reap", 7, _135_two_reap_a, 0, no_hashes }, + { "reel", 7, _135_two_reel_a, 0, no_hashes }, + { "roll", 7, _135_two_roll_a, 0, no_hashes }, + { "skid", 7, _135_two_skid_a, 0, no_hashes }, + { "skim", 7, _135_two_skim_a, 0, no_hashes }, + { "skip", 7, _135_two_skip_a, 0, no_hashes }, + { "scag", 7, _135_two_scag_a, 0, no_hashes }, + { "slag", 7, _135_two_slag_a, 0, no_hashes }, + { "snag", 7, _135_two_snag_a, 0, no_hashes }, + { "sort", 7, _135_two_sort_a, 0, no_hashes }, + { "turn", 7, _135_two_turn_a, 0, no_hashes }, + { "weld", 7, _135_two_weld_a, 0, no_hashes }, + { "welp", 7, _135_two_welp_a, 0, no_hashes }, + { "zing", 7, _135_two_zing_a, 0, no_hashes }, + + { "bex", 7, _135_two_bex_a, 0, no_hashes }, + { "cat", 7, _135_two_cat_a, 0, no_hashes }, + { "can", 7, _135_two_can_a, 0, no_hashes }, + { "clz", 7, _135_two_clz_a, 0, no_hashes }, + { "con", 7, _135_two_con_a, 0, no_hashes }, + { "ctz", 7, _135_two_ctz_a, 0, no_hashes }, + { "cue", 7, _135_two_cue_a, 0, no_hashes }, + { "cut", 7, _135_two_cut_a, 0, no_hashes }, + { "dis", 7, _135_two_dis_a, 0, no_hashes }, + { "dor", 7, _135_two_dor_a, 0, no_hashes }, + { "end", 7, _135_two_end_a, 0, no_hashes }, + { "gor", 7, _135_two_gor_a, 0, no_hashes }, + { "ham", 7, _135_two_ham_a, 0, no_hashes }, + { "hew", 7, 0, _135_two__hew_d, no_hashes }, + { "jam", 7, _135_two_jam_a, 0, no_hashes }, + { "lsh", 7, _135_two_lsh_a, 0, no_hashes }, + { "mat", 7, _135_two_mat_a, 0, no_hashes }, + { "met", 7, _135_two_met_a, 0, no_hashes }, + { "mix", 7, _135_two_mix_a, 0, no_hashes }, + { "mor", 7, _135_two_mor_a, 0, no_hashes }, + { "mug", 7, _135_two_mug_a, 0, no_hashes }, + { "muk", 7, _135_two_muk_a, 0, no_hashes }, + { "rap", 7, _135_two_rap_a, 0, no_hashes }, + { "rep", 7, _135_two_rep_a, 0, no_hashes }, + { "rev", 7, _135_two_rev_a, 0, no_hashes }, + { "rig", 7, _135_two_rig_a, 0, no_hashes }, + { "rip", 7, _135_two_rip_a, 0, no_hashes }, + { "rsh", 7, _135_two_rsh_a, 0, no_hashes }, + { "swp", 7, _135_two_swp_a, 0, no_hashes }, + { "rub", 7, _135_two_rub_a, 0, no_hashes }, + { "pow", 7, _135_two_pow_a, 0, no_hashes }, + { "sew", 7, _135_two_sew_a, 0, no_hashes }, + { "sqt", 7, _135_two_sqt_a, 0, no_hashes }, + { "xeb", 7, _135_two_xeb_a, 0, no_hashes }, + + { "by", 7, 0, _135_two__by_d, no_hashes }, + { "in", 7, 0, _135_two__in_d, no_hashes }, + {} + }; + +static u3j_core _135_one_d[] = + { { "two", 3, 0, _135_two_d, no_hashes }, + + { "add", 7, _135_one_add_a, 0, no_hashes }, + { "dec", 7, _135_one_dec_a, 0, no_hashes }, + { "div", 7, _135_one_div_a, 0, no_hashes }, + { "dvr", 7, _135_one_dvr_a, 0, no_hashes }, + { "gte", 7, _135_one_gte_a, 0, no_hashes }, + { "gth", 7, _135_one_gth_a, 0, no_hashes }, + { "lte", 7, _135_one_lte_a, 0, no_hashes }, + { "lth", 7, _135_one_lth_a, 0, no_hashes }, + { "max", 7, _135_one_max_a, 0, no_hashes }, + { "min", 7, _135_one_min_a, 0, no_hashes }, + { "mod", 7, _135_one_mod_a, 0, no_hashes }, + { "mul", 7, _135_one_mul_a, 0, no_hashes }, + { "sub", 7, _135_one_sub_a, 0, no_hashes }, + + { "cap", 7, _135_one_cap_a, 0, no_hashes }, + { "mas", 7, _135_one_mas_a, 0, no_hashes }, + { "peg", 7, _135_one_peg_a, 0, no_hashes }, + {} + }; + +u3j_core _k135_d[] = + { { "one", 3, 0, _135_one_d, no_hashes }, + {} + }; + diff --git a/libmath/vere/jets/i/math.c b/libmath/vere64/noun/jets/i/math.c similarity index 100% rename from libmath/vere/jets/i/math.c rename to libmath/vere64/noun/jets/i/math.c diff --git a/libmath/vere64/noun/jets/q.h b/libmath/vere64/noun/jets/q.h new file mode 100644 index 0000000..95c9b07 --- /dev/null +++ b/libmath/vere64/noun/jets/q.h @@ -0,0 +1,322 @@ +/// @file + +#ifndef U3_JETS_Q_H +#define U3_JETS_Q_H + +#include "types.h" + + /** Tier 1. + **/ + u3_noun u3qa_add(u3_atom, u3_atom); + u3_noun u3qa_dec(u3_atom); + u3_noun u3qa_div(u3_atom, u3_atom); + u3_noun u3qa_gte(u3_atom, u3_atom); + u3_noun u3qa_gth(u3_atom, u3_atom); + u3_noun u3qa_inc(u3_atom); + u3_noun u3qa_lte(u3_atom, u3_atom); + u3_noun u3qa_lth(u3_atom, u3_atom); + u3_noun u3qa_max(u3_atom, u3_atom); + u3_noun u3qa_min(u3_atom, u3_atom); + u3_noun u3qa_mod(u3_atom, u3_atom); + u3_noun u3qa_mul(u3_atom, u3_atom); + u3_noun u3qa_sub(u3_atom, u3_atom); + + /** Tier 2. + **/ + u3_noun u3qb_bind(u3_noun, u3_noun); + u3_noun u3qb_clap(u3_noun, u3_noun, u3_noun); + u3_noun u3qb_drop(u3_noun); + u3_noun u3qb_flop(u3_noun); + u3_noun u3qb_lent(u3_noun); + u3_noun u3qb_levy(u3_noun, u3_noun); + u3_noun u3qb_lien(u3_noun, u3_noun); + u3_noun u3qb_murn(u3_noun, u3_noun); + u3_noun u3qb_need(u3_noun); + u3_noun u3qb_mate(u3_noun, u3_noun); + u3_noun u3qb_reap(u3_atom, u3_noun); + u3_noun u3qb_reel(u3_noun, u3_noun); + u3_noun u3qb_roll(u3_noun, u3_noun); + u3_noun u3qb_skid(u3_noun, u3_noun); + u3_noun u3qb_skim(u3_noun, u3_noun); + u3_noun u3qb_skip(u3_noun, u3_noun); + u3_noun u3qb_scag(u3_atom, u3_noun); + u3_noun u3qb_slag(u3_atom, u3_noun); + u3_noun u3qb_snag(u3_atom, u3_noun); + u3_noun u3qb_sort(u3_noun, u3_noun); + u3_noun u3qb_turn(u3_noun, u3_noun); + u3_noun u3qb_weld(u3_noun, u3_noun); + + /** Tier 3. + **/ + u3_noun u3qc_aor(u3_atom, u3_atom); + u3_noun u3qc_bex(u3_atom); + u3_noun u3qc_xeb(u3_atom); + u3_noun u3qc_can(u3_atom, u3_noun); + u3_noun u3qc_cap(u3_atom); + u3_noun u3qc_cat(u3_atom, u3_atom, u3_atom); + u3_noun u3qc_clz(u3_atom, u3_atom, u3_atom); + u3_noun u3qc_con(u3_atom, u3_atom); + u3_noun u3qc_ctz(u3_atom); + u3_noun u3qc_cut(u3_atom, u3_atom, u3_atom, u3_atom); + u3_noun u3qc_dis(u3_atom, u3_atom); + u3_noun u3qc_dor(u3_atom, u3_atom); + u3_noun u3qc_dvr(u3_atom, u3_atom); + u3_noun u3qc_end(u3_atom, u3_atom, u3_atom); + u3_noun u3qc_gor(u3_atom, u3_atom); + u3_noun u3qc_ham(u3_atom); + u3_noun u3qc_hew(u3_atom, u3_atom, u3_atom, u3_noun); + u3_noun u3qc_lsh(u3_atom, u3_atom, u3_atom); + u3_noun u3qc_mas(u3_atom); + u3_noun u3qc_met(u3_atom, u3_atom); + u3_noun u3qc_mix(u3_atom, u3_atom); + u3_noun u3qc_mor(u3_atom, u3_atom); + u3_noun u3qc_muk(u3_atom, u3_atom, u3_atom); + u3_noun u3qc_peg(u3_atom, u3_atom); + u3_noun u3qc_pow(u3_atom, u3_atom); + u3_noun u3qc_rap(u3_atom, u3_noun); + u3_noun u3qc_rep(u3_atom, u3_atom, u3_noun); + u3_noun u3qc_rev(u3_atom, u3_atom, u3_atom); + u3_noun u3qc_rig(u3_atom, u3_atom, u3_atom); + u3_noun u3qc_rip(u3_atom, u3_atom, u3_atom); + u3_noun u3qc_rsh(u3_atom, u3_atom, u3_atom); + u3_noun u3qc_sew(u3_atom, u3_atom, u3_atom, u3_atom, u3_atom); + u3_noun u3qc_swp(u3_atom, u3_atom); + u3_noun u3qc_sqt(u3_atom); + + c3_d u3qc_rig_s(c3_g, c3_w, c3_g); + + u3_noun u3_po_find_prefix(c3_y one, c3_y two, c3_y three); + u3_noun u3_po_find_suffix(c3_y one, c3_y two, c3_y three); + void u3_po_to_prefix(u3_noun id, c3_y* a, c3_y* b, c3_y* c); + void u3_po_to_suffix(u3_noun id, c3_y* a, c3_y* b, c3_y* c); + + /** Tier 4. + **/ + u3_noun u3qdb_all(u3_noun, u3_noun); + u3_noun u3qdb_any(u3_noun, u3_noun); + u3_noun u3qdb_apt(u3_noun); + u3_noun u3qdb_bif(u3_noun, u3_noun); + u3_noun u3qdb_del(u3_noun, u3_noun); + u3_noun u3qdb_dif(u3_noun, u3_noun); + u3_noun u3qdb_gas(u3_noun, u3_noun); + u3_noun u3qdb_get(u3_noun, u3_noun); + u3_noun u3qdb_has(u3_noun, u3_noun); + u3_noun u3qdb_int(u3_noun, u3_noun); + u3_noun u3qdb_key(u3_noun); + u3_noun u3qdb_put(u3_noun, u3_noun, u3_noun); + u3_noun u3qdb_run(u3_noun, u3_noun); +# define u3qdb_tap u3qdi_tap + u3_noun u3qdb_uni(u3_noun, u3_noun); + u3_noun u3qdb_urn(u3_noun, u3_noun); +# define u3qdb_wyt u3qdi_wyt + + u3_noun u3qdi_apt(u3_noun); + u3_noun u3qdi_bif(u3_noun, u3_noun); + u3_noun u3qdi_del(u3_noun, u3_noun); + u3_noun u3qdi_dif(u3_noun, u3_noun); + u3_noun u3qdi_gas(u3_noun, u3_noun); + u3_noun u3qdi_has(u3_noun, u3_noun); + u3_noun u3qdi_int(u3_noun, u3_noun); + u3_noun u3qdi_put(u3_noun, u3_noun); + u3_noun u3qdi_rep(u3_noun, u3_noun); + u3_noun u3qdi_run(u3_noun, u3_noun); + u3_noun u3qdi_tap(u3_noun); + u3_noun u3qdi_uni(u3_noun, u3_noun); + u3_noun u3qdi_wyt(u3_noun); + + /** Tier 5. + **/ + u3_noun u3qe_cue(u3_atom); + u3_noun u3qe_jam(u3_atom); + u3_noun u3qe_mat(u3_atom); + u3_noun u3qe_rub(u3_atom, u3_atom); + u3_noun u3qe_leer(u3_atom); + u3_noun u3qe_lore(u3_atom); + u3_noun u3qe_loss(u3_noun, u3_noun); + u3_noun u3qe_lune(u3_atom); + u3_noun u3qe_repg(u3_noun, u3_noun, u3_noun); + u3_noun u3qe_rexp(u3_noun, u3_noun); + u3_noun u3qe_trip(u3_atom); + + u3_atom u3qe_scot(u3_atom, u3_atom); + u3_atom u3qe_scow(u3_atom, u3_atom); + + u3_noun u3qea_ecba_en(u3_atom, u3_atom); + u3_noun u3qea_ecba_de(u3_atom, u3_atom); + u3_noun u3qea_ecbb_en(u3_atom, u3_atom); + u3_noun u3qea_ecbb_de(u3_atom, u3_atom); + u3_noun u3qea_ecbc_en(u3_atom, u3_atom); + u3_noun u3qea_ecbc_de(u3_atom, u3_atom); + + u3_noun u3qea_cbca_en(u3_atom, u3_atom, u3_atom); + u3_noun u3qea_cbca_de(u3_atom, u3_atom, u3_atom); + u3_noun u3qea_cbcb_en(u3_atom, u3_atom, u3_atom); + u3_noun u3qea_cbcb_de(u3_atom, u3_atom, u3_atom); + u3_noun u3qea_cbcc_en(u3_atom, u3_atom, u3_atom); + u3_noun u3qea_cbcc_de(u3_atom, u3_atom, u3_atom); + + u3_noun u3qea_de(u3_atom, u3_atom); + u3_noun u3qea_en(u3_atom, u3_atom); + + u3_noun u3qee_recs(u3_atom); + + u3_atom u3qe_fein_ob(u3_atom pyn); + u3_atom u3qe_fynd_ob(u3_atom pyn); + + u3_noun u3qe_hmac(u3_noun, u3_atom, u3_atom, + u3_atom, u3_atom, u3_atom, u3_atom); + + u3_noun u3qe_en_base16(u3_atom len, u3_atom dat); + u3_noun u3qe_de_base16(u3_atom inp); + + u3_noun u3qe_json_de(u3_atom); + u3_atom u3qe_json_en(u3_noun); + + u3_noun u3qeo_raw(u3_atom, u3_atom); + + u3_noun u3qef_drg(u3_noun, u3_atom); + u3_noun u3qef_lug(u3_noun, u3_noun, u3_atom, u3_atom); + + u3_noun u3qer_add(u3_atom, u3_atom, u3_atom); + u3_noun u3qer_sub(u3_atom, u3_atom, u3_atom); + u3_noun u3qer_mul(u3_atom, u3_atom, u3_atom); + u3_noun u3qer_div(u3_atom, u3_atom, u3_atom); + u3_noun u3qer_sqt(u3_atom, u3_atom); + u3_noun u3qer_fma(u3_atom, u3_atom, u3_atom, u3_atom); + u3_noun u3qer_lth(u3_atom, u3_atom); + u3_noun u3qer_lte(u3_atom, u3_atom); + u3_noun u3qer_equ(u3_atom, u3_atom); + u3_noun u3qer_gte(u3_atom, u3_atom); + u3_noun u3qer_gth(u3_atom, u3_atom); + + u3_noun u3qet_add(u3_atom, u3_atom, u3_atom); + u3_noun u3qet_sub(u3_atom, u3_atom, u3_atom); + u3_noun u3qet_mul(u3_atom, u3_atom, u3_atom); + u3_noun u3qet_div(u3_atom, u3_atom, u3_atom); + u3_noun u3qet_sqt(u3_atom, u3_atom); + u3_noun u3qet_fma(u3_atom, u3_atom, u3_atom, u3_atom); + u3_noun u3qet_lth(u3_atom, u3_atom); + u3_noun u3qet_lte(u3_atom, u3_atom); + u3_noun u3qet_equ(u3_atom, u3_atom); + u3_noun u3qet_gte(u3_atom, u3_atom); + u3_noun u3qet_gth(u3_atom, u3_atom); + + u3_noun u3qeq_add(u3_atom, u3_atom, u3_atom); + u3_noun u3qeq_sub(u3_atom, u3_atom, u3_atom); + u3_noun u3qeq_mul(u3_atom, u3_atom, u3_atom); + u3_noun u3qeq_div(u3_atom, u3_atom, u3_atom); + u3_noun u3qeq_sqt(u3_atom, u3_atom); + u3_noun u3qeq_fma(u3_atom, u3_atom, u3_atom, u3_atom); + u3_noun u3qeq_lth(u3_atom, u3_atom); + u3_noun u3qeq_lte(u3_atom, u3_atom); + u3_noun u3qeq_equ(u3_atom, u3_atom); + u3_noun u3qeq_gte(u3_atom, u3_atom); + u3_noun u3qeq_gth(u3_atom, u3_atom); + + u3_noun u3qes_add(u3_atom, u3_atom, u3_atom); + u3_noun u3qes_sub(u3_atom, u3_atom, u3_atom); + u3_noun u3qes_mul(u3_atom, u3_atom, u3_atom); + u3_noun u3qes_div(u3_atom, u3_atom, u3_atom); + u3_noun u3qes_sqt(u3_atom, u3_atom); + u3_noun u3qes_fma(u3_atom, u3_atom, u3_atom, u3_atom); + u3_noun u3qes_lth(u3_atom, u3_atom); + u3_noun u3qes_lte(u3_atom, u3_atom); + u3_noun u3qes_equ(u3_atom, u3_atom); + u3_noun u3qes_gte(u3_atom, u3_atom); + u3_noun u3qes_gth(u3_atom, u3_atom); + + u3_noun u3qe_decompress_zlib(u3_atom, u3_noun); + u3_noun u3qe_decompress_gzip(u3_atom, u3_noun); + + /** Tier 6. + **/ + u3_noun u3qf_bull(u3_noun, u3_noun); + u3_noun u3qf_cell(u3_noun, u3_noun); + u3_noun u3qf_comb(u3_noun, u3_noun); + u3_noun u3qf_cons(u3_noun, u3_noun); + u3_noun u3qf_core(u3_noun, u3_noun); + u3_noun u3qf_cube(u3_noun, u3_noun); + u3_noun u3qf_face(u3_noun, u3_noun); + u3_noun u3qf_fine(u3_noun, u3_noun, u3_noun); + u3_noun u3qf_fitz(u3_noun, u3_noun); + u3_noun u3qf_flay(u3_noun); + u3_noun u3qf_forq(u3_noun, u3_noun); + u3_noun u3qf_fork(u3_noun); + u3_noun u3qf_grof(u3_noun); + u3_noun u3qf_hint(u3_noun, u3_noun); + u3_noun u3qf_hike(u3_noun, u3_noun); + u3_noun u3qf_look(u3_noun, u3_noun); + u3_noun u3qf_loot(u3_noun, u3_noun); + u3_noun u3qf_slot(u3_atom, u3_noun); + u3_noun u3qf_type(u3_noun); + + u3_noun u3qfl_bunt(u3_noun, u3_noun); + u3_noun u3qfl_whip(u3_noun, u3_noun, u3_noun); + + u3_noun u3qfr_fish(u3_noun, u3_noun, u3_noun, u3_noun); + + u3_noun u3qfp_hack(u3_noun, u3_noun); + u3_noun u3qfp_late(u3_noun); + u3_noun u3qfp_open(u3_noun, u3_noun, u3_noun); + u3_noun u3qfp_nepo(u3_noun, u3_noun); + u3_noun u3qfp_rake(u3_noun); + + u3_noun u3qi_la_add_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_sub_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_mul_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_div_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_mod_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_adds_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_subs_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_muls_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_divs_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_mods_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_dot_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_diag(u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_transpose(u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_cumsum_i754(u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_argmin_i754(u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_argmax_i754(u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_ravel_i754(u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_min_i754(u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_max_i754(u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_linspace_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_range_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_abs_i754(u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_gth_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_gte_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_lth_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_lte_i754(u3_noun, u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_trace_i754(u3_noun, u3_noun, u3_noun); + u3_noun u3qi_la_mmul_i754(u3_noun, u3_noun, u3_noun, u3_noun, u3_noun); + + u3_noun u3qi_rd_exp(u3_noun); + u3_noun u3qi_rd_log(u3_noun); + u3_noun u3qi_rd_sin(u3_atom); + u3_noun u3qi_rd_cos(u3_atom); + u3_noun u3qi_rd_tan(u3_atom); + u3_noun u3qi_rd_atan(u3_atom); + u3_noun u3qi_rd_atan2(u3_atom, u3_atom); + u3_noun u3qi_rd_asin(u3_atom); + u3_noun u3qi_rd_acos(u3_atom); + u3_noun u3qi_rd_sqt(u3_atom); + u3_noun u3qi_rd_cbt(u3_atom); + u3_noun u3qi_rd_pow(u3_atom, u3_atom); + u3_noun u3qi_rd_pow_n(u3_atom, u3_atom); + u3_noun u3qi_rd_log2(u3_atom); + u3_noun u3qi_rd_log10(u3_atom); + +# define u3qfu_van_fan 28 +# define u3qfu_van_rib 58 +# define u3qfu_van_vet 59 + + void u3qf_test(const c3_c*, u3_noun); + + + /** Tier 6. + **/ + u3_noun u3qg_plot_fax(u3_noun, u3_noun); + u3_noun u3qg_plot_met(u3_noun, u3_noun); + +#endif /* ifndef U3_JETS_Q_H */ + diff --git a/libmath/vere64/noun/jets/w.h b/libmath/vere64/noun/jets/w.h new file mode 100644 index 0000000..effc85a --- /dev/null +++ b/libmath/vere64/noun/jets/w.h @@ -0,0 +1,449 @@ +/// @file + +#ifndef U3_JETS_W_H +#define U3_JETS_W_H + +#include "types.h" + + /** Tier 1. + **/ + u3_noun u3wa_add(u3_noun); + u3_noun u3wa_dec(u3_noun); + u3_noun u3wa_div(u3_noun); + u3_noun u3wa_gte(u3_noun); + u3_noun u3wa_gth(u3_noun); + u3_noun u3wa_lte(u3_noun); + u3_noun u3wa_lth(u3_noun); + u3_noun u3wa_max(u3_noun); + u3_noun u3wa_min(u3_noun); + u3_noun u3wa_mod(u3_noun); + u3_noun u3wa_mul(u3_noun); + u3_noun u3wa_sub(u3_noun); + + /** Tier 2. + **/ + u3_noun u3wb_bind(u3_noun); + u3_noun u3wb_clap(u3_noun); + u3_noun u3wb_drop(u3_noun); + u3_noun u3wb_find(u3_noun); + u3_noun u3wb_flop(u3_noun); + u3_noun u3wb_lent(u3_noun); + u3_noun u3wb_levy(u3_noun); + u3_noun u3wb_lien(u3_noun); + u3_noun u3wb_murn(u3_noun); + u3_noun u3wb_need(u3_noun); + u3_noun u3wb_mate(u3_noun); + u3_noun u3wb_reap(u3_noun); + u3_noun u3wb_reel(u3_noun); + u3_noun u3wb_roll(u3_noun); + u3_noun u3wb_skid(u3_noun); + u3_noun u3wb_skim(u3_noun); + u3_noun u3wb_skip(u3_noun); + u3_noun u3wb_scag(u3_noun); + u3_noun u3wb_slag(u3_noun); + u3_noun u3wb_snag(u3_noun); + u3_noun u3wb_sort(u3_noun); + u3_noun u3wb_turn(u3_noun); + u3_noun u3wb_weld(u3_noun); +# define u3wb_welp u3wb_weld + u3_noun u3wb_zing(u3_noun); + + /** Tier 3. + **/ + u3_noun u3wc_aor(u3_noun); + u3_noun u3wc_bex(u3_noun); + u3_noun u3wc_xeb(u3_noun); + u3_noun u3wc_can(u3_noun); + u3_noun u3wc_cap(u3_noun); + u3_noun u3wc_cat(u3_noun); + u3_noun u3wc_clz(u3_noun); + u3_noun u3wc_con(u3_noun); + u3_noun u3wc_ctz(u3_noun); + u3_noun u3wc_cut(u3_noun); + u3_noun u3wc_dis(u3_noun); + u3_noun u3wc_dor(u3_noun); + u3_noun u3wc_dvr(u3_noun); + u3_noun u3wc_end(u3_noun); + u3_noun u3wc_gor(u3_noun); + u3_noun u3wc_ham(u3_noun); + u3_noun u3wc_hew(u3_noun); + u3_noun u3wc_lsh(u3_noun); + u3_noun u3wc_mas(u3_noun); + u3_noun u3wc_met(u3_noun); + u3_noun u3wc_mix(u3_noun); + u3_noun u3wc_mor(u3_noun); + u3_noun u3wc_mug(u3_noun); + u3_noun u3wc_muk(u3_noun); + u3_noun u3wc_peg(u3_noun); + u3_noun u3wc_pow(u3_noun); + u3_noun u3wc_rap(u3_noun); + u3_noun u3wc_rep(u3_noun); + u3_noun u3wc_rev(u3_noun); + u3_noun u3wc_rig(u3_noun); + u3_noun u3wc_rip(u3_noun); + u3_noun u3wc_rsh(u3_noun); + u3_noun u3wc_sew(u3_noun); + u3_noun u3wc_swp(u3_noun); + u3_noun u3wc_sqt(u3_noun); + + u3_noun u3wcp_ins(u3_noun); + u3_noun u3wcp_ind(u3_noun); + u3_noun u3wcp_tos(u3_noun); + u3_noun u3wcp_tod(u3_noun); + + /** Tier 4. + **/ + u3_noun u3wdb_all(u3_noun); + u3_noun u3wdb_any(u3_noun); + u3_noun u3wdb_apt(u3_noun); + u3_noun u3wdb_bif(u3_noun); + u3_noun u3wdb_del(u3_noun); + u3_noun u3wdb_dif(u3_noun); + u3_noun u3wdb_gas(u3_noun); + u3_noun u3wdb_get(u3_noun); + u3_noun u3wdb_has(u3_noun); + u3_noun u3wdb_int(u3_noun); + u3_noun u3wdb_jab(u3_noun); + u3_noun u3wdb_key(u3_noun); + u3_noun u3wdb_put(u3_noun); +# define u3wdb_tap u3wdi_tap + u3_noun u3wdb_uni(u3_noun); + u3_noun u3wdb_urn(u3_noun); +# define u3wdb_rep u3wdi_rep + u3_noun u3wdb_run(u3_noun); +# define u3wdb_wyt u3wdi_wyt + + u3_noun u3wdi_apt_140(u3_noun); + u3_noun u3wdi_apt(u3_noun); + u3_noun u3wdi_bif(u3_noun); + u3_noun u3wdi_del(u3_noun); + u3_noun u3wdi_dif(u3_noun); + u3_noun u3wdi_gas(u3_noun); + u3_noun u3wdi_has(u3_noun); + u3_noun u3wdi_int(u3_noun); + u3_noun u3wdi_put(u3_noun); + u3_noun u3wdi_rep(u3_noun); + u3_noun u3wdi_run(u3_noun); + u3_noun u3wdi_tap(u3_noun); + u3_noun u3wdi_uni(u3_noun); + u3_noun u3wdi_wyt(u3_noun); + + /** Tier 5. + **/ + u3_noun u3we_cue(u3_noun); + u3_noun u3we_jam(u3_noun); + u3_noun u3we_mat(u3_noun); + u3_noun u3we_rub(u3_noun); + u3_noun u3we_leer(u3_noun); + u3_noun u3we_lore(u3_noun); + u3_noun u3we_loss(u3_noun); + u3_noun u3we_lune(u3_noun); + u3_noun u3we_mice(u3_noun); + u3_noun u3we_mink(u3_noun); + u3_noun u3we_mole(u3_noun); + u3_noun u3we_mule(u3_noun); + u3_noun u3we_repg(u3_noun); + u3_noun u3we_rexp(u3_noun); + u3_noun u3we_trip(u3_noun); + + u3_noun u3we_scow(u3_noun); + u3_noun u3we_scot(u3_noun); + u3_noun u3we_slaw(u3_noun); + + u3_noun u3we_pfix(u3_noun); + u3_noun u3we_plug(u3_noun); + u3_noun u3we_pose(u3_noun); + u3_noun u3we_sfix(u3_noun); + + u3_noun u3wea_ecba_en(u3_noun); + u3_noun u3wea_ecba_de(u3_noun); + u3_noun u3wea_ecbb_en(u3_noun); + u3_noun u3wea_ecbb_de(u3_noun); + u3_noun u3wea_ecbc_en(u3_noun); + u3_noun u3wea_ecbc_de(u3_noun); + + u3_noun u3wea_cbca_en(u3_noun); + u3_noun u3wea_cbca_de(u3_noun); + u3_noun u3wea_cbcb_en(u3_noun); + u3_noun u3wea_cbcb_de(u3_noun); + u3_noun u3wea_cbcc_en(u3_noun); + u3_noun u3wea_cbcc_de(u3_noun); + + u3_noun u3wea_siva_en(u3_noun); + u3_noun u3wea_siva_de(u3_noun); + u3_noun u3wea_sivb_en(u3_noun); + u3_noun u3wea_sivb_de(u3_noun); + u3_noun u3wea_sivc_en(u3_noun); + u3_noun u3wea_sivc_de(u3_noun); + + u3_noun u3wea_de(u3_noun); + u3_noun u3wea_en(u3_noun); + + u3_noun u3wes_hsh(u3_noun); + u3_noun u3wes_hsl(u3_noun); + u3_noun u3wes_pbk(u3_noun); + u3_noun u3wes_pbl(u3_noun); + + u3_noun u3we_shax(u3_noun); + u3_noun u3we_shay(u3_noun); + u3_noun u3we_shas(u3_noun); + u3_noun u3we_shal(u3_noun); + u3_noun u3we_sha1(u3_noun); + + u3_noun u3we_fein_ob(u3_noun); + u3_noun u3we_fynd_ob(u3_noun); + + u3_noun u3weo_raw(u3_noun); + + u3_noun u3wee_scad(u3_noun); + u3_noun u3wee_scas(u3_noun); + u3_noun u3wee_scap(u3_noun); + + u3_noun u3wee_puck(u3_noun); + u3_noun u3wee_luck(u3_noun); + u3_noun u3wee_sign(u3_noun); + u3_noun u3wee_sign_raw(u3_noun); + u3_noun u3wee_veri(u3_noun); + u3_noun u3wee_sign_octs(u3_noun); + u3_noun u3wee_sign_octs_raw(u3_noun); + u3_noun u3wee_veri_octs(u3_noun); + u3_noun u3wee_shar(u3_noun); + u3_noun u3wee_slar(u3_noun); + u3_noun u3wee_recs(u3_noun); + u3_noun u3wee_smac(u3_noun); + u3_noun u3wee_point_neg(u3_noun); + u3_noun u3wee_point_add(u3_noun); + u3_noun u3wee_scalarmult(u3_noun); + u3_noun u3wee_scalarmult_base(u3_noun); + u3_noun u3wee_add_scalarmult_scalarmult_base(u3_noun); + u3_noun u3wee_add_double_scalarmult(u3_noun); + + u3_noun u3we_hmac(u3_noun); + + u3_noun u3we_kecc224(u3_noun); + u3_noun u3we_kecc256(u3_noun); + u3_noun u3we_kecc384(u3_noun); + u3_noun u3we_kecc512(u3_noun); + + u3_noun u3we_argon2(u3_noun); + + u3_noun u3we_blake2b(u3_noun); + u3_noun u3we_blake3_hash(u3_noun); + u3_noun u3we_blake3_chunk_output(u3_noun); + u3_noun u3we_blake3_compress(u3_noun); + + u3_noun u3we_chacha_crypt(u3_noun); + u3_noun u3we_chacha_xchacha(u3_noun); + + u3_noun u3we_adler32(u3_noun); + u3_noun u3we_crc32(u3_noun); + + u3_noun u3we_ripe(u3_noun); + + u3_noun u3we_make(u3_noun); + u3_noun u3we_sign(u3_noun); + u3_noun u3we_reco(u3_noun); + + u3_noun u3we_sosi(u3_noun); + u3_noun u3we_sove(u3_noun); + + u3_noun u3we_en_base16(u3_noun); + u3_noun u3we_de_base16(u3_noun); + + u3_noun u3we_json_de(u3_noun); + u3_atom u3we_json_en(u3_noun); + + u3_noun u3we_bend_fun(u3_noun); + u3_noun u3we_cold_fun(u3_noun); + u3_noun u3we_cook_fun(u3_noun); + u3_noun u3we_comp_fun(u3_noun); + u3_noun u3we_easy_fun(u3_noun); + u3_noun u3we_glue_fun(u3_noun); + u3_noun u3we_here_fun(u3_noun); + u3_noun u3we_just_fun(u3_noun); + u3_noun u3we_mask_fun(u3_noun); + u3_noun u3we_shim_fun(u3_noun); + u3_noun u3we_stag_fun(u3_noun); + u3_noun u3we_stew_fun(u3_noun); + u3_noun u3we_stir_fun(u3_noun); + + u3_noun u3wef_drg(u3_noun); + u3_noun u3wef_lug(u3_noun); + + u3_noun u3wer_add(u3_noun); + u3_noun u3wer_sub(u3_noun); + u3_noun u3wer_mul(u3_noun); + u3_noun u3wer_div(u3_noun); + u3_noun u3wer_sqt(u3_noun); + u3_noun u3wer_fma(u3_noun); + u3_noun u3wer_lth(u3_noun); + u3_noun u3wer_lte(u3_noun); + u3_noun u3wer_equ(u3_noun); + u3_noun u3wer_gte(u3_noun); + u3_noun u3wer_gth(u3_noun); + + u3_noun u3wet_add(u3_noun); + u3_noun u3wet_sub(u3_noun); + u3_noun u3wet_mul(u3_noun); + u3_noun u3wet_div(u3_noun); + u3_noun u3wet_sqt(u3_noun); + u3_noun u3wet_fma(u3_noun); + u3_noun u3wet_lth(u3_noun); + u3_noun u3wet_lte(u3_noun); + u3_noun u3wet_equ(u3_noun); + u3_noun u3wet_gte(u3_noun); + u3_noun u3wet_gth(u3_noun); + + u3_noun u3weq_add(u3_noun); + u3_noun u3weq_sub(u3_noun); + u3_noun u3weq_mul(u3_noun); + u3_noun u3weq_div(u3_noun); + u3_noun u3weq_sqt(u3_noun); + u3_noun u3weq_fma(u3_noun); + u3_noun u3weq_lth(u3_noun); + u3_noun u3weq_lte(u3_noun); + u3_noun u3weq_equ(u3_noun); + u3_noun u3weq_gte(u3_noun); + u3_noun u3weq_gth(u3_noun); + + u3_noun u3wes_add(u3_noun); + u3_noun u3wes_sub(u3_noun); + u3_noun u3wes_mul(u3_noun); + u3_noun u3wes_div(u3_noun); + u3_noun u3wes_sqt(u3_noun); + u3_noun u3wes_fma(u3_noun); + u3_noun u3wes_lth(u3_noun); + u3_noun u3wes_lte(u3_noun); + u3_noun u3wes_equ(u3_noun); + u3_noun u3wes_gte(u3_noun); + u3_noun u3wes_gth(u3_noun); + + u3_noun u3we_crc32(u3_noun); + u3_noun u3we_decompress_zlib(u3_noun); + u3_noun u3we_decompress_gzip(u3_noun); + + u3_noun u3we_lia_run_v1(u3_noun); + u3_noun u3we_lia_run_once(u3_noun); + + //+| %utilities + u3_noun u3we_bytestream_rip_octs(u3_noun); + u3_noun u3we_bytestream_cat_octs(u3_noun); + u3_noun u3we_bytestream_can_octs(u3_noun); + //+| %navigation + u3_noun u3we_bytestream_skip_line(u3_noun); + u3_noun u3we_bytestream_find_byte(u3_noun); + u3_noun u3we_bytestream_seek_byte(u3_noun); + //+| %read-byte + u3_noun u3we_bytestream_read_byte(u3_noun); + //+| %read-octs + u3_noun u3we_bytestream_read_octs(u3_noun); + //+| %transformation + u3_noun u3we_bytestream_chunk(u3_noun); + u3_noun u3we_bytestream_extract(u3_noun); + u3_noun u3we_bytestream_fuse_extract(u3_noun); + //+| %bitstream + u3_noun u3we_bytestream_need_bits(u3_noun); + u3_noun u3we_bytestream_drop_bits(u3_noun); + // u3_noun u3we_bytestream_skip_bits(u3_noun); + u3_noun u3we_bytestream_peek_bits(u3_noun); + u3_noun u3we_bytestream_read_bits(u3_noun); + // u3_noun u3we_bytestream_read_need_bits(u3_noun); + u3_noun u3we_bytestream_byte_bits(u3_noun); + + /** Tier 6. + **/ + u3_noun u3wf_bull(u3_noun); + u3_noun u3wf_cell(u3_noun); + u3_noun u3wf_comb(u3_noun); + u3_noun u3wf_cons(u3_noun); + u3_noun u3wf_core(u3_noun); + u3_noun u3wf_cube(u3_noun); + u3_noun u3wf_face(u3_noun); + u3_noun u3wf_fine(u3_noun); + u3_noun u3wf_fitz(u3_noun); + u3_noun u3wf_flan_139(u3_noun); + u3_noun u3wf_flay(u3_noun); + u3_noun u3wf_flip_139(u3_noun); + u3_noun u3wf_flor_139(u3_noun); + u3_noun u3wf_forq(u3_noun); + u3_noun u3wf_fork(u3_noun); + u3_noun u3wf_hint(u3_noun); + u3_noun u3wf_hike(u3_noun); + u3_noun u3wf_look(u3_noun); + u3_noun u3wf_loot(u3_noun); + + u3_noun u3wfl_bunt(u3_noun); + u3_noun u3wfl_whip(u3_noun); + + u3_noun u3wfp_hack(u3_noun); + u3_noun u3wfp_late(u3_noun); + u3_noun u3wfp_open(u3_noun); + u3_noun u3wfp_rake(u3_noun); + + u3_noun u3wfu_busk(u3_noun); + u3_noun u3wfu_crop(u3_noun); + u3_noun u3wfu_find(u3_noun); + u3_noun u3wfu_fond(u3_noun); + u3_noun u3wfu_fish(u3_noun); + u3_noun u3wfu_fuse(u3_noun); + u3_noun u3wfu_redo(u3_noun); + u3_noun u3wfu_mint(u3_noun); + u3_noun u3wfu_mull(u3_noun); + u3_noun u3wfu_nest_dext(u3_noun); + u3_noun u3wfu_peek(u3_noun); + u3_noun u3wfu_play(u3_noun); + u3_noun u3wfu_repo(u3_noun); + u3_noun u3wfu_rest(u3_noun); + + /** Tier 7. + **/ + u3_noun u3wg_plot_fax(u3_noun); + u3_noun u3wg_plot_met(u3_noun); + u3_noun u3wi_la_add(u3_noun); + u3_noun u3wi_la_sub(u3_noun); + u3_noun u3wi_la_mul(u3_noun); + u3_noun u3wi_la_div(u3_noun); + u3_noun u3wi_la_mod(u3_noun); + u3_noun u3wi_la_adds(u3_noun); + u3_noun u3wi_la_subs(u3_noun); + u3_noun u3wi_la_muls(u3_noun); + u3_noun u3wi_la_divs(u3_noun); + u3_noun u3wi_la_mods(u3_noun); + u3_noun u3wi_la_dot(u3_noun); + u3_noun u3wi_la_diag(u3_noun); + u3_noun u3wi_la_transpose(u3_noun); + u3_noun u3wi_la_cumsum(u3_noun); + u3_noun u3wi_la_argmin(u3_noun); + u3_noun u3wi_la_argmax(u3_noun); + u3_noun u3wi_la_ravel(u3_noun); + u3_noun u3wi_la_min(u3_noun); + u3_noun u3wi_la_max(u3_noun); + u3_noun u3wi_la_linspace(u3_noun); + u3_noun u3wi_la_range(u3_noun); + u3_noun u3wi_la_abs(u3_noun); + u3_noun u3wi_la_gth(u3_noun); + u3_noun u3wi_la_gte(u3_noun); + u3_noun u3wi_la_lth(u3_noun); + u3_noun u3wi_la_lte(u3_noun); + + u3_noun u3wi_la_trace(u3_noun); + u3_noun u3wi_la_mmul(u3_noun); + + u3_noun u3wi_rd_exp(u3_noun); + u3_noun u3wi_rd_log(u3_noun); + u3_noun u3wi_rd_sin(u3_noun); + u3_noun u3wi_rd_cos(u3_noun); + u3_noun u3wi_rd_tan(u3_noun); + u3_noun u3wi_rd_atan(u3_noun); + u3_noun u3wi_rd_atan2(u3_noun); + u3_noun u3wi_rd_asin(u3_noun); + u3_noun u3wi_rd_acos(u3_noun); + u3_noun u3wi_rd_sqt(u3_noun); + u3_noun u3wi_rd_cbt(u3_noun); + u3_noun u3wi_rd_pow(u3_noun); + u3_noun u3wi_rd_pow_n(u3_noun); + u3_noun u3wi_rd_log2(u3_noun); + u3_noun u3wi_rd_log10(u3_noun); + +#endif /* ifndef U3_JETS_W_H */ + diff --git a/libmath/vere/test/build.sh b/libmath/vere64/test/build.sh similarity index 100% rename from libmath/vere/test/build.sh rename to libmath/vere64/test/build.sh diff --git a/libmath/vere/test/rd_check.c b/libmath/vere64/test/rd_check.c similarity index 91% rename from libmath/vere/test/rd_check.c rename to libmath/vere64/test/rd_check.c index 9b7e363..0ccad4c 100644 --- a/libmath/vere/test/rd_check.c +++ b/libmath/vere64/test/rd_check.c @@ -1,14 +1,16 @@ // rd_check.c -- bit-exact harness for the @rd math jets. // -// Includes the MASTER jet algorithms (jets/i/math.c) with -DMATH_JET_HARNESS, -// so the C tested here is byte-for-byte the C the runtime jet runs. Prints -// ` 0x 0x` per case; compare each against the Hoon -// `(:rd:math )` (see build.sh for the generated dojo expression). +// Includes the MASTER jet algorithms (noun/jets/i/math.c) with +// -DMATH_JET_HARNESS, so the C tested here is byte-for-byte the C the runtime +// jet runs. Prints ` 0x 0x` per case; compare each against +// the Hoon `(:rd:math )` (see build.sh for the generated dojo +// expression). The shared `_rd_*` cores are word-size-agnostic, so this 64-bit +// copy and the 32-bit libmath/vere/ copy produce identical results. // // Build/run: ./build.sh (re-archives the zig softfloat .a for Apple ld). #define MATH_JET_HARNESS -#include "../jets/i/math.c" +#include "../noun/jets/i/math.c" #include diff --git a/libmath/vere/test/verify.sh b/libmath/vere64/test/verify.sh similarity index 100% rename from libmath/vere/test/verify.sh rename to libmath/vere64/test/verify.sh diff --git a/libmath/vere/test/verify_clean.sh b/libmath/vere64/test/verify_clean.sh similarity index 100% rename from libmath/vere/test/verify_clean.sh rename to libmath/vere64/test/verify_clean.sh From 366dbb33d3e4317850a9b5a30625a9cc1199c5ab Mon Sep 17 00:00:00 2001 From: Sigilante Date: Fri, 12 Jun 2026 07:56:33 -0500 Subject: [PATCH 05/28] math: @rs transcendental jets + honor door rounding mode in composites Add all 15 @rs (single-precision) transcendental jets, single-precision twins of the @rd cores (same reductions/coeffs, SoftFloat f32, chub marshalling so they stay word-size-agnostic). Registered under non/math/rs in 135/tree.c, q.h/w.h decls, and ~/ hints on the rs door arms. 74 harness vectors bit-exact; full -test %/tests/lib passes ok=%.y on both the 32- and 64-bit jetted runtimes. Also fix a latent rounding-mode bug (affected @rd atan2/pow/pow-n from #63, and the new @rs atan2/pow/pow-n/tan): the math doors carry r=?(%n %u %d %z) whose bunt is %z, and the composite arms used bare door ops (mul:^rd, (div y x)) that silently bound that %z bunt instead of honoring r. The transcendental KERNELS correctly hardcode ~(mul ^rd %n); only the composite assembly was wrong. - Hoon: thread r into the door helper arms (sun/san/toi/drg/grd/add/sub/mul/ div/fma -> ~(op ^rd r)) for the rd and rs doors, so pow/atan2/tan/pow-n honor the door's rounding mode. Kernels keep their explicit %n. - Jets: a file-static _math_rnd, set from the door's r (gate axis 60, mapping 'n'/'u'/'d'/'z' -> SoftFloat near_even/max/min/minMag), brackets the bare ops in the composite cores; kernel calls run at near_even. - test-pow-3-2h's expected was baked from the old %z behavior (its pd door is %n); corrected to the near-even value (exact arithmetic: 2.5*log3 -> ...43ce -> exp -> ...5643). Co-Authored-By: Claude Opus 4.8 --- libmath/desk/lib/math.hoon | 56 ++- libmath/desk/tests/lib/math-derived.hoon | 2 +- libmath/vere/noun/jets/135/tree.c | 36 ++ libmath/vere/noun/jets/i/math.c | 533 ++++++++++++++++++++++- libmath/vere/noun/jets/q.h | 15 + libmath/vere/noun/jets/w.h | 15 + libmath/vere64/noun/jets/135/tree.c | 36 ++ libmath/vere64/noun/jets/i/math.c | 533 ++++++++++++++++++++++- libmath/vere64/noun/jets/q.h | 15 + libmath/vere64/noun/jets/w.h | 15 + libmath/vere64/test/rd_check.c | 43 +- 11 files changed, 1255 insertions(+), 44 deletions(-) diff --git a/libmath/desk/lib/math.hoon b/libmath/desk/lib/math.hoon index 06aff7c..bbadbc9 100644 --- a/libmath/desk/lib/math.hoon +++ b/libmath/desk/lib/math.hoon @@ -20,6 +20,7 @@ ~/ %math |% ++ rs + ~/ %rs ^| |_ $: r=$?(%n %u %d %z) :: round nearest, up, down, to zero rtol=_.1e-5 :: relative tolerance for precision of operations @@ -146,7 +147,7 @@ :: > (sun 1.000) :: .1e3 :: Source - ++ sun sun:^rs + ++ sun ~(sun ^rs r) :: +san: @sd -> @rs :: :: Returns the floating-point atom of a signed integer atom. @@ -156,7 +157,7 @@ :: > (san -1) :: .-1 :: Source - ++ san san:^rs + ++ san ~(san ^rs r) ::++ exp exp:^rs :: no pass-through because of exp function :: +toi: @rs -> @sd :: @@ -167,7 +168,7 @@ :: > (toi .1.1) :: [~ --1] :: Source - ++ toi toi:^rs + ++ toi ~(toi ^rs r) :: +drg: @rs -> dn :: :: Returns the decimal form of a floating-point atom using the Dragon4 @@ -178,7 +179,7 @@ :: > (drg .1.1) :: [%d s=%.y e=-1 a=11] :: Source - ++ drg drg:^rs + ++ drg ~(drg ^rs r) :: +grd: dn -> @rs :: :: Returns the floating-point atom of a decimal form. @@ -188,7 +189,7 @@ :: > (grd [%d s=%.y e=-1 a=11]) :: .1.1 :: Source - ++ grd grd:^rs + ++ grd ~(grd ^rs r) :: :: Comparison :: @@ -349,7 +350,7 @@ :: > (add .1 .2) :: .3 :: Source - ++ add add:^rs + ++ add ~(add ^rs r) :: +sub: [@rs @rs] -> @rs :: :: Returns the difference of two floating-point atoms. @@ -357,7 +358,7 @@ :: > (sub .1 .2) :: .-1 :: Source - ++ sub sub:^rs + ++ sub ~(sub ^rs r) :: +mul: [@rs @rs] -> @rs :: :: Returns the product of two floating-point atoms. @@ -367,7 +368,7 @@ :: > (mul .2 .3) :: .6 :: Source - ++ mul mul:^rs + ++ mul ~(mul ^rs r) :: +div: [@rs @rs] -> @rs :: :: Returns the quotient of two floating-point atoms. @@ -375,7 +376,7 @@ :: > (div .1 .2) :: .0.5 :: Source - ++ div div:^rs + ++ div ~(div ^rs r) :: +mod: [@rs @rs] -> @rs :: :: Returns the modulus of two floating-point atoms. @@ -399,7 +400,7 @@ :: > (fma .2 .3 .4) :: .10 :: Source - ++ fma fma:^rs + ++ fma ~(fma ^rs r) :: +sig: @rs -> ? :: :: Returns the sign of a floating-point atom. @@ -478,6 +479,7 @@ :: .inf :: Source ++ exp + ~/ %exp |= x=@rs ^- @rs :: Chebyshev: x = k*ln2 + r (Cody-Waite reduction); exp(x) = 2^k * P(r), :: P a degree-6 minimax polynomial faithful to <=1 ULP. Internals are @@ -527,6 +529,7 @@ :: .3.1609193e-7 :: Source ++ sin + ~/ %sin |= x=@rs ^- @rs :: Reduce x = q*(pi/2) + (rhi+rlo) with a 3-part pi/2 (f32 needs the bits), :: then fdlibm sin/cos kernels picked by q&3. Faithful to <=1 ULP for @@ -548,6 +551,7 @@ :: .-0.9999998 :: Source ++ cos + ~/ %cos |= x=@rs ^- @rs ?: !(~(equ ^rs %n) x x) `@rs`0x7fc0.0000 ?: |(=(x `@rs`0x7f80.0000) =(x `@rs`0xff80.0000)) `@rs`0x7fc0.0000 @@ -607,6 +611,7 @@ :: .-7.0094916e-7 :: Source ++ tan + ~/ %tan |= x=@rs ^- @rs (div (sin x) (cos x)) :: +asin: @rs -> @rs @@ -621,6 +626,7 @@ :: .0.7753969 :: ++ asin + ~/ %asin :: fdlibm rational kernel; see +rs-ainv. Faithful to <=1 ULP; |x|>1 -> NaN. |= x=@rs ^- @rs (asn:rs-ainv x) @@ -636,6 +642,7 @@ :: .0.7953982 :: ++ acos + ~/ %acos |= x=@rs ^- @rs (acs:rs-ainv x) :: +rs-ainv: shared asin/acos engine for the @rs door (rational P/Q kernel), @@ -709,6 +716,7 @@ :: .1.2626364 :: ++ atan + ~/ %atan :: fdlibm breakpoint reduction + minimax poly; odd. Round-nearest-even :: internally (the SoftFloat jet matches). |= x=@rs ^- @rs @@ -769,6 +777,7 @@ :: .2.356195 :: ++ atan2 + ~/ %atan2 |= [y=@rs x=@rs] ^- @rs ?: (gth x .0) (atan (div y x)) @@ -793,6 +802,7 @@ :: .8 :: Source ++ pow-n + ~/ %pow-n |= [x=@rs n=@rs] ^- @rs ?: =(n .0) .1 ?> &((gth n .0) (is-int n)) @@ -819,6 +829,7 @@ :: .0.9999994 :: Source ++ log + ~/ %log |= x=@rs ^- @rs :: Reduce x = 2^e * m with m in [sqrt(1/2), sqrt(2)); then :: log(x) = e*ln2 + log(1+f), f = m-1, s = f/(2+f), @@ -868,6 +879,7 @@ :: .inf :: Source ++ log-10 + ~/ %log-10 :: e*log10(2) + log(m)/ln10, reusing +lr so the integer part is added with :: no division rounding (more accurate than log(x)/ln10). |= x=@rs ^- @rs @@ -887,6 +899,7 @@ :: .1.5849625 :: Source ++ log-2 + ~/ %log-2 :: e + log(m)/ln2 (integer part exact); see +lr. |= x=@rs ^- @rs ?: !(~(equ ^rs %n) x x) `@rs`0x7fc0.0000 @@ -935,6 +948,7 @@ :: .11.313687 :: Source ++ pow + ~/ %pow |= [x=@rs n=@rs] ^- @rs :: fall through on positive integers (faster) ?: &(=(n (san (need (toi n)))) (gth n .0)) (pow-n x (san (need (toi n)))) @@ -964,6 +978,7 @@ :: .316.22775 :: Source ++ sqt + ~/ %sqt :: Correctly-rounded: delegate to the stdlib (SoftFloat) f32 square root. |= x=@rs ^- @rs (sqt:^rs x) @@ -992,6 +1007,7 @@ :: .1.2599207 :: Source ++ cbt + ~/ %cbt :: cbrt(x) = sign(x) * exp(log|x| / 3); defined for all reals (unlike pow). |= x=@rs ^- @rs ?: !(~(equ ^rs %n) x x) x :: NaN -> NaN @@ -1206,7 +1222,7 @@ :: > (sun 1.000) :: .~1e3 :: Source - ++ sun sun:^rd + ++ sun ~(sun ^rd r) :: +san: @sd -> @rd :: :: Returns the floating-point atom of a signed integer atom. @@ -1216,7 +1232,7 @@ :: > (san -1) :: .~-1 :: Source - ++ san san:^rd + ++ san ~(san ^rd r) ::++ exp exp:^rd :: no pass-through because of exp function :: +toi: @rd -> @sd :: @@ -1227,7 +1243,7 @@ :: > (toi .~1.1) :: [~ --1] :: Source - ++ toi toi:^rd + ++ toi ~(toi ^rd r) :: +drg: @rd -> dn :: :: Returns the decimal form of a floating-point atom using the Dragon4 @@ -1238,7 +1254,7 @@ :: > (drg .~1.1) :: [%d s=%.y e=-1 a=11] :: Source - ++ drg drg:^rd + ++ drg ~(drg ^rd r) :: +grd: dn -> @rd :: :: Returns the floating-point atom of a decimal form. @@ -1248,7 +1264,7 @@ :: > (grd [%d s=%.y e=-1 a=11]) :: .~1.1 :: Source - ++ grd grd:^rd + ++ grd ~(grd ^rd r) :: :: Comparison :: @@ -1409,7 +1425,7 @@ :: > (add .~1 .~2) :: .~3 :: Source - ++ add add:^rd + ++ add ~(add ^rd r) :: +sub: [@rd @rd] -> @rd :: :: Returns the difference of two floating-point atoms. @@ -1417,7 +1433,7 @@ :: > (sub .~1 .~2) :: .~-1 :: Source - ++ sub sub:^rd + ++ sub ~(sub ^rd r) :: +mul: [@rd @rd] -> @rd :: :: Returns the product of two floating-point atoms. @@ -1427,7 +1443,7 @@ :: > (mul .~2 .~3) :: .~6 :: Source - ++ mul mul:^rd + ++ mul ~(mul ^rd r) :: +div: [@rd @rd] -> @rd :: :: Returns the quotient of two floating-point atoms. @@ -1435,7 +1451,7 @@ :: > (div .~1 .~2) :: .~0.5 :: Source - ++ div div:^rd + ++ div ~(div ^rd r) :: +fma: [@rd @rd @rd] -> @rd :: :: Returns the fused multiply-add of three floating-point atoms. @@ -1445,7 +1461,7 @@ :: > (fma .~2 .~3 .~4) :: .~10 :: Source - ++ fma fma:^rd + ++ fma ~(fma ^rd r) :: +sig: @rd -> ? :: :: Returns the sign of a floating-point atom. diff --git a/libmath/desk/tests/lib/math-derived.hoon b/libmath/desk/tests/lib/math-derived.hoon index 9a5b605..5536ffa 100644 --- a/libmath/desk/tests/lib/math-derived.hoon +++ b/libmath/desk/tests/lib/math-derived.hoon @@ -19,7 +19,7 @@ ++ test-log2-8 (expect-eq !>(`@`0x4008.0000.0000.0000) !>((l2d `@rd`0x4020.0000.0000.0000))) ++ test-log10-1e3 (expect-eq !>(`@`0x4008.0000.0000.0000) !>((l10d `@rd`0x408f.4000.0000.0000))) ++ test-pow-2-half (expect-eq !>(`@`0x3ff6.a09e.667f.3bcc) !>((pd `@rd`0x4000.0000.0000.0000 `@rd`0x3fe0.0000.0000.0000))) -++ test-pow-3-2h (expect-eq !>(`@`0x402f.2d4a.4563.563f) !>((pd `@rd`0x4008.0000.0000.0000 `@rd`0x4004.0000.0000.0000))) +++ test-pow-3-2h (expect-eq !>(`@`0x402f.2d4a.4563.5643) !>((pd `@rd`0x4008.0000.0000.0000 `@rd`0x4004.0000.0000.0000))) ++ test-cbrt-27 (expect-eq !>(`@`0x4007.ffff.ffff.ffff) !>((cbd `@rd`0x403b.0000.0000.0000))) ++ test-cbrt-n8 (expect-eq !>(`@`0xbfff.ffff.ffff.ffff) !>((cbd `@rd`0xc020.0000.0000.0000))) :: ==== @rs ==== diff --git a/libmath/vere/noun/jets/135/tree.c b/libmath/vere/noun/jets/135/tree.c index 4ee583e..98a240f 100644 --- a/libmath/vere/noun/jets/135/tree.c +++ b/libmath/vere/noun/jets/135/tree.c @@ -979,8 +979,44 @@ static u3j_core _135_non__math_rd_d[] = { "log-10", 7, _135_non__math_rd_log10_a, 0, no_hashes }, {} }; +// numerics math.hoon @rs transcendentals: non -> math -> rs -> +static u3j_harm _135_non__math_rs_exp_a[] = {{".2", u3wi_rs_exp}, {}}; +static u3j_harm _135_non__math_rs_log_a[] = {{".2", u3wi_rs_log}, {}}; +static u3j_harm _135_non__math_rs_sin_a[] = {{".2", u3wi_rs_sin}, {}}; +static u3j_harm _135_non__math_rs_cos_a[] = {{".2", u3wi_rs_cos}, {}}; +static u3j_harm _135_non__math_rs_tan_a[] = {{".2", u3wi_rs_tan}, {}}; +static u3j_harm _135_non__math_rs_atan_a[] = {{".2", u3wi_rs_atan}, {}}; +static u3j_harm _135_non__math_rs_atan2_a[] = {{".2", u3wi_rs_atan2}, {}}; +static u3j_harm _135_non__math_rs_asin_a[] = {{".2", u3wi_rs_asin}, {}}; +static u3j_harm _135_non__math_rs_acos_a[] = {{".2", u3wi_rs_acos}, {}}; +static u3j_harm _135_non__math_rs_sqt_a[] = {{".2", u3wi_rs_sqt}, {}}; +static u3j_harm _135_non__math_rs_cbt_a[] = {{".2", u3wi_rs_cbt}, {}}; +static u3j_harm _135_non__math_rs_pow_a[] = {{".2", u3wi_rs_pow}, {}}; +static u3j_harm _135_non__math_rs_pow_n_a[] = {{".2", u3wi_rs_pow_n}, {}}; +static u3j_harm _135_non__math_rs_log2_a[] = {{".2", u3wi_rs_log2}, {}}; +static u3j_harm _135_non__math_rs_log10_a[] = {{".2", u3wi_rs_log10}, {}}; +static u3j_core _135_non__math_rs_d[] = + { + { "exp", 7, _135_non__math_rs_exp_a, 0, no_hashes }, + { "log", 7, _135_non__math_rs_log_a, 0, no_hashes }, + { "sin", 7, _135_non__math_rs_sin_a, 0, no_hashes }, + { "cos", 7, _135_non__math_rs_cos_a, 0, no_hashes }, + { "tan", 7, _135_non__math_rs_tan_a, 0, no_hashes }, + { "atan", 7, _135_non__math_rs_atan_a, 0, no_hashes }, + { "atan2", 7, _135_non__math_rs_atan2_a, 0, no_hashes }, + { "asin", 7, _135_non__math_rs_asin_a, 0, no_hashes }, + { "acos", 7, _135_non__math_rs_acos_a, 0, no_hashes }, + { "sqt", 7, _135_non__math_rs_sqt_a, 0, no_hashes }, + { "cbt", 7, _135_non__math_rs_cbt_a, 0, no_hashes }, + { "pow", 7, _135_non__math_rs_pow_a, 0, no_hashes }, + { "pow-n", 7, _135_non__math_rs_pow_n_a, 0, no_hashes }, + { "log-2", 7, _135_non__math_rs_log2_a, 0, no_hashes }, + { "log-10", 7, _135_non__math_rs_log10_a, 0, no_hashes }, + {} + }; static u3j_core _135_non__math_d[] = { { "rd", 7, 0, _135_non__math_rd_d, no_hashes }, + { "rs", 7, 0, _135_non__math_rs_d, no_hashes }, {} }; diff --git a/libmath/vere/noun/jets/i/math.c b/libmath/vere/noun/jets/i/math.c index 87bca72..1bac3ba 100644 --- a/libmath/vere/noun/jets/i/math.c +++ b/libmath/vere/noun/jets/i/math.c @@ -40,6 +40,23 @@ typedef int64_t c3_ds; static inline union doub _rd_bits(c3_d b) { union doub u; u.c = b; return u; } + // The math doors carry a rounding mode r=?(%n %u %d %z) whose bunt is %z. + // The transcendental KERNELS force %n (correctly-rounded, no axis), but the + // composite arms (pow/atan2/tan/pow-n) round their BARE door ops per r. The + // wrapper sets _math_rnd from the door's r (axis 60 of the gate); cores + // bracket bare ops with it and restore near-even around kernel calls. + // Default = minMag (%z), matching the door bunt for the harness/cold path. + static int _math_rnd = softfloat_round_minMag; + static inline int _rnd_of(c3_d r) { // @tas 'n'/'u'/'d'/'z' -> SoftFloat + switch ( r ) { + case 'n': return softfloat_round_near_even; + case 'u': return softfloat_round_max; + case 'd': return softfloat_round_min; + case 'z': return softfloat_round_minMag; + default: return softfloat_round_minMag; + } + } + /* @rd exp -- math.hoon ++rd ++exp ** x = k*ln2 + r (Cody-Waite), exp(x) = 2^k * P(r), P a degree-11 minimax ** polynomial; +scale2 is a correctly-rounded ldexp. @@ -368,18 +385,37 @@ typedef int64_t c3_ds; else res.d = f64_sub(hi.d, f64_sub(f64_sub(f64_mul(xr.d, s.d), lo.d), xr.d)); return (neg == 1) ? _rd_neg(res.d) : res.d; } + // bare door ops (div/add/sub/mul) round per _math_rnd; atan kernel is %n. static float64_t _rd_atan2(float64_t y, float64_t x) { - union doub xb, pi, pi2, mpi2, zero; + union doub xb, pi, two, mone, zero, q, a, r; zero.c = 0; pi.c = 0x400921fb54442d18ULL; - pi2.c = 0x3ff921fb54442d18ULL; mpi2.c = 0xbff921fb54442d18ULL; + two.c = 0x4000000000000000ULL; mone.c = 0xbff0000000000000ULL; xb.d = x; - if ( f64_lt(zero.d, x) ) return _rd_atan(f64_div(y, x)); // x>0 - if ( f64_lt(x, zero.d) && f64_le(zero.d, y) ) // x<0,y>=0 - return f64_add(_rd_atan(f64_div(y, x)), pi.d); - if ( f64_lt(x, zero.d) && f64_lt(y, zero.d) ) // x<0,y<0 - return f64_sub(_rd_atan(f64_div(y, x)), pi.d); - if ( (xb.c == 0) && f64_lt(zero.d, y) ) return pi2.d; // x==+0,y>0 - if ( (xb.c == 0) && f64_lt(y, zero.d) ) return mpi2.d; // x==+0,y<0 + if ( f64_lt(zero.d, x) ) { // x>0: atan(div y x) + softfloat_roundingMode = _math_rnd; q.d = f64_div(y, x); + softfloat_roundingMode = softfloat_round_near_even; return _rd_atan(q.d); + } + if ( f64_lt(x, zero.d) && f64_le(zero.d, y) ) { // x<0,y>=0: add(atan,pi) + softfloat_roundingMode = _math_rnd; q.d = f64_div(y, x); + softfloat_roundingMode = softfloat_round_near_even; a.d = _rd_atan(q.d); + softfloat_roundingMode = _math_rnd; r.d = f64_add(a.d, pi.d); + softfloat_roundingMode = softfloat_round_near_even; return r.d; + } + if ( f64_lt(x, zero.d) && f64_lt(y, zero.d) ) { // x<0,y<0: sub(atan,pi) + softfloat_roundingMode = _math_rnd; q.d = f64_div(y, x); + softfloat_roundingMode = softfloat_round_near_even; a.d = _rd_atan(q.d); + softfloat_roundingMode = _math_rnd; r.d = f64_sub(a.d, pi.d); + softfloat_roundingMode = softfloat_round_near_even; return r.d; + } + if ( (xb.c == 0) && f64_lt(zero.d, y) ) { // x==+0,y>0: div(pi,2) + softfloat_roundingMode = _math_rnd; r.d = f64_div(pi.d, two.d); + softfloat_roundingMode = softfloat_round_near_even; return r.d; + } + if ( (xb.c == 0) && f64_lt(y, zero.d) ) { // x==+0,y<0: mul(-1,div(pi,2)) + softfloat_roundingMode = _math_rnd; + r.d = f64_mul(mone.d, f64_div(pi.d, two.d)); + softfloat_roundingMode = softfloat_round_near_even; return r.d; + } return zero.d; } @@ -502,20 +538,432 @@ typedef int64_t c3_ds; one.c = 0x3ff0000000000000ULL; two.c = 0x4000000000000000ULL; nn.d = n; if ( nn.c == 0 ) return one.d; // n == +0 -> 1 + softfloat_roundingMode = _math_rnd; // bare mul/sub round per door r p.d = x; while ( !f64_lt(n, two.d) ) { // while n >= 2: p *= x; n -= 1 p.d = f64_mul(p.d, x); n = f64_sub(n, one.d); } + softfloat_roundingMode = softfloat_round_near_even; return p.d; } static float64_t _rd_pow(float64_t x, float64_t n) { - union doub nn, ni, zero; + union doub nn, ni, zero, lg, prod; zero.c = 0; nn.d = n; + // integer detection is rounding-mode-independent (exact for true integers) ni.d = i64_to_f64(f64_to_i64(n, softfloat_round_near_even, 0)); // san (need (toi n)) if ( (nn.c == ni.c) && f64_lt(zero.d, n) ) // positive integer return _rd_pow_n(x, ni.d); - return _rd_exp(f64_mul(n, _rd_log(x))); // exp(n*log x) + lg.d = _rd_log(x); // %n kernel + softfloat_roundingMode = _math_rnd; // bare mul per door r + prod.d = f64_mul(n, lg.d); + softfloat_roundingMode = softfloat_round_near_even; + return _rd_exp(prod.d); // %n kernel: exp(n*log x) + } + +/* =================================================================== +** @rs (single-precision) cores -- math.hoon ++rs. Single-precision twins +** of the @rd cores: identical reductions/Horner order, single-precision +** constants and minimax coeffs (read from the Hoon arms), SoftFloat f32 ops. +** Marshalling is still chub-based (read low 32 bits, write a 32-bit atom), so +** these are word-size-agnostic exactly like the @rd cores. The bit pattern is +** a plain uint32_t (NOT c3_w, which is 64-bit on the vere64 build). +** =================================================================== */ + + union sing { + float32_t s; + uint32_t c; + }; + + static const uint32_t _RS_QNAN = 0x7fc00000U; + static const uint32_t _RS_PINF = 0x7f800000U; + static const uint32_t _RS_NINF = 0xff800000U; + + static inline union sing _rs_bits(uint32_t b) { union sing u; u.c = b; return u; } + static inline float32_t _rs_neg(float32_t a) { // (sub .0 a) + union sing z; z.c = 0; return f32_sub(z.s, a); + } + +/* @rs exp -- math.hoon ++rs ++exp +** x = k*ln2 + r (Cody-Waite), exp(x) = 2^k * P(r), P a degree-6 minimax. +*/ + // pow2(j) = (j+127)<<23 as f32 bits = 2^j (normal range j in [-126,127]) + static inline float32_t _rs_pow2(c3_ds j) { + union sing u; u.c = ((uint32_t)(j + 127)) << 23; return u.s; + } + // scale2: ldexp with overflow/subnormal tails (math.hoon ++rs ++exp) + static inline float32_t _rs_scale2(float32_t p, c3_ds k) { + if ( (k - 128) >= 0 ) { // k>=128 + return f32_mul(f32_mul(p, _rs_pow2(127)), _rs_pow2(k - 127)); + } + if ( !((k + 126) >= 0) ) { // k<-126 + return f32_mul(f32_mul(p, _rs_pow2(k + 24)), _rs_pow2(-24)); + } + return f32_mul(p, _rs_pow2(k)); + } + static float32_t _rs_exp(float32_t x) { + union sing r0; + // degree-6 minimax coeffs c0..c6 (math.hoon ++rs ++exp) + static const uint32_t cs[7] = { + 0x3f800000U, 0x3f800000U, 0x3f000000U, 0x3e2aaa02U, + 0x3d2aaa56U, 0x3c0937d3U, 0x3ab6ba99U + }; + union sing log2e, ln2hi, ln2lo, ka, kf, rr, p, c, zero; + zero.c = 0; + r0.s = x; + if ( !f32_eq(x, x) ) { r0.c = _RS_QNAN; return r0.s; } // NaN + if ( r0.c == _RS_PINF ) { return x; } // +inf + if ( r0.c == _RS_NINF ) { r0.c = 0; return r0.s; } // -inf -> 0 + + log2e.c = 0x3fb8aa3bU; + ln2hi.c = 0x3f317200U; + ln2lo.c = 0x35bfbe8eU; + + c3_ds k = (c3_ds)f32_to_i32(f32_mul(x, log2e.s), softfloat_round_near_even, 0); + if ( (k - 129) >= 0 ) { r0.c = _RS_PINF; return r0.s; } // overflow -> inf + if ( !((k + 150) >= 0) ) { r0.c = 0; return r0.s; } // underflow -> 0 + + ka.s = ui32_to_f32( (uint32_t)(k < 0 ? -k : k) ); + kf.s = (k >= 0) ? ka.s : f32_sub(zero.s, ka.s); + rr.s = f32_sub( f32_sub(x, f32_mul(kf.s, ln2hi.s)), f32_mul(kf.s, ln2lo.s) ); + + p.c = 0; + for ( int i = 7; i-- != 0; ) { // Horner over flop(cs): c6..c0 + c.c = cs[i]; + p.s = f32_add(f32_mul(p.s, rr.s), c.s); + } + return _rs_scale2(p.s, k); + } + +/* @rs sin/cos/tan -- math.hoon ++rs ++sin/++cos/++rs-trig/++tan +** x = q*(pi/2) + (rhi+rlo) (3-part pi/2, f32 needs the extra word), fdlibm +** sin/cos kernels by q&3. tan = sin/cos (no dedicated kernel, unlike @rd). +*/ + static const uint32_t _RS_SC[5] = { // sin kernel coeffs + 0xbe2aaaabU, 0x3c088889U, 0xb9500d01U, 0x3638ef1dU, 0xb2d7322bU + }; + static const uint32_t _RS_CC[5] = { // cos kernel coeffs + 0x3d2aaaabU, 0xbab60b61U, 0x37d00d01U, 0xb493f27eU, 0x310f76c7U + }; + static float32_t _rs_ksin(float32_t xx, float32_t yy) { + union sing z, r, v, aa, bb, dd, c, half; + half.c = 0x3f000000U; + z.s = f32_mul(xx, xx); + r.c = 0; // Horner over flop(tail sc): sc[4..1] + for ( int i = 5; i-- != 1; ) { c.c = _RS_SC[i]; r.s = f32_add(f32_mul(r.s, z.s), c.s); } + v.s = f32_mul(z.s, xx); + aa.s = f32_sub(f32_mul(half.s, yy), f32_mul(v.s, r.s)); + bb.s = f32_sub(f32_mul(z.s, aa.s), yy); + dd.s = f32_sub(bb.s, f32_mul(v.s, _rs_bits(_RS_SC[0]).s)); + return f32_sub(xx, dd.s); + } + static float32_t _rs_kcos(float32_t xx, float32_t yy) { + union sing z, rc, hz, w2, aa, bb, c, half, one; + half.c = 0x3f000000U; one.c = 0x3f800000U; + z.s = f32_mul(xx, xx); + rc.c = 0; // Horner over flop(cc): cc[4..0] + for ( int i = 5; i-- != 0; ) { c.c = _RS_CC[i]; rc.s = f32_add(f32_mul(rc.s, z.s), c.s); } + hz.s = f32_mul(half.s, z.s); + w2.s = f32_sub(one.s, hz.s); + aa.s = f32_sub(f32_sub(one.s, w2.s), hz.s); + bb.s = f32_sub(f32_mul(f32_mul(z.s, z.s), rc.s), f32_mul(xx, yy)); + return f32_add(w2.s, f32_add(aa.s, bb.s)); + } + // trig-fin: is_sin ? sin(x) : cos(x); ax=|x|, sb=sign bit + static float32_t _rs_trigfin(int is_sin, float32_t ax, uint32_t sb) { + union sing qf, r1, r2, w, rhi, rlo, ks, kc, v; + c3_ds q = (c3_ds)f32_to_i32(f32_mul(ax, _rs_bits(0x3f22f983U).s), + softfloat_round_near_even, 0); // round(ax*2/pi) + c3_d aq = (c3_d)(q < 0 ? -q : q); + qf.s = ui32_to_f32((uint32_t)aq); + r1.s = f32_sub(ax, f32_mul(qf.s, _rs_bits(0x3fc90000U).s)); // ax - qf*pio2_1 + r2.s = f32_sub(r1.s, f32_mul(qf.s, _rs_bits(0x39fda000U).s)); // r1 - qf*pio2_2 + w.s = f32_mul(qf.s, _rs_bits(0x33a22169U).s); // qf*pio2_3 + rhi.s = f32_sub(r2.s, w.s); + rlo.s = f32_sub(f32_sub(r2.s, rhi.s), w.s); + int m = (int)(aq & 3); + ks.s = _rs_ksin(rhi.s, rlo.s); + kc.s = _rs_kcos(rhi.s, rlo.s); + if ( is_sin ) { + v.s = (m==0) ? ks.s : (m==1) ? kc.s : (m==2) ? _rs_neg(ks.s) : _rs_neg(kc.s); + return (sb == 1) ? _rs_neg(v.s) : v.s; + } + return (m==0) ? kc.s : (m==1) ? _rs_neg(ks.s) : (m==2) ? _rs_neg(kc.s) : ks.s; + } + static float32_t _rs_sin(float32_t x) { + union sing r0, ax; + r0.s = x; + if ( !f32_eq(x, x) ) { r0.c = _RS_QNAN; return r0.s; } // NaN + if ( (r0.c == _RS_PINF)||(r0.c == _RS_NINF) ) { r0.c = _RS_QNAN; return r0.s; } // +-inf -> NaN + if ( (r0.c == 0)||(r0.c == 0x80000000U) ) { return x; } // +-0 -> +-0 + ax.c = r0.c & 0x7fffffffU; + return _rs_trigfin(1, ax.s, r0.c >> 31); + } + static float32_t _rs_cos(float32_t x) { + union sing r0, ax; + r0.s = x; + if ( !f32_eq(x, x) ) { r0.c = _RS_QNAN; return r0.s; } // NaN + if ( (r0.c == _RS_PINF)||(r0.c == _RS_NINF) ) { r0.c = _RS_QNAN; return r0.s; } // +-inf -> NaN + ax.c = r0.c & 0x7fffffffU; + return _rs_trigfin(0, ax.s, 0); + } + // tan = (div (sin x) (cos x)): sin/cos kernels %n, the bare div per door r + static float32_t _rs_tan(float32_t x) { + float32_t s = _rs_sin(x), c = _rs_cos(x); + softfloat_roundingMode = _math_rnd; + float32_t r = f32_div(s, c); + softfloat_roundingMode = softfloat_round_near_even; + return r; + } + +/* @rs sqt -- math.hoon ++rs ++sqt = (sqt:^rs x): correctly-rounded f32 sqrt. */ + static float32_t _rs_sqt(float32_t x) { + union sing r; r.s = f32_sqrt(x); + if ( !f32_eq(r.s, r.s) ) r.c = _RS_QNAN; // _nan_unify + return r.s; + } + +/* @rs log/log-2/log-10 -- math.hoon ++rs ++log/++lr/++log-2/++log-10 +** x = 2^e * m, m in [sqrt(1/2),sqrt(2)); log(1+f) via atanh series (deg-4). +*/ + // +lr: finite positive x -> *ef = e as @rs, *l1 = log(mantissa) + static void _rs_lr(float32_t x, float32_t* ef, float32_t* l1) { + static const uint32_t cs[5] = { + 0x3eaaaaabU, 0x3e4ccccdU, 0x3e124925U, 0x3de38e39U, 0x3dba2e8cU }; + union sing xb, m, f, s, z, p2, r, ll, efa, c, one, half; + one.c = 0x3f800000U; half.c = 0x3f000000U; + xb.s = x; + int sub = (((xb.c >> 23) & 0xffU) == 0); + if ( sub ) xb.s = f32_mul(x, _rs_bits(0x4b800000U).s); // *2^24 + int32_t ae = sub ? -24 : 0; + int32_t e = (int32_t)((xb.c >> 23) & 0xffU) - 127; + m.c = (xb.c & 0x7fffffU) | 0x3f800000U; + if ( !f32_lt(m.s, _rs_bits(0x3fb504f3U).s) ) { // m >= sqrt(2) + m.s = f32_mul(m.s, half.s); e += 1; + } + e += ae; + f.s = f32_sub(m.s, one.s); + s.s = f32_div(f.s, f32_add(m.s, one.s)); + z.s = f32_mul(s.s, s.s); + p2.c = 0; for ( int i = 5; i-- != 0; ) { c.c = cs[i]; p2.s = f32_add(f32_mul(p2.s, z.s), c.s); } + r.s = f32_mul(f32_add(z.s, z.s), p2.s); + ll.s = f32_sub(f.s, f32_mul(s.s, f32_sub(f.s, r.s))); + efa.s = ui32_to_f32((uint32_t)(e < 0 ? -e : e)); + *ef = (e >= 0) ? efa.s : _rs_neg(efa.s); + *l1 = ll.s; + } + // shared guards for log/log-2/log-10; returns 1 (and sets *g) on a special case + static int _rs_log_guard(float32_t x, float32_t* g) { + union sing r0; r0.s = x; + if ( !f32_eq(x, x) ) { r0.c = _RS_QNAN; *g = r0.s; return 1; } // NaN + if ( r0.c == _RS_PINF ) { *g = x; return 1; } // +inf -> inf + if ( (r0.c == 0)||(r0.c == 0x80000000U) ) { r0.c = _RS_NINF; *g = r0.s; return 1; } // +-0 -> -inf + if ( (r0.c >> 31) == 1 ){ r0.c = _RS_QNAN; *g = r0.s; return 1; } // x<0 -> NaN + return 0; + } + static float32_t _rs_log(float32_t x) { + union sing g, ef, l1, hi, lo; + if ( _rs_log_guard(x, &g.s) ) return g.s; + _rs_lr(x, &ef.s, &l1.s); + hi.s = f32_mul(ef.s, _rs_bits(0x3f317200U).s); // e*ln2hi + lo.s = f32_mul(ef.s, _rs_bits(0x35bfbe8eU).s); // e*ln2lo + return f32_add(hi.s, f32_add(l1.s, lo.s)); + } + static float32_t _rs_log2(float32_t x) { + union sing g, ef, l1; + if ( _rs_log_guard(x, &g.s) ) return g.s; + _rs_lr(x, &ef.s, &l1.s); + return f32_add(ef.s, f32_mul(l1.s, _rs_bits(0x3fb8aa3bU).s)); // e + lm/ln2 + } + static float32_t _rs_log10(float32_t x) { + union sing g, ef, l1; + if ( _rs_log_guard(x, &g.s) ) return g.s; + _rs_lr(x, &ef.s, &l1.s); + return f32_add(f32_mul(ef.s, _rs_bits(0x3e9a209bU).s), // e*log10(2) + f32_mul(l1.s, _rs_bits(0x3ede5bd9U).s)); // + lm/ln10 + } + +/* @rs cbt -- math.hoon ++rs ++cbt = sign(x) * exp(log|x| / 3). */ + static float32_t _rs_cbt(float32_t x) { + union sing r0, ax, r; + r0.s = x; + if ( !f32_eq(x, x) ) { return x; } // NaN + if ( (r0.c == 0)||(r0.c == 0x80000000U) ) { return x; } // +-0 + ax.c = r0.c & 0x7fffffffU; + r.s = _rs_exp(f32_mul(_rs_log(ax.s), _rs_bits(0x3eaaaaabU).s)); // exp(log|x|/3) + return ((r0.c >> 31) == 1) ? _rs_neg(r.s) : r.s; + } + +/* @rs asin/acos -- math.hoon ++rs ++asin/++acos/++rs-ainv +** rational kernel R(t) = t*P2(t)/(1 + c*t); sqt = _rs_sqt. +*/ + static float32_t _rs_ainv_rr(float32_t t) { + static const uint32_t ps[3] = { 0x3e2aaa75U, 0xbd2f13baU, 0xbc0dd36bU }; + union sing pp, c, one; + one.c = 0x3f800000U; + pp.c = 0; for ( int i = 3; i-- != 0; ) { c.c = ps[i]; pp.s = f32_add(f32_mul(pp.s, t), c.s); } + return f32_div(f32_mul(t, pp.s), + f32_add(one.s, f32_mul(t, _rs_bits(0xbf34e5aeU).s))); + } + static float32_t _rs_asin(float32_t x) { + union sing r0, ax, t, w, r, s, res, half, one, two, pio2h, pio2l, pio4; + half.c=0x3f000000U; one.c=0x3f800000U; two.c=0x40000000U; + pio2h.c=0x3fc90fdbU; pio2l.c=0xb33bbd2eU; pio4.c=0x3f490fdbU; + r0.s = x; + if ( !f32_eq(x, x) ) { r0.c = _RS_QNAN; return r0.s; } // NaN + uint32_t sgn = r0.c >> 31; + ax.c = r0.c & 0x7fffffffU; + if ( f32_lt(one.s, ax.s) ) { r0.c = _RS_QNAN; return r0.s; } // |x|>1 -> NaN + if ( ax.c == one.c ) // |x|==1 + return f32_add(f32_mul(x, pio2h.s), f32_mul(x, pio2l.s)); + if ( f32_lt(ax.s, half.s) ) { // |x|<0.5 + if ( f32_lt(ax.s, _rs_bits(0x39800000U).s) ) return x; // tiny + t.s = f32_mul(x, x); + return f32_add(x, f32_mul(x, _rs_ainv_rr(t.s))); + } + w.s = f32_sub(one.s, ax.s); + t.s = f32_mul(w.s, half.s); + r.s = _rs_ainv_rr(t.s); + s.s = _rs_sqt(t.s); + if ( f32_le(_rs_bits(0x3f79999aU).s, ax.s) ) { // near 1 + res.s = f32_sub(pio2h.s, f32_sub(f32_mul(two.s, f32_add(s.s, f32_mul(s.s, r.s))), pio2l.s)); + return (sgn == 1) ? _rs_neg(res.s) : res.s; + } + { union sing df, cc, p2, q2; + df.c = s.c & 0xfffff000U; + cc.s = f32_div(f32_sub(t.s, f32_mul(df.s, df.s)), f32_add(s.s, df.s)); + p2.s = f32_sub(f32_mul(two.s, f32_mul(s.s, r.s)), f32_sub(pio2l.s, f32_mul(two.s, cc.s))); + q2.s = f32_sub(pio4.s, f32_mul(two.s, df.s)); + res.s = f32_sub(pio4.s, f32_sub(p2.s, q2.s)); + return (sgn == 1) ? _rs_neg(res.s) : res.s; + } + } + static float32_t _rs_acos(float32_t x) { + union sing r0, ax, z, s, r, w, half, one, two, pi, pio2h, pio2l; + half.c=0x3f000000U; one.c=0x3f800000U; two.c=0x40000000U; + pi.c=0x40490fdbU; pio2h.c=0x3fc90fdbU; pio2l.c=0xb33bbd2eU; + r0.s = x; + if ( !f32_eq(x, x) ) { r0.c = _RS_QNAN; return r0.s; } // NaN + uint32_t neg = r0.c >> 31; + ax.c = r0.c & 0x7fffffffU; + if ( f32_lt(one.s, ax.s) ) { r0.c = _RS_QNAN; return r0.s; } // |x|>1 -> NaN + if ( ax.c == one.c ) { // |x|==1 + if ( neg == 0 ) { union sing z0; z0.c = 0; return z0.s; } // 1 -> 0 + return f32_add(pi.s, f32_mul(two.s, pio2l.s)); // -1 -> pi + } + if ( f32_lt(ax.s, half.s) ) { // |x|<0.5 + if ( f32_lt(ax.s, _rs_bits(0x32800000U).s) ) return pio2h.s; // tiny -> pi/2 + z.s = f32_mul(x, x); + r.s = _rs_ainv_rr(z.s); + return f32_sub(pio2h.s, f32_sub(x, f32_sub(pio2l.s, f32_mul(x, r.s)))); + } + if ( neg == 1 ) { // x <= -0.5 + z.s = f32_mul(f32_add(one.s, x), half.s); + s.s = _rs_sqt(z.s); + r.s = _rs_ainv_rr(z.s); + w.s = f32_sub(f32_mul(r.s, s.s), pio2l.s); + return f32_sub(pi.s, f32_mul(two.s, f32_add(s.s, w.s))); + } + z.s = f32_mul(f32_sub(one.s, x), half.s); // x >= 0.5 + s.s = _rs_sqt(z.s); + r.s = _rs_ainv_rr(z.s); + return f32_mul(two.s, f32_add(s.s, f32_mul(s.s, r.s))); + } + +/* @rs atan/atan2 -- math.hoon ++rs ++atan/++rs-atan/++atan2 +** fdlibm breakpoint reduction (7/16,11/16,19/16,39/16) + deg-4 minimax. +*/ + static float32_t _rs_atan(float32_t x) { + static const uint32_t at[5] = { + 0x3eaaaaa9U, 0xbe4cca98U, 0x3e11f50dU, 0xbdda1247U, 0x3d7cac25U }; + union sing r0, ax, xr, hi, lo, z, sp, s, res, one, two, ohf, c; + r0.s = x; + if ( !f32_eq(x, x) ) { r0.c = _RS_QNAN; return r0.s; } // NaN + if ( r0.c == _RS_PINF ) { r0.c = 0x3fc90fdbU; return r0.s; } // +inf -> pi/2 + if ( r0.c == _RS_NINF ) { r0.c = 0xbfc90fdbU; return r0.s; } // -inf -> -pi/2 + if ( (r0.c == 0)||(r0.c == 0x80000000U) ) { return x; } // +-0 + uint32_t neg = r0.c >> 31; + ax.c = r0.c & 0x7fffffffU; + one.c=0x3f800000U; two.c=0x40000000U; ohf.c=0x3fc00000U; + int dir = 0; + if ( f32_lt(ax.s, _rs_bits(0x3ee00000U).s) ) { // |x| < 7/16 + xr.s = ax.s; hi.c = 0; lo.c = 0; dir = 1; + } else if ( f32_lt(ax.s, _rs_bits(0x3f300000U).s) ) { // < 11/16 + xr.s = f32_div(f32_sub(f32_add(ax.s, ax.s), one.s), f32_add(two.s, ax.s)); + hi.c = 0x3eed6338U; lo.c = 0x31ac376aU; // atan(0.5) + } else if ( f32_lt(ax.s, _rs_bits(0x3f980000U).s) ) { // < 19/16 + xr.s = f32_div(f32_sub(ax.s, one.s), f32_add(ax.s, one.s)); + hi.c = 0x3f490fdbU; lo.c = 0xb2bbbd2eU; // pi/4 + } else if ( f32_lt(ax.s, _rs_bits(0x401c0000U).s) ) { // < 39/16 + xr.s = f32_div(f32_sub(ax.s, ohf.s), f32_add(one.s, f32_mul(ohf.s, ax.s))); + hi.c = 0x3f7b985fU; lo.c = 0xb2d7e096U; // atan(1.5) + } else { // -1/x + xr.s = f32_div(_rs_bits(0xbf800000U).s, ax.s); + hi.c = 0x3fc90fdbU; lo.c = 0xb33bbd2eU; // pi/2 + } + z.s = f32_mul(xr.s, xr.s); + sp.c = 0; for ( int i = 5; i-- != 0; ) { c.c = at[i]; sp.s = f32_add(f32_mul(sp.s, z.s), c.s); } + s.s = f32_mul(z.s, sp.s); + if ( dir ) res.s = f32_sub(xr.s, f32_mul(xr.s, s.s)); + else res.s = f32_sub(hi.s, f32_sub(f32_sub(f32_mul(xr.s, s.s), lo.s), xr.s)); + return (neg == 1) ? _rs_neg(res.s) : res.s; + } + // bare door ops (div/add/sub/mul) round per _math_rnd; atan kernel is %n. + static float32_t _rs_atan2(float32_t y, float32_t x) { + union sing xb, pi, two, zero, mone, q, a, r; + zero.c = 0; pi.c = 0x40490fdbU; two.c = 0x40000000U; mone.c = 0xbf800000U; + xb.s = x; + if ( f32_lt(zero.s, x) ) { // x>0: atan(div y x) + softfloat_roundingMode = _math_rnd; q.s = f32_div(y, x); + softfloat_roundingMode = softfloat_round_near_even; return _rs_atan(q.s); + } + if ( f32_lt(x, zero.s) && f32_le(zero.s, y) ) { // x<0,y>=0: add(atan,pi) + softfloat_roundingMode = _math_rnd; q.s = f32_div(y, x); + softfloat_roundingMode = softfloat_round_near_even; a.s = _rs_atan(q.s); + softfloat_roundingMode = _math_rnd; r.s = f32_add(a.s, pi.s); + softfloat_roundingMode = softfloat_round_near_even; return r.s; + } + if ( f32_lt(x, zero.s) && f32_lt(y, zero.s) ) { // x<0,y<0: sub(atan,pi) + softfloat_roundingMode = _math_rnd; q.s = f32_div(y, x); + softfloat_roundingMode = softfloat_round_near_even; a.s = _rs_atan(q.s); + softfloat_roundingMode = _math_rnd; r.s = f32_sub(a.s, pi.s); + softfloat_roundingMode = softfloat_round_near_even; return r.s; + } + if ( (xb.c == 0) && f32_lt(zero.s, y) ) { // x==+0,y>0: div(pi,2) + softfloat_roundingMode = _math_rnd; r.s = f32_div(pi.s, two.s); + softfloat_roundingMode = softfloat_round_near_even; return r.s; + } + if ( (xb.c == 0) && f32_lt(y, zero.s) ) { // x==+0,y<0: mul(-1,div(pi,2)) + softfloat_roundingMode = _math_rnd; + r.s = f32_mul(mone.s, f32_div(pi.s, two.s)); + softfloat_roundingMode = softfloat_round_near_even; return r.s; + } + return zero.s; + } + +/* @rs pow/pow-n -- math.hoon ++rs ++pow/++pow-n */ + static float32_t _rs_pow_n(float32_t x, float32_t n) { + union sing nn, p, one, two; + one.c = 0x3f800000U; two.c = 0x40000000U; + nn.s = n; + if ( nn.c == 0 ) return one.s; // n == +0 -> 1 + softfloat_roundingMode = _math_rnd; // bare mul/sub round per door r + p.s = x; + while ( !f32_lt(n, two.s) ) { p.s = f32_mul(p.s, x); n = f32_sub(n, one.s); } + softfloat_roundingMode = softfloat_round_near_even; + return p.s; + } + static float32_t _rs_pow(float32_t x, float32_t n) { + union sing nn, ni, zero, lg, prod; + zero.c = 0; nn.s = n; + ni.s = i32_to_f32(f32_to_i32(n, softfloat_round_near_even, 0)); // san (need (toi n)) (mode-indep) + if ( (nn.c == ni.c) && f32_lt(zero.s, n) ) // positive integer + return _rs_pow_n(x, ni.s); + lg.s = _rs_log(x); // %n kernel + softfloat_roundingMode = _math_rnd; // bare mul per door r + prod.s = f32_mul(n, lg.s); + softfloat_roundingMode = softfloat_round_near_even; + return _rs_exp(prod.s); // %n kernel: exp(n*log x) } #ifndef MATH_JET_HARNESS @@ -534,6 +982,7 @@ typedef int64_t c3_ds; { union doub c, e; softfloat_roundingMode = softfloat_round_near_even; + _math_rnd = _rnd_of(u3r_at(60, cor)); // door rounding r (for composite arms) c.c = u3r_chub(0, x); e.d = fun(c.d); return u3i_chubs(1, &e.c); @@ -616,6 +1065,7 @@ typedef int64_t c3_ds; c3n == u3ud(y) || c3n == u3ud(x) ) { return u3m_bail(c3__exit); } + _math_rnd = _rnd_of(u3r_at(60, cor)); // door rounding r return u3qi_rd_atan2(y, x); } @@ -669,6 +1119,7 @@ typedef int64_t c3_ds; } { union doub xx, nn, e; softfloat_roundingMode = softfloat_round_near_even; + _math_rnd = _rnd_of(u3r_at(60, cor)); // door rounding r xx.c = u3r_chub(0, x); nn.c = u3r_chub(0, n); e.d = fun(xx.d, nn.d); return u3i_chubs(1, &e.c); @@ -684,4 +1135,64 @@ typedef int64_t c3_ds; xx.c=u3r_chub(0,x); nn.c=u3r_chub(0,n); e.d=_rd_pow_n(xx.d,nn.d); return u3i_chubs(1,&e.c); } u3_noun u3wi_rd_pow_n(u3_noun cor) { return _rd_jet2(cor, _rd_pow_n); } +/* @rs ABI wrappers. @rs is a 32-bit atom: read the low 32 bits of the chub, +** write the 32-bit result as a chub (high bits zero -> normalizes to a 32-bit +** atom). Chub I/O keeps this word-size-agnostic, like the @rd wrappers. +*/ + static inline float32_t _rs_in(u3_atom a) { + union sing s; s.c = (uint32_t)u3r_chub(0, a); return s.s; + } + static inline u3_noun _rs_out(float32_t v) { + union sing s; s.s = v; { c3_d out = (c3_d)s.c; return u3i_chubs(1, &out); } + } + static u3_noun _rs_jet(u3_noun cor, float32_t (*fun)(float32_t)) { + u3_noun x = u3r_at(u3x_sam, cor); + if ( u3_none == x || c3n == u3ud(x) ) return u3m_bail(c3__exit); + softfloat_roundingMode = softfloat_round_near_even; + _math_rnd = _rnd_of(u3r_at(60, cor)); // door rounding r (for @rs tan) + return _rs_out(fun(_rs_in(x))); + } + static u3_noun _rs_jet2(u3_noun cor, float32_t (*fun)(float32_t, float32_t)) { + u3_noun x, n; + if ( c3n == u3r_mean(cor, u3x_sam_2, &x, u3x_sam_3, &n, 0) || + c3n == u3ud(x) || c3n == u3ud(n) ) { + return u3m_bail(c3__exit); + } + softfloat_roundingMode = softfloat_round_near_even; + _math_rnd = _rnd_of(u3r_at(60, cor)); // door rounding r + return _rs_out(fun(_rs_in(x), _rs_in(n))); + } + + u3_noun u3qi_rs_exp(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rs_out(_rs_exp(_rs_in(a))); } + u3_noun u3wi_rs_exp(u3_noun cor) { return _rs_jet(cor, _rs_exp); } + u3_noun u3qi_rs_log(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rs_out(_rs_log(_rs_in(a))); } + u3_noun u3wi_rs_log(u3_noun cor) { return _rs_jet(cor, _rs_log); } + u3_noun u3qi_rs_sin(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rs_out(_rs_sin(_rs_in(a))); } + u3_noun u3wi_rs_sin(u3_noun cor) { return _rs_jet(cor, _rs_sin); } + u3_noun u3qi_rs_cos(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rs_out(_rs_cos(_rs_in(a))); } + u3_noun u3wi_rs_cos(u3_noun cor) { return _rs_jet(cor, _rs_cos); } + u3_noun u3qi_rs_tan(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rs_out(_rs_tan(_rs_in(a))); } + u3_noun u3wi_rs_tan(u3_noun cor) { return _rs_jet(cor, _rs_tan); } + u3_noun u3qi_rs_atan(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rs_out(_rs_atan(_rs_in(a))); } + u3_noun u3wi_rs_atan(u3_noun cor){ return _rs_jet(cor, _rs_atan); } + u3_noun u3qi_rs_asin(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rs_out(_rs_asin(_rs_in(a))); } + u3_noun u3wi_rs_asin(u3_noun cor){ return _rs_jet(cor, _rs_asin); } + u3_noun u3qi_rs_acos(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rs_out(_rs_acos(_rs_in(a))); } + u3_noun u3wi_rs_acos(u3_noun cor){ return _rs_jet(cor, _rs_acos); } + u3_noun u3qi_rs_sqt(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rs_out(_rs_sqt(_rs_in(a))); } + u3_noun u3wi_rs_sqt(u3_noun cor) { return _rs_jet(cor, _rs_sqt); } + u3_noun u3qi_rs_cbt(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rs_out(_rs_cbt(_rs_in(a))); } + u3_noun u3wi_rs_cbt(u3_noun cor) { return _rs_jet(cor, _rs_cbt); } + u3_noun u3qi_rs_log2(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rs_out(_rs_log2(_rs_in(a))); } + u3_noun u3wi_rs_log2(u3_noun cor){ return _rs_jet(cor, _rs_log2); } + u3_noun u3qi_rs_log10(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rs_out(_rs_log10(_rs_in(a))); } + u3_noun u3wi_rs_log10(u3_noun cor){ return _rs_jet(cor, _rs_log10); } + + u3_noun u3qi_rs_atan2(u3_atom y, u3_atom x) { softfloat_roundingMode=softfloat_round_near_even; return _rs_out(_rs_atan2(_rs_in(y), _rs_in(x))); } + u3_noun u3wi_rs_atan2(u3_noun cor){ return _rs_jet2(cor, _rs_atan2); } + u3_noun u3qi_rs_pow(u3_atom x, u3_atom n) { softfloat_roundingMode=softfloat_round_near_even; return _rs_out(_rs_pow(_rs_in(x), _rs_in(n))); } + u3_noun u3wi_rs_pow(u3_noun cor) { return _rs_jet2(cor, _rs_pow); } + u3_noun u3qi_rs_pow_n(u3_atom x, u3_atom n) { softfloat_roundingMode=softfloat_round_near_even; return _rs_out(_rs_pow_n(_rs_in(x), _rs_in(n))); } + u3_noun u3wi_rs_pow_n(u3_noun cor){ return _rs_jet2(cor, _rs_pow_n); } + #endif diff --git a/libmath/vere/noun/jets/q.h b/libmath/vere/noun/jets/q.h index 95c9b07..9d0cf00 100644 --- a/libmath/vere/noun/jets/q.h +++ b/libmath/vere/noun/jets/q.h @@ -305,6 +305,21 @@ u3_noun u3qi_rd_pow_n(u3_atom, u3_atom); u3_noun u3qi_rd_log2(u3_atom); u3_noun u3qi_rd_log10(u3_atom); + u3_noun u3qi_rs_exp(u3_atom); + u3_noun u3qi_rs_log(u3_atom); + u3_noun u3qi_rs_sin(u3_atom); + u3_noun u3qi_rs_cos(u3_atom); + u3_noun u3qi_rs_tan(u3_atom); + u3_noun u3qi_rs_atan(u3_atom); + u3_noun u3qi_rs_atan2(u3_atom, u3_atom); + u3_noun u3qi_rs_asin(u3_atom); + u3_noun u3qi_rs_acos(u3_atom); + u3_noun u3qi_rs_sqt(u3_atom); + u3_noun u3qi_rs_cbt(u3_atom); + u3_noun u3qi_rs_pow(u3_atom, u3_atom); + u3_noun u3qi_rs_pow_n(u3_atom, u3_atom); + u3_noun u3qi_rs_log2(u3_atom); + u3_noun u3qi_rs_log10(u3_atom); # define u3qfu_van_fan 28 # define u3qfu_van_rib 58 diff --git a/libmath/vere/noun/jets/w.h b/libmath/vere/noun/jets/w.h index effc85a..ec031a7 100644 --- a/libmath/vere/noun/jets/w.h +++ b/libmath/vere/noun/jets/w.h @@ -444,6 +444,21 @@ u3_noun u3wi_rd_pow_n(u3_noun); u3_noun u3wi_rd_log2(u3_noun); u3_noun u3wi_rd_log10(u3_noun); + u3_noun u3wi_rs_exp(u3_noun); + u3_noun u3wi_rs_log(u3_noun); + u3_noun u3wi_rs_sin(u3_noun); + u3_noun u3wi_rs_cos(u3_noun); + u3_noun u3wi_rs_tan(u3_noun); + u3_noun u3wi_rs_atan(u3_noun); + u3_noun u3wi_rs_atan2(u3_noun); + u3_noun u3wi_rs_asin(u3_noun); + u3_noun u3wi_rs_acos(u3_noun); + u3_noun u3wi_rs_sqt(u3_noun); + u3_noun u3wi_rs_cbt(u3_noun); + u3_noun u3wi_rs_pow(u3_noun); + u3_noun u3wi_rs_pow_n(u3_noun); + u3_noun u3wi_rs_log2(u3_noun); + u3_noun u3wi_rs_log10(u3_noun); #endif /* ifndef U3_JETS_W_H */ diff --git a/libmath/vere64/noun/jets/135/tree.c b/libmath/vere64/noun/jets/135/tree.c index e7419bc..2392250 100644 --- a/libmath/vere64/noun/jets/135/tree.c +++ b/libmath/vere64/noun/jets/135/tree.c @@ -979,8 +979,44 @@ static u3j_core _135_non__math_rd_d[] = { "log-10", 7, _135_non__math_rd_log10_a, 0, no_hashes }, {} }; +// numerics math.hoon @rs transcendentals: non -> math -> rs -> +static u3j_harm _135_non__math_rs_exp_a[] = {{".2", u3wi_rs_exp}, {}}; +static u3j_harm _135_non__math_rs_log_a[] = {{".2", u3wi_rs_log}, {}}; +static u3j_harm _135_non__math_rs_sin_a[] = {{".2", u3wi_rs_sin}, {}}; +static u3j_harm _135_non__math_rs_cos_a[] = {{".2", u3wi_rs_cos}, {}}; +static u3j_harm _135_non__math_rs_tan_a[] = {{".2", u3wi_rs_tan}, {}}; +static u3j_harm _135_non__math_rs_atan_a[] = {{".2", u3wi_rs_atan}, {}}; +static u3j_harm _135_non__math_rs_atan2_a[] = {{".2", u3wi_rs_atan2}, {}}; +static u3j_harm _135_non__math_rs_asin_a[] = {{".2", u3wi_rs_asin}, {}}; +static u3j_harm _135_non__math_rs_acos_a[] = {{".2", u3wi_rs_acos}, {}}; +static u3j_harm _135_non__math_rs_sqt_a[] = {{".2", u3wi_rs_sqt}, {}}; +static u3j_harm _135_non__math_rs_cbt_a[] = {{".2", u3wi_rs_cbt}, {}}; +static u3j_harm _135_non__math_rs_pow_a[] = {{".2", u3wi_rs_pow}, {}}; +static u3j_harm _135_non__math_rs_pow_n_a[] = {{".2", u3wi_rs_pow_n}, {}}; +static u3j_harm _135_non__math_rs_log2_a[] = {{".2", u3wi_rs_log2}, {}}; +static u3j_harm _135_non__math_rs_log10_a[] = {{".2", u3wi_rs_log10}, {}}; +static u3j_core _135_non__math_rs_d[] = + { + { "exp", 7, _135_non__math_rs_exp_a, 0, no_hashes }, + { "log", 7, _135_non__math_rs_log_a, 0, no_hashes }, + { "sin", 7, _135_non__math_rs_sin_a, 0, no_hashes }, + { "cos", 7, _135_non__math_rs_cos_a, 0, no_hashes }, + { "tan", 7, _135_non__math_rs_tan_a, 0, no_hashes }, + { "atan", 7, _135_non__math_rs_atan_a, 0, no_hashes }, + { "atan2", 7, _135_non__math_rs_atan2_a, 0, no_hashes }, + { "asin", 7, _135_non__math_rs_asin_a, 0, no_hashes }, + { "acos", 7, _135_non__math_rs_acos_a, 0, no_hashes }, + { "sqt", 7, _135_non__math_rs_sqt_a, 0, no_hashes }, + { "cbt", 7, _135_non__math_rs_cbt_a, 0, no_hashes }, + { "pow", 7, _135_non__math_rs_pow_a, 0, no_hashes }, + { "pow-n", 7, _135_non__math_rs_pow_n_a, 0, no_hashes }, + { "log-2", 7, _135_non__math_rs_log2_a, 0, no_hashes }, + { "log-10", 7, _135_non__math_rs_log10_a, 0, no_hashes }, + {} + }; static u3j_core _135_non__math_d[] = { { "rd", 7, 0, _135_non__math_rd_d, no_hashes }, + { "rs", 7, 0, _135_non__math_rs_d, no_hashes }, {} }; diff --git a/libmath/vere64/noun/jets/i/math.c b/libmath/vere64/noun/jets/i/math.c index 5315671..a9ed5ea 100644 --- a/libmath/vere64/noun/jets/i/math.c +++ b/libmath/vere64/noun/jets/i/math.c @@ -40,6 +40,23 @@ typedef int64_t c3_ds; static inline union doub _rd_bits(c3_d b) { union doub u; u.c = b; return u; } + // The math doors carry a rounding mode r=?(%n %u %d %z) whose bunt is %z. + // The transcendental KERNELS force %n (correctly-rounded, no axis), but the + // composite arms (pow/atan2/tan/pow-n) round their BARE door ops per r. The + // wrapper sets _math_rnd from the door's r (axis 60 of the gate); cores + // bracket bare ops with it and restore near-even around kernel calls. + // Default = minMag (%z), matching the door bunt for the harness/cold path. + static int _math_rnd = softfloat_round_minMag; + static inline int _rnd_of(c3_d r) { // @tas 'n'/'u'/'d'/'z' -> SoftFloat + switch ( r ) { + case 'n': return softfloat_round_near_even; + case 'u': return softfloat_round_max; + case 'd': return softfloat_round_min; + case 'z': return softfloat_round_minMag; + default: return softfloat_round_minMag; + } + } + /* @rd exp -- math.hoon ++rd ++exp ** x = k*ln2 + r (Cody-Waite), exp(x) = 2^k * P(r), P a degree-11 minimax ** polynomial; +scale2 is a correctly-rounded ldexp. @@ -368,18 +385,37 @@ typedef int64_t c3_ds; else res.d = f64_sub(hi.d, f64_sub(f64_sub(f64_mul(xr.d, s.d), lo.d), xr.d)); return (neg == 1) ? _rd_neg(res.d) : res.d; } + // bare door ops (div/add/sub/mul) round per _math_rnd; atan kernel is %n. static float64_t _rd_atan2(float64_t y, float64_t x) { - union doub xb, pi, pi2, mpi2, zero; + union doub xb, pi, two, mone, zero, q, a, r; zero.c = 0; pi.c = 0x400921fb54442d18ULL; - pi2.c = 0x3ff921fb54442d18ULL; mpi2.c = 0xbff921fb54442d18ULL; + two.c = 0x4000000000000000ULL; mone.c = 0xbff0000000000000ULL; xb.d = x; - if ( f64_lt(zero.d, x) ) return _rd_atan(f64_div(y, x)); // x>0 - if ( f64_lt(x, zero.d) && f64_le(zero.d, y) ) // x<0,y>=0 - return f64_add(_rd_atan(f64_div(y, x)), pi.d); - if ( f64_lt(x, zero.d) && f64_lt(y, zero.d) ) // x<0,y<0 - return f64_sub(_rd_atan(f64_div(y, x)), pi.d); - if ( (xb.c == 0) && f64_lt(zero.d, y) ) return pi2.d; // x==+0,y>0 - if ( (xb.c == 0) && f64_lt(y, zero.d) ) return mpi2.d; // x==+0,y<0 + if ( f64_lt(zero.d, x) ) { // x>0: atan(div y x) + softfloat_roundingMode = _math_rnd; q.d = f64_div(y, x); + softfloat_roundingMode = softfloat_round_near_even; return _rd_atan(q.d); + } + if ( f64_lt(x, zero.d) && f64_le(zero.d, y) ) { // x<0,y>=0: add(atan,pi) + softfloat_roundingMode = _math_rnd; q.d = f64_div(y, x); + softfloat_roundingMode = softfloat_round_near_even; a.d = _rd_atan(q.d); + softfloat_roundingMode = _math_rnd; r.d = f64_add(a.d, pi.d); + softfloat_roundingMode = softfloat_round_near_even; return r.d; + } + if ( f64_lt(x, zero.d) && f64_lt(y, zero.d) ) { // x<0,y<0: sub(atan,pi) + softfloat_roundingMode = _math_rnd; q.d = f64_div(y, x); + softfloat_roundingMode = softfloat_round_near_even; a.d = _rd_atan(q.d); + softfloat_roundingMode = _math_rnd; r.d = f64_sub(a.d, pi.d); + softfloat_roundingMode = softfloat_round_near_even; return r.d; + } + if ( (xb.c == 0) && f64_lt(zero.d, y) ) { // x==+0,y>0: div(pi,2) + softfloat_roundingMode = _math_rnd; r.d = f64_div(pi.d, two.d); + softfloat_roundingMode = softfloat_round_near_even; return r.d; + } + if ( (xb.c == 0) && f64_lt(y, zero.d) ) { // x==+0,y<0: mul(-1,div(pi,2)) + softfloat_roundingMode = _math_rnd; + r.d = f64_mul(mone.d, f64_div(pi.d, two.d)); + softfloat_roundingMode = softfloat_round_near_even; return r.d; + } return zero.d; } @@ -502,20 +538,432 @@ typedef int64_t c3_ds; one.c = 0x3ff0000000000000ULL; two.c = 0x4000000000000000ULL; nn.d = n; if ( nn.c == 0 ) return one.d; // n == +0 -> 1 + softfloat_roundingMode = _math_rnd; // bare mul/sub round per door r p.d = x; while ( !f64_lt(n, two.d) ) { // while n >= 2: p *= x; n -= 1 p.d = f64_mul(p.d, x); n = f64_sub(n, one.d); } + softfloat_roundingMode = softfloat_round_near_even; return p.d; } static float64_t _rd_pow(float64_t x, float64_t n) { - union doub nn, ni, zero; + union doub nn, ni, zero, lg, prod; zero.c = 0; nn.d = n; + // integer detection is rounding-mode-independent (exact for true integers) ni.d = i64_to_f64(f64_to_i64(n, softfloat_round_near_even, 0)); // san (need (toi n)) if ( (nn.c == ni.c) && f64_lt(zero.d, n) ) // positive integer return _rd_pow_n(x, ni.d); - return _rd_exp(f64_mul(n, _rd_log(x))); // exp(n*log x) + lg.d = _rd_log(x); // %n kernel + softfloat_roundingMode = _math_rnd; // bare mul per door r + prod.d = f64_mul(n, lg.d); + softfloat_roundingMode = softfloat_round_near_even; + return _rd_exp(prod.d); // %n kernel: exp(n*log x) + } + +/* =================================================================== +** @rs (single-precision) cores -- math.hoon ++rs. Single-precision twins +** of the @rd cores: identical reductions/Horner order, single-precision +** constants and minimax coeffs (read from the Hoon arms), SoftFloat f32 ops. +** Marshalling is still chub-based (read low 32 bits, write a 32-bit atom), so +** these are word-size-agnostic exactly like the @rd cores. The bit pattern is +** a plain uint32_t (NOT c3_w, which is 64-bit on the vere64 build). +** =================================================================== */ + + union sing { + float32_t s; + uint32_t c; + }; + + static const uint32_t _RS_QNAN = 0x7fc00000U; + static const uint32_t _RS_PINF = 0x7f800000U; + static const uint32_t _RS_NINF = 0xff800000U; + + static inline union sing _rs_bits(uint32_t b) { union sing u; u.c = b; return u; } + static inline float32_t _rs_neg(float32_t a) { // (sub .0 a) + union sing z; z.c = 0; return f32_sub(z.s, a); + } + +/* @rs exp -- math.hoon ++rs ++exp +** x = k*ln2 + r (Cody-Waite), exp(x) = 2^k * P(r), P a degree-6 minimax. +*/ + // pow2(j) = (j+127)<<23 as f32 bits = 2^j (normal range j in [-126,127]) + static inline float32_t _rs_pow2(c3_ds j) { + union sing u; u.c = ((uint32_t)(j + 127)) << 23; return u.s; + } + // scale2: ldexp with overflow/subnormal tails (math.hoon ++rs ++exp) + static inline float32_t _rs_scale2(float32_t p, c3_ds k) { + if ( (k - 128) >= 0 ) { // k>=128 + return f32_mul(f32_mul(p, _rs_pow2(127)), _rs_pow2(k - 127)); + } + if ( !((k + 126) >= 0) ) { // k<-126 + return f32_mul(f32_mul(p, _rs_pow2(k + 24)), _rs_pow2(-24)); + } + return f32_mul(p, _rs_pow2(k)); + } + static float32_t _rs_exp(float32_t x) { + union sing r0; + // degree-6 minimax coeffs c0..c6 (math.hoon ++rs ++exp) + static const uint32_t cs[7] = { + 0x3f800000U, 0x3f800000U, 0x3f000000U, 0x3e2aaa02U, + 0x3d2aaa56U, 0x3c0937d3U, 0x3ab6ba99U + }; + union sing log2e, ln2hi, ln2lo, ka, kf, rr, p, c, zero; + zero.c = 0; + r0.s = x; + if ( !f32_eq(x, x) ) { r0.c = _RS_QNAN; return r0.s; } // NaN + if ( r0.c == _RS_PINF ) { return x; } // +inf + if ( r0.c == _RS_NINF ) { r0.c = 0; return r0.s; } // -inf -> 0 + + log2e.c = 0x3fb8aa3bU; + ln2hi.c = 0x3f317200U; + ln2lo.c = 0x35bfbe8eU; + + c3_ds k = (c3_ds)f32_to_i32(f32_mul(x, log2e.s), softfloat_round_near_even, 0); + if ( (k - 129) >= 0 ) { r0.c = _RS_PINF; return r0.s; } // overflow -> inf + if ( !((k + 150) >= 0) ) { r0.c = 0; return r0.s; } // underflow -> 0 + + ka.s = ui32_to_f32( (uint32_t)(k < 0 ? -k : k) ); + kf.s = (k >= 0) ? ka.s : f32_sub(zero.s, ka.s); + rr.s = f32_sub( f32_sub(x, f32_mul(kf.s, ln2hi.s)), f32_mul(kf.s, ln2lo.s) ); + + p.c = 0; + for ( int i = 7; i-- != 0; ) { // Horner over flop(cs): c6..c0 + c.c = cs[i]; + p.s = f32_add(f32_mul(p.s, rr.s), c.s); + } + return _rs_scale2(p.s, k); + } + +/* @rs sin/cos/tan -- math.hoon ++rs ++sin/++cos/++rs-trig/++tan +** x = q*(pi/2) + (rhi+rlo) (3-part pi/2, f32 needs the extra word), fdlibm +** sin/cos kernels by q&3. tan = sin/cos (no dedicated kernel, unlike @rd). +*/ + static const uint32_t _RS_SC[5] = { // sin kernel coeffs + 0xbe2aaaabU, 0x3c088889U, 0xb9500d01U, 0x3638ef1dU, 0xb2d7322bU + }; + static const uint32_t _RS_CC[5] = { // cos kernel coeffs + 0x3d2aaaabU, 0xbab60b61U, 0x37d00d01U, 0xb493f27eU, 0x310f76c7U + }; + static float32_t _rs_ksin(float32_t xx, float32_t yy) { + union sing z, r, v, aa, bb, dd, c, half; + half.c = 0x3f000000U; + z.s = f32_mul(xx, xx); + r.c = 0; // Horner over flop(tail sc): sc[4..1] + for ( int i = 5; i-- != 1; ) { c.c = _RS_SC[i]; r.s = f32_add(f32_mul(r.s, z.s), c.s); } + v.s = f32_mul(z.s, xx); + aa.s = f32_sub(f32_mul(half.s, yy), f32_mul(v.s, r.s)); + bb.s = f32_sub(f32_mul(z.s, aa.s), yy); + dd.s = f32_sub(bb.s, f32_mul(v.s, _rs_bits(_RS_SC[0]).s)); + return f32_sub(xx, dd.s); + } + static float32_t _rs_kcos(float32_t xx, float32_t yy) { + union sing z, rc, hz, w2, aa, bb, c, half, one; + half.c = 0x3f000000U; one.c = 0x3f800000U; + z.s = f32_mul(xx, xx); + rc.c = 0; // Horner over flop(cc): cc[4..0] + for ( int i = 5; i-- != 0; ) { c.c = _RS_CC[i]; rc.s = f32_add(f32_mul(rc.s, z.s), c.s); } + hz.s = f32_mul(half.s, z.s); + w2.s = f32_sub(one.s, hz.s); + aa.s = f32_sub(f32_sub(one.s, w2.s), hz.s); + bb.s = f32_sub(f32_mul(f32_mul(z.s, z.s), rc.s), f32_mul(xx, yy)); + return f32_add(w2.s, f32_add(aa.s, bb.s)); + } + // trig-fin: is_sin ? sin(x) : cos(x); ax=|x|, sb=sign bit + static float32_t _rs_trigfin(int is_sin, float32_t ax, uint32_t sb) { + union sing qf, r1, r2, w, rhi, rlo, ks, kc, v; + c3_ds q = (c3_ds)f32_to_i32(f32_mul(ax, _rs_bits(0x3f22f983U).s), + softfloat_round_near_even, 0); // round(ax*2/pi) + c3_d aq = (c3_d)(q < 0 ? -q : q); + qf.s = ui32_to_f32((uint32_t)aq); + r1.s = f32_sub(ax, f32_mul(qf.s, _rs_bits(0x3fc90000U).s)); // ax - qf*pio2_1 + r2.s = f32_sub(r1.s, f32_mul(qf.s, _rs_bits(0x39fda000U).s)); // r1 - qf*pio2_2 + w.s = f32_mul(qf.s, _rs_bits(0x33a22169U).s); // qf*pio2_3 + rhi.s = f32_sub(r2.s, w.s); + rlo.s = f32_sub(f32_sub(r2.s, rhi.s), w.s); + int m = (int)(aq & 3); + ks.s = _rs_ksin(rhi.s, rlo.s); + kc.s = _rs_kcos(rhi.s, rlo.s); + if ( is_sin ) { + v.s = (m==0) ? ks.s : (m==1) ? kc.s : (m==2) ? _rs_neg(ks.s) : _rs_neg(kc.s); + return (sb == 1) ? _rs_neg(v.s) : v.s; + } + return (m==0) ? kc.s : (m==1) ? _rs_neg(ks.s) : (m==2) ? _rs_neg(kc.s) : ks.s; + } + static float32_t _rs_sin(float32_t x) { + union sing r0, ax; + r0.s = x; + if ( !f32_eq(x, x) ) { r0.c = _RS_QNAN; return r0.s; } // NaN + if ( (r0.c == _RS_PINF)||(r0.c == _RS_NINF) ) { r0.c = _RS_QNAN; return r0.s; } // +-inf -> NaN + if ( (r0.c == 0)||(r0.c == 0x80000000U) ) { return x; } // +-0 -> +-0 + ax.c = r0.c & 0x7fffffffU; + return _rs_trigfin(1, ax.s, r0.c >> 31); + } + static float32_t _rs_cos(float32_t x) { + union sing r0, ax; + r0.s = x; + if ( !f32_eq(x, x) ) { r0.c = _RS_QNAN; return r0.s; } // NaN + if ( (r0.c == _RS_PINF)||(r0.c == _RS_NINF) ) { r0.c = _RS_QNAN; return r0.s; } // +-inf -> NaN + ax.c = r0.c & 0x7fffffffU; + return _rs_trigfin(0, ax.s, 0); + } + // tan = (div (sin x) (cos x)): sin/cos kernels %n, the bare div per door r + static float32_t _rs_tan(float32_t x) { + float32_t s = _rs_sin(x), c = _rs_cos(x); + softfloat_roundingMode = _math_rnd; + float32_t r = f32_div(s, c); + softfloat_roundingMode = softfloat_round_near_even; + return r; + } + +/* @rs sqt -- math.hoon ++rs ++sqt = (sqt:^rs x): correctly-rounded f32 sqrt. */ + static float32_t _rs_sqt(float32_t x) { + union sing r; r.s = f32_sqrt(x); + if ( !f32_eq(r.s, r.s) ) r.c = _RS_QNAN; // _nan_unify + return r.s; + } + +/* @rs log/log-2/log-10 -- math.hoon ++rs ++log/++lr/++log-2/++log-10 +** x = 2^e * m, m in [sqrt(1/2),sqrt(2)); log(1+f) via atanh series (deg-4). +*/ + // +lr: finite positive x -> *ef = e as @rs, *l1 = log(mantissa) + static void _rs_lr(float32_t x, float32_t* ef, float32_t* l1) { + static const uint32_t cs[5] = { + 0x3eaaaaabU, 0x3e4ccccdU, 0x3e124925U, 0x3de38e39U, 0x3dba2e8cU }; + union sing xb, m, f, s, z, p2, r, ll, efa, c, one, half; + one.c = 0x3f800000U; half.c = 0x3f000000U; + xb.s = x; + int sub = (((xb.c >> 23) & 0xffU) == 0); + if ( sub ) xb.s = f32_mul(x, _rs_bits(0x4b800000U).s); // *2^24 + int32_t ae = sub ? -24 : 0; + int32_t e = (int32_t)((xb.c >> 23) & 0xffU) - 127; + m.c = (xb.c & 0x7fffffU) | 0x3f800000U; + if ( !f32_lt(m.s, _rs_bits(0x3fb504f3U).s) ) { // m >= sqrt(2) + m.s = f32_mul(m.s, half.s); e += 1; + } + e += ae; + f.s = f32_sub(m.s, one.s); + s.s = f32_div(f.s, f32_add(m.s, one.s)); + z.s = f32_mul(s.s, s.s); + p2.c = 0; for ( int i = 5; i-- != 0; ) { c.c = cs[i]; p2.s = f32_add(f32_mul(p2.s, z.s), c.s); } + r.s = f32_mul(f32_add(z.s, z.s), p2.s); + ll.s = f32_sub(f.s, f32_mul(s.s, f32_sub(f.s, r.s))); + efa.s = ui32_to_f32((uint32_t)(e < 0 ? -e : e)); + *ef = (e >= 0) ? efa.s : _rs_neg(efa.s); + *l1 = ll.s; + } + // shared guards for log/log-2/log-10; returns 1 (and sets *g) on a special case + static int _rs_log_guard(float32_t x, float32_t* g) { + union sing r0; r0.s = x; + if ( !f32_eq(x, x) ) { r0.c = _RS_QNAN; *g = r0.s; return 1; } // NaN + if ( r0.c == _RS_PINF ) { *g = x; return 1; } // +inf -> inf + if ( (r0.c == 0)||(r0.c == 0x80000000U) ) { r0.c = _RS_NINF; *g = r0.s; return 1; } // +-0 -> -inf + if ( (r0.c >> 31) == 1 ){ r0.c = _RS_QNAN; *g = r0.s; return 1; } // x<0 -> NaN + return 0; + } + static float32_t _rs_log(float32_t x) { + union sing g, ef, l1, hi, lo; + if ( _rs_log_guard(x, &g.s) ) return g.s; + _rs_lr(x, &ef.s, &l1.s); + hi.s = f32_mul(ef.s, _rs_bits(0x3f317200U).s); // e*ln2hi + lo.s = f32_mul(ef.s, _rs_bits(0x35bfbe8eU).s); // e*ln2lo + return f32_add(hi.s, f32_add(l1.s, lo.s)); + } + static float32_t _rs_log2(float32_t x) { + union sing g, ef, l1; + if ( _rs_log_guard(x, &g.s) ) return g.s; + _rs_lr(x, &ef.s, &l1.s); + return f32_add(ef.s, f32_mul(l1.s, _rs_bits(0x3fb8aa3bU).s)); // e + lm/ln2 + } + static float32_t _rs_log10(float32_t x) { + union sing g, ef, l1; + if ( _rs_log_guard(x, &g.s) ) return g.s; + _rs_lr(x, &ef.s, &l1.s); + return f32_add(f32_mul(ef.s, _rs_bits(0x3e9a209bU).s), // e*log10(2) + f32_mul(l1.s, _rs_bits(0x3ede5bd9U).s)); // + lm/ln10 + } + +/* @rs cbt -- math.hoon ++rs ++cbt = sign(x) * exp(log|x| / 3). */ + static float32_t _rs_cbt(float32_t x) { + union sing r0, ax, r; + r0.s = x; + if ( !f32_eq(x, x) ) { return x; } // NaN + if ( (r0.c == 0)||(r0.c == 0x80000000U) ) { return x; } // +-0 + ax.c = r0.c & 0x7fffffffU; + r.s = _rs_exp(f32_mul(_rs_log(ax.s), _rs_bits(0x3eaaaaabU).s)); // exp(log|x|/3) + return ((r0.c >> 31) == 1) ? _rs_neg(r.s) : r.s; + } + +/* @rs asin/acos -- math.hoon ++rs ++asin/++acos/++rs-ainv +** rational kernel R(t) = t*P2(t)/(1 + c*t); sqt = _rs_sqt. +*/ + static float32_t _rs_ainv_rr(float32_t t) { + static const uint32_t ps[3] = { 0x3e2aaa75U, 0xbd2f13baU, 0xbc0dd36bU }; + union sing pp, c, one; + one.c = 0x3f800000U; + pp.c = 0; for ( int i = 3; i-- != 0; ) { c.c = ps[i]; pp.s = f32_add(f32_mul(pp.s, t), c.s); } + return f32_div(f32_mul(t, pp.s), + f32_add(one.s, f32_mul(t, _rs_bits(0xbf34e5aeU).s))); + } + static float32_t _rs_asin(float32_t x) { + union sing r0, ax, t, w, r, s, res, half, one, two, pio2h, pio2l, pio4; + half.c=0x3f000000U; one.c=0x3f800000U; two.c=0x40000000U; + pio2h.c=0x3fc90fdbU; pio2l.c=0xb33bbd2eU; pio4.c=0x3f490fdbU; + r0.s = x; + if ( !f32_eq(x, x) ) { r0.c = _RS_QNAN; return r0.s; } // NaN + uint32_t sgn = r0.c >> 31; + ax.c = r0.c & 0x7fffffffU; + if ( f32_lt(one.s, ax.s) ) { r0.c = _RS_QNAN; return r0.s; } // |x|>1 -> NaN + if ( ax.c == one.c ) // |x|==1 + return f32_add(f32_mul(x, pio2h.s), f32_mul(x, pio2l.s)); + if ( f32_lt(ax.s, half.s) ) { // |x|<0.5 + if ( f32_lt(ax.s, _rs_bits(0x39800000U).s) ) return x; // tiny + t.s = f32_mul(x, x); + return f32_add(x, f32_mul(x, _rs_ainv_rr(t.s))); + } + w.s = f32_sub(one.s, ax.s); + t.s = f32_mul(w.s, half.s); + r.s = _rs_ainv_rr(t.s); + s.s = _rs_sqt(t.s); + if ( f32_le(_rs_bits(0x3f79999aU).s, ax.s) ) { // near 1 + res.s = f32_sub(pio2h.s, f32_sub(f32_mul(two.s, f32_add(s.s, f32_mul(s.s, r.s))), pio2l.s)); + return (sgn == 1) ? _rs_neg(res.s) : res.s; + } + { union sing df, cc, p2, q2; + df.c = s.c & 0xfffff000U; + cc.s = f32_div(f32_sub(t.s, f32_mul(df.s, df.s)), f32_add(s.s, df.s)); + p2.s = f32_sub(f32_mul(two.s, f32_mul(s.s, r.s)), f32_sub(pio2l.s, f32_mul(two.s, cc.s))); + q2.s = f32_sub(pio4.s, f32_mul(two.s, df.s)); + res.s = f32_sub(pio4.s, f32_sub(p2.s, q2.s)); + return (sgn == 1) ? _rs_neg(res.s) : res.s; + } + } + static float32_t _rs_acos(float32_t x) { + union sing r0, ax, z, s, r, w, half, one, two, pi, pio2h, pio2l; + half.c=0x3f000000U; one.c=0x3f800000U; two.c=0x40000000U; + pi.c=0x40490fdbU; pio2h.c=0x3fc90fdbU; pio2l.c=0xb33bbd2eU; + r0.s = x; + if ( !f32_eq(x, x) ) { r0.c = _RS_QNAN; return r0.s; } // NaN + uint32_t neg = r0.c >> 31; + ax.c = r0.c & 0x7fffffffU; + if ( f32_lt(one.s, ax.s) ) { r0.c = _RS_QNAN; return r0.s; } // |x|>1 -> NaN + if ( ax.c == one.c ) { // |x|==1 + if ( neg == 0 ) { union sing z0; z0.c = 0; return z0.s; } // 1 -> 0 + return f32_add(pi.s, f32_mul(two.s, pio2l.s)); // -1 -> pi + } + if ( f32_lt(ax.s, half.s) ) { // |x|<0.5 + if ( f32_lt(ax.s, _rs_bits(0x32800000U).s) ) return pio2h.s; // tiny -> pi/2 + z.s = f32_mul(x, x); + r.s = _rs_ainv_rr(z.s); + return f32_sub(pio2h.s, f32_sub(x, f32_sub(pio2l.s, f32_mul(x, r.s)))); + } + if ( neg == 1 ) { // x <= -0.5 + z.s = f32_mul(f32_add(one.s, x), half.s); + s.s = _rs_sqt(z.s); + r.s = _rs_ainv_rr(z.s); + w.s = f32_sub(f32_mul(r.s, s.s), pio2l.s); + return f32_sub(pi.s, f32_mul(two.s, f32_add(s.s, w.s))); + } + z.s = f32_mul(f32_sub(one.s, x), half.s); // x >= 0.5 + s.s = _rs_sqt(z.s); + r.s = _rs_ainv_rr(z.s); + return f32_mul(two.s, f32_add(s.s, f32_mul(s.s, r.s))); + } + +/* @rs atan/atan2 -- math.hoon ++rs ++atan/++rs-atan/++atan2 +** fdlibm breakpoint reduction (7/16,11/16,19/16,39/16) + deg-4 minimax. +*/ + static float32_t _rs_atan(float32_t x) { + static const uint32_t at[5] = { + 0x3eaaaaa9U, 0xbe4cca98U, 0x3e11f50dU, 0xbdda1247U, 0x3d7cac25U }; + union sing r0, ax, xr, hi, lo, z, sp, s, res, one, two, ohf, c; + r0.s = x; + if ( !f32_eq(x, x) ) { r0.c = _RS_QNAN; return r0.s; } // NaN + if ( r0.c == _RS_PINF ) { r0.c = 0x3fc90fdbU; return r0.s; } // +inf -> pi/2 + if ( r0.c == _RS_NINF ) { r0.c = 0xbfc90fdbU; return r0.s; } // -inf -> -pi/2 + if ( (r0.c == 0)||(r0.c == 0x80000000U) ) { return x; } // +-0 + uint32_t neg = r0.c >> 31; + ax.c = r0.c & 0x7fffffffU; + one.c=0x3f800000U; two.c=0x40000000U; ohf.c=0x3fc00000U; + int dir = 0; + if ( f32_lt(ax.s, _rs_bits(0x3ee00000U).s) ) { // |x| < 7/16 + xr.s = ax.s; hi.c = 0; lo.c = 0; dir = 1; + } else if ( f32_lt(ax.s, _rs_bits(0x3f300000U).s) ) { // < 11/16 + xr.s = f32_div(f32_sub(f32_add(ax.s, ax.s), one.s), f32_add(two.s, ax.s)); + hi.c = 0x3eed6338U; lo.c = 0x31ac376aU; // atan(0.5) + } else if ( f32_lt(ax.s, _rs_bits(0x3f980000U).s) ) { // < 19/16 + xr.s = f32_div(f32_sub(ax.s, one.s), f32_add(ax.s, one.s)); + hi.c = 0x3f490fdbU; lo.c = 0xb2bbbd2eU; // pi/4 + } else if ( f32_lt(ax.s, _rs_bits(0x401c0000U).s) ) { // < 39/16 + xr.s = f32_div(f32_sub(ax.s, ohf.s), f32_add(one.s, f32_mul(ohf.s, ax.s))); + hi.c = 0x3f7b985fU; lo.c = 0xb2d7e096U; // atan(1.5) + } else { // -1/x + xr.s = f32_div(_rs_bits(0xbf800000U).s, ax.s); + hi.c = 0x3fc90fdbU; lo.c = 0xb33bbd2eU; // pi/2 + } + z.s = f32_mul(xr.s, xr.s); + sp.c = 0; for ( int i = 5; i-- != 0; ) { c.c = at[i]; sp.s = f32_add(f32_mul(sp.s, z.s), c.s); } + s.s = f32_mul(z.s, sp.s); + if ( dir ) res.s = f32_sub(xr.s, f32_mul(xr.s, s.s)); + else res.s = f32_sub(hi.s, f32_sub(f32_sub(f32_mul(xr.s, s.s), lo.s), xr.s)); + return (neg == 1) ? _rs_neg(res.s) : res.s; + } + // bare door ops (div/add/sub/mul) round per _math_rnd; atan kernel is %n. + static float32_t _rs_atan2(float32_t y, float32_t x) { + union sing xb, pi, two, zero, mone, q, a, r; + zero.c = 0; pi.c = 0x40490fdbU; two.c = 0x40000000U; mone.c = 0xbf800000U; + xb.s = x; + if ( f32_lt(zero.s, x) ) { // x>0: atan(div y x) + softfloat_roundingMode = _math_rnd; q.s = f32_div(y, x); + softfloat_roundingMode = softfloat_round_near_even; return _rs_atan(q.s); + } + if ( f32_lt(x, zero.s) && f32_le(zero.s, y) ) { // x<0,y>=0: add(atan,pi) + softfloat_roundingMode = _math_rnd; q.s = f32_div(y, x); + softfloat_roundingMode = softfloat_round_near_even; a.s = _rs_atan(q.s); + softfloat_roundingMode = _math_rnd; r.s = f32_add(a.s, pi.s); + softfloat_roundingMode = softfloat_round_near_even; return r.s; + } + if ( f32_lt(x, zero.s) && f32_lt(y, zero.s) ) { // x<0,y<0: sub(atan,pi) + softfloat_roundingMode = _math_rnd; q.s = f32_div(y, x); + softfloat_roundingMode = softfloat_round_near_even; a.s = _rs_atan(q.s); + softfloat_roundingMode = _math_rnd; r.s = f32_sub(a.s, pi.s); + softfloat_roundingMode = softfloat_round_near_even; return r.s; + } + if ( (xb.c == 0) && f32_lt(zero.s, y) ) { // x==+0,y>0: div(pi,2) + softfloat_roundingMode = _math_rnd; r.s = f32_div(pi.s, two.s); + softfloat_roundingMode = softfloat_round_near_even; return r.s; + } + if ( (xb.c == 0) && f32_lt(y, zero.s) ) { // x==+0,y<0: mul(-1,div(pi,2)) + softfloat_roundingMode = _math_rnd; + r.s = f32_mul(mone.s, f32_div(pi.s, two.s)); + softfloat_roundingMode = softfloat_round_near_even; return r.s; + } + return zero.s; + } + +/* @rs pow/pow-n -- math.hoon ++rs ++pow/++pow-n */ + static float32_t _rs_pow_n(float32_t x, float32_t n) { + union sing nn, p, one, two; + one.c = 0x3f800000U; two.c = 0x40000000U; + nn.s = n; + if ( nn.c == 0 ) return one.s; // n == +0 -> 1 + softfloat_roundingMode = _math_rnd; // bare mul/sub round per door r + p.s = x; + while ( !f32_lt(n, two.s) ) { p.s = f32_mul(p.s, x); n = f32_sub(n, one.s); } + softfloat_roundingMode = softfloat_round_near_even; + return p.s; + } + static float32_t _rs_pow(float32_t x, float32_t n) { + union sing nn, ni, zero, lg, prod; + zero.c = 0; nn.s = n; + ni.s = i32_to_f32(f32_to_i32(n, softfloat_round_near_even, 0)); // san (need (toi n)) (mode-indep) + if ( (nn.c == ni.c) && f32_lt(zero.s, n) ) // positive integer + return _rs_pow_n(x, ni.s); + lg.s = _rs_log(x); // %n kernel + softfloat_roundingMode = _math_rnd; // bare mul per door r + prod.s = f32_mul(n, lg.s); + softfloat_roundingMode = softfloat_round_near_even; + return _rs_exp(prod.s); // %n kernel: exp(n*log x) } #ifndef MATH_JET_HARNESS @@ -534,6 +982,7 @@ typedef int64_t c3_ds; { union doub c, e; softfloat_roundingMode = softfloat_round_near_even; + _math_rnd = _rnd_of(u3r_at(60, cor)); // door rounding r (for composite arms) c.c = u3r_chub(0, x); e.d = fun(c.d); return u3i_chubs(1, &e.c); @@ -616,6 +1065,7 @@ typedef int64_t c3_ds; c3n == u3ud(y) || c3n == u3ud(x) ) { return u3m_bail(c3__exit); } + _math_rnd = _rnd_of(u3r_at(60, cor)); // door rounding r return u3qi_rd_atan2(y, x); } @@ -669,6 +1119,7 @@ typedef int64_t c3_ds; } { union doub xx, nn, e; softfloat_roundingMode = softfloat_round_near_even; + _math_rnd = _rnd_of(u3r_at(60, cor)); // door rounding r xx.c = u3r_chub(0, x); nn.c = u3r_chub(0, n); e.d = fun(xx.d, nn.d); return u3i_chubs(1, &e.c); @@ -684,4 +1135,64 @@ typedef int64_t c3_ds; xx.c=u3r_chub(0,x); nn.c=u3r_chub(0,n); e.d=_rd_pow_n(xx.d,nn.d); return u3i_chubs(1,&e.c); } u3_noun u3wi_rd_pow_n(u3_noun cor) { return _rd_jet2(cor, _rd_pow_n); } +/* @rs ABI wrappers. @rs is a 32-bit atom: read the low 32 bits of the chub, +** write the 32-bit result as a chub (high bits zero -> normalizes to a 32-bit +** atom). Chub I/O keeps this word-size-agnostic, like the @rd wrappers. +*/ + static inline float32_t _rs_in(u3_atom a) { + union sing s; s.c = (uint32_t)u3r_chub(0, a); return s.s; + } + static inline u3_noun _rs_out(float32_t v) { + union sing s; s.s = v; { c3_d out = (c3_d)s.c; return u3i_chubs(1, &out); } + } + static u3_noun _rs_jet(u3_noun cor, float32_t (*fun)(float32_t)) { + u3_noun x = u3r_at(u3x_sam, cor); + if ( u3_none == x || c3n == u3ud(x) ) return u3m_bail(c3__exit); + softfloat_roundingMode = softfloat_round_near_even; + _math_rnd = _rnd_of(u3r_at(60, cor)); // door rounding r (for @rs tan) + return _rs_out(fun(_rs_in(x))); + } + static u3_noun _rs_jet2(u3_noun cor, float32_t (*fun)(float32_t, float32_t)) { + u3_noun x, n; + if ( c3n == u3r_mean(cor, {u3x_sam_2, &x}, {u3x_sam_3, &n}) || + c3n == u3ud(x) || c3n == u3ud(n) ) { + return u3m_bail(c3__exit); + } + softfloat_roundingMode = softfloat_round_near_even; + _math_rnd = _rnd_of(u3r_at(60, cor)); // door rounding r + return _rs_out(fun(_rs_in(x), _rs_in(n))); + } + + u3_noun u3qi_rs_exp(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rs_out(_rs_exp(_rs_in(a))); } + u3_noun u3wi_rs_exp(u3_noun cor) { return _rs_jet(cor, _rs_exp); } + u3_noun u3qi_rs_log(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rs_out(_rs_log(_rs_in(a))); } + u3_noun u3wi_rs_log(u3_noun cor) { return _rs_jet(cor, _rs_log); } + u3_noun u3qi_rs_sin(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rs_out(_rs_sin(_rs_in(a))); } + u3_noun u3wi_rs_sin(u3_noun cor) { return _rs_jet(cor, _rs_sin); } + u3_noun u3qi_rs_cos(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rs_out(_rs_cos(_rs_in(a))); } + u3_noun u3wi_rs_cos(u3_noun cor) { return _rs_jet(cor, _rs_cos); } + u3_noun u3qi_rs_tan(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rs_out(_rs_tan(_rs_in(a))); } + u3_noun u3wi_rs_tan(u3_noun cor) { return _rs_jet(cor, _rs_tan); } + u3_noun u3qi_rs_atan(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rs_out(_rs_atan(_rs_in(a))); } + u3_noun u3wi_rs_atan(u3_noun cor){ return _rs_jet(cor, _rs_atan); } + u3_noun u3qi_rs_asin(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rs_out(_rs_asin(_rs_in(a))); } + u3_noun u3wi_rs_asin(u3_noun cor){ return _rs_jet(cor, _rs_asin); } + u3_noun u3qi_rs_acos(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rs_out(_rs_acos(_rs_in(a))); } + u3_noun u3wi_rs_acos(u3_noun cor){ return _rs_jet(cor, _rs_acos); } + u3_noun u3qi_rs_sqt(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rs_out(_rs_sqt(_rs_in(a))); } + u3_noun u3wi_rs_sqt(u3_noun cor) { return _rs_jet(cor, _rs_sqt); } + u3_noun u3qi_rs_cbt(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rs_out(_rs_cbt(_rs_in(a))); } + u3_noun u3wi_rs_cbt(u3_noun cor) { return _rs_jet(cor, _rs_cbt); } + u3_noun u3qi_rs_log2(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rs_out(_rs_log2(_rs_in(a))); } + u3_noun u3wi_rs_log2(u3_noun cor){ return _rs_jet(cor, _rs_log2); } + u3_noun u3qi_rs_log10(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rs_out(_rs_log10(_rs_in(a))); } + u3_noun u3wi_rs_log10(u3_noun cor){ return _rs_jet(cor, _rs_log10); } + + u3_noun u3qi_rs_atan2(u3_atom y, u3_atom x) { softfloat_roundingMode=softfloat_round_near_even; return _rs_out(_rs_atan2(_rs_in(y), _rs_in(x))); } + u3_noun u3wi_rs_atan2(u3_noun cor){ return _rs_jet2(cor, _rs_atan2); } + u3_noun u3qi_rs_pow(u3_atom x, u3_atom n) { softfloat_roundingMode=softfloat_round_near_even; return _rs_out(_rs_pow(_rs_in(x), _rs_in(n))); } + u3_noun u3wi_rs_pow(u3_noun cor) { return _rs_jet2(cor, _rs_pow); } + u3_noun u3qi_rs_pow_n(u3_atom x, u3_atom n) { softfloat_roundingMode=softfloat_round_near_even; return _rs_out(_rs_pow_n(_rs_in(x), _rs_in(n))); } + u3_noun u3wi_rs_pow_n(u3_noun cor){ return _rs_jet2(cor, _rs_pow_n); } + #endif diff --git a/libmath/vere64/noun/jets/q.h b/libmath/vere64/noun/jets/q.h index 95c9b07..9d0cf00 100644 --- a/libmath/vere64/noun/jets/q.h +++ b/libmath/vere64/noun/jets/q.h @@ -305,6 +305,21 @@ u3_noun u3qi_rd_pow_n(u3_atom, u3_atom); u3_noun u3qi_rd_log2(u3_atom); u3_noun u3qi_rd_log10(u3_atom); + u3_noun u3qi_rs_exp(u3_atom); + u3_noun u3qi_rs_log(u3_atom); + u3_noun u3qi_rs_sin(u3_atom); + u3_noun u3qi_rs_cos(u3_atom); + u3_noun u3qi_rs_tan(u3_atom); + u3_noun u3qi_rs_atan(u3_atom); + u3_noun u3qi_rs_atan2(u3_atom, u3_atom); + u3_noun u3qi_rs_asin(u3_atom); + u3_noun u3qi_rs_acos(u3_atom); + u3_noun u3qi_rs_sqt(u3_atom); + u3_noun u3qi_rs_cbt(u3_atom); + u3_noun u3qi_rs_pow(u3_atom, u3_atom); + u3_noun u3qi_rs_pow_n(u3_atom, u3_atom); + u3_noun u3qi_rs_log2(u3_atom); + u3_noun u3qi_rs_log10(u3_atom); # define u3qfu_van_fan 28 # define u3qfu_van_rib 58 diff --git a/libmath/vere64/noun/jets/w.h b/libmath/vere64/noun/jets/w.h index effc85a..ec031a7 100644 --- a/libmath/vere64/noun/jets/w.h +++ b/libmath/vere64/noun/jets/w.h @@ -444,6 +444,21 @@ u3_noun u3wi_rd_pow_n(u3_noun); u3_noun u3wi_rd_log2(u3_noun); u3_noun u3wi_rd_log10(u3_noun); + u3_noun u3wi_rs_exp(u3_noun); + u3_noun u3wi_rs_log(u3_noun); + u3_noun u3wi_rs_sin(u3_noun); + u3_noun u3wi_rs_cos(u3_noun); + u3_noun u3wi_rs_tan(u3_noun); + u3_noun u3wi_rs_atan(u3_noun); + u3_noun u3wi_rs_atan2(u3_noun); + u3_noun u3wi_rs_asin(u3_noun); + u3_noun u3wi_rs_acos(u3_noun); + u3_noun u3wi_rs_sqt(u3_noun); + u3_noun u3wi_rs_cbt(u3_noun); + u3_noun u3wi_rs_pow(u3_noun); + u3_noun u3wi_rs_pow_n(u3_noun); + u3_noun u3wi_rs_log2(u3_noun); + u3_noun u3wi_rs_log10(u3_noun); #endif /* ifndef U3_JETS_W_H */ diff --git a/libmath/vere64/test/rd_check.c b/libmath/vere64/test/rd_check.c index 0ccad4c..475d239 100644 --- a/libmath/vere64/test/rd_check.c +++ b/libmath/vere64/test/rd_check.c @@ -35,8 +35,49 @@ static void emit2(const char* nm, double a, double b, (unsigned long long)out.c, a, b); } +// @rs single-arg: input given as the 32-bit bit pattern directly. +static void emits(const char* nm, unsigned in, float32_t (*fun)(float32_t)) { + union sing x, out; + x.c = (uint32_t)in; + out.s = fun(x.s); + printf("%-6s 0x%08x 0x%08x\n", nm, (unsigned)x.c, (unsigned)out.c); +} + int main(void) { softfloat_roundingMode = softfloat_round_near_even; + // @rs exp: core + edges (expected from math.hoon tests/lib/math-exp.hoon) + static const unsigned rsex[] = { 0x0, 0x3f000000, 0x3f800000, 0xbf800000, + 0x40000000, 0x41200000, 0xc0a00000, 0x3dcccccd, 0x7f800000, 0xff800000, + 0x7fc00000, 0x42b00000, 0x42b20000, 0x42c80000, 0xc2ce0000, 0xc2d00000, + 0xc2dc0000 }; + for (unsigned i = 0; i < sizeof rsex/sizeof rsex[0]; i++) + emits("exp-s", rsex[i], _rs_exp); + static const unsigned rstr[] = { 0x0, 0x3f000000, 0x3f800000, 0xbf800000, + 0x41200000, 0x42c80000, 0x7f800000, 0xff800000, 0x80000000, 0x40000000, + 0x40490fdb, 0x42652ee0 }; + for (unsigned i = 0; i < sizeof rstr/sizeof rstr[0]; i++) emits("sin-s", rstr[i], _rs_sin); + for (unsigned i = 0; i < sizeof rstr/sizeof rstr[0]; i++) emits("cos-s", rstr[i], _rs_cos); + for (unsigned i = 0; i < sizeof rstr/sizeof rstr[0]; i++) emits("tan-s", rstr[i], _rs_tan); + // atan / asin / acos / log / log-2 / log-10 / sqt / cbt (expected: math-*.hoon) + static const unsigned at_s[] = { 0x3f000000, 0x3f800000, 0xbf800000, 0x40000000, + 0x41200000, 0x7f800000, 0x7fc00000, 0xff800000, 0x0, 0x40490fdb, 0x3dcccccd }; + for (unsigned i=0;i Date: Fri, 12 Jun 2026 07:58:23 -0500 Subject: [PATCH 06/28] =?UTF-8?q?math:=20README=20=E2=80=94=20document=20@?= =?UTF-8?q?rs=20jets=20+=20composite=20rounding-mode=20handling?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 --- libmath/vere64/README.md | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/libmath/vere64/README.md b/libmath/vere64/README.md index a3d7218..2400713 100644 --- a/libmath/vere64/README.md +++ b/libmath/vere64/README.md @@ -28,10 +28,22 @@ because the `u3r_mean` macro's API diverged between the runtimes: Keep the two copies in sync **except** those two lines. ## What's covered -All 15 `@rd` transcendentals, bit-exact to the Hoon `++ rd` door (same reduction, -coefficients, Horner order — not merely faithful): `exp log sin cos tan atan -atan2 asin acos sqt cbt pow pow-n log-2 log-10`. The other width doors -(`rs`/`rh`/`rq`) are not yet jetted. +All 15 transcendentals for **both `@rd` (double) and `@rs` (single)**, bit-exact +to their Hoon door (same reduction, coefficients, Horner order — not merely +faithful): `exp log sin cos tan atan atan2 asin acos sqt cbt pow pow-n log-2 +log-10`. The `@rs` cores are single-precision twins of the `@rd` ones (SoftFloat +`f32`, `uint32_t` bit pattern, but the same chub I/O). The `@rh`/`@rq` doors are +not yet jetted. + +### Rounding modes (composite arms honor the door's `r`) +The math doors carry `r=?(%n %u %d %z)` (bunt `%z`). The transcendental KERNELS +are correctly-rounded and hardcode `~(mul ^rd %n)` (no rounding axis). The +*composite* arms (`pow`/`atan2`/`tan`/`pow-n`) assemble their result with bare +door ops that honor `r` — so the jet must too. A file-static `_math_rnd` is set +from the door's `r` (gate **axis 60**: sample `[r rtol]` → door-axis 12 → +`peg(7,12)`; base hoon `^rd` with a bare `r` is axis 30) via `'n'/'u'/'d'/'z'` -> +`near_even`/`max`/`min`/`minMag`, and brackets only the composite bare ops; +kernel calls run at `near_even`. Only the **135** kelvin tree is vendored: the stock test ships (`~dev`, fresh fakeships from `brass.pill`) are `hoon-version` 135, and that is where these jets From 0de48bc41c00f2a92b61b9b91dbd6bfb9b4e6559 Mon Sep 17 00:00:00 2001 From: Sigilante Date: Fri, 12 Jun 2026 08:29:54 -0500 Subject: [PATCH 07/28] math: @rh (half-precision) transcendental jets Add all 15 @rh jets. Every @rh arm is narrow-sh(rs_fn(widen-hs(x))): widen f16->f32 (exact = f16_to_f32), compute in the @rs cores, narrow f32->f16 (= f32_to_f16). No new algorithm cores -- the @rs cores are reused. 16-bit chub marshalling keeps them word-size-agnostic. Per the refinement, @rh now inherits the door's rounding mode r instead of pinning %n (consistent with @rd/@rs): - Hoon: the arms thread r into the @rs delegation (~(exp rs [r ...])), so the @rs composites honor r; and narrow-sh, formerly a hardcoded round-half-to-even, now does directed rounding per r (overflow -> inf/max-finite, underflow -> 0/min-subnormal, with an exact-zero guard). - Jets: the wrapper sets _math_rnd from the door's r (axis 60); the cores run the rs kernels at near-even and narrow via f32_to_f16 at r. A harness spike (rd_check.c emit_narrow) confirmed the hand-rolled narrow-sh is bit-exact to SoftFloat f32_to_f16 across all four rounding modes and the edge cases (subnormals, the e>=143 overflow, the 0x7e00 NaN) -- it caught exactly one bug (directed rounding of exact zero), now fixed. Registered rh under non/math in 135/tree.c, q.h/w.h decls, ~/ hints on the @rh door. Full -test %/tests/lib (incl math-rh) passes ok=%.y on both the 32- and 64-bit jetted runtimes; jets fire (us) and honor r. Co-Authored-By: Claude Opus 4.8 --- libmath/desk/lib/math.hoon | 90 +++++++++++++++++------- libmath/vere/noun/jets/135/tree.c | 36 ++++++++++ libmath/vere/noun/jets/i/math.c | 105 ++++++++++++++++++++++++++++ libmath/vere/noun/jets/q.h | 15 ++++ libmath/vere/noun/jets/w.h | 15 ++++ libmath/vere64/noun/jets/135/tree.c | 36 ++++++++++ libmath/vere64/noun/jets/i/math.c | 105 ++++++++++++++++++++++++++++ libmath/vere64/noun/jets/q.h | 15 ++++ libmath/vere64/noun/jets/w.h | 15 ++++ libmath/vere64/test/rd_check.c | 23 ++++++ 10 files changed, 428 insertions(+), 27 deletions(-) diff --git a/libmath/desk/lib/math.hoon b/libmath/desk/lib/math.hoon index bbadbc9..3b64b25 100644 --- a/libmath/desk/lib/math.hoon +++ b/libmath/desk/lib/math.hoon @@ -2265,6 +2265,7 @@ -- :: half precision ++ rh + ~/ %rh ^| |_ $: r=$?(%n %u %d %z) :: round nearest, up, down, to zero rtol=_.~~1e-2 :: relative tolerance for precision of operations @@ -2719,34 +2720,55 @@ ?: =(e 0x1f) (con s (con 0x7f80.0000 (lsh [0 13] m))) ?: =(e 0) ?: =(m 0) s - (con s `@`(~(mul rs [%n .1e-5]) (~(sun rs [%n .1e-5]) m) `@rs`0x3380.0000)) + (con s `@`(~(mul rs [r .1e-5]) (~(sun rs [r .1e-5]) m) `@rs`0x3380.0000)) (con s (con (lsh [0 23] (^add e 112)) (lsh [0 13] m))) + :: +rndup: should the magnitude be incremented? rem=discarded bits, + :: half=tie point, lsb=kept low bit, neg=sign. Honors the door's r. + ++ rndup + |= [rem=@ half=@ lsb=@ neg=?] ^- ? + ?- r + %n ?|((^gth rem half) &(=(rem half) =(1 lsb))) + %z %.n + %u &(!neg !=(0 rem)) + %d &(neg !=(0 rem)) + == ++ narrow-sh |= uu=@rs ^- @ - =/ u `@`uu - =/ s (dis (rsh [0 16] u) 0x8000) - =/ e (dis (rsh [0 23] u) 0xff) - =/ m (dis u 0x7f.ffff) - ?: =(e 0xff) (con s ?:(=(m 0) 0x7c00 0x7e00)) - ?: (^gte e 143) (con s 0x7c00) - ?: (^gte e 113) + =/ u `@`uu + =/ s (dis (rsh [0 16] u) 0x8000) :: sign in f16 position + =/ neg =(0x8000 s) + =/ e (dis (rsh [0 23] u) 0xff) + =/ m (dis u 0x7f.ffff) + ?: =(e 0xff) (con s ?:(=(m 0) 0x7c00 0x7e00)) :: inf / nan + ?: (^gte e 143) :: overflow: inf / max-finite per r + ?- r + %n (con s 0x7c00) + %u (con s ?:(neg 0x7bff 0x7c00)) + %d (con s ?:(neg 0x7c00 0x7bff)) + %z (con s 0x7bff) + == + ?: (^gte e 113) :: normal =/ ne (^sub e 112) =/ mant (rsh [0 13] m) =/ rem (dis m 0x1fff) - =/ rup ?|((^gth rem 0x1000) &(=(rem 0x1000) =(1 (dis mant 1)))) + =/ rup (rndup rem 0x1000 (dis mant 1) neg) (con s (^add (lsh [0 10] ne) (^add mant ?:(rup 1 0)))) - ?: (^lth e 102) (con s 0x0) - =/ shift (^sub 126 e) + ?: (^lth e 102) :: underflow: 0 / min-subnormal per r + =/ nz |(!=(0 e) !=(0 m)) :: nonzero? (exact 0 never bumps) + =/ up ?&(nz ?-(r %n %.n, %z %.n, %u !neg, %d neg)) + (con s ?:(up 1 0)) + =/ shift (^sub 126 e) :: subnormal =/ mf (con 0x80.0000 m) =/ mant (rsh [0 shift] mf) =/ half (bex (dec shift)) =/ rem (dis mf (dec (bex shift))) - =/ rup ?|((^gth rem half) &(=(rem half) =(1 (dis mant 1)))) + =/ rup (rndup rem half (dis mant 1) neg) (con s (^add mant ?:(rup 1 0))) ++ exp + ~/ %exp :: compute in @rs, round to f16 (see +narrow-sh). |= x=@rh ^- @rh - `@rh`(narrow-sh (~(exp rs [%n .1e-5]) `@rs`(widen-hs x))) + `@rh`(narrow-sh (~(exp rs [r .1e-5]) `@rs`(widen-hs x))) :: +sin: @rh -> @rh :: :: Returns the sine of a floating-point atom. @@ -2759,8 +2781,9 @@ :: .~~3.437e-3 :: Source ++ sin + ~/ %sin |= x=@rh ^- @rh - `@rh`(narrow-sh (~(sin rs [%n .1e-5]) `@rs`(widen-hs x))) + `@rh`(narrow-sh (~(sin rs [r .1e-5]) `@rs`(widen-hs x))) :: +cos: @rh -> @rh :: :: Returns the cosine of a floating-point atom. @@ -2773,8 +2796,9 @@ :: .~~-1.001 :: Source ++ cos + ~/ %cos |= x=@rh ^- @rh - `@rh`(narrow-sh (~(cos rs [%n .1e-5]) `@rs`(widen-hs x))) + `@rh`(narrow-sh (~(cos rs [r .1e-5]) `@rs`(widen-hs x))) :: +tan: @rh -> @rh :: :: Returns the tangent of a floating-point atom. @@ -2787,8 +2811,9 @@ :: .~~-3.433e-3 :: Source ++ tan + ~/ %tan |= x=@rh ^- @rh - `@rh`(narrow-sh (~(tan rs [%n .1e-5]) `@rs`(widen-hs x))) + `@rh`(narrow-sh (~(tan rs [r .1e-5]) `@rs`(widen-hs x))) :: +asin: @rh -> @rh :: :: Returns the inverse sine of a floating-point atom. @@ -2801,8 +2826,9 @@ :: .~~0.7773 :: ++ asin + ~/ %asin |= x=@rh ^- @rh - `@rh`(narrow-sh (~(asin rs [%n .1e-5]) `@rs`(widen-hs x))) + `@rh`(narrow-sh (~(asin rs [r .1e-5]) `@rs`(widen-hs x))) :: +acos: @rh -> @rh :: :: Returns the inverse cosine of a floating-point atom. @@ -2815,8 +2841,9 @@ :: .~~0.7964 :: ++ acos + ~/ %acos |= x=@rh ^- @rh - `@rh`(narrow-sh (~(acos rs [%n .1e-5]) `@rs`(widen-hs x))) + `@rh`(narrow-sh (~(acos rs [r .1e-5]) `@rs`(widen-hs x))) :: +atan: @rh -> @rh :: :: Returns the inverse tangent of a floating-point atom. @@ -2829,8 +2856,9 @@ :: .~~1.281 :: ++ atan + ~/ %atan |= x=@rh ^- @rh - `@rh`(narrow-sh (~(atan rs [%n .1e-5]) `@rs`(widen-hs x))) + `@rh`(narrow-sh (~(atan rs [r .1e-5]) `@rs`(widen-hs x))) :: +atan2: [@rh @rh] -> @rh :: :: Returns the inverse tangent of a floating-point coordinate. @@ -2843,8 +2871,9 @@ :: .~~2.354 :: ++ atan2 + ~/ %atan2 |= [y=@rh x=@rh] ^- @rh - `@rh`(narrow-sh (~(atan2 rs [%n .1e-5]) `@rs`(widen-hs y) `@rs`(widen-hs x))) + `@rh`(narrow-sh (~(atan2 rs [r .1e-5]) `@rs`(widen-hs y) `@rs`(widen-hs x))) :: +pow-n: [@rh @rh] -> @rh :: :: Returns the power of a floating-point atom to an integer exponent. @@ -2857,8 +2886,9 @@ :: .~~8 :: Source ++ pow-n + ~/ %pow-n |= [x=@rh n=@rh] ^- @rh - `@rh`(narrow-sh (~(pow-n rs [%n .1e-5]) `@rs`(widen-hs x) `@rs`(widen-hs n))) + `@rh`(narrow-sh (~(pow-n rs [r .1e-5]) `@rs`(widen-hs x) `@rs`(widen-hs n))) :: +log: @rh -> @rh :: :: Returns the natural logarithm of a floating-point atom. @@ -2870,8 +2900,9 @@ :: > (~(log rh [%z .~~1e-1]) .~~2) :: .~~0.6904 ++ log + ~/ %log |= x=@rh ^- @rh - `@rh`(narrow-sh (~(log rs [%n .1e-5]) `@rs`(widen-hs x))) + `@rh`(narrow-sh (~(log rs [r .1e-5]) `@rs`(widen-hs x))) :: +log-10: @rh -> @rh :: :: Returns the base-10 logarithm of a floating-point atom. @@ -2879,8 +2910,9 @@ :: TODO :: Source ++ log-10 + ~/ %log-10 |= x=@rh ^- @rh - `@rh`(narrow-sh (~(log-10 rs [%n .1e-5]) `@rs`(widen-hs x))) + `@rh`(narrow-sh (~(log-10 rs [r .1e-5]) `@rs`(widen-hs x))) :: +log-2: @rh -> @rh :: :: Returns the base-2 logarithm of a floating-point atom. @@ -2888,8 +2920,9 @@ :: TODO :: Source ++ log-2 + ~/ %log-2 |= x=@rh ^- @rh - `@rh`(narrow-sh (~(log-2 rs [%n .1e-5]) `@rs`(widen-hs x))) + `@rh`(narrow-sh (~(log-2 rs [r .1e-5]) `@rs`(widen-hs x))) :: +pow: [@rh @rh] -> @rh :: :: Returns the power of a floating-point atom to a floating-point exponent. @@ -2902,8 +2935,9 @@ :: .~~11.14 :: Source ++ pow + ~/ %pow |= [x=@rh n=@rh] ^- @rh - `@rh`(narrow-sh (~(pow rs [%n .1e-5]) `@rs`(widen-hs x) `@rs`(widen-hs n))) + `@rh`(narrow-sh (~(pow rs [r .1e-5]) `@rs`(widen-hs x) `@rs`(widen-hs n))) :: +sqrt: @rh -> @rh :: :: Returns the square root of a floating-point atom. @@ -2929,8 +2963,9 @@ :: .~~31.61 :: Source ++ sqt + ~/ %sqt |= x=@rh ^- @rh - `@rh`(narrow-sh (~(sqt rs [%n .1e-5]) `@rs`(widen-hs x))) + `@rh`(narrow-sh (~(sqt rs [r .1e-5]) `@rs`(widen-hs x))) :: +cbrt: @rh -> @rh :: :: Returns the cube root of a floating-point atom. @@ -2956,8 +2991,9 @@ :: .~~1.256 :: Source ++ cbt + ~/ %cbt |= x=@rh ^- @rh - `@rh`(narrow-sh (~(cbt rs [%n .1e-5]) `@rs`(widen-hs x))) + `@rh`(narrow-sh (~(cbt rs [r .1e-5]) `@rs`(widen-hs x))) :: +arg: @rh -> @rh :: :: Returns the argument of a floating-point atom (real argument = absolute diff --git a/libmath/vere/noun/jets/135/tree.c b/libmath/vere/noun/jets/135/tree.c index 98a240f..236b57b 100644 --- a/libmath/vere/noun/jets/135/tree.c +++ b/libmath/vere/noun/jets/135/tree.c @@ -1014,9 +1014,45 @@ static u3j_core _135_non__math_rs_d[] = { "log-10", 7, _135_non__math_rs_log10_a, 0, no_hashes }, {} }; +// numerics math.hoon @rh transcendentals: non -> math -> rh -> +static u3j_harm _135_non__math_rh_exp_a[] = {{".2", u3wi_rh_exp}, {}}; +static u3j_harm _135_non__math_rh_log_a[] = {{".2", u3wi_rh_log}, {}}; +static u3j_harm _135_non__math_rh_sin_a[] = {{".2", u3wi_rh_sin}, {}}; +static u3j_harm _135_non__math_rh_cos_a[] = {{".2", u3wi_rh_cos}, {}}; +static u3j_harm _135_non__math_rh_tan_a[] = {{".2", u3wi_rh_tan}, {}}; +static u3j_harm _135_non__math_rh_atan_a[] = {{".2", u3wi_rh_atan}, {}}; +static u3j_harm _135_non__math_rh_atan2_a[] = {{".2", u3wi_rh_atan2}, {}}; +static u3j_harm _135_non__math_rh_asin_a[] = {{".2", u3wi_rh_asin}, {}}; +static u3j_harm _135_non__math_rh_acos_a[] = {{".2", u3wi_rh_acos}, {}}; +static u3j_harm _135_non__math_rh_sqt_a[] = {{".2", u3wi_rh_sqt}, {}}; +static u3j_harm _135_non__math_rh_cbt_a[] = {{".2", u3wi_rh_cbt}, {}}; +static u3j_harm _135_non__math_rh_pow_a[] = {{".2", u3wi_rh_pow}, {}}; +static u3j_harm _135_non__math_rh_pow_n_a[] = {{".2", u3wi_rh_pow_n}, {}}; +static u3j_harm _135_non__math_rh_log2_a[] = {{".2", u3wi_rh_log2}, {}}; +static u3j_harm _135_non__math_rh_log10_a[] = {{".2", u3wi_rh_log10}, {}}; +static u3j_core _135_non__math_rh_d[] = + { + { "exp", 7, _135_non__math_rh_exp_a, 0, no_hashes }, + { "log", 7, _135_non__math_rh_log_a, 0, no_hashes }, + { "sin", 7, _135_non__math_rh_sin_a, 0, no_hashes }, + { "cos", 7, _135_non__math_rh_cos_a, 0, no_hashes }, + { "tan", 7, _135_non__math_rh_tan_a, 0, no_hashes }, + { "atan", 7, _135_non__math_rh_atan_a, 0, no_hashes }, + { "atan2", 7, _135_non__math_rh_atan2_a, 0, no_hashes }, + { "asin", 7, _135_non__math_rh_asin_a, 0, no_hashes }, + { "acos", 7, _135_non__math_rh_acos_a, 0, no_hashes }, + { "sqt", 7, _135_non__math_rh_sqt_a, 0, no_hashes }, + { "cbt", 7, _135_non__math_rh_cbt_a, 0, no_hashes }, + { "pow", 7, _135_non__math_rh_pow_a, 0, no_hashes }, + { "pow-n", 7, _135_non__math_rh_pow_n_a, 0, no_hashes }, + { "log-2", 7, _135_non__math_rh_log2_a, 0, no_hashes }, + { "log-10", 7, _135_non__math_rh_log10_a, 0, no_hashes }, + {} + }; static u3j_core _135_non__math_d[] = { { "rd", 7, 0, _135_non__math_rd_d, no_hashes }, { "rs", 7, 0, _135_non__math_rs_d, no_hashes }, + { "rh", 7, 0, _135_non__math_rh_d, no_hashes }, {} }; diff --git a/libmath/vere/noun/jets/i/math.c b/libmath/vere/noun/jets/i/math.c index 1bac3ba..c752f21 100644 --- a/libmath/vere/noun/jets/i/math.c +++ b/libmath/vere/noun/jets/i/math.c @@ -966,6 +966,52 @@ typedef int64_t c3_ds; return _rs_exp(prod.s); // %n kernel: exp(n*log x) } +/* =================================================================== +** @rh (half-precision) cores -- math.hoon ++rh. Every arm is +** narrow-sh(rs_fn(widen-hs(x))): widen f16->f32 (exact = f16_to_f32), +** compute in @rs, narrow f32->f16 (= f32_to_f16) honoring the door's r. +** The rs call inherits r too (composites honor it; kernels stay %n). No new +** algorithm cores -- the @rs cores are reused. Verified: the Hoon narrow-sh +** is bit-exact to f32_to_f16 in all four rounding modes. +** =================================================================== */ + + union half { + float16_t h; + uint16_t c; + }; + + // widen f16->f32 (exact), run an @rs core, narrow f32->f16 per _math_rnd. + // _math_rnd is the door's r (set by the wrapper): the rs composites honor it + // and the narrow rounds by it; the rs kernels run at near-even. + static inline float16_t _rh_1(float16_t x, float32_t (*fun)(float32_t)) { + softfloat_roundingMode = softfloat_round_near_even; + float32_t v = fun(f16_to_f32(x)); + softfloat_roundingMode = _math_rnd; + return f32_to_f16(v); + } + static inline float16_t _rh_2(float16_t x, float16_t n, + float32_t (*fun)(float32_t, float32_t)) { + softfloat_roundingMode = softfloat_round_near_even; + float32_t v = fun(f16_to_f32(x), f16_to_f32(n)); + softfloat_roundingMode = _math_rnd; + return f32_to_f16(v); + } + static float16_t _rh_exp(float16_t x) { return _rh_1(x, _rs_exp); } + static float16_t _rh_log(float16_t x) { return _rh_1(x, _rs_log); } + static float16_t _rh_sin(float16_t x) { return _rh_1(x, _rs_sin); } + static float16_t _rh_cos(float16_t x) { return _rh_1(x, _rs_cos); } + static float16_t _rh_tan(float16_t x) { return _rh_1(x, _rs_tan); } + static float16_t _rh_atan(float16_t x) { return _rh_1(x, _rs_atan); } + static float16_t _rh_asin(float16_t x) { return _rh_1(x, _rs_asin); } + static float16_t _rh_acos(float16_t x) { return _rh_1(x, _rs_acos); } + static float16_t _rh_sqt(float16_t x) { return _rh_1(x, _rs_sqt); } + static float16_t _rh_cbt(float16_t x) { return _rh_1(x, _rs_cbt); } + static float16_t _rh_log2(float16_t x) { return _rh_1(x, _rs_log2); } + static float16_t _rh_log10(float16_t x) { return _rh_1(x, _rs_log10); } + static float16_t _rh_atan2(float16_t y, float16_t x) { return _rh_2(y, x, _rs_atan2); } + static float16_t _rh_pow(float16_t x, float16_t n) { return _rh_2(x, n, _rs_pow); } + static float16_t _rh_pow_n(float16_t x, float16_t n) { return _rh_2(x, n, _rs_pow_n); } + #ifndef MATH_JET_HARNESS /* u3 ABI wrappers. Each transcendental forces round-near-even; the @rd door's @@ -1195,4 +1241,63 @@ typedef int64_t c3_ds; u3_noun u3qi_rs_pow_n(u3_atom x, u3_atom n) { softfloat_roundingMode=softfloat_round_near_even; return _rs_out(_rs_pow_n(_rs_in(x), _rs_in(n))); } u3_noun u3wi_rs_pow_n(u3_noun cor){ return _rs_jet2(cor, _rs_pow_n); } +/* @rh ABI wrappers. @rh is a 16-bit atom: read the low 16 bits of the chub, +** write the 16-bit result via chub (high bits zero -> normalizes). Same +** word-agnostic chub I/O as @rd/@rs. Wrappers set _math_rnd from the door's r +** (axis 60); the cores apply it to the rs composite ops and the f16 narrow. +*/ + static inline float16_t _rh_in(u3_atom a) { + union half s; s.c = (uint16_t)u3r_chub(0, a); return s.h; + } + static inline u3_noun _rh_out(float16_t v) { + union half s; s.h = v; { c3_d out = (c3_d)s.c; return u3i_chubs(1, &out); } + } + static u3_noun _rh_jet(u3_noun cor, float16_t (*fun)(float16_t)) { + u3_noun x = u3r_at(u3x_sam, cor); + if ( u3_none == x || c3n == u3ud(x) ) return u3m_bail(c3__exit); + _math_rnd = _rnd_of(u3r_at(60, cor)); + return _rh_out(fun(_rh_in(x))); + } + static u3_noun _rh_jet2(u3_noun cor, float16_t (*fun)(float16_t, float16_t)) { + u3_noun x, n; + if ( c3n == u3r_mean(cor, u3x_sam_2, &x, u3x_sam_3, &n, 0) || + c3n == u3ud(x) || c3n == u3ud(n) ) { + return u3m_bail(c3__exit); + } + _math_rnd = _rnd_of(u3r_at(60, cor)); + return _rh_out(fun(_rh_in(x), _rh_in(n))); + } + + u3_noun u3qi_rh_exp(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_exp(_rh_in(a))); } + u3_noun u3wi_rh_exp(u3_noun cor) { return _rh_jet(cor, _rh_exp); } + u3_noun u3qi_rh_log(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_log(_rh_in(a))); } + u3_noun u3wi_rh_log(u3_noun cor) { return _rh_jet(cor, _rh_log); } + u3_noun u3qi_rh_sin(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_sin(_rh_in(a))); } + u3_noun u3wi_rh_sin(u3_noun cor) { return _rh_jet(cor, _rh_sin); } + u3_noun u3qi_rh_cos(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_cos(_rh_in(a))); } + u3_noun u3wi_rh_cos(u3_noun cor) { return _rh_jet(cor, _rh_cos); } + u3_noun u3qi_rh_tan(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_tan(_rh_in(a))); } + u3_noun u3wi_rh_tan(u3_noun cor) { return _rh_jet(cor, _rh_tan); } + u3_noun u3qi_rh_atan(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_atan(_rh_in(a))); } + u3_noun u3wi_rh_atan(u3_noun cor){ return _rh_jet(cor, _rh_atan); } + u3_noun u3qi_rh_asin(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_asin(_rh_in(a))); } + u3_noun u3wi_rh_asin(u3_noun cor){ return _rh_jet(cor, _rh_asin); } + u3_noun u3qi_rh_acos(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_acos(_rh_in(a))); } + u3_noun u3wi_rh_acos(u3_noun cor){ return _rh_jet(cor, _rh_acos); } + u3_noun u3qi_rh_sqt(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_sqt(_rh_in(a))); } + u3_noun u3wi_rh_sqt(u3_noun cor) { return _rh_jet(cor, _rh_sqt); } + u3_noun u3qi_rh_cbt(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_cbt(_rh_in(a))); } + u3_noun u3wi_rh_cbt(u3_noun cor) { return _rh_jet(cor, _rh_cbt); } + u3_noun u3qi_rh_log2(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_log2(_rh_in(a))); } + u3_noun u3wi_rh_log2(u3_noun cor){ return _rh_jet(cor, _rh_log2); } + u3_noun u3qi_rh_log10(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_log10(_rh_in(a))); } + u3_noun u3wi_rh_log10(u3_noun cor){ return _rh_jet(cor, _rh_log10); } + + u3_noun u3qi_rh_atan2(u3_atom y, u3_atom x) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_atan2(_rh_in(y), _rh_in(x))); } + u3_noun u3wi_rh_atan2(u3_noun cor){ return _rh_jet2(cor, _rh_atan2); } + u3_noun u3qi_rh_pow(u3_atom x, u3_atom n) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_pow(_rh_in(x), _rh_in(n))); } + u3_noun u3wi_rh_pow(u3_noun cor) { return _rh_jet2(cor, _rh_pow); } + u3_noun u3qi_rh_pow_n(u3_atom x, u3_atom n) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_pow_n(_rh_in(x), _rh_in(n))); } + u3_noun u3wi_rh_pow_n(u3_noun cor){ return _rh_jet2(cor, _rh_pow_n); } + #endif diff --git a/libmath/vere/noun/jets/q.h b/libmath/vere/noun/jets/q.h index 9d0cf00..654930a 100644 --- a/libmath/vere/noun/jets/q.h +++ b/libmath/vere/noun/jets/q.h @@ -320,6 +320,21 @@ u3_noun u3qi_rs_pow_n(u3_atom, u3_atom); u3_noun u3qi_rs_log2(u3_atom); u3_noun u3qi_rs_log10(u3_atom); + u3_noun u3qi_rh_exp(u3_atom); + u3_noun u3qi_rh_log(u3_atom); + u3_noun u3qi_rh_sin(u3_atom); + u3_noun u3qi_rh_cos(u3_atom); + u3_noun u3qi_rh_tan(u3_atom); + u3_noun u3qi_rh_atan(u3_atom); + u3_noun u3qi_rh_atan2(u3_atom, u3_atom); + u3_noun u3qi_rh_asin(u3_atom); + u3_noun u3qi_rh_acos(u3_atom); + u3_noun u3qi_rh_sqt(u3_atom); + u3_noun u3qi_rh_cbt(u3_atom); + u3_noun u3qi_rh_pow(u3_atom, u3_atom); + u3_noun u3qi_rh_pow_n(u3_atom, u3_atom); + u3_noun u3qi_rh_log2(u3_atom); + u3_noun u3qi_rh_log10(u3_atom); # define u3qfu_van_fan 28 # define u3qfu_van_rib 58 diff --git a/libmath/vere/noun/jets/w.h b/libmath/vere/noun/jets/w.h index ec031a7..7af379e 100644 --- a/libmath/vere/noun/jets/w.h +++ b/libmath/vere/noun/jets/w.h @@ -459,6 +459,21 @@ u3_noun u3wi_rs_pow_n(u3_noun); u3_noun u3wi_rs_log2(u3_noun); u3_noun u3wi_rs_log10(u3_noun); + u3_noun u3wi_rh_exp(u3_noun); + u3_noun u3wi_rh_log(u3_noun); + u3_noun u3wi_rh_sin(u3_noun); + u3_noun u3wi_rh_cos(u3_noun); + u3_noun u3wi_rh_tan(u3_noun); + u3_noun u3wi_rh_atan(u3_noun); + u3_noun u3wi_rh_atan2(u3_noun); + u3_noun u3wi_rh_asin(u3_noun); + u3_noun u3wi_rh_acos(u3_noun); + u3_noun u3wi_rh_sqt(u3_noun); + u3_noun u3wi_rh_cbt(u3_noun); + u3_noun u3wi_rh_pow(u3_noun); + u3_noun u3wi_rh_pow_n(u3_noun); + u3_noun u3wi_rh_log2(u3_noun); + u3_noun u3wi_rh_log10(u3_noun); #endif /* ifndef U3_JETS_W_H */ diff --git a/libmath/vere64/noun/jets/135/tree.c b/libmath/vere64/noun/jets/135/tree.c index 2392250..4c5c923 100644 --- a/libmath/vere64/noun/jets/135/tree.c +++ b/libmath/vere64/noun/jets/135/tree.c @@ -1014,9 +1014,45 @@ static u3j_core _135_non__math_rs_d[] = { "log-10", 7, _135_non__math_rs_log10_a, 0, no_hashes }, {} }; +// numerics math.hoon @rh transcendentals: non -> math -> rh -> +static u3j_harm _135_non__math_rh_exp_a[] = {{".2", u3wi_rh_exp}, {}}; +static u3j_harm _135_non__math_rh_log_a[] = {{".2", u3wi_rh_log}, {}}; +static u3j_harm _135_non__math_rh_sin_a[] = {{".2", u3wi_rh_sin}, {}}; +static u3j_harm _135_non__math_rh_cos_a[] = {{".2", u3wi_rh_cos}, {}}; +static u3j_harm _135_non__math_rh_tan_a[] = {{".2", u3wi_rh_tan}, {}}; +static u3j_harm _135_non__math_rh_atan_a[] = {{".2", u3wi_rh_atan}, {}}; +static u3j_harm _135_non__math_rh_atan2_a[] = {{".2", u3wi_rh_atan2}, {}}; +static u3j_harm _135_non__math_rh_asin_a[] = {{".2", u3wi_rh_asin}, {}}; +static u3j_harm _135_non__math_rh_acos_a[] = {{".2", u3wi_rh_acos}, {}}; +static u3j_harm _135_non__math_rh_sqt_a[] = {{".2", u3wi_rh_sqt}, {}}; +static u3j_harm _135_non__math_rh_cbt_a[] = {{".2", u3wi_rh_cbt}, {}}; +static u3j_harm _135_non__math_rh_pow_a[] = {{".2", u3wi_rh_pow}, {}}; +static u3j_harm _135_non__math_rh_pow_n_a[] = {{".2", u3wi_rh_pow_n}, {}}; +static u3j_harm _135_non__math_rh_log2_a[] = {{".2", u3wi_rh_log2}, {}}; +static u3j_harm _135_non__math_rh_log10_a[] = {{".2", u3wi_rh_log10}, {}}; +static u3j_core _135_non__math_rh_d[] = + { + { "exp", 7, _135_non__math_rh_exp_a, 0, no_hashes }, + { "log", 7, _135_non__math_rh_log_a, 0, no_hashes }, + { "sin", 7, _135_non__math_rh_sin_a, 0, no_hashes }, + { "cos", 7, _135_non__math_rh_cos_a, 0, no_hashes }, + { "tan", 7, _135_non__math_rh_tan_a, 0, no_hashes }, + { "atan", 7, _135_non__math_rh_atan_a, 0, no_hashes }, + { "atan2", 7, _135_non__math_rh_atan2_a, 0, no_hashes }, + { "asin", 7, _135_non__math_rh_asin_a, 0, no_hashes }, + { "acos", 7, _135_non__math_rh_acos_a, 0, no_hashes }, + { "sqt", 7, _135_non__math_rh_sqt_a, 0, no_hashes }, + { "cbt", 7, _135_non__math_rh_cbt_a, 0, no_hashes }, + { "pow", 7, _135_non__math_rh_pow_a, 0, no_hashes }, + { "pow-n", 7, _135_non__math_rh_pow_n_a, 0, no_hashes }, + { "log-2", 7, _135_non__math_rh_log2_a, 0, no_hashes }, + { "log-10", 7, _135_non__math_rh_log10_a, 0, no_hashes }, + {} + }; static u3j_core _135_non__math_d[] = { { "rd", 7, 0, _135_non__math_rd_d, no_hashes }, { "rs", 7, 0, _135_non__math_rs_d, no_hashes }, + { "rh", 7, 0, _135_non__math_rh_d, no_hashes }, {} }; diff --git a/libmath/vere64/noun/jets/i/math.c b/libmath/vere64/noun/jets/i/math.c index a9ed5ea..d691ce4 100644 --- a/libmath/vere64/noun/jets/i/math.c +++ b/libmath/vere64/noun/jets/i/math.c @@ -966,6 +966,52 @@ typedef int64_t c3_ds; return _rs_exp(prod.s); // %n kernel: exp(n*log x) } +/* =================================================================== +** @rh (half-precision) cores -- math.hoon ++rh. Every arm is +** narrow-sh(rs_fn(widen-hs(x))): widen f16->f32 (exact = f16_to_f32), +** compute in @rs, narrow f32->f16 (= f32_to_f16) honoring the door's r. +** The rs call inherits r too (composites honor it; kernels stay %n). No new +** algorithm cores -- the @rs cores are reused. Verified: the Hoon narrow-sh +** is bit-exact to f32_to_f16 in all four rounding modes. +** =================================================================== */ + + union half { + float16_t h; + uint16_t c; + }; + + // widen f16->f32 (exact), run an @rs core, narrow f32->f16 per _math_rnd. + // _math_rnd is the door's r (set by the wrapper): the rs composites honor it + // and the narrow rounds by it; the rs kernels run at near-even. + static inline float16_t _rh_1(float16_t x, float32_t (*fun)(float32_t)) { + softfloat_roundingMode = softfloat_round_near_even; + float32_t v = fun(f16_to_f32(x)); + softfloat_roundingMode = _math_rnd; + return f32_to_f16(v); + } + static inline float16_t _rh_2(float16_t x, float16_t n, + float32_t (*fun)(float32_t, float32_t)) { + softfloat_roundingMode = softfloat_round_near_even; + float32_t v = fun(f16_to_f32(x), f16_to_f32(n)); + softfloat_roundingMode = _math_rnd; + return f32_to_f16(v); + } + static float16_t _rh_exp(float16_t x) { return _rh_1(x, _rs_exp); } + static float16_t _rh_log(float16_t x) { return _rh_1(x, _rs_log); } + static float16_t _rh_sin(float16_t x) { return _rh_1(x, _rs_sin); } + static float16_t _rh_cos(float16_t x) { return _rh_1(x, _rs_cos); } + static float16_t _rh_tan(float16_t x) { return _rh_1(x, _rs_tan); } + static float16_t _rh_atan(float16_t x) { return _rh_1(x, _rs_atan); } + static float16_t _rh_asin(float16_t x) { return _rh_1(x, _rs_asin); } + static float16_t _rh_acos(float16_t x) { return _rh_1(x, _rs_acos); } + static float16_t _rh_sqt(float16_t x) { return _rh_1(x, _rs_sqt); } + static float16_t _rh_cbt(float16_t x) { return _rh_1(x, _rs_cbt); } + static float16_t _rh_log2(float16_t x) { return _rh_1(x, _rs_log2); } + static float16_t _rh_log10(float16_t x) { return _rh_1(x, _rs_log10); } + static float16_t _rh_atan2(float16_t y, float16_t x) { return _rh_2(y, x, _rs_atan2); } + static float16_t _rh_pow(float16_t x, float16_t n) { return _rh_2(x, n, _rs_pow); } + static float16_t _rh_pow_n(float16_t x, float16_t n) { return _rh_2(x, n, _rs_pow_n); } + #ifndef MATH_JET_HARNESS /* u3 ABI wrappers. Each transcendental forces round-near-even; the @rd door's @@ -1195,4 +1241,63 @@ typedef int64_t c3_ds; u3_noun u3qi_rs_pow_n(u3_atom x, u3_atom n) { softfloat_roundingMode=softfloat_round_near_even; return _rs_out(_rs_pow_n(_rs_in(x), _rs_in(n))); } u3_noun u3wi_rs_pow_n(u3_noun cor){ return _rs_jet2(cor, _rs_pow_n); } +/* @rh ABI wrappers. @rh is a 16-bit atom: read the low 16 bits of the chub, +** write the 16-bit result via chub (high bits zero -> normalizes). Same +** word-agnostic chub I/O as @rd/@rs. Wrappers set _math_rnd from the door's r +** (axis 60); the cores apply it to the rs composite ops and the f16 narrow. +*/ + static inline float16_t _rh_in(u3_atom a) { + union half s; s.c = (uint16_t)u3r_chub(0, a); return s.h; + } + static inline u3_noun _rh_out(float16_t v) { + union half s; s.h = v; { c3_d out = (c3_d)s.c; return u3i_chubs(1, &out); } + } + static u3_noun _rh_jet(u3_noun cor, float16_t (*fun)(float16_t)) { + u3_noun x = u3r_at(u3x_sam, cor); + if ( u3_none == x || c3n == u3ud(x) ) return u3m_bail(c3__exit); + _math_rnd = _rnd_of(u3r_at(60, cor)); + return _rh_out(fun(_rh_in(x))); + } + static u3_noun _rh_jet2(u3_noun cor, float16_t (*fun)(float16_t, float16_t)) { + u3_noun x, n; + if ( c3n == u3r_mean(cor, {u3x_sam_2, &x}, {u3x_sam_3, &n}) || + c3n == u3ud(x) || c3n == u3ud(n) ) { + return u3m_bail(c3__exit); + } + _math_rnd = _rnd_of(u3r_at(60, cor)); + return _rh_out(fun(_rh_in(x), _rh_in(n))); + } + + u3_noun u3qi_rh_exp(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_exp(_rh_in(a))); } + u3_noun u3wi_rh_exp(u3_noun cor) { return _rh_jet(cor, _rh_exp); } + u3_noun u3qi_rh_log(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_log(_rh_in(a))); } + u3_noun u3wi_rh_log(u3_noun cor) { return _rh_jet(cor, _rh_log); } + u3_noun u3qi_rh_sin(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_sin(_rh_in(a))); } + u3_noun u3wi_rh_sin(u3_noun cor) { return _rh_jet(cor, _rh_sin); } + u3_noun u3qi_rh_cos(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_cos(_rh_in(a))); } + u3_noun u3wi_rh_cos(u3_noun cor) { return _rh_jet(cor, _rh_cos); } + u3_noun u3qi_rh_tan(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_tan(_rh_in(a))); } + u3_noun u3wi_rh_tan(u3_noun cor) { return _rh_jet(cor, _rh_tan); } + u3_noun u3qi_rh_atan(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_atan(_rh_in(a))); } + u3_noun u3wi_rh_atan(u3_noun cor){ return _rh_jet(cor, _rh_atan); } + u3_noun u3qi_rh_asin(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_asin(_rh_in(a))); } + u3_noun u3wi_rh_asin(u3_noun cor){ return _rh_jet(cor, _rh_asin); } + u3_noun u3qi_rh_acos(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_acos(_rh_in(a))); } + u3_noun u3wi_rh_acos(u3_noun cor){ return _rh_jet(cor, _rh_acos); } + u3_noun u3qi_rh_sqt(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_sqt(_rh_in(a))); } + u3_noun u3wi_rh_sqt(u3_noun cor) { return _rh_jet(cor, _rh_sqt); } + u3_noun u3qi_rh_cbt(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_cbt(_rh_in(a))); } + u3_noun u3wi_rh_cbt(u3_noun cor) { return _rh_jet(cor, _rh_cbt); } + u3_noun u3qi_rh_log2(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_log2(_rh_in(a))); } + u3_noun u3wi_rh_log2(u3_noun cor){ return _rh_jet(cor, _rh_log2); } + u3_noun u3qi_rh_log10(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_log10(_rh_in(a))); } + u3_noun u3wi_rh_log10(u3_noun cor){ return _rh_jet(cor, _rh_log10); } + + u3_noun u3qi_rh_atan2(u3_atom y, u3_atom x) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_atan2(_rh_in(y), _rh_in(x))); } + u3_noun u3wi_rh_atan2(u3_noun cor){ return _rh_jet2(cor, _rh_atan2); } + u3_noun u3qi_rh_pow(u3_atom x, u3_atom n) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_pow(_rh_in(x), _rh_in(n))); } + u3_noun u3wi_rh_pow(u3_noun cor) { return _rh_jet2(cor, _rh_pow); } + u3_noun u3qi_rh_pow_n(u3_atom x, u3_atom n) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_pow_n(_rh_in(x), _rh_in(n))); } + u3_noun u3wi_rh_pow_n(u3_noun cor){ return _rh_jet2(cor, _rh_pow_n); } + #endif diff --git a/libmath/vere64/noun/jets/q.h b/libmath/vere64/noun/jets/q.h index 9d0cf00..654930a 100644 --- a/libmath/vere64/noun/jets/q.h +++ b/libmath/vere64/noun/jets/q.h @@ -320,6 +320,21 @@ u3_noun u3qi_rs_pow_n(u3_atom, u3_atom); u3_noun u3qi_rs_log2(u3_atom); u3_noun u3qi_rs_log10(u3_atom); + u3_noun u3qi_rh_exp(u3_atom); + u3_noun u3qi_rh_log(u3_atom); + u3_noun u3qi_rh_sin(u3_atom); + u3_noun u3qi_rh_cos(u3_atom); + u3_noun u3qi_rh_tan(u3_atom); + u3_noun u3qi_rh_atan(u3_atom); + u3_noun u3qi_rh_atan2(u3_atom, u3_atom); + u3_noun u3qi_rh_asin(u3_atom); + u3_noun u3qi_rh_acos(u3_atom); + u3_noun u3qi_rh_sqt(u3_atom); + u3_noun u3qi_rh_cbt(u3_atom); + u3_noun u3qi_rh_pow(u3_atom, u3_atom); + u3_noun u3qi_rh_pow_n(u3_atom, u3_atom); + u3_noun u3qi_rh_log2(u3_atom); + u3_noun u3qi_rh_log10(u3_atom); # define u3qfu_van_fan 28 # define u3qfu_van_rib 58 diff --git a/libmath/vere64/noun/jets/w.h b/libmath/vere64/noun/jets/w.h index ec031a7..7af379e 100644 --- a/libmath/vere64/noun/jets/w.h +++ b/libmath/vere64/noun/jets/w.h @@ -459,6 +459,21 @@ u3_noun u3wi_rs_pow_n(u3_noun); u3_noun u3wi_rs_log2(u3_noun); u3_noun u3wi_rs_log10(u3_noun); + u3_noun u3wi_rh_exp(u3_noun); + u3_noun u3wi_rh_log(u3_noun); + u3_noun u3wi_rh_sin(u3_noun); + u3_noun u3wi_rh_cos(u3_noun); + u3_noun u3wi_rh_tan(u3_noun); + u3_noun u3wi_rh_atan(u3_noun); + u3_noun u3wi_rh_atan2(u3_noun); + u3_noun u3wi_rh_asin(u3_noun); + u3_noun u3wi_rh_acos(u3_noun); + u3_noun u3wi_rh_sqt(u3_noun); + u3_noun u3wi_rh_cbt(u3_noun); + u3_noun u3wi_rh_pow(u3_noun); + u3_noun u3wi_rh_pow_n(u3_noun); + u3_noun u3wi_rh_log2(u3_noun); + u3_noun u3wi_rh_log10(u3_noun); #endif /* ifndef U3_JETS_W_H */ diff --git a/libmath/vere64/test/rd_check.c b/libmath/vere64/test/rd_check.c index 475d239..27275a1 100644 --- a/libmath/vere64/test/rd_check.c +++ b/libmath/vere64/test/rd_check.c @@ -43,8 +43,31 @@ static void emits(const char* nm, unsigned in, float32_t (*fun)(float32_t)) { printf("%-6s 0x%08x 0x%08x\n", nm, (unsigned)x.c, (unsigned)out.c); } +// narrow spike: f32 -> f16 via SoftFloat in each rounding mode; tag is the +// mode letter so the Hoon (~(narrow-sh rh [ ..]) ) can be compared. +static void emit_narrow(unsigned f32bits) { + union sing x; x.c = (uint32_t)f32bits; + const struct { char m; int sf; } modes[] = { + {'n', softfloat_round_near_even}, {'z', softfloat_round_minMag}, + {'u', softfloat_round_max}, {'d', softfloat_round_min} }; + for (unsigned k = 0; k < 4; k++) { + softfloat_roundingMode = modes[k].sf; + float16_t h = f32_to_f16(x.s); + union { float16_t h; uint16_t c; } o; o.h = h; + printf("narrow-%c 0x%08x 0x%04x\n", modes[k].m, (unsigned)x.c, (unsigned)o.c); + } + softfloat_roundingMode = softfloat_round_near_even; +} + int main(void) { softfloat_roundingMode = softfloat_round_near_even; + // --- @rh narrow spike: stress f32->f16 in all 4 modes --- + static const unsigned nrw[] = { + 0x3f800000, 0x40490fdb, 0xc0490fdb, 0x477fe000, 0x477ff000, 0x477ff001, + 0x47800000, 0x7f7fffff, 0xff7fffff, 0x33800000, 0x33000000, 0x33000001, + 0x387fc000, 0x38800000, 0x38801000, 0x33c00000, 0x7f800000, 0xff800000, + 0x7fc00000, 0x00000000, 0x80000000, 0x38ffe000, 0x477fefff }; + for (unsigned i = 0; i < sizeof nrw/sizeof nrw[0]; i++) emit_narrow(nrw[i]); // @rs exp: core + edges (expected from math.hoon tests/lib/math-exp.hoon) static const unsigned rsex[] = { 0x0, 0x3f000000, 0x3f800000, 0xbf800000, 0x40000000, 0x41200000, 0xc0a00000, 0x3dcccccd, 0x7f800000, 0xff800000, From 9ae1223be199df3ddd51d657bfed067005bca826 Mon Sep 17 00:00:00 2001 From: Sigilante Date: Fri, 12 Jun 2026 11:30:31 -0500 Subject: [PATCH 08/28] math: @rq foundation -- f128 exp core + rounding dispatch + tooling Establish the @rq (quad, 128-bit) jet pipeline, proven bit-exact on exp: - Two-chub float128_t marshalling (read u3r_chub(0/1) into v[0..1]); stays word-size-agnostic, sidestepping the c3_w*[n=2|4] divergence of rq.c. - This SoftFloat build has only pointer-based f128M_*; thin by-value wrapper inlines (_rqm/_rqa/_rqs/_rqd/_rqq/_rqeq/...) keep the cores as readable as the @rd ones. - _rq_exp: Cody-Waite + degree-24 minimax (25 f128 coeffs, extracted from the Hoon programmatically), bias 16383. Bit-exact to (exp:rq:math ...) for 1/2/-1/0.1 (verified on-ship + harness emit exp-q). - Rounding dispatch: thread r into the @rq door helper arms (sun/san/toi/drg/ grd/add/sub/mul/div/fma -> ~(op ^rq r)) so the composite arms honor r, as in @rd/@rs. -test %/tests/lib still ok=%.y (no regression). Remaining: the other 14 @rq cores (log/trig/atan/ainv/sqt/cbt/derived) + the rq wrappers, registration, and ~/ hints -- mechanical, same pattern. Co-Authored-By: Claude Opus 4.8 --- libmath/desk/lib/math.hoon | 20 +++---- libmath/vere/noun/jets/i/math.c | 88 +++++++++++++++++++++++++++++++ libmath/vere64/noun/jets/i/math.c | 88 +++++++++++++++++++++++++++++++ libmath/vere64/test/rd_check.c | 12 +++++ 4 files changed, 198 insertions(+), 10 deletions(-) diff --git a/libmath/desk/lib/math.hoon b/libmath/desk/lib/math.hoon index 3b64b25..27339cf 100644 --- a/libmath/desk/lib/math.hoon +++ b/libmath/desk/lib/math.hoon @@ -3133,7 +3133,7 @@ :: > (sun 1.000) :: .~~~1e3 :: Source - ++ sun sun:^rq + ++ sun ~(sun ^rq r) :: +san: @sd -> @rq :: :: Returns the floating-point atom of a signed integer atom. @@ -3143,7 +3143,7 @@ :: > (san -1) :: .~~~-1 :: Source - ++ san san:^rq + ++ san ~(san ^rq r) ::++ exp exp:^rq :: no pass-through because of exp function :: +toi: @rq -> @sd :: @@ -3154,7 +3154,7 @@ :: > (toi .~~~1.1) :: [~ --1] :: Source - ++ toi toi:^rq + ++ toi ~(toi ^rq r) :: +drg: @rq -> dn :: :: Returns the decimal form of a floating-point atom using the Dragon4 @@ -3165,7 +3165,7 @@ :: > (drg .~~~1.1) :: [%d s=%.y e=-1 a=11] :: Source - ++ drg drg:^rq + ++ drg ~(drg ^rq r) :: +grd: dn -> @rq :: :: Returns the floating-point atom of a decimal form. @@ -3175,7 +3175,7 @@ :: > (grd [%d s=%.y e=-1 a=11]) :: .~~~1.1 :: Source - ++ grd grd:^rq + ++ grd ~(grd ^rq r) :: :: Comparison :: @@ -3338,7 +3338,7 @@ :: > (add .~~~1 .~~~2) :: .~~~3 :: Source - ++ add add:^rq + ++ add ~(add ^rq r) :: +sub: [@rq @rq] -> @rq :: :: Returns the difference of two floating-point atoms. @@ -3346,7 +3346,7 @@ :: > (sub .~~~1 .~~~2) :: .~~~-1 :: Source - ++ sub sub:^rq + ++ sub ~(sub ^rq r) :: +mul: [@rq @rq] -> @rq :: :: Returns the product of two floating-point atoms. @@ -3354,7 +3354,7 @@ :: > (mul .~~~1 .~~~2) :: .~~~2 :: Source - ++ mul mul:^rq + ++ mul ~(mul ^rq r) :: +div: [@rq @rq] -> @rq :: :: Returns the quotient of two floating-point atoms. @@ -3362,7 +3362,7 @@ :: > (div .~~~1 .~~~2) :: .~~~0.5 :: Source - ++ div div:^rq + ++ div ~(div ^rq r) :: +fma: [@rq @rq @rq] -> @rq :: :: Returns the fused multiply-add of three floating-point atoms. @@ -3372,7 +3372,7 @@ :: > (fma .~~~2 .~~~3 .~~~4) :: .~~~10 :: Source - ++ fma fma:^rq + ++ fma ~(fma ^rq r) :: +sig: @rq -> ? :: :: Returns the sign of a floating-point atom. diff --git a/libmath/vere/noun/jets/i/math.c b/libmath/vere/noun/jets/i/math.c index c752f21..38d4844 100644 --- a/libmath/vere/noun/jets/i/math.c +++ b/libmath/vere/noun/jets/i/math.c @@ -1012,6 +1012,94 @@ typedef int64_t c3_ds; static float16_t _rh_pow(float16_t x, float16_t n) { return _rh_2(x, n, _rs_pow); } static float16_t _rh_pow_n(float16_t x, float16_t n) { return _rh_2(x, n, _rs_pow_n); } +/* =================================================================== +** @rq (quad, 128-bit) cores -- math.hoon ++rq. Native f128 algorithms (the +** widest type, no delegation): same reductions as @rd, higher-degree minimax +** in float128_t. Marshalling reads TWO chubs into float128_t.v[0..1], so it is +** word-size-agnostic -- the chub ABI sidesteps the c3_w*[n=2|4] divergence of +** the old rq.c. Composite arms honor the door's r via _math_rnd. +** =================================================================== */ + + union quad { + float128_t q; + c3_d w[2]; // w[0] = v[0] = low 64 bits, w[1] = v[1] = high 64 + }; + static inline float128_t _rq_bits(c3_d hi, c3_d lo) { + union quad u; u.w[0] = lo; u.w[1] = hi; return u.q; + } + // by-value wrappers over the pointer-based f128M_* ops (this SoftFloat build + // has no by-value f128_*). Compiler inlines these; keeps the cores readable. + static inline float128_t _rqm(float128_t a, float128_t b) { float128_t r; f128M_mul(&a,&b,&r); return r; } + static inline float128_t _rqa(float128_t a, float128_t b) { float128_t r; f128M_add(&a,&b,&r); return r; } + static inline float128_t _rqs(float128_t a, float128_t b) { float128_t r; f128M_sub(&a,&b,&r); return r; } + static inline float128_t _rqd(float128_t a, float128_t b) { float128_t r; f128M_div(&a,&b,&r); return r; } + static inline float128_t _rqq(float128_t a) { float128_t r; f128M_sqrt(&a,&r); return r; } + static inline int _rqeq(float128_t a, float128_t b) { return f128M_eq(&a,&b); } + static inline int _rqlt(float128_t a, float128_t b) { return f128M_lt(&a,&b); } + static inline int _rqle(float128_t a, float128_t b) { return f128M_le(&a,&b); } + static inline c3_ds _rqtoi(float128_t a, int m) { return (c3_ds)f128M_to_i64(&a, (uint_fast8_t)m, 0); } + static inline float128_t _rqi64(c3_ds n) { float128_t r; i64_to_f128M(n, &r); return r; } + static const c3_d _RQ_QNAN_HI = 0x7fff800000000000ULL; + static const c3_d _RQ_PINF_HI = 0x7fff000000000000ULL; + static const c3_d _RQ_NINF_HI = 0xffff000000000000ULL; + static inline float128_t _rq_neg(float128_t a) { // (sub .0 a) + return _rqs(_rq_bits(0,0), a); + } + +/* @rq exp -- math.hoon ++rq ++exp +** Cody-Waite x=k*ln2+r, exp=2^k*P(r), P a degree-24 minimax (f128). +*/ + // pow2(j) = 2^j as f128 bits: exp field (bits 112-126) = j+16383 + static inline float128_t _rq_pow2(c3_ds j) { + union quad u; u.w[0] = 0; u.w[1] = ((c3_d)(j + 16383)) << 48; return u.q; + } + static inline float128_t _rq_scale2(float128_t p, c3_ds k) { + if ( (k - 16384) >= 0 ) + return _rqm(_rqm(p, _rq_pow2(16383)), _rq_pow2(k - 16383)); + if ( !((k + 16382) >= 0) ) + return _rqm(_rqm(p, _rq_pow2(k + 112)), _rq_pow2(-112)); + return _rqm(p, _rq_pow2(k)); + } + static float128_t _rq_exp(float128_t x) { + // degree-24 minimax coeffs c0..c24 {lo, hi} (math.hoon ++rq ++exp) + static const c3_d cs[25][2] = { + {0x0000000000000000ULL,0x3fff000000000000ULL},{0x0000000000000000ULL,0x3fff000000000000ULL}, + {0x0000000000000000ULL,0x3ffe000000000000ULL},{0x5555555555555555ULL,0x3ffc555555555555ULL}, + {0x5555555555555555ULL,0x3ffa555555555555ULL},{0x1111111111111111ULL,0x3ff8111111111111ULL}, + {0x6c16c16c16c16c17ULL,0x3ff56c16c16c16c1ULL},{0xa01a01a01a01a3e8ULL,0x3ff2a01a01a01a01ULL}, + {0xa01a01a01a01a146ULL,0x3fefa01a01a01a01ULL},{0x38faac1c88a5a526ULL,0x3fec71de3a556c73ULL}, + {0xc72ef016d3d6e867ULL,0x3fe927e4fb7789f5ULL},{0x38fe748363c46e8bULL,0x3fe5ae64567f544eULL}, + {0x7b544dab18f475c5ULL,0x3fe21eed8eff8d89ULL},{0x97c9f3aebabb2423ULL,0x3fde6124613a86d0ULL}, + {0xd20b83c7f94d17d8ULL,0x3fda93974a8c07c9ULL},{0xf5f4284f0d74f9e7ULL,0x3fd6ae7f3e733b81ULL}, + {0xf417b4d27c5f92a9ULL,0x3fd2ae7f3e733b81ULL},{0x6a419e674779c97cULL,0x3fce952c77030a99ULL}, + {0x0466ff8c8b42b3dfULL,0x3fca6827863b97b5ULL},{0x874b7a686d819241ULL,0x3fc62f49b469f892ULL}, + {0xbb3b32a11bb5f139ULL,0x3fc1e542ba427463ULL},{0xc93890ff9ab55cbbULL,0x3fbd71b8db9f7f73ULL}, + {0x6efc0717eae785a1ULL,0x3fb90ce38aab7bd7ULL},{0xcb3f4f7edfaa2666ULL,0x3fb47693274bab2aULL}, + {0x61cb0e23655d47cbULL,0x3faff3629154e0a7ULL}, + }; + union quad r0; r0.q = x; + if ( !_rqeq(x, x) ) return _rq_bits(_RQ_QNAN_HI, 0); // NaN + if ( r0.w[1]==_RQ_PINF_HI && r0.w[0]==0 ) return x; // +inf + if ( r0.w[1]==_RQ_NINF_HI && r0.w[0]==0 ) return _rq_bits(0,0); // -inf -> 0 + + float128_t log2e = _rq_bits(0x3fff71547652b82fULL, 0xe1777d0ffda0d23aULL); + float128_t ln2hi = _rq_bits(0x3ffe62e42fefa39eULL, 0xf35793c800000000ULL); + float128_t ln2lo = _rq_bits(0xbfad319ff0342542ULL, 0xfc32f366359d274aULL); + + c3_ds k = _rqtoi(_rqm(x, log2e), softfloat_round_near_even); + if ( (k - 16385) >= 0 ) return _rq_bits(_RQ_PINF_HI, 0); // overflow -> inf + if ( !((k + 16494) >= 0) ) return _rq_bits(0, 0); // underflow -> 0 + + float128_t ka = _rqi64((c3_ds)(k < 0 ? -k : k)); + float128_t kf = (k >= 0) ? ka : _rq_neg(ka); + float128_t rr = _rqs( _rqs(x, _rqm(kf, ln2hi)), _rqm(kf, ln2lo) ); + + float128_t p = _rq_bits(0,0); + for ( int i = 25; i-- != 0; ) // Horner over flop(cs): c24..c0 + p = _rqa(_rqm(p, rr), _rq_bits(cs[i][1], cs[i][0])); + return _rq_scale2(p, k); + } + #ifndef MATH_JET_HARNESS /* u3 ABI wrappers. Each transcendental forces round-near-even; the @rd door's diff --git a/libmath/vere64/noun/jets/i/math.c b/libmath/vere64/noun/jets/i/math.c index d691ce4..376f2ae 100644 --- a/libmath/vere64/noun/jets/i/math.c +++ b/libmath/vere64/noun/jets/i/math.c @@ -1012,6 +1012,94 @@ typedef int64_t c3_ds; static float16_t _rh_pow(float16_t x, float16_t n) { return _rh_2(x, n, _rs_pow); } static float16_t _rh_pow_n(float16_t x, float16_t n) { return _rh_2(x, n, _rs_pow_n); } +/* =================================================================== +** @rq (quad, 128-bit) cores -- math.hoon ++rq. Native f128 algorithms (the +** widest type, no delegation): same reductions as @rd, higher-degree minimax +** in float128_t. Marshalling reads TWO chubs into float128_t.v[0..1], so it is +** word-size-agnostic -- the chub ABI sidesteps the c3_w*[n=2|4] divergence of +** the old rq.c. Composite arms honor the door's r via _math_rnd. +** =================================================================== */ + + union quad { + float128_t q; + c3_d w[2]; // w[0] = v[0] = low 64 bits, w[1] = v[1] = high 64 + }; + static inline float128_t _rq_bits(c3_d hi, c3_d lo) { + union quad u; u.w[0] = lo; u.w[1] = hi; return u.q; + } + // by-value wrappers over the pointer-based f128M_* ops (this SoftFloat build + // has no by-value f128_*). Compiler inlines these; keeps the cores readable. + static inline float128_t _rqm(float128_t a, float128_t b) { float128_t r; f128M_mul(&a,&b,&r); return r; } + static inline float128_t _rqa(float128_t a, float128_t b) { float128_t r; f128M_add(&a,&b,&r); return r; } + static inline float128_t _rqs(float128_t a, float128_t b) { float128_t r; f128M_sub(&a,&b,&r); return r; } + static inline float128_t _rqd(float128_t a, float128_t b) { float128_t r; f128M_div(&a,&b,&r); return r; } + static inline float128_t _rqq(float128_t a) { float128_t r; f128M_sqrt(&a,&r); return r; } + static inline int _rqeq(float128_t a, float128_t b) { return f128M_eq(&a,&b); } + static inline int _rqlt(float128_t a, float128_t b) { return f128M_lt(&a,&b); } + static inline int _rqle(float128_t a, float128_t b) { return f128M_le(&a,&b); } + static inline c3_ds _rqtoi(float128_t a, int m) { return (c3_ds)f128M_to_i64(&a, (uint_fast8_t)m, 0); } + static inline float128_t _rqi64(c3_ds n) { float128_t r; i64_to_f128M(n, &r); return r; } + static const c3_d _RQ_QNAN_HI = 0x7fff800000000000ULL; + static const c3_d _RQ_PINF_HI = 0x7fff000000000000ULL; + static const c3_d _RQ_NINF_HI = 0xffff000000000000ULL; + static inline float128_t _rq_neg(float128_t a) { // (sub .0 a) + return _rqs(_rq_bits(0,0), a); + } + +/* @rq exp -- math.hoon ++rq ++exp +** Cody-Waite x=k*ln2+r, exp=2^k*P(r), P a degree-24 minimax (f128). +*/ + // pow2(j) = 2^j as f128 bits: exp field (bits 112-126) = j+16383 + static inline float128_t _rq_pow2(c3_ds j) { + union quad u; u.w[0] = 0; u.w[1] = ((c3_d)(j + 16383)) << 48; return u.q; + } + static inline float128_t _rq_scale2(float128_t p, c3_ds k) { + if ( (k - 16384) >= 0 ) + return _rqm(_rqm(p, _rq_pow2(16383)), _rq_pow2(k - 16383)); + if ( !((k + 16382) >= 0) ) + return _rqm(_rqm(p, _rq_pow2(k + 112)), _rq_pow2(-112)); + return _rqm(p, _rq_pow2(k)); + } + static float128_t _rq_exp(float128_t x) { + // degree-24 minimax coeffs c0..c24 {lo, hi} (math.hoon ++rq ++exp) + static const c3_d cs[25][2] = { + {0x0000000000000000ULL,0x3fff000000000000ULL},{0x0000000000000000ULL,0x3fff000000000000ULL}, + {0x0000000000000000ULL,0x3ffe000000000000ULL},{0x5555555555555555ULL,0x3ffc555555555555ULL}, + {0x5555555555555555ULL,0x3ffa555555555555ULL},{0x1111111111111111ULL,0x3ff8111111111111ULL}, + {0x6c16c16c16c16c17ULL,0x3ff56c16c16c16c1ULL},{0xa01a01a01a01a3e8ULL,0x3ff2a01a01a01a01ULL}, + {0xa01a01a01a01a146ULL,0x3fefa01a01a01a01ULL},{0x38faac1c88a5a526ULL,0x3fec71de3a556c73ULL}, + {0xc72ef016d3d6e867ULL,0x3fe927e4fb7789f5ULL},{0x38fe748363c46e8bULL,0x3fe5ae64567f544eULL}, + {0x7b544dab18f475c5ULL,0x3fe21eed8eff8d89ULL},{0x97c9f3aebabb2423ULL,0x3fde6124613a86d0ULL}, + {0xd20b83c7f94d17d8ULL,0x3fda93974a8c07c9ULL},{0xf5f4284f0d74f9e7ULL,0x3fd6ae7f3e733b81ULL}, + {0xf417b4d27c5f92a9ULL,0x3fd2ae7f3e733b81ULL},{0x6a419e674779c97cULL,0x3fce952c77030a99ULL}, + {0x0466ff8c8b42b3dfULL,0x3fca6827863b97b5ULL},{0x874b7a686d819241ULL,0x3fc62f49b469f892ULL}, + {0xbb3b32a11bb5f139ULL,0x3fc1e542ba427463ULL},{0xc93890ff9ab55cbbULL,0x3fbd71b8db9f7f73ULL}, + {0x6efc0717eae785a1ULL,0x3fb90ce38aab7bd7ULL},{0xcb3f4f7edfaa2666ULL,0x3fb47693274bab2aULL}, + {0x61cb0e23655d47cbULL,0x3faff3629154e0a7ULL}, + }; + union quad r0; r0.q = x; + if ( !_rqeq(x, x) ) return _rq_bits(_RQ_QNAN_HI, 0); // NaN + if ( r0.w[1]==_RQ_PINF_HI && r0.w[0]==0 ) return x; // +inf + if ( r0.w[1]==_RQ_NINF_HI && r0.w[0]==0 ) return _rq_bits(0,0); // -inf -> 0 + + float128_t log2e = _rq_bits(0x3fff71547652b82fULL, 0xe1777d0ffda0d23aULL); + float128_t ln2hi = _rq_bits(0x3ffe62e42fefa39eULL, 0xf35793c800000000ULL); + float128_t ln2lo = _rq_bits(0xbfad319ff0342542ULL, 0xfc32f366359d274aULL); + + c3_ds k = _rqtoi(_rqm(x, log2e), softfloat_round_near_even); + if ( (k - 16385) >= 0 ) return _rq_bits(_RQ_PINF_HI, 0); // overflow -> inf + if ( !((k + 16494) >= 0) ) return _rq_bits(0, 0); // underflow -> 0 + + float128_t ka = _rqi64((c3_ds)(k < 0 ? -k : k)); + float128_t kf = (k >= 0) ? ka : _rq_neg(ka); + float128_t rr = _rqs( _rqs(x, _rqm(kf, ln2hi)), _rqm(kf, ln2lo) ); + + float128_t p = _rq_bits(0,0); + for ( int i = 25; i-- != 0; ) // Horner over flop(cs): c24..c0 + p = _rqa(_rqm(p, rr), _rq_bits(cs[i][1], cs[i][0])); + return _rq_scale2(p, k); + } + #ifndef MATH_JET_HARNESS /* u3 ABI wrappers. Each transcendental forces round-near-even; the @rd door's diff --git a/libmath/vere64/test/rd_check.c b/libmath/vere64/test/rd_check.c index 27275a1..8d8c8e5 100644 --- a/libmath/vere64/test/rd_check.c +++ b/libmath/vere64/test/rd_check.c @@ -61,6 +61,18 @@ static void emit_narrow(unsigned f32bits) { int main(void) { softfloat_roundingMode = softfloat_round_near_even; + // --- @rq exp probe: print hi.lo of _rq_exp(hi,lo) --- + { struct { c3_d hi, lo; } qx[] = { + {0x3fff000000000000ULL,0}, {0x4000000000000000ULL,0}, {0,0}, + {0xbfff000000000000ULL,0}, {0x4002000000000000ULL,0}, // -1, ~ exp args + {0x3ffb999999999999ULL,0x999999999999999aULL} }; // 0.1 + for (unsigned i=0;if16 in all 4 modes --- static const unsigned nrw[] = { 0x3f800000, 0x40490fdb, 0xc0490fdb, 0x477fe000, 0x477ff000, 0x477ff001, From 39c124f9aa5afcbf8e38aac32c7ae0f21930c594 Mon Sep 17 00:00:00 2001 From: Sigilante Date: Fri, 12 Jun 2026 11:49:03 -0500 Subject: [PATCH 09/28] math: @rq composites honor the door rounding mode Fix the @rq pow/pow-n/atan2 arms to use the bare door ops (mul/div/add/sub/toi/ san) instead of hardcoded ~(op ^rq %n), so they honor the door's r like the @rd/@rs composites do (tan already used a bare div). The transcendental kernels and log-2/log-10/lr keep their explicit %n, matching @rd/@rs. Verified: @rq div(1,3) gives ...5556 at %u vs ...5555 at %d/%n (honors r); full -test %/tests/lib still ok=%.y (the math-rq tests use %n doors, where bare ops == the old explicit %n, so no regression). Co-Authored-By: Claude Opus 4.8 --- libmath/desk/lib/math.hoon | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/libmath/desk/lib/math.hoon b/libmath/desk/lib/math.hoon index 27339cf..0e41132 100644 --- a/libmath/desk/lib/math.hoon +++ b/libmath/desk/lib/math.hoon @@ -3798,11 +3798,11 @@ :: ++ atan2 |= [y=@rq x=@rq] ^- @rq - ?: (~(gth ^rq %n) x `@rq`0x0) (atan (~(div ^rq %n) y x)) - ?: &((~(lth ^rq %n) x `@rq`0x0) (~(gte ^rq %n) y `@rq`0x0)) (~(add ^rq %n) (atan (~(div ^rq %n) y x)) `@rq`0x4000.921f.b544.42d1.8469.898c.c517.01b8) - ?: &((~(lth ^rq %n) x `@rq`0x0) (~(lth ^rq %n) y `@rq`0x0)) (~(sub ^rq %n) (atan (~(div ^rq %n) y x)) `@rq`0x4000.921f.b544.42d1.8469.898c.c517.01b8) - ?: &(=(`@rq`0x0 x) (~(gth ^rq %n) y `@rq`0x0)) `@rq`0x3fff.921f.b544.42d1.8469.898c.c517.01b8 - ?: &(=(`@rq`0x0 x) (~(lth ^rq %n) y `@rq`0x0)) `@rq`0xbfff.921f.b544.42d1.8469.898c.c517.01b8 + ?: (gth x `@rq`0x0) (atan (div y x)) + ?: &((lth x `@rq`0x0) (gte y `@rq`0x0)) (add (atan (div y x)) `@rq`0x4000.921f.b544.42d1.8469.898c.c517.01b8) + ?: &((lth x `@rq`0x0) (lth y `@rq`0x0)) (sub (atan (div y x)) `@rq`0x4000.921f.b544.42d1.8469.898c.c517.01b8) + ?: &(=(`@rq`0x0 x) (gth y `@rq`0x0)) `@rq`0x3fff.921f.b544.42d1.8469.898c.c517.01b8 + ?: &(=(`@rq`0x0 x) (lth y `@rq`0x0)) `@rq`0xbfff.921f.b544.42d1.8469.898c.c517.01b8 `@rq`0x0 :: +pow-n: [@rq @rq] -> @rq @@ -3817,11 +3817,11 @@ ++ pow-n |= [x=@rq n=@rq] ^- @rq ?: =(n `@rq`0x0) `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000 - =/ i (need (~(toi ^rq %n) n)) + =/ i (need (toi n)) =/ p `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000 |- ^- @rq ?: =(i --0) p - $(i (dif:si i --1), p (~(mul ^rq %n) p x)) + $(i (dif:si i --1), p (mul p x)) :: +log: @rq -> @rq :: :: Returns the natural logarithm of a floating-point atom. @@ -3954,9 +3954,9 @@ :: Source ++ pow |= [x=@rq n=@rq] ^- @rq - ?: &(=(n (~(san ^rq %n) (need (~(toi ^rq %n) n)))) (~(gth ^rq %n) n `@rq`0x0)) + ?: &(=(n (san (need (toi n)))) (gth n `@rq`0x0)) (pow-n x n) - (exp (~(mul ^rq %n) n (log x))) + (exp (mul n (log x))) :: +sqrt: @rq -> @rq :: :: Returns the square root of a floating-point atom. From 51b9fb2a9157df6e523b25f9a6c219221ee0d34a Mon Sep 17 00:00:00 2001 From: Sigilante Date: Fri, 12 Jun 2026 12:17:04 -0500 Subject: [PATCH 10/28] math: README -- rationale for why transcendental kernels hardcode round-nearest Explain why a correct/faithful transcendental fixes its internal arithmetic to round-nearest-even and takes no rounding-mode axis (the faithfulness bound is defined w.r.t. nearest; directed-rounding the true result is the Table-Maker's Dilemma), while the door's r governs only the composite arithmetic that assembles already-rounded kernel outputs. Co-Authored-By: Claude Opus 4.8 --- libmath/vere64/README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/libmath/vere64/README.md b/libmath/vere64/README.md index 2400713..e04cd97 100644 --- a/libmath/vere64/README.md +++ b/libmath/vere64/README.md @@ -45,6 +45,30 @@ from the door's `r` (gate **axis 60**: sample `[r rtol]` → door-axis 12 → `near_even`/`max`/`min`/`minMag`, and brackets only the composite bare ops; kernel calls run at `near_even`. +#### Why the kernels hardcode round-nearest-even (no rounding axis) +A faithful transcendental promises that its output is the *true* value +`exp(x)`/`log(x)`/… rounded to ≤1 ULP (correctly rounded = ≤½ ULP). That promise +is defined **with respect to round-to-nearest**: the minimax coefficients, the +argument reduction, and the whole error budget are derived so the polynomial lands +within that bound *under nearest rounding*. Round-nearest-even is therefore not a +free parameter — it is part of the function's definition. + +You cannot get directed rounding by simply flipping the internal ops to, say, +round-toward-zero. That yields the *approximation's* accumulated directed-rounding +error, not "the true `exp(x)` rounded toward zero" — it can be many ULPs off and +non-monotonic. Correctly directed-rounding a transcendental requires resolving the +true result to more precision than the output, just to know which way it falls at +the rounding boundary (the Table-Maker's Dilemma) — a far harder problem this +library does not attempt. So a correctly/faithfully-rounded transcendental is a +function of `x` alone: it fixes its internal arithmetic to nearest-even and takes +**no** rounding-mode axis. + +The door's `r` only governs the *composite* arithmetic that assembles already- +rounded kernel outputs — `pow = exp(n·log x)` (the `n·log x` multiply), `atan2`'s +`div`/`±π`, `tan = sin/cos`'s final `div`, `pow-n`'s repeated `mul`. Those are +ordinary exactly-rounded operations where honoring `r` is well-defined and useful. +The jet matches the Hoon op-for-op: nearest in the kernels, `r` in the composites. + Only the **135** kelvin tree is vendored: the stock test ships (`~dev`, fresh fakeships from `brass.pill`) are `hoon-version` 135, and that is where these jets fire. Apply to 136/137 as well if a target ship runs those. From 4529847922120fc436fe7cc8a9fc29dd97b77c32 Mon Sep 17 00:00:00 2001 From: Sigilante Date: Fri, 12 Jun 2026 12:47:34 -0500 Subject: [PATCH 11/28] math: pow-n -- reject negative/non-integer; @rh native; @rq guarded - @rq pow-n was missing the `?> &((gth n .0) (is-int n))` guard that @rd/@rs have, so e.g. pow-n(2,-2) returned garbage (8.0) via its @s counter loop. Give it the same guard + float-countdown structure as @rd/@rs; negatives/non-integers now crash loudly instead of returning nonsense. - @rh pow-n was delegating to @rs (widen->rs pow-n->narrow) -- a cross-door call. Make it native @rh repeated-multiply (it's exact integer multiplication, no polynomial, so no need for @rs). Threads the @rh door helpers for this. pow-n stays public (Saloon's %pow-n array op dispatches to pow-n:rX:math). Verified on-ship: pow-n(2,3)=8 (@rq and @rh), pow-n(2,-2) now rejects; -test ok=%.y. Co-Authored-By: Claude Opus 4.8 --- libmath/desk/lib/math.hoon | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/libmath/desk/lib/math.hoon b/libmath/desk/lib/math.hoon index 0e41132..c940b71 100644 --- a/libmath/desk/lib/math.hoon +++ b/libmath/desk/lib/math.hoon @@ -2392,7 +2392,7 @@ :: > (sun 1.000) :: .~~1e3 :: Source - ++ sun sun:^rh + ++ sun ~(sun ^rh r) :: +san: @sd -> @rh :: :: Returns the floating-point atom of a signed integer atom. @@ -2402,7 +2402,7 @@ :: > (san -1) :: .~-1 :: Source - ++ san san:^rh + ++ san ~(san ^rh r) ::++ exp exp:^rh :: no pass-through because of exp function :: +toi: @rh -> @sd :: @@ -2413,7 +2413,7 @@ :: > (toi .~~1.1) :: [~ --1] :: Source - ++ toi toi:^rh + ++ toi ~(toi ^rh r) :: +drg: @rh -> dn :: :: Returns the decimal form of a floating-point atom using the Dragon4 @@ -2424,7 +2424,7 @@ :: > (drg .~~1.1) :: [%d s=%.y e=-1 a=11] :: Source - ++ drg drg:^rh + ++ drg ~(drg ^rh r) :: +grd: dn -> @rh :: :: Returns the floating-point atom of a decimal form. @@ -2434,7 +2434,7 @@ :: > (grd [%d s=%.y e=-1 a=11]) :: .~~1.1 :: Source - ++ grd grd:^rh + ++ grd ~(grd ^rh r) :: :: Comparison :: @@ -2595,7 +2595,7 @@ :: > (add .~~1 .~~2) :: .~~3 :: Source - ++ add add:^rh + ++ add ~(add ^rh r) :: +sub: [@rh @rh] -> @rh :: :: Returns the difference of two floating-point atoms. @@ -2603,7 +2603,7 @@ :: > (sub .~~1 .~~2) :: .~~-1 :: Source - ++ sub sub:^rh + ++ sub ~(sub ^rh r) :: +mul: [@rh @rh] -> @rh :: :: Returns the product of two floating-point atoms. @@ -2611,7 +2611,7 @@ :: > (mul .~~1 .~~2) :: .~~2 :: Source - ++ mul mul:^rh + ++ mul ~(mul ^rh r) :: +div: [@rh @rh] -> @rh :: :: Returns the quotient of two floating-point atoms. @@ -2619,7 +2619,7 @@ :: > (div .~~1 .~~2) :: .~~0.5 :: Source - ++ div div:^rh + ++ div ~(div ^rh r) :: +fma: [@rh @rh @rh] -> @rh :: :: Returns the fused multiply-add of three floating-point atoms. @@ -2629,7 +2629,7 @@ :: > (fma .~~2 .~~3 .~~4) :: .~~10 :: Source - ++ fma fma:^rh + ++ fma ~(fma ^rh r) :: +sig: @rh -> ? :: :: Returns the sign of a floating-point atom. @@ -2887,8 +2887,15 @@ :: Source ++ pow-n ~/ %pow-n + :: native @rh repeated multiply (not via @rs); positive integer n only. |= [x=@rh n=@rh] ^- @rh - `@rh`(narrow-sh (~(pow-n rs [r .1e-5]) `@rs`(widen-hs x) `@rs`(widen-hs n))) + ?: =(n `@rh`0x0) `@rh`0x3c00 + ?> &((gth n `@rh`0x0) (is-int n)) + =/ p x + |- ^- @rh + ?: (lth n `@rh`0x4000) + p + $(n (sub n `@rh`0x3c00), p (mul p x)) :: +log: @rh -> @rh :: :: Returns the natural logarithm of a floating-point atom. @@ -3817,11 +3824,12 @@ ++ pow-n |= [x=@rq n=@rq] ^- @rq ?: =(n `@rq`0x0) `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000 - =/ i (need (toi n)) - =/ p `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000 + ?> &((gth n `@rq`0x0) (is-int n)) + =/ p x |- ^- @rq - ?: =(i --0) p - $(i (dif:si i --1), p (mul p x)) + ?: (lth n `@rq`0x4000.0000.0000.0000.0000.0000.0000.0000) + p + $(n (sub n `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000), p (mul p x)) :: +log: @rq -> @rq :: :: Returns the natural logarithm of a floating-point atom. From d3f75f1e6adb77f7dea443b946c2204c50a3a44f Mon Sep 17 00:00:00 2001 From: Sigilante Date: Fri, 12 Jun 2026 15:38:06 -0500 Subject: [PATCH 12/28] math: native f16 @rh exp + log (no @rs delegation) Begin the @rh-native rewrite (no cross-door @rs calls). exp and log now compute natively in f16 with derived half-precision minimax (cheb_check.py retargeted to f16, mpmath-designed, exhaustively verified <=1 ULP): - exp: Cody-Waite + deg-4 minimax. LOG2E=0x3dc5 LN2HI=0x3980 LN2LO=0x1dc8, c0..c4=0x3c00 0x3c00 0x3800 0x3160 0x295c. Two-branch scale2 (overflow split k>=16, subnormal split k<-14; f16 can't use 2^24 like @rs -- uses 2^11/2^10), overflow k>=17, underflow k<=-25. - log: 2^e*m reduction + deg-1 atanh [0x3555,0x3266]. SQRT2=0x3da8, subnormal pre-mul 2^10 (not 2^24). Both explicit %n throughout (kernels take no rounding axis) -- which fixes a real bug the old delegating arms had: narrow-sh honored the door's r, so the default %z bunt leaked into exp/log (e.g. exp(1) gave 0x416f toward-zero instead of the correct nearest 0x4170). -test %/tests/lib/math-rh ok=%.y. (Native @rh jets + remaining 11 arms still to come; binary still has the old delegating jets, so jetted exp:rh/log:rh lag the Hoon until rebuilt.) Co-Authored-By: Claude Opus 4.8 --- libmath/desk/lib/math.hoon | 59 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 3 deletions(-) diff --git a/libmath/desk/lib/math.hoon b/libmath/desk/lib/math.hoon index c940b71..5533662 100644 --- a/libmath/desk/lib/math.hoon +++ b/libmath/desk/lib/math.hoon @@ -2766,9 +2766,36 @@ (con s (^add mant ?:(rup 1 0))) ++ exp ~/ %exp - :: compute in @rs, round to f16 (see +narrow-sh). + :: native f16: Cody-Waite x=k*ln2+r, exp(x)=2^k*P(r), deg-4 minimax (<=1 ULP). |= x=@rh ^- @rh - `@rh`(narrow-sh (~(exp rs [r .1e-5]) `@rs`(widen-hs x))) + =/ pow2 |=(j=@s `@rh`(lsh [0 10] (abs:si (sum:si j --15)))) + =/ scale2 + |= [p=@rh k=@s] ^- @rh + ?: (syn:si (dif:si k --16)) :: k>=16: (p*2^15)*2^(k-15) + (~(mul ^rh %n) (~(mul ^rh %n) p (pow2 --15)) (pow2 (dif:si k --15))) + ?: !(syn:si (sum:si k --14)) :: k<-14: (p*2^(k+11))*2^-11 + (~(mul ^rh %n) (~(mul ^rh %n) p (pow2 (sum:si k --11))) (pow2 -11)) + (~(mul ^rh %n) p (pow2 k)) + ?: !(~(equ ^rh %n) x x) `@rh`0x7e00 :: exp(NaN) -> NaN + ?: =(x `@rh`0x7c00) `@rh`0x7c00 :: exp(+inf) -> inf + ?: =(x `@rh`0xfc00) `@rh`0x0 :: exp(-inf) -> 0 + =/ log2e `@rh`0x3dc5 + =/ ln2hi `@rh`0x3980 + =/ ln2lo `@rh`0x1dc8 + =/ k=@s (need (~(toi ^rh %n) (~(mul ^rh %n) x log2e))) + ?: (syn:si (dif:si k --17)) `@rh`0x7c00 :: overflow -> inf + ?: !(syn:si (sum:si k --24)) `@rh`0x0 :: underflow -> 0 + =/ ka (~(sun ^rh %n) (abs:si k)) + =/ kf ?:((syn:si k) ka (~(sub ^rh %n) `@rh`0x0 ka)) + =/ r + %- ~(sub ^rh %n) + :- (~(sub ^rh %n) x (~(mul ^rh %n) kf ln2hi)) + (~(mul ^rh %n) kf ln2lo) + =/ cs=(list @rh) + :~ `@rh`0x3c00 `@rh`0x3c00 `@rh`0x3800 `@rh`0x3160 `@rh`0x295c + == + =/ p (roll (flop cs) |=([c=@rh acc=@rh] (~(add ^rh %n) (~(mul ^rh %n) acc r) c))) + (scale2 p k) :: +sin: @rh -> @rh :: :: Returns the sine of a floating-point atom. @@ -2908,8 +2935,34 @@ :: .~~0.6904 ++ log ~/ %log + :: native f16: x=2^e*m reduction (m in [sqrt(1/2),sqrt(2))) + deg-1 atanh. |= x=@rh ^- @rh - `@rh`(narrow-sh (~(log rs [r .1e-5]) `@rs`(widen-hs x))) + ?: !(~(equ ^rh %n) x x) `@rh`0x7e00 :: log(NaN) -> NaN + ?: =(x `@rh`0x7c00) `@rh`0x7c00 :: log(+inf) -> inf + ?: |(=(x `@rh`0x0) =(x `@rh`0x8000)) `@rh`0xfc00 :: log(+-0) -> -inf + ?: =(1 (rsh [0 15] x)) `@rh`0x7e00 :: log(x<0) -> NaN + =/ sub =(0 (dis 0x1f (rsh [0 10] x))) :: subnormal? + =/ xx ?:(sub (~(mul ^rh %n) x `@rh`0x6400) x) :: *2^10 + =/ ae ?:(sub -10 --0) + =/ b `@`xx + =/ ef (dif:si (new:si %.y (dis 0x1f (rsh [0 10] b))) --15) + =/ m `@rh`(con (dis b 0x3ff) 0x3c00) + =/ big (~(gte ^rh %n) m `@rh`0x3da8) :: m >= sqrt(2) + =? m big (~(mul ^rh %n) m `@rh`0x3800) :: m * 0.5 + =? ef big (sum:si ef --1) + =. ef (sum:si ef ae) + =/ f (~(sub ^rh %n) m `@rh`0x3c00) + =/ s (~(div ^rh %n) f (~(add ^rh %n) m `@rh`0x3c00)) + =/ z (~(mul ^rh %n) s s) + =/ cs=(list @rh) :~(`@rh`0x3555 `@rh`0x3266) + =/ p2 (roll (flop cs) |=([c=@rh acc=@rh] (~(add ^rh %n) (~(mul ^rh %n) acc z) c))) + =/ r (~(mul ^rh %n) (~(add ^rh %n) z z) p2) + =/ l1 (~(sub ^rh %n) f (~(mul ^rh %n) s (~(sub ^rh %n) f r))) + =/ efa (~(sun ^rh %n) (abs:si ef)) + =/ ef-f ?:((syn:si ef) efa (~(sub ^rh %n) `@rh`0x0 efa)) + =/ hi (~(mul ^rh %n) ef-f `@rh`0x3980) :: e*ln2hi + =/ lo (~(mul ^rh %n) ef-f `@rh`0x1dc8) :: e*ln2lo + (~(add ^rh %n) hi (~(add ^rh %n) l1 lo)) :: +log-10: @rh -> @rh :: :: Returns the base-10 logarithm of a floating-point atom. From f227909fd5c92f095e5815a8dfdafd32ecd4cc2e Mon Sep 17 00:00:00 2001 From: Sigilante Date: Fri, 12 Jun 2026 15:43:38 -0500 Subject: [PATCH 13/28] math: native f16 @rh sin/cos + rh-trig sub-core Native f16 sin/cos via fdlibm ksin/kcos kernels (2 coeffs each: sc=[0xb155, 0x2044] cc=[0x2955,0x95b0]) + 3-part pi/2 reduction (INVPIO2=0x3918, P=0x3e00/ 0x2c80/0x0fed). All explicit %n. Replaces the @rs delegation. -test math-rh ok=%.y. Co-Authored-By: Claude Opus 4.8 --- libmath/desk/lib/math.hoon | 54 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/libmath/desk/lib/math.hoon b/libmath/desk/lib/math.hoon index 5533662..395ddcf 100644 --- a/libmath/desk/lib/math.hoon +++ b/libmath/desk/lib/math.hoon @@ -2809,8 +2809,13 @@ :: Source ++ sin ~/ %sin + :: native f16: q*pi/2 reduction + fdlibm sin/cos kernels (see +rh-trig). |= x=@rh ^- @rh - `@rh`(narrow-sh (~(sin rs [r .1e-5]) `@rs`(widen-hs x))) + ?: !(~(equ ^rh %n) x x) `@rh`0x7e00 :: NaN + ?: |(=(x `@rh`0x7c00) =(x `@rh`0xfc00)) `@rh`0x7e00 :: +-inf + ?: |(=(x `@rh`0x0) =(x `@rh`0x8000)) x :: +-0 -> +-0 + %- trig-fin:rh-trig + [%.y `@rh`(dis x 0x7fff) (rsh [0 15] x)] :: +cos: @rh -> @rh :: :: Returns the cosine of a floating-point atom. @@ -2825,7 +2830,52 @@ ++ cos ~/ %cos |= x=@rh ^- @rh - `@rh`(narrow-sh (~(cos rs [r .1e-5]) `@rs`(widen-hs x))) + ?: !(~(equ ^rh %n) x x) `@rh`0x7e00 + ?: |(=(x `@rh`0x7c00) =(x `@rh`0xfc00)) `@rh`0x7e00 + %- trig-fin:rh-trig + [%.n `@rh`(dis x 0x7fff) 0] + :: +rh-trig: native f16 sin/cos engine (fdlibm kernels, 2-coeff each). + ++ rh-trig + |% + ++ sc ^-((list @rh) :~(`@rh`0xb155 `@rh`0x2044)) + ++ cc ^-((list @rh) :~(`@rh`0x2955 `@rh`0x95b0)) + ++ neg |=(a=@rh ^-(@rh (~(sub ^rh %n) `@rh`0x0 a))) + ++ ksin + |= [xx=@rh yy=@rh] ^- @rh + =/ z (~(mul ^rh %n) xx xx) + =/ r (roll (flop (tail sc)) |=([c=@rh a=@rh] (~(add ^rh %n) (~(mul ^rh %n) a z) c))) + =/ v (~(mul ^rh %n) z xx) + =/ aa (~(sub ^rh %n) (~(mul ^rh %n) `@rh`0x3800 yy) (~(mul ^rh %n) v r)) + =/ bb (~(sub ^rh %n) (~(mul ^rh %n) z aa) yy) + =/ dd (~(sub ^rh %n) bb (~(mul ^rh %n) v (head sc))) + (~(sub ^rh %n) xx dd) + ++ kcos + |= [xx=@rh yy=@rh] ^- @rh + =/ z (~(mul ^rh %n) xx xx) + =/ rc (roll (flop cc) |=([c=@rh a=@rh] (~(add ^rh %n) (~(mul ^rh %n) a z) c))) + =/ hz (~(mul ^rh %n) `@rh`0x3800 z) + =/ w2 (~(sub ^rh %n) `@rh`0x3c00 hz) + =/ aa (~(sub ^rh %n) (~(sub ^rh %n) `@rh`0x3c00 w2) hz) + =/ bb (~(sub ^rh %n) (~(mul ^rh %n) (~(mul ^rh %n) z z) rc) (~(mul ^rh %n) xx yy)) + (~(add ^rh %n) w2 (~(add ^rh %n) aa bb)) + :: +trig-fin: [is-sin? |x| sign-bit] -> sin x (is-sin?) or cos x + ++ trig-fin + |= [s=? ax=@rh sb=@] ^- @rh + =/ q (need (~(toi ^rh %n) (~(mul ^rh %n) ax `@rh`0x3918))) + =/ qf (~(sun ^rh %n) (abs:si q)) + =/ r1 (~(sub ^rh %n) ax (~(mul ^rh %n) qf `@rh`0x3e00)) + =/ r2 (~(sub ^rh %n) r1 (~(mul ^rh %n) qf `@rh`0x2c80)) + =/ w (~(mul ^rh %n) qf `@rh`0x0fed) + =/ rhi (~(sub ^rh %n) r2 w) + =/ rlo (~(sub ^rh %n) (~(sub ^rh %n) r2 rhi) w) + =/ m (dis (abs:si q) 3) + =/ ks (ksin rhi rlo) + =/ kc (kcos rhi rlo) + ?: s + =/ v ?:(=(m 0) ks ?:(=(m 1) kc ?:(=(m 2) (neg ks) (neg kc)))) + ?:(=(sb 1) (neg v) v) + ?:(=(m 0) kc ?:(=(m 1) (neg ks) ?:(=(m 2) (neg kc) ks))) + -- :: +tan: @rh -> @rh :: :: Returns the tangent of a floating-point atom. From 1b5fff05a1184e8687f0b5639be7b4cd30411869 Mon Sep 17 00:00:00 2001 From: Sigilante Date: Fri, 12 Jun 2026 16:09:11 -0500 Subject: [PATCH 14/28] math: native f16 @rh atan + rh-atan sub-core; fix leading-zero hex literals Co-Authored-By: Claude Opus 4.8 --- libmath/desk/lib/math.hoon | 45 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/libmath/desk/lib/math.hoon b/libmath/desk/lib/math.hoon index 395ddcf..c283c1a 100644 --- a/libmath/desk/lib/math.hoon +++ b/libmath/desk/lib/math.hoon @@ -2865,7 +2865,7 @@ =/ qf (~(sun ^rh %n) (abs:si q)) =/ r1 (~(sub ^rh %n) ax (~(mul ^rh %n) qf `@rh`0x3e00)) =/ r2 (~(sub ^rh %n) r1 (~(mul ^rh %n) qf `@rh`0x2c80)) - =/ w (~(mul ^rh %n) qf `@rh`0x0fed) + =/ w (~(mul ^rh %n) qf `@rh`0xfed) =/ rhi (~(sub ^rh %n) r2 w) =/ rlo (~(sub ^rh %n) (~(sub ^rh %n) r2 rhi) w) =/ m (dis (abs:si q) 3) @@ -2934,8 +2934,49 @@ :: ++ atan ~/ %atan + :: native f16: fdlibm breakpoint reduction + deg-2 atan minimax. |= x=@rh ^- @rh - `@rh`(narrow-sh (~(atan rs [r .1e-5]) `@rs`(widen-hs x))) + ?: !(~(equ ^rh %n) x x) `@rh`0x7e00 :: NaN + ?: =(x `@rh`0x7c00) `@rh`0x3e48 :: +inf -> pi/2 + ?: =(x `@rh`0xfc00) `@rh`0xbe48 :: -inf -> -pi/2 + ?: |(=(x `@rh`0x0) =(x `@rh`0x8000)) x :: +-0 -> +-0 + =/ neg (rsh [0 15] x) + =/ r (ker:rh-atan `@rh`(dis x 0x7fff)) + ?:(=(neg 1) (~(sub ^rh %n) `@rh`0x0 r) r) + :: +rh-atan: native f16 atan engine (breakpoint reduction + poly). + ++ rh-atan + |% + ++ at ^-((list @rh) :~(`@rh`0x3555 `@rh`0xb266 `@rh`0x3092)) :: 1/3,-1/5,1/7 + ++ atred + |= ax=@rh ^- [xr=@rh hi=@rh lo=@rh dir=?] + =/ one `@rh`0x3c00 + =/ two `@rh`0x4000 + =/ ohf `@rh`0x3e00 + ?: (~(lth ^rh %n) ax `@rh`0x3700) :: < 7/16 + [ax `@rh`0x0 `@rh`0x0 %.y] + ?: (~(lth ^rh %n) ax `@rh`0x3980) :: < 11/16 + :* (~(div ^rh %n) (~(sub ^rh %n) (~(add ^rh %n) ax ax) one) (~(add ^rh %n) two ax)) + `@rh`0x376b `@rh`0x19c %.n + == + ?: (~(lth ^rh %n) ax `@rh`0x3cc0) :: < 19/16 + :* (~(div ^rh %n) (~(sub ^rh %n) ax one) (~(add ^rh %n) ax one)) + `@rh`0x3a48 `@rh`0xbed %.n + == + ?: (~(lth ^rh %n) ax `@rh`0x40e0) :: < 39/16 + :* (~(div ^rh %n) (~(sub ^rh %n) ax ohf) (~(add ^rh %n) one (~(mul ^rh %n) ohf ax))) + `@rh`0x3bdd `@rh`0x87a1 %.n + == + :* (~(div ^rh %n) `@rh`0xbc00 ax) :: -1/ax + `@rh`0x3e48 `@rh`0xfed %.n + == + ++ ker + |= ax=@rh ^- @rh + =/ q (atred ax) + =/ z (~(mul ^rh %n) xr.q xr.q) + =/ s (~(mul ^rh %n) z (roll (flop at) |=([c=@rh a=@rh] (~(add ^rh %n) (~(mul ^rh %n) a z) c)))) + ?: dir.q (~(sub ^rh %n) xr.q (~(mul ^rh %n) xr.q s)) + (~(sub ^rh %n) hi.q (~(sub ^rh %n) (~(sub ^rh %n) (~(mul ^rh %n) xr.q s) lo.q) xr.q)) + -- :: +atan2: [@rh @rh] -> @rh :: :: Returns the inverse tangent of a floating-point coordinate. From bcd10e66ecdaac65ee9ee7e7368cdec3a5881653 Mon Sep 17 00:00:00 2001 From: Sigilante Date: Fri, 12 Jun 2026 16:17:15 -0500 Subject: [PATCH 15/28] math: native f16 @rh asin/acos + rh-ainv sub-core Co-Authored-By: Claude Opus 4.8 --- libmath/desk/lib/math.hoon | 67 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 65 insertions(+), 2 deletions(-) diff --git a/libmath/desk/lib/math.hoon b/libmath/desk/lib/math.hoon index c283c1a..ffb1bc4 100644 --- a/libmath/desk/lib/math.hoon +++ b/libmath/desk/lib/math.hoon @@ -2904,8 +2904,9 @@ :: ++ asin ~/ %asin + :: native f16: fdlibm rational kernel; see +rh-ainv. |x|>1 -> NaN. |= x=@rh ^- @rh - `@rh`(narrow-sh (~(asin rs [r .1e-5]) `@rs`(widen-hs x))) + (asn:rh-ainv x) :: +acos: @rh -> @rh :: :: Returns the inverse cosine of a floating-point atom. @@ -2919,8 +2920,70 @@ :: ++ acos ~/ %acos + :: native f16: fdlibm rational kernel; see +rh-ainv. |x|>1 -> NaN. |= x=@rh ^- @rh - `@rh`(narrow-sh (~(acos rs [r .1e-5]) `@rs`(widen-hs x))) + (acs:rh-ainv x) + :: +rh-ainv: shared native f16 asin/acos engine (poly R(t)=t*P(t)), + :: see +asin / +acos. Round-nearest-even internally; deg-4 minimax P, + :: faithful to ~1 ULP. PIO2L=0xfed is the low half of pi/2 (positive). + ++ rh-ainv + |% + ++ rr + |= t=@rh ^- @rh + =/ ps=(list @rh) + ^-((list @rh) :~(`@rh`0x3155 `@rh`0x2cea `@rh`0x2729 `@rh`0x2ccc)) + %+ ~(mul ^rh %n) t + (roll (flop ps) |=([c=@rh a=@rh] (~(add ^rh %n) (~(mul ^rh %n) a t) c))) + ++ asn + |= x=@rh ^- @rh + ?: !(~(equ ^rh %n) x x) `@rh`0x7e00 + =/ sgn (rsh [0 15] x) + =/ ax `@rh`(dis x 0x7fff) + ?: (~(gth ^rh %n) ax `@rh`0x3c00) `@rh`0x7e00 :: |x|>1 -> NaN + ?: =(ax `@rh`0x3c00) :: |x|==1 -> +-pi/2 + (~(add ^rh %n) (~(mul ^rh %n) x `@rh`0x3e48) (~(mul ^rh %n) x `@rh`0xfed)) + ?: (~(lth ^rh %n) ax `@rh`0x3800) :: |x|<0.5 + ?: (~(lth ^rh %n) ax `@rh`0xc00) x :: |x|<2^-12 -> x + =/ t (~(mul ^rh %n) x x) + (~(add ^rh %n) x (~(mul ^rh %n) x (rr t))) + =/ w (~(sub ^rh %n) `@rh`0x3c00 ax) :: 0.5<=|x|<1 + =/ t (~(mul ^rh %n) w `@rh`0x3800) + =/ r (rr t) + =/ s (~(sqt ^rh %n) t) + ?: (~(gte ^rh %n) ax `@rh`0x3bcd) :: |x|>=0.975 + =/ res + (~(sub ^rh %n) `@rh`0x3e48 (~(mul ^rh %n) `@rh`0x4000 (~(add ^rh %n) s (~(mul ^rh %n) s r)))) + ?:(=(sgn 1) (~(sub ^rh %n) `@rh`0x0 res) res) + =/ df `@rh`(dis s 0xfff0) + =/ c (~(div ^rh %n) (~(sub ^rh %n) t (~(mul ^rh %n) df df)) (~(add ^rh %n) s df)) + =/ p2 (~(sub ^rh %n) (~(mul ^rh %n) `@rh`0x4000 (~(mul ^rh %n) s r)) (~(sub ^rh %n) `@rh`0xfed (~(mul ^rh %n) `@rh`0x4000 c))) + =/ q2 (~(sub ^rh %n) `@rh`0x3a48 (~(mul ^rh %n) `@rh`0x4000 df)) + =/ res (~(sub ^rh %n) `@rh`0x3a48 (~(sub ^rh %n) p2 q2)) + ?:(=(sgn 1) (~(sub ^rh %n) `@rh`0x0 res) res) + ++ acs + |= x=@rh ^- @rh + ?: !(~(equ ^rh %n) x x) `@rh`0x7e00 + =/ neg (rsh [0 15] x) + =/ ax `@rh`(dis x 0x7fff) + ?: (~(gth ^rh %n) ax `@rh`0x3c00) `@rh`0x7e00 :: |x|>1 -> NaN + ?: =(ax `@rh`0x3c00) :: |x|==1 + ?: =(neg 0) `@rh`0x0 + (~(add ^rh %n) `@rh`0x4248 (~(mul ^rh %n) `@rh`0x4000 `@rh`0xfed)) + ?: (~(lth ^rh %n) ax `@rh`0x3800) :: |x|<0.5 + =/ z (~(mul ^rh %n) x x) + =/ r (rr z) + (~(sub ^rh %n) `@rh`0x3e48 (~(sub ^rh %n) x (~(sub ^rh %n) `@rh`0xfed (~(mul ^rh %n) x r)))) + ?: =(neg 1) :: -1 @rh :: :: Returns the inverse tangent of a floating-point atom. From 03cca93d7aebd3837df58791534427fdac15bebc Mon Sep 17 00:00:00 2001 From: Sigilante Date: Fri, 12 Jun 2026 16:25:56 -0500 Subject: [PATCH 16/28] math: native f16 @rh tan/atan2/pow/sqt/cbt/log-2/log-10 + lr Completes the native f16 @rh door -- no cross-door delegation remains (only widen-hs/narrow-sh conversions). tan is the sin/cos ratio; atan2/pow honor the door r via bare composite ops; cbt/log-2/log-10 reuse the native exp/log kernels; sqt is the stdlib f16 root; lr is the f16 log reduction. Updated test-tan-1 vector 0x3e3b->0x3e3a (native sin/cos ratio, 0.79 ULP, faithful). Co-Authored-By: Claude Opus 4.8 --- libmath/desk/lib/math.hoon | 73 ++++++++++++++++++++++++++--- libmath/desk/tests/lib/math-rh.hoon | 2 +- 2 files changed, 67 insertions(+), 8 deletions(-) diff --git a/libmath/desk/lib/math.hoon b/libmath/desk/lib/math.hoon index ffb1bc4..79ed8d2 100644 --- a/libmath/desk/lib/math.hoon +++ b/libmath/desk/lib/math.hoon @@ -2889,8 +2889,9 @@ :: Source ++ tan ~/ %tan + :: native f16: sin/cos ratio (the final div honors the door's r). |= x=@rh ^- @rh - `@rh`(narrow-sh (~(tan rs [r .1e-5]) `@rs`(widen-hs x))) + (div (sin x) (cos x)) :: +asin: @rh -> @rh :: :: Returns the inverse sine of a floating-point atom. @@ -3053,8 +3054,20 @@ :: ++ atan2 ~/ %atan2 + :: native f16: quadrant dispatch over the native +atan (composite ops + :: honor the door's r). |= [y=@rh x=@rh] ^- @rh - `@rh`(narrow-sh (~(atan2 rs [r .1e-5]) `@rs`(widen-hs y) `@rs`(widen-hs x))) + ?: (gth x .~~0) + (atan (div y x)) + ?: &((lth x .~~0) (gte y .~~0)) + (add (atan (div y x)) pi) + ?: &((lth x .~~0) (lth y .~~0)) + (sub (atan (div y x)) pi) + ?: &(=(.~~0 x) (gth y .~~0)) + (div pi .~~2) + ?: &(=(.~~0 x) (lth y .~~0)) + (mul .~~-1 (div pi .~~2)) + .~~0 :: undefined :: +pow-n: [@rh @rh] -> @rh :: :: Returns the power of a floating-point atom to an integer exponent. @@ -3125,8 +3138,15 @@ :: Source ++ log-10 ~/ %log-10 + :: native f16: e*log10(2) + log(m)/ln10, reusing +lr (integer part added + :: with no division rounding). |= x=@rh ^- @rh - `@rh`(narrow-sh (~(log-10 rs [r .1e-5]) `@rs`(widen-hs x))) + ?: !(~(equ ^rh %n) x x) `@rh`0x7e00 + ?: =(x `@rh`0x7c00) `@rh`0x7c00 + ?: |(=(x `@rh`0x0) =(x `@rh`0x8000)) `@rh`0xfc00 + ?: =(1 (rsh [0 15] x)) `@rh`0x7e00 + =/ el (lr x) + (~(add ^rh %n) (~(mul ^rh %n) ef.el `@rh`0x34d1) (~(mul ^rh %n) lm.el `@rh`0x36f3)) :: +log-2: @rh -> @rh :: :: Returns the base-2 logarithm of a floating-point atom. @@ -3135,8 +3155,38 @@ :: Source ++ log-2 ~/ %log-2 + :: native f16: e + log(m)/ln2 (integer part exact); see +lr. |= x=@rh ^- @rh - `@rh`(narrow-sh (~(log-2 rs [r .1e-5]) `@rs`(widen-hs x))) + ?: !(~(equ ^rh %n) x x) `@rh`0x7e00 + ?: =(x `@rh`0x7c00) `@rh`0x7c00 + ?: |(=(x `@rh`0x0) =(x `@rh`0x8000)) `@rh`0xfc00 + ?: =(1 (rsh [0 15] x)) `@rh`0x7e00 + =/ el (lr x) + (~(add ^rh %n) ef.el (~(mul ^rh %n) lm.el `@rh`0x3dc5)) + :: +lr: native f16 log reduction for finite positive x -> [e (as @rh), + :: log(mantissa)]. Mirrors the reduction inside +log; see +log-2 / +log-10. + ++ lr + |= x=@rh ^- [ef=@rh lm=@rh] + =/ sub =(0 (dis 0x1f (rsh [0 10] x))) + =/ xx ?:(sub (~(mul ^rh %n) x `@rh`0x6400) x) :: *2^10 + =/ ae ?:(sub -10 --0) + =/ b `@`xx + =/ e (dif:si (new:si %.y (dis 0x1f (rsh [0 10] b))) --15) + =/ m `@rh`(con (dis b 0x3ff) 0x3c00) + =/ big (~(gte ^rh %n) m `@rh`0x3da8) :: m >= sqrt(2) + =? m big (~(mul ^rh %n) m `@rh`0x3800) + =? e big (sum:si e --1) + =. e (sum:si e ae) + =/ f (~(sub ^rh %n) m `@rh`0x3c00) + =/ s (~(div ^rh %n) f (~(add ^rh %n) m `@rh`0x3c00)) + =/ z (~(mul ^rh %n) s s) + =/ cs=(list @rh) :~(`@rh`0x3555 `@rh`0x3266) + =/ p2 (roll (flop cs) |=([c=@rh a=@rh] (~(add ^rh %n) (~(mul ^rh %n) a z) c))) + =/ r (~(mul ^rh %n) (~(add ^rh %n) z z) p2) + =/ l1 (~(sub ^rh %n) f (~(mul ^rh %n) s (~(sub ^rh %n) f r))) + =/ efa (~(sun ^rh %n) (abs:si e)) + =/ ef ?:((syn:si e) efa (~(sub ^rh %n) `@rh`0x0 efa)) + [ef l1] :: +pow: [@rh @rh] -> @rh :: :: Returns the power of a floating-point atom to a floating-point exponent. @@ -3150,8 +3200,11 @@ :: Source ++ pow ~/ %pow + :: native f16: positive-integer exponents via +pow-n; else exp(n*log x) + :: (the n*log x multiply honors the door's r). |= [x=@rh n=@rh] ^- @rh - `@rh`(narrow-sh (~(pow rs [r .1e-5]) `@rs`(widen-hs x) `@rs`(widen-hs n))) + ?: &(=(n (san (need (toi n)))) (gth n .~~0)) (pow-n x (san (need (toi n)))) + (exp (mul n (log x))) :: +sqrt: @rh -> @rh :: :: Returns the square root of a floating-point atom. @@ -3178,8 +3231,9 @@ :: Source ++ sqt ~/ %sqt + :: native f16: correctly-rounded stdlib (SoftFloat) f16 square root. |= x=@rh ^- @rh - `@rh`(narrow-sh (~(sqt rs [r .1e-5]) `@rs`(widen-hs x))) + (sqt:^rh x) :: +cbrt: @rh -> @rh :: :: Returns the cube root of a floating-point atom. @@ -3206,8 +3260,13 @@ :: Source ++ cbt ~/ %cbt + :: native f16: cbrt(x) = sign(x) * exp(log|x| / 3); all reals. |= x=@rh ^- @rh - `@rh`(narrow-sh (~(cbt rs [r .1e-5]) `@rs`(widen-hs x))) + ?: !(~(equ ^rh %n) x x) x :: NaN -> NaN + ?: |(=(x `@rh`0x0) =(x `@rh`0x8000)) x :: +-0 -> +-0 + =/ ax `@rh`(dis x 0x7fff) + =/ r (exp (~(mul ^rh %n) (log ax) `@rh`0x3555)) + ?:(=(1 (rsh [0 15] x)) (~(sub ^rh %n) `@rh`0x0 r) r) :: +arg: @rh -> @rh :: :: Returns the argument of a floating-point atom (real argument = absolute diff --git a/libmath/desk/tests/lib/math-rh.hoon b/libmath/desk/tests/lib/math-rh.hoon index 85632fa..bdb2829 100644 --- a/libmath/desk/tests/lib/math-rh.hoon +++ b/libmath/desk/tests/lib/math-rh.hoon @@ -27,7 +27,7 @@ ++ test-sin-1 (expect-eq !>(`@`0x3abb) !>((sh `@rh`0x3c00))) ++ test-sin-pi (expect-eq !>(`@`0x13ed) !>((sh `@rh`0x4248))) ++ test-cos-1 (expect-eq !>(`@`0x3853) !>((ch `@rh`0x3c00))) -++ test-tan-1 (expect-eq !>(`@`0x3e3b) !>((th `@rh`0x3c00))) +++ test-tan-1 (expect-eq !>(`@`0x3e3a) !>((th `@rh`0x3c00))) ++ test-atan-1 (expect-eq !>(`@`0x3a48) !>((ath `@rh`0x3c00))) ++ test-atan-2 (expect-eq !>(`@`0x3c6e) !>((ath `@rh`0x4000))) ++ test-asin-half (expect-eq !>(`@`0x3830) !>((ash `@rh`0x3800))) From 6b22add746419196f1f5530c51a6c0aec894d428 Mon Sep 17 00:00:00 2001 From: Sigilante Date: Fri, 12 Jun 2026 16:50:01 -0500 Subject: [PATCH 17/28] math: native f16 @rh C jets (drop _rh_1/_rh_2 -> _rs_* delegation) The 15 _rh_* cores now compute entirely in half-precision (SoftFloat f16 ops), mirroring the native Hoon arms op-for-op -- f16 minimax coeffs, lower poly degrees (sin/cos/atan/ainv shorter, ainv no denominator, acos no tiny branch). Verified bit-exact to all 20 math-rh.hoon vectors (test/rh_check.c) and faithful (<=1.01 ULP) across all 64k finite f16 inputs for exp/log/atan/asin/acos/sqt; sin/cos faithful for small |x|, lossy for large |x| exactly as the Hoon reduction intends (test/rh_sweep.c). Co-Authored-By: Claude Opus 4.8 --- libmath/vere64/noun/jets/i/math.c | 416 +++++++++++++++++++++++++++--- libmath/vere64/test/rh_check.c | 48 ++++ libmath/vere64/test/rh_sweep.c | 29 +++ 3 files changed, 459 insertions(+), 34 deletions(-) create mode 100644 libmath/vere64/test/rh_check.c create mode 100644 libmath/vere64/test/rh_sweep.c diff --git a/libmath/vere64/noun/jets/i/math.c b/libmath/vere64/noun/jets/i/math.c index 376f2ae..66d76a8 100644 --- a/libmath/vere64/noun/jets/i/math.c +++ b/libmath/vere64/noun/jets/i/math.c @@ -967,12 +967,14 @@ typedef int64_t c3_ds; } /* =================================================================== -** @rh (half-precision) cores -- math.hoon ++rh. Every arm is -** narrow-sh(rs_fn(widen-hs(x))): widen f16->f32 (exact = f16_to_f32), -** compute in @rs, narrow f32->f16 (= f32_to_f16) honoring the door's r. -** The rs call inherits r too (composites honor it; kernels stay %n). No new -** algorithm cores -- the @rs cores are reused. Verified: the Hoon narrow-sh -** is bit-exact to f32_to_f16 in all four rounding modes. +** @rh (half-precision) cores -- math.hoon ++rh. NATIVE f16: each core +** computes entirely in half-precision (SoftFloat f16 ops), mirroring the +** native Hoon arms op-for-op -- NOT widen-to-f32-and-narrow. Same reductions +** and Horner order as @rd/@rs but with the f16 minimax coeffs read from the +** Hoon (lower polynomial degrees: sin/cos/atan/ainv are shorter, ainv has no +** denominator, acos has no tiny branch). Marshalling is chub-based (low 16 +** bits), so word-size-agnostic like @rd/@rs. Kernels round near-even; the +** composites (tan/atan2/pow/pow-n) honor the door's r via _math_rnd. ** =================================================================== */ union half { @@ -980,37 +982,383 @@ typedef int64_t c3_ds; uint16_t c; }; - // widen f16->f32 (exact), run an @rs core, narrow f32->f16 per _math_rnd. - // _math_rnd is the door's r (set by the wrapper): the rs composites honor it - // and the narrow rounds by it; the rs kernels run at near-even. - static inline float16_t _rh_1(float16_t x, float32_t (*fun)(float32_t)) { - softfloat_roundingMode = softfloat_round_near_even; - float32_t v = fun(f16_to_f32(x)); + static const uint16_t _RH_QNAN = 0x7e00U; + static const uint16_t _RH_PINF = 0x7c00U; + static const uint16_t _RH_NINF = 0xfc00U; + + static inline union half _rh_bits(uint16_t b) { union half u; u.c = b; return u; } + static inline float16_t _rh_neg(float16_t a) { // (sub .0 a) + union half z; z.c = 0; return f16_sub(z.h, a); + } + +/* @rh exp -- math.hoon ++rh ++exp +** x = k*ln2 + r (Cody-Waite), exp(x) = 2^k * P(r), P a degree-4 minimax. +*/ + // pow2(j) = (|j+15|)<<10 as f16 bits = 2^j (normal range j in [-14,15]) + static inline float16_t _rh_pow2(c3_ds j) { + int v = (int)(j + 15); if ( v < 0 ) v = -v; + union half u; u.c = (uint16_t)(v << 10); return u.h; + } + // scale2: ldexp with overflow/subnormal tails (math.hoon ++rh ++exp) + static inline float16_t _rh_scale2(float16_t p, c3_ds k) { + if ( (k - 16) >= 0 ) { // k>=16 + return f16_mul(f16_mul(p, _rh_pow2(15)), _rh_pow2(k - 15)); + } + if ( !((k + 14) >= 0) ) { // k<-14 + return f16_mul(f16_mul(p, _rh_pow2(k + 11)), _rh_pow2(-11)); + } + return f16_mul(p, _rh_pow2(k)); + } + static float16_t _rh_exp(float16_t x) { + union half r0; + static const uint16_t cs[5] = { 0x3c00, 0x3c00, 0x3800, 0x3160, 0x295c }; + union half log2e, ln2hi, ln2lo, ka, kf, rr, p, c, zero; + zero.c = 0; + r0.h = x; + if ( !f16_eq(x, x) ) { r0.c = _RH_QNAN; return r0.h; } // NaN + if ( r0.c == _RH_PINF ) { return x; } // +inf + if ( r0.c == _RH_NINF ) { r0.c = 0; return r0.h; } // -inf -> 0 + + log2e.c = 0x3dc5; ln2hi.c = 0x3980; ln2lo.c = 0x1dc8; + + c3_ds k = (c3_ds)f16_to_i32(f16_mul(x, log2e.h), softfloat_round_near_even, 0); + if ( (k - 17) >= 0 ) { r0.c = _RH_PINF; return r0.h; } // overflow -> inf + if ( !((k + 24) >= 0) ) { r0.c = 0; return r0.h; } // underflow -> 0 + + ka.h = ui32_to_f16( (uint32_t)(k < 0 ? -k : k) ); + kf.h = (k >= 0) ? ka.h : f16_sub(zero.h, ka.h); + rr.h = f16_sub( f16_sub(x, f16_mul(kf.h, ln2hi.h)), f16_mul(kf.h, ln2lo.h) ); + + p.c = 0; + for ( int i = 5; i-- != 0; ) { // Horner over flop(cs): c4..c0 + c.c = cs[i]; + p.h = f16_add(f16_mul(p.h, rr.h), c.h); + } + return _rh_scale2(p.h, k); + } + +/* @rh sin/cos/tan -- math.hoon ++rh ++sin/++cos/++rh-trig/++tan +** x = q*(pi/2) + (rhi+rlo) (3-part pi/2), fdlibm sin/cos kernels by q&3 (each +** with just 2 coeffs). tan = sin/cos (the div honors the door r). +*/ + static const uint16_t _RH_SC[2] = { 0xb155, 0x2044 }; // sin kernel coeffs + static const uint16_t _RH_CC[2] = { 0x2955, 0x95b0 }; // cos kernel coeffs + static float16_t _rh_ksin(float16_t xx, float16_t yy) { + union half z, r, v, aa, bb, dd, c, half; + half.c = 0x3800; + z.h = f16_mul(xx, xx); + r.c = 0; // Horner over flop(tail sc): sc[1] + for ( int i = 2; i-- != 1; ) { c.c = _RH_SC[i]; r.h = f16_add(f16_mul(r.h, z.h), c.h); } + v.h = f16_mul(z.h, xx); + aa.h = f16_sub(f16_mul(half.h, yy), f16_mul(v.h, r.h)); + bb.h = f16_sub(f16_mul(z.h, aa.h), yy); + dd.h = f16_sub(bb.h, f16_mul(v.h, _rh_bits(_RH_SC[0]).h)); + return f16_sub(xx, dd.h); + } + static float16_t _rh_kcos(float16_t xx, float16_t yy) { + union half z, rc, hz, w2, aa, bb, c, half, one; + half.c = 0x3800; one.c = 0x3c00; + z.h = f16_mul(xx, xx); + rc.c = 0; // Horner over flop(cc): cc[1..0] + for ( int i = 2; i-- != 0; ) { c.c = _RH_CC[i]; rc.h = f16_add(f16_mul(rc.h, z.h), c.h); } + hz.h = f16_mul(half.h, z.h); + w2.h = f16_sub(one.h, hz.h); + aa.h = f16_sub(f16_sub(one.h, w2.h), hz.h); + bb.h = f16_sub(f16_mul(f16_mul(z.h, z.h), rc.h), f16_mul(xx, yy)); + return f16_add(w2.h, f16_add(aa.h, bb.h)); + } + // trig-fin: is_sin ? sin(x) : cos(x); ax=|x|, sb=sign bit + static float16_t _rh_trigfin(int is_sin, float16_t ax, uint16_t sb) { + union half qf, r1, r2, w, rhi, rlo, ks, kc, v; + c3_ds q = (c3_ds)f16_to_i32(f16_mul(ax, _rh_bits(0x3918).h), + softfloat_round_near_even, 0); // round(ax*2/pi) + c3_d aq = (c3_d)(q < 0 ? -q : q); + qf.h = ui32_to_f16((uint32_t)aq); + r1.h = f16_sub(ax, f16_mul(qf.h, _rh_bits(0x3e00).h)); // ax - qf*pio2_1 + r2.h = f16_sub(r1.h, f16_mul(qf.h, _rh_bits(0x2c80).h)); // r1 - qf*pio2_2 + w.h = f16_mul(qf.h, _rh_bits(0x0fed).h); // qf*pio2_3 + rhi.h = f16_sub(r2.h, w.h); + rlo.h = f16_sub(f16_sub(r2.h, rhi.h), w.h); + int m = (int)(aq & 3); + ks.h = _rh_ksin(rhi.h, rlo.h); + kc.h = _rh_kcos(rhi.h, rlo.h); + if ( is_sin ) { + v.h = (m==0) ? ks.h : (m==1) ? kc.h : (m==2) ? _rh_neg(ks.h) : _rh_neg(kc.h); + return (sb == 1) ? _rh_neg(v.h) : v.h; + } + return (m==0) ? kc.h : (m==1) ? _rh_neg(ks.h) : (m==2) ? _rh_neg(kc.h) : ks.h; + } + static float16_t _rh_sin(float16_t x) { + union half r0, ax; + r0.h = x; + if ( !f16_eq(x, x) ) { r0.c = _RH_QNAN; return r0.h; } // NaN + if ( (r0.c == _RH_PINF)||(r0.c == _RH_NINF) ) { r0.c = _RH_QNAN; return r0.h; } // +-inf -> NaN + if ( (r0.c == 0)||(r0.c == 0x8000U) ) { return x; } // +-0 -> +-0 + ax.c = r0.c & 0x7fffU; + return _rh_trigfin(1, ax.h, r0.c >> 15); + } + static float16_t _rh_cos(float16_t x) { + union half r0, ax; + r0.h = x; + if ( !f16_eq(x, x) ) { r0.c = _RH_QNAN; return r0.h; } // NaN + if ( (r0.c == _RH_PINF)||(r0.c == _RH_NINF) ) { r0.c = _RH_QNAN; return r0.h; } // +-inf -> NaN + ax.c = r0.c & 0x7fffU; + return _rh_trigfin(0, ax.h, 0); + } + // tan = (div (sin x) (cos x)): sin/cos kernels %n, the bare div per door r + static float16_t _rh_tan(float16_t x) { + float16_t s = _rh_sin(x), c = _rh_cos(x); softfloat_roundingMode = _math_rnd; - return f32_to_f16(v); + float16_t r = f16_div(s, c); + softfloat_roundingMode = softfloat_round_near_even; + return r; + } + +/* @rh sqt -- math.hoon ++rh ++sqt = (sqt:^rh x): correctly-rounded f16 sqrt. */ + static float16_t _rh_sqt(float16_t x) { + union half r; r.h = f16_sqrt(x); + if ( !f16_eq(r.h, r.h) ) r.c = _RH_QNAN; // _nan_unify + return r.h; + } + +/* @rh log/log-2/log-10 -- math.hoon ++rh ++log/++lr/++log-2/++log-10 +** x = 2^e * m, m in [sqrt(1/2),sqrt(2)); log(1+f) via atanh series (deg-1). +*/ + // +lr: finite positive x -> *ef = e as @rh, *l1 = log(mantissa) + static void _rh_lr(float16_t x, float16_t* ef, float16_t* l1) { + static const uint16_t cs[2] = { 0x3555, 0x3266 }; + union half xb, m, f, s, z, p2, r, ll, efa, c, one, half; + one.c = 0x3c00; half.c = 0x3800; + xb.h = x; + int sub = (((xb.c >> 10) & 0x1fU) == 0); + if ( sub ) xb.h = f16_mul(x, _rh_bits(0x6400).h); // *2^10 + int32_t ae = sub ? -10 : 0; + int32_t e = (int32_t)((xb.c >> 10) & 0x1fU) - 15; + m.c = (xb.c & 0x3ffU) | 0x3c00U; + if ( !f16_lt(m.h, _rh_bits(0x3da8).h) ) { // m >= sqrt(2) + m.h = f16_mul(m.h, half.h); e += 1; + } + e += ae; + f.h = f16_sub(m.h, one.h); + s.h = f16_div(f.h, f16_add(m.h, one.h)); + z.h = f16_mul(s.h, s.h); + p2.c = 0; for ( int i = 2; i-- != 0; ) { c.c = cs[i]; p2.h = f16_add(f16_mul(p2.h, z.h), c.h); } + r.h = f16_mul(f16_add(z.h, z.h), p2.h); + ll.h = f16_sub(f.h, f16_mul(s.h, f16_sub(f.h, r.h))); + efa.h = ui32_to_f16((uint32_t)(e < 0 ? -e : e)); + *ef = (e >= 0) ? efa.h : _rh_neg(efa.h); + *l1 = ll.h; + } + // shared guards for log/log-2/log-10; returns 1 (and sets *g) on a special case + static int _rh_log_guard(float16_t x, float16_t* g) { + union half r0; r0.h = x; + if ( !f16_eq(x, x) ) { r0.c = _RH_QNAN; *g = r0.h; return 1; } // NaN + if ( r0.c == _RH_PINF ) { *g = x; return 1; } // +inf -> inf + if ( (r0.c == 0)||(r0.c == 0x8000U) ) { r0.c = _RH_NINF; *g = r0.h; return 1; } // +-0 -> -inf + if ( (r0.c >> 15) == 1 ){ r0.c = _RH_QNAN; *g = r0.h; return 1; } // x<0 -> NaN + return 0; + } + static float16_t _rh_log(float16_t x) { + union half g, ef, l1, hi, lo; + if ( _rh_log_guard(x, &g.h) ) return g.h; + _rh_lr(x, &ef.h, &l1.h); + hi.h = f16_mul(ef.h, _rh_bits(0x3980).h); // e*ln2hi + lo.h = f16_mul(ef.h, _rh_bits(0x1dc8).h); // e*ln2lo + return f16_add(hi.h, f16_add(l1.h, lo.h)); + } + static float16_t _rh_log2(float16_t x) { + union half g, ef, l1; + if ( _rh_log_guard(x, &g.h) ) return g.h; + _rh_lr(x, &ef.h, &l1.h); + return f16_add(ef.h, f16_mul(l1.h, _rh_bits(0x3dc5).h)); // e + lm/ln2 + } + static float16_t _rh_log10(float16_t x) { + union half g, ef, l1; + if ( _rh_log_guard(x, &g.h) ) return g.h; + _rh_lr(x, &ef.h, &l1.h); + return f16_add(f16_mul(ef.h, _rh_bits(0x34d1).h), // e*log10(2) + f16_mul(l1.h, _rh_bits(0x36f3).h)); // + lm/ln10 + } + +/* @rh cbt -- math.hoon ++rh ++cbt = sign(x) * exp(log|x| / 3). */ + static float16_t _rh_cbt(float16_t x) { + union half r0, ax, r; + r0.h = x; + if ( !f16_eq(x, x) ) { return x; } // NaN + if ( (r0.c == 0)||(r0.c == 0x8000U) ) { return x; } // +-0 + ax.c = r0.c & 0x7fffU; + r.h = _rh_exp(f16_mul(_rh_log(ax.h), _rh_bits(0x3555).h)); // exp(log|x|/3) + return ((r0.c >> 15) == 1) ? _rh_neg(r.h) : r.h; + } + +/* @rh asin/acos -- math.hoon ++rh ++asin/++acos/++rh-ainv +** poly kernel R(t) = t*P(t) (deg-4, NO denominator); sqt = f16_sqrt. The +** near-1 asin branch omits pio2l (f16 script), acos has no tiny branch. +*/ + static float16_t _rh_ainv_rr(float16_t t) { + static const uint16_t ps[4] = { 0x3155, 0x2cea, 0x2729, 0x2ccc }; + union half pp, c; + pp.c = 0; for ( int i = 4; i-- != 0; ) { c.c = ps[i]; pp.h = f16_add(f16_mul(pp.h, t), c.h); } + return f16_mul(t, pp.h); + } + static float16_t _rh_asin(float16_t x) { + union half r0, ax, t, w, r, s, res, half, one, two, pio2h, pio2l, pio4, near; + half.c=0x3800; one.c=0x3c00; two.c=0x4000; + pio2h.c=0x3e48; pio2l.c=0x0fed; pio4.c=0x3a48; near.c=0x3bcd; + r0.h = x; + if ( !f16_eq(x, x) ) { r0.c = _RH_QNAN; return r0.h; } // NaN + uint16_t sgn = r0.c >> 15; + ax.c = r0.c & 0x7fffU; + if ( f16_lt(one.h, ax.h) ) { r0.c = _RH_QNAN; return r0.h; } // |x|>1 -> NaN + if ( ax.c == one.c ) // |x|==1 + return f16_add(f16_mul(x, pio2h.h), f16_mul(x, pio2l.h)); + if ( f16_lt(ax.h, half.h) ) { // |x|<0.5 + if ( f16_lt(ax.h, _rh_bits(0x0c00).h) ) return x; // |x|<2^-12 -> x + t.h = f16_mul(x, x); + return f16_add(x, f16_mul(x, _rh_ainv_rr(t.h))); + } + w.h = f16_sub(one.h, ax.h); + t.h = f16_mul(w.h, half.h); + r.h = _rh_ainv_rr(t.h); + s.h = f16_sqrt(t.h); + if ( f16_le(near.h, ax.h) ) { // |x|>=0.975 + res.h = f16_sub(pio2h.h, f16_mul(two.h, f16_add(s.h, f16_mul(s.h, r.h)))); + return (sgn == 1) ? _rh_neg(res.h) : res.h; + } + { union half df, cc, p2, q2; + df.c = s.c & 0xfff0U; + cc.h = f16_div(f16_sub(t.h, f16_mul(df.h, df.h)), f16_add(s.h, df.h)); + p2.h = f16_sub(f16_mul(two.h, f16_mul(s.h, r.h)), f16_sub(pio2l.h, f16_mul(two.h, cc.h))); + q2.h = f16_sub(pio4.h, f16_mul(two.h, df.h)); + res.h = f16_sub(pio4.h, f16_sub(p2.h, q2.h)); + return (sgn == 1) ? _rh_neg(res.h) : res.h; + } + } + static float16_t _rh_acos(float16_t x) { + union half r0, ax, z, s, r, w, half, one, two, pih, pio2h, pio2l; + half.c=0x3800; one.c=0x3c00; two.c=0x4000; + pih.c=0x4248; pio2h.c=0x3e48; pio2l.c=0x0fed; + r0.h = x; + if ( !f16_eq(x, x) ) { r0.c = _RH_QNAN; return r0.h; } // NaN + uint16_t neg = r0.c >> 15; + ax.c = r0.c & 0x7fffU; + if ( f16_lt(one.h, ax.h) ) { r0.c = _RH_QNAN; return r0.h; } // |x|>1 -> NaN + if ( ax.c == one.c ) { // |x|==1 + if ( neg == 0 ) { union half z0; z0.c = 0; return z0.h; } // 1 -> 0 + return f16_add(pih.h, f16_mul(two.h, pio2l.h)); // -1 -> pi + } + if ( f16_lt(ax.h, half.h) ) { // |x|<0.5 + z.h = f16_mul(x, x); + r.h = _rh_ainv_rr(z.h); + return f16_sub(pio2h.h, f16_sub(x, f16_sub(pio2l.h, f16_mul(x, r.h)))); + } + if ( neg == 1 ) { // x <= -0.5 + z.h = f16_mul(f16_add(one.h, x), half.h); + s.h = f16_sqrt(z.h); + r.h = _rh_ainv_rr(z.h); + w.h = f16_sub(f16_mul(r.h, s.h), pio2l.h); + return f16_sub(pih.h, f16_mul(two.h, f16_add(s.h, w.h))); + } + z.h = f16_mul(f16_sub(one.h, x), half.h); // x >= 0.5 + s.h = f16_sqrt(z.h); + r.h = _rh_ainv_rr(z.h); + return f16_mul(two.h, f16_add(s.h, f16_mul(s.h, r.h))); + } + +/* @rh atan/atan2 -- math.hoon ++rh ++atan/++rh-atan/++atan2 +** fdlibm breakpoint reduction (7/16,11/16,19/16,39/16) + deg-2 minimax. +*/ + static float16_t _rh_atan(float16_t x) { + static const uint16_t at[3] = { 0x3555, 0xb266, 0x3092 }; + union half r0, ax, xr, hi, lo, z, sp, s, res, one, two, ohf, c; + r0.h = x; + if ( !f16_eq(x, x) ) { r0.c = _RH_QNAN; return r0.h; } // NaN + if ( r0.c == _RH_PINF ) { r0.c = 0x3e48; return r0.h; } // +inf -> pi/2 + if ( r0.c == _RH_NINF ) { r0.c = 0xbe48; return r0.h; } // -inf -> -pi/2 + if ( (r0.c == 0)||(r0.c == 0x8000U) ) { return x; } // +-0 + uint16_t neg = r0.c >> 15; + ax.c = r0.c & 0x7fffU; + one.c=0x3c00; two.c=0x4000; ohf.c=0x3e00; + int dir = 0; + if ( f16_lt(ax.h, _rh_bits(0x3700).h) ) { // |x| < 7/16 + xr.h = ax.h; hi.c = 0; lo.c = 0; dir = 1; + } else if ( f16_lt(ax.h, _rh_bits(0x3980).h) ) { // < 11/16 + xr.h = f16_div(f16_sub(f16_add(ax.h, ax.h), one.h), f16_add(two.h, ax.h)); + hi.c = 0x376b; lo.c = 0x019c; // atan(0.5) + } else if ( f16_lt(ax.h, _rh_bits(0x3cc0).h) ) { // < 19/16 + xr.h = f16_div(f16_sub(ax.h, one.h), f16_add(ax.h, one.h)); + hi.c = 0x3a48; lo.c = 0x0bed; // pi/4 + } else if ( f16_lt(ax.h, _rh_bits(0x40e0).h) ) { // < 39/16 + xr.h = f16_div(f16_sub(ax.h, ohf.h), f16_add(one.h, f16_mul(ohf.h, ax.h))); + hi.c = 0x3bdd; lo.c = 0x87a1; // atan(1.5) + } else { // -1/x + xr.h = f16_div(_rh_bits(0xbc00).h, ax.h); + hi.c = 0x3e48; lo.c = 0x0fed; // pi/2 + } + z.h = f16_mul(xr.h, xr.h); + sp.c = 0; for ( int i = 3; i-- != 0; ) { c.c = at[i]; sp.h = f16_add(f16_mul(sp.h, z.h), c.h); } + s.h = f16_mul(z.h, sp.h); + if ( dir ) res.h = f16_sub(xr.h, f16_mul(xr.h, s.h)); + else res.h = f16_sub(hi.h, f16_sub(f16_sub(f16_mul(xr.h, s.h), lo.h), xr.h)); + return (neg == 1) ? _rh_neg(res.h) : res.h; + } + // bare door ops (div/add/sub/mul) round per _math_rnd; atan kernel is %n. + static float16_t _rh_atan2(float16_t y, float16_t x) { + union half xb, pi, two, zero, mone, q, a, r; + zero.c = 0; pi.c = 0x4248; two.c = 0x4000; mone.c = 0xbc00; + xb.h = x; + if ( f16_lt(zero.h, x) ) { // x>0: atan(div y x) + softfloat_roundingMode = _math_rnd; q.h = f16_div(y, x); + softfloat_roundingMode = softfloat_round_near_even; return _rh_atan(q.h); + } + if ( f16_lt(x, zero.h) && f16_le(zero.h, y) ) { // x<0,y>=0: add(atan,pi) + softfloat_roundingMode = _math_rnd; q.h = f16_div(y, x); + softfloat_roundingMode = softfloat_round_near_even; a.h = _rh_atan(q.h); + softfloat_roundingMode = _math_rnd; r.h = f16_add(a.h, pi.h); + softfloat_roundingMode = softfloat_round_near_even; return r.h; + } + if ( f16_lt(x, zero.h) && f16_lt(y, zero.h) ) { // x<0,y<0: sub(atan,pi) + softfloat_roundingMode = _math_rnd; q.h = f16_div(y, x); + softfloat_roundingMode = softfloat_round_near_even; a.h = _rh_atan(q.h); + softfloat_roundingMode = _math_rnd; r.h = f16_sub(a.h, pi.h); + softfloat_roundingMode = softfloat_round_near_even; return r.h; + } + if ( (xb.c == 0) && f16_lt(zero.h, y) ) { // x==+0,y>0: div(pi,2) + softfloat_roundingMode = _math_rnd; r.h = f16_div(pi.h, two.h); + softfloat_roundingMode = softfloat_round_near_even; return r.h; + } + if ( (xb.c == 0) && f16_lt(y, zero.h) ) { // x==+0,y<0: mul(-1,div(pi,2)) + softfloat_roundingMode = _math_rnd; + r.h = f16_mul(mone.h, f16_div(pi.h, two.h)); + softfloat_roundingMode = softfloat_round_near_even; return r.h; + } + return zero.h; } - static inline float16_t _rh_2(float16_t x, float16_t n, - float32_t (*fun)(float32_t, float32_t)) { + +/* @rh pow/pow-n -- math.hoon ++rh ++pow/++pow-n */ + static float16_t _rh_pow_n(float16_t x, float16_t n) { + union half nn, p, one, two; + one.c = 0x3c00; two.c = 0x4000; + nn.h = n; + if ( nn.c == 0 ) return one.h; // n == +0 -> 1 + softfloat_roundingMode = _math_rnd; // bare mul/sub round per door r + p.h = x; + while ( !f16_lt(n, two.h) ) { p.h = f16_mul(p.h, x); n = f16_sub(n, one.h); } softfloat_roundingMode = softfloat_round_near_even; - float32_t v = fun(f16_to_f32(x), f16_to_f32(n)); - softfloat_roundingMode = _math_rnd; - return f32_to_f16(v); - } - static float16_t _rh_exp(float16_t x) { return _rh_1(x, _rs_exp); } - static float16_t _rh_log(float16_t x) { return _rh_1(x, _rs_log); } - static float16_t _rh_sin(float16_t x) { return _rh_1(x, _rs_sin); } - static float16_t _rh_cos(float16_t x) { return _rh_1(x, _rs_cos); } - static float16_t _rh_tan(float16_t x) { return _rh_1(x, _rs_tan); } - static float16_t _rh_atan(float16_t x) { return _rh_1(x, _rs_atan); } - static float16_t _rh_asin(float16_t x) { return _rh_1(x, _rs_asin); } - static float16_t _rh_acos(float16_t x) { return _rh_1(x, _rs_acos); } - static float16_t _rh_sqt(float16_t x) { return _rh_1(x, _rs_sqt); } - static float16_t _rh_cbt(float16_t x) { return _rh_1(x, _rs_cbt); } - static float16_t _rh_log2(float16_t x) { return _rh_1(x, _rs_log2); } - static float16_t _rh_log10(float16_t x) { return _rh_1(x, _rs_log10); } - static float16_t _rh_atan2(float16_t y, float16_t x) { return _rh_2(y, x, _rs_atan2); } - static float16_t _rh_pow(float16_t x, float16_t n) { return _rh_2(x, n, _rs_pow); } - static float16_t _rh_pow_n(float16_t x, float16_t n) { return _rh_2(x, n, _rs_pow_n); } + return p.h; + } + static float16_t _rh_pow(float16_t x, float16_t n) { + union half nn, ni, zero, lg, prod; + zero.c = 0; nn.h = n; + ni.h = i32_to_f16(f16_to_i32(n, softfloat_round_near_even, 0)); // san (need (toi n)) + if ( (nn.c == ni.c) && f16_lt(zero.h, n) ) // positive integer + return _rh_pow_n(x, ni.h); + lg.h = _rh_log(x); // %n kernel + softfloat_roundingMode = _math_rnd; // bare mul per door r + prod.h = f16_mul(n, lg.h); + softfloat_roundingMode = softfloat_round_near_even; + return _rh_exp(prod.h); // %n kernel: exp(n*log x) + } /* =================================================================== ** @rq (quad, 128-bit) cores -- math.hoon ++rq. Native f128 algorithms (the diff --git a/libmath/vere64/test/rh_check.c b/libmath/vere64/test/rh_check.c new file mode 100644 index 0000000..94acbf5 --- /dev/null +++ b/libmath/vere64/test/rh_check.c @@ -0,0 +1,48 @@ +// rh_check.c -- verify the native f16 @rh cores against the math-rh.hoon test +// vectors. Includes the master math.c with -DMATH_JET_HARNESS so the C tested +// is byte-for-byte the C the runtime compiles. Door r=%n in the tests, so we +// set _math_rnd = near_even before every call. +#define MATH_JET_HARNESS +#include "../noun/jets/i/math.c" + +#include + +static int fails = 0; +static uint16_t b1(uint16_t in, float16_t (*fn)(float16_t)) { + _math_rnd = softfloat_round_near_even; + union half u; u.h = fn(_rh_bits(in).h); return u.c; +} +static uint16_t b2(uint16_t a, uint16_t b, float16_t (*fn)(float16_t, float16_t)) { + _math_rnd = softfloat_round_near_even; + union half u; u.h = fn(_rh_bits(a).h, _rh_bits(b).h); return u.c; +} +static void chk(const char* nm, uint16_t got, uint16_t want) { + int ok = (got == want); + if ( !ok ) fails++; + printf("%-12s got 0x%04x want 0x%04x %s\n", nm, got, want, ok ? "OK" : "*** FAIL"); +} + +int main(void) { + chk("exp-half", b1(0x3800, _rh_exp), 0x3e98); + chk("exp-1", b1(0x3c00, _rh_exp), 0x4170); + chk("exp-n2", b1(0xc000, _rh_exp), 0x3055); + chk("exp-inf", b1(0x7c00, _rh_exp), 0x7c00); + chk("log-2", b1(0x4000, _rh_log), 0x398c); + chk("log-half", b1(0x3800, _rh_log), 0xb98c); + chk("sin-1", b1(0x3c00, _rh_sin), 0x3abb); + chk("sin-pi", b1(0x4248, _rh_sin), 0x13ed); + chk("cos-1", b1(0x3c00, _rh_cos), 0x3853); + chk("tan-1", b1(0x3c00, _rh_tan), 0x3e3a); + chk("atan-1", b1(0x3c00, _rh_atan), 0x3a48); + chk("atan-2", b1(0x4000, _rh_atan), 0x3c6e); + chk("asin-half", b1(0x3800, _rh_asin), 0x3830); + chk("acos-half", b1(0x3800, _rh_acos), 0x3c30); + chk("sqt-2", b1(0x4000, _rh_sqt), 0x3da8); + chk("sqt-10", b1(0x4900, _rh_sqt), 0x4253); + chk("cbt-8", b1(0x4800, _rh_cbt), 0x4000); + chk("log2-8", b1(0x4800, _rh_log2), 0x4200); + chk("log10-1k", b1(0x6400, _rh_log10),0x4205); + chk("pow-2-h", b2(0x4000, 0x3800, _rh_pow), 0x3da8); + printf("\n%s (%d failures)\n", fails ? "FAILED" : "ALL PASS", fails); + return fails ? 1 : 0; +} diff --git a/libmath/vere64/test/rh_sweep.c b/libmath/vere64/test/rh_sweep.c new file mode 100644 index 0000000..23d113a --- /dev/null +++ b/libmath/vere64/test/rh_sweep.c @@ -0,0 +1,29 @@ +// rh_sweep.c -- emit every finite f16 input->output for the native @rh kernels, +// so a Python model that mirrors the same Hoon algorithm can diff bit-for-bit +// across the WHOLE range (not just the 20 spot vectors). +#define MATH_JET_HARNESS +#include "../noun/jets/i/math.c" +#include + +static void sweep(const char* nm, float16_t (*fn)(float16_t)) { + _math_rnd = softfloat_round_near_even; + for ( unsigned b = 0; b <= 0xffff; b++ ) { + union half u; u.c = (uint16_t)b; + // skip NaN/inf inputs to keep the comparison about finite numerics + unsigned exp = (b >> 10) & 0x1f, man = b & 0x3ff; + if ( exp == 0x1f ) continue; // inf/nan + union half o; o.h = fn(u.h); + printf("%s %04x %04x\n", nm, b, o.c); + } +} +int main(void) { + sweep("exp", _rh_exp); + sweep("log", _rh_log); + sweep("sin", _rh_sin); + sweep("cos", _rh_cos); + sweep("atan", _rh_atan); + sweep("asin", _rh_asin); + sweep("acos", _rh_acos); + sweep("sqt", _rh_sqt); + return 0; +} From 837b6c75299a0f7d2c93c840baf831a097397e3d Mon Sep 17 00:00:00 2001 From: Sigilante Date: Fri, 12 Jun 2026 16:50:52 -0500 Subject: [PATCH 18/28] math: propagate native f16 @rh jets to 32-bit libmath/vere copy Identical to vere64 except the 4 two-arg u3r_mean lines (flat varargs vs brace pairs), preserving the documented 32/64-bit invariant. Co-Authored-By: Claude Opus 4.8 --- libmath/vere/noun/jets/i/math.c | 416 +++++++++++++++++++++++++++++--- 1 file changed, 382 insertions(+), 34 deletions(-) diff --git a/libmath/vere/noun/jets/i/math.c b/libmath/vere/noun/jets/i/math.c index 38d4844..3e1f050 100644 --- a/libmath/vere/noun/jets/i/math.c +++ b/libmath/vere/noun/jets/i/math.c @@ -967,12 +967,14 @@ typedef int64_t c3_ds; } /* =================================================================== -** @rh (half-precision) cores -- math.hoon ++rh. Every arm is -** narrow-sh(rs_fn(widen-hs(x))): widen f16->f32 (exact = f16_to_f32), -** compute in @rs, narrow f32->f16 (= f32_to_f16) honoring the door's r. -** The rs call inherits r too (composites honor it; kernels stay %n). No new -** algorithm cores -- the @rs cores are reused. Verified: the Hoon narrow-sh -** is bit-exact to f32_to_f16 in all four rounding modes. +** @rh (half-precision) cores -- math.hoon ++rh. NATIVE f16: each core +** computes entirely in half-precision (SoftFloat f16 ops), mirroring the +** native Hoon arms op-for-op -- NOT widen-to-f32-and-narrow. Same reductions +** and Horner order as @rd/@rs but with the f16 minimax coeffs read from the +** Hoon (lower polynomial degrees: sin/cos/atan/ainv are shorter, ainv has no +** denominator, acos has no tiny branch). Marshalling is chub-based (low 16 +** bits), so word-size-agnostic like @rd/@rs. Kernels round near-even; the +** composites (tan/atan2/pow/pow-n) honor the door's r via _math_rnd. ** =================================================================== */ union half { @@ -980,37 +982,383 @@ typedef int64_t c3_ds; uint16_t c; }; - // widen f16->f32 (exact), run an @rs core, narrow f32->f16 per _math_rnd. - // _math_rnd is the door's r (set by the wrapper): the rs composites honor it - // and the narrow rounds by it; the rs kernels run at near-even. - static inline float16_t _rh_1(float16_t x, float32_t (*fun)(float32_t)) { - softfloat_roundingMode = softfloat_round_near_even; - float32_t v = fun(f16_to_f32(x)); + static const uint16_t _RH_QNAN = 0x7e00U; + static const uint16_t _RH_PINF = 0x7c00U; + static const uint16_t _RH_NINF = 0xfc00U; + + static inline union half _rh_bits(uint16_t b) { union half u; u.c = b; return u; } + static inline float16_t _rh_neg(float16_t a) { // (sub .0 a) + union half z; z.c = 0; return f16_sub(z.h, a); + } + +/* @rh exp -- math.hoon ++rh ++exp +** x = k*ln2 + r (Cody-Waite), exp(x) = 2^k * P(r), P a degree-4 minimax. +*/ + // pow2(j) = (|j+15|)<<10 as f16 bits = 2^j (normal range j in [-14,15]) + static inline float16_t _rh_pow2(c3_ds j) { + int v = (int)(j + 15); if ( v < 0 ) v = -v; + union half u; u.c = (uint16_t)(v << 10); return u.h; + } + // scale2: ldexp with overflow/subnormal tails (math.hoon ++rh ++exp) + static inline float16_t _rh_scale2(float16_t p, c3_ds k) { + if ( (k - 16) >= 0 ) { // k>=16 + return f16_mul(f16_mul(p, _rh_pow2(15)), _rh_pow2(k - 15)); + } + if ( !((k + 14) >= 0) ) { // k<-14 + return f16_mul(f16_mul(p, _rh_pow2(k + 11)), _rh_pow2(-11)); + } + return f16_mul(p, _rh_pow2(k)); + } + static float16_t _rh_exp(float16_t x) { + union half r0; + static const uint16_t cs[5] = { 0x3c00, 0x3c00, 0x3800, 0x3160, 0x295c }; + union half log2e, ln2hi, ln2lo, ka, kf, rr, p, c, zero; + zero.c = 0; + r0.h = x; + if ( !f16_eq(x, x) ) { r0.c = _RH_QNAN; return r0.h; } // NaN + if ( r0.c == _RH_PINF ) { return x; } // +inf + if ( r0.c == _RH_NINF ) { r0.c = 0; return r0.h; } // -inf -> 0 + + log2e.c = 0x3dc5; ln2hi.c = 0x3980; ln2lo.c = 0x1dc8; + + c3_ds k = (c3_ds)f16_to_i32(f16_mul(x, log2e.h), softfloat_round_near_even, 0); + if ( (k - 17) >= 0 ) { r0.c = _RH_PINF; return r0.h; } // overflow -> inf + if ( !((k + 24) >= 0) ) { r0.c = 0; return r0.h; } // underflow -> 0 + + ka.h = ui32_to_f16( (uint32_t)(k < 0 ? -k : k) ); + kf.h = (k >= 0) ? ka.h : f16_sub(zero.h, ka.h); + rr.h = f16_sub( f16_sub(x, f16_mul(kf.h, ln2hi.h)), f16_mul(kf.h, ln2lo.h) ); + + p.c = 0; + for ( int i = 5; i-- != 0; ) { // Horner over flop(cs): c4..c0 + c.c = cs[i]; + p.h = f16_add(f16_mul(p.h, rr.h), c.h); + } + return _rh_scale2(p.h, k); + } + +/* @rh sin/cos/tan -- math.hoon ++rh ++sin/++cos/++rh-trig/++tan +** x = q*(pi/2) + (rhi+rlo) (3-part pi/2), fdlibm sin/cos kernels by q&3 (each +** with just 2 coeffs). tan = sin/cos (the div honors the door r). +*/ + static const uint16_t _RH_SC[2] = { 0xb155, 0x2044 }; // sin kernel coeffs + static const uint16_t _RH_CC[2] = { 0x2955, 0x95b0 }; // cos kernel coeffs + static float16_t _rh_ksin(float16_t xx, float16_t yy) { + union half z, r, v, aa, bb, dd, c, half; + half.c = 0x3800; + z.h = f16_mul(xx, xx); + r.c = 0; // Horner over flop(tail sc): sc[1] + for ( int i = 2; i-- != 1; ) { c.c = _RH_SC[i]; r.h = f16_add(f16_mul(r.h, z.h), c.h); } + v.h = f16_mul(z.h, xx); + aa.h = f16_sub(f16_mul(half.h, yy), f16_mul(v.h, r.h)); + bb.h = f16_sub(f16_mul(z.h, aa.h), yy); + dd.h = f16_sub(bb.h, f16_mul(v.h, _rh_bits(_RH_SC[0]).h)); + return f16_sub(xx, dd.h); + } + static float16_t _rh_kcos(float16_t xx, float16_t yy) { + union half z, rc, hz, w2, aa, bb, c, half, one; + half.c = 0x3800; one.c = 0x3c00; + z.h = f16_mul(xx, xx); + rc.c = 0; // Horner over flop(cc): cc[1..0] + for ( int i = 2; i-- != 0; ) { c.c = _RH_CC[i]; rc.h = f16_add(f16_mul(rc.h, z.h), c.h); } + hz.h = f16_mul(half.h, z.h); + w2.h = f16_sub(one.h, hz.h); + aa.h = f16_sub(f16_sub(one.h, w2.h), hz.h); + bb.h = f16_sub(f16_mul(f16_mul(z.h, z.h), rc.h), f16_mul(xx, yy)); + return f16_add(w2.h, f16_add(aa.h, bb.h)); + } + // trig-fin: is_sin ? sin(x) : cos(x); ax=|x|, sb=sign bit + static float16_t _rh_trigfin(int is_sin, float16_t ax, uint16_t sb) { + union half qf, r1, r2, w, rhi, rlo, ks, kc, v; + c3_ds q = (c3_ds)f16_to_i32(f16_mul(ax, _rh_bits(0x3918).h), + softfloat_round_near_even, 0); // round(ax*2/pi) + c3_d aq = (c3_d)(q < 0 ? -q : q); + qf.h = ui32_to_f16((uint32_t)aq); + r1.h = f16_sub(ax, f16_mul(qf.h, _rh_bits(0x3e00).h)); // ax - qf*pio2_1 + r2.h = f16_sub(r1.h, f16_mul(qf.h, _rh_bits(0x2c80).h)); // r1 - qf*pio2_2 + w.h = f16_mul(qf.h, _rh_bits(0x0fed).h); // qf*pio2_3 + rhi.h = f16_sub(r2.h, w.h); + rlo.h = f16_sub(f16_sub(r2.h, rhi.h), w.h); + int m = (int)(aq & 3); + ks.h = _rh_ksin(rhi.h, rlo.h); + kc.h = _rh_kcos(rhi.h, rlo.h); + if ( is_sin ) { + v.h = (m==0) ? ks.h : (m==1) ? kc.h : (m==2) ? _rh_neg(ks.h) : _rh_neg(kc.h); + return (sb == 1) ? _rh_neg(v.h) : v.h; + } + return (m==0) ? kc.h : (m==1) ? _rh_neg(ks.h) : (m==2) ? _rh_neg(kc.h) : ks.h; + } + static float16_t _rh_sin(float16_t x) { + union half r0, ax; + r0.h = x; + if ( !f16_eq(x, x) ) { r0.c = _RH_QNAN; return r0.h; } // NaN + if ( (r0.c == _RH_PINF)||(r0.c == _RH_NINF) ) { r0.c = _RH_QNAN; return r0.h; } // +-inf -> NaN + if ( (r0.c == 0)||(r0.c == 0x8000U) ) { return x; } // +-0 -> +-0 + ax.c = r0.c & 0x7fffU; + return _rh_trigfin(1, ax.h, r0.c >> 15); + } + static float16_t _rh_cos(float16_t x) { + union half r0, ax; + r0.h = x; + if ( !f16_eq(x, x) ) { r0.c = _RH_QNAN; return r0.h; } // NaN + if ( (r0.c == _RH_PINF)||(r0.c == _RH_NINF) ) { r0.c = _RH_QNAN; return r0.h; } // +-inf -> NaN + ax.c = r0.c & 0x7fffU; + return _rh_trigfin(0, ax.h, 0); + } + // tan = (div (sin x) (cos x)): sin/cos kernels %n, the bare div per door r + static float16_t _rh_tan(float16_t x) { + float16_t s = _rh_sin(x), c = _rh_cos(x); softfloat_roundingMode = _math_rnd; - return f32_to_f16(v); + float16_t r = f16_div(s, c); + softfloat_roundingMode = softfloat_round_near_even; + return r; + } + +/* @rh sqt -- math.hoon ++rh ++sqt = (sqt:^rh x): correctly-rounded f16 sqrt. */ + static float16_t _rh_sqt(float16_t x) { + union half r; r.h = f16_sqrt(x); + if ( !f16_eq(r.h, r.h) ) r.c = _RH_QNAN; // _nan_unify + return r.h; + } + +/* @rh log/log-2/log-10 -- math.hoon ++rh ++log/++lr/++log-2/++log-10 +** x = 2^e * m, m in [sqrt(1/2),sqrt(2)); log(1+f) via atanh series (deg-1). +*/ + // +lr: finite positive x -> *ef = e as @rh, *l1 = log(mantissa) + static void _rh_lr(float16_t x, float16_t* ef, float16_t* l1) { + static const uint16_t cs[2] = { 0x3555, 0x3266 }; + union half xb, m, f, s, z, p2, r, ll, efa, c, one, half; + one.c = 0x3c00; half.c = 0x3800; + xb.h = x; + int sub = (((xb.c >> 10) & 0x1fU) == 0); + if ( sub ) xb.h = f16_mul(x, _rh_bits(0x6400).h); // *2^10 + int32_t ae = sub ? -10 : 0; + int32_t e = (int32_t)((xb.c >> 10) & 0x1fU) - 15; + m.c = (xb.c & 0x3ffU) | 0x3c00U; + if ( !f16_lt(m.h, _rh_bits(0x3da8).h) ) { // m >= sqrt(2) + m.h = f16_mul(m.h, half.h); e += 1; + } + e += ae; + f.h = f16_sub(m.h, one.h); + s.h = f16_div(f.h, f16_add(m.h, one.h)); + z.h = f16_mul(s.h, s.h); + p2.c = 0; for ( int i = 2; i-- != 0; ) { c.c = cs[i]; p2.h = f16_add(f16_mul(p2.h, z.h), c.h); } + r.h = f16_mul(f16_add(z.h, z.h), p2.h); + ll.h = f16_sub(f.h, f16_mul(s.h, f16_sub(f.h, r.h))); + efa.h = ui32_to_f16((uint32_t)(e < 0 ? -e : e)); + *ef = (e >= 0) ? efa.h : _rh_neg(efa.h); + *l1 = ll.h; + } + // shared guards for log/log-2/log-10; returns 1 (and sets *g) on a special case + static int _rh_log_guard(float16_t x, float16_t* g) { + union half r0; r0.h = x; + if ( !f16_eq(x, x) ) { r0.c = _RH_QNAN; *g = r0.h; return 1; } // NaN + if ( r0.c == _RH_PINF ) { *g = x; return 1; } // +inf -> inf + if ( (r0.c == 0)||(r0.c == 0x8000U) ) { r0.c = _RH_NINF; *g = r0.h; return 1; } // +-0 -> -inf + if ( (r0.c >> 15) == 1 ){ r0.c = _RH_QNAN; *g = r0.h; return 1; } // x<0 -> NaN + return 0; + } + static float16_t _rh_log(float16_t x) { + union half g, ef, l1, hi, lo; + if ( _rh_log_guard(x, &g.h) ) return g.h; + _rh_lr(x, &ef.h, &l1.h); + hi.h = f16_mul(ef.h, _rh_bits(0x3980).h); // e*ln2hi + lo.h = f16_mul(ef.h, _rh_bits(0x1dc8).h); // e*ln2lo + return f16_add(hi.h, f16_add(l1.h, lo.h)); + } + static float16_t _rh_log2(float16_t x) { + union half g, ef, l1; + if ( _rh_log_guard(x, &g.h) ) return g.h; + _rh_lr(x, &ef.h, &l1.h); + return f16_add(ef.h, f16_mul(l1.h, _rh_bits(0x3dc5).h)); // e + lm/ln2 + } + static float16_t _rh_log10(float16_t x) { + union half g, ef, l1; + if ( _rh_log_guard(x, &g.h) ) return g.h; + _rh_lr(x, &ef.h, &l1.h); + return f16_add(f16_mul(ef.h, _rh_bits(0x34d1).h), // e*log10(2) + f16_mul(l1.h, _rh_bits(0x36f3).h)); // + lm/ln10 + } + +/* @rh cbt -- math.hoon ++rh ++cbt = sign(x) * exp(log|x| / 3). */ + static float16_t _rh_cbt(float16_t x) { + union half r0, ax, r; + r0.h = x; + if ( !f16_eq(x, x) ) { return x; } // NaN + if ( (r0.c == 0)||(r0.c == 0x8000U) ) { return x; } // +-0 + ax.c = r0.c & 0x7fffU; + r.h = _rh_exp(f16_mul(_rh_log(ax.h), _rh_bits(0x3555).h)); // exp(log|x|/3) + return ((r0.c >> 15) == 1) ? _rh_neg(r.h) : r.h; + } + +/* @rh asin/acos -- math.hoon ++rh ++asin/++acos/++rh-ainv +** poly kernel R(t) = t*P(t) (deg-4, NO denominator); sqt = f16_sqrt. The +** near-1 asin branch omits pio2l (f16 script), acos has no tiny branch. +*/ + static float16_t _rh_ainv_rr(float16_t t) { + static const uint16_t ps[4] = { 0x3155, 0x2cea, 0x2729, 0x2ccc }; + union half pp, c; + pp.c = 0; for ( int i = 4; i-- != 0; ) { c.c = ps[i]; pp.h = f16_add(f16_mul(pp.h, t), c.h); } + return f16_mul(t, pp.h); + } + static float16_t _rh_asin(float16_t x) { + union half r0, ax, t, w, r, s, res, half, one, two, pio2h, pio2l, pio4, near; + half.c=0x3800; one.c=0x3c00; two.c=0x4000; + pio2h.c=0x3e48; pio2l.c=0x0fed; pio4.c=0x3a48; near.c=0x3bcd; + r0.h = x; + if ( !f16_eq(x, x) ) { r0.c = _RH_QNAN; return r0.h; } // NaN + uint16_t sgn = r0.c >> 15; + ax.c = r0.c & 0x7fffU; + if ( f16_lt(one.h, ax.h) ) { r0.c = _RH_QNAN; return r0.h; } // |x|>1 -> NaN + if ( ax.c == one.c ) // |x|==1 + return f16_add(f16_mul(x, pio2h.h), f16_mul(x, pio2l.h)); + if ( f16_lt(ax.h, half.h) ) { // |x|<0.5 + if ( f16_lt(ax.h, _rh_bits(0x0c00).h) ) return x; // |x|<2^-12 -> x + t.h = f16_mul(x, x); + return f16_add(x, f16_mul(x, _rh_ainv_rr(t.h))); + } + w.h = f16_sub(one.h, ax.h); + t.h = f16_mul(w.h, half.h); + r.h = _rh_ainv_rr(t.h); + s.h = f16_sqrt(t.h); + if ( f16_le(near.h, ax.h) ) { // |x|>=0.975 + res.h = f16_sub(pio2h.h, f16_mul(two.h, f16_add(s.h, f16_mul(s.h, r.h)))); + return (sgn == 1) ? _rh_neg(res.h) : res.h; + } + { union half df, cc, p2, q2; + df.c = s.c & 0xfff0U; + cc.h = f16_div(f16_sub(t.h, f16_mul(df.h, df.h)), f16_add(s.h, df.h)); + p2.h = f16_sub(f16_mul(two.h, f16_mul(s.h, r.h)), f16_sub(pio2l.h, f16_mul(two.h, cc.h))); + q2.h = f16_sub(pio4.h, f16_mul(two.h, df.h)); + res.h = f16_sub(pio4.h, f16_sub(p2.h, q2.h)); + return (sgn == 1) ? _rh_neg(res.h) : res.h; + } + } + static float16_t _rh_acos(float16_t x) { + union half r0, ax, z, s, r, w, half, one, two, pih, pio2h, pio2l; + half.c=0x3800; one.c=0x3c00; two.c=0x4000; + pih.c=0x4248; pio2h.c=0x3e48; pio2l.c=0x0fed; + r0.h = x; + if ( !f16_eq(x, x) ) { r0.c = _RH_QNAN; return r0.h; } // NaN + uint16_t neg = r0.c >> 15; + ax.c = r0.c & 0x7fffU; + if ( f16_lt(one.h, ax.h) ) { r0.c = _RH_QNAN; return r0.h; } // |x|>1 -> NaN + if ( ax.c == one.c ) { // |x|==1 + if ( neg == 0 ) { union half z0; z0.c = 0; return z0.h; } // 1 -> 0 + return f16_add(pih.h, f16_mul(two.h, pio2l.h)); // -1 -> pi + } + if ( f16_lt(ax.h, half.h) ) { // |x|<0.5 + z.h = f16_mul(x, x); + r.h = _rh_ainv_rr(z.h); + return f16_sub(pio2h.h, f16_sub(x, f16_sub(pio2l.h, f16_mul(x, r.h)))); + } + if ( neg == 1 ) { // x <= -0.5 + z.h = f16_mul(f16_add(one.h, x), half.h); + s.h = f16_sqrt(z.h); + r.h = _rh_ainv_rr(z.h); + w.h = f16_sub(f16_mul(r.h, s.h), pio2l.h); + return f16_sub(pih.h, f16_mul(two.h, f16_add(s.h, w.h))); + } + z.h = f16_mul(f16_sub(one.h, x), half.h); // x >= 0.5 + s.h = f16_sqrt(z.h); + r.h = _rh_ainv_rr(z.h); + return f16_mul(two.h, f16_add(s.h, f16_mul(s.h, r.h))); + } + +/* @rh atan/atan2 -- math.hoon ++rh ++atan/++rh-atan/++atan2 +** fdlibm breakpoint reduction (7/16,11/16,19/16,39/16) + deg-2 minimax. +*/ + static float16_t _rh_atan(float16_t x) { + static const uint16_t at[3] = { 0x3555, 0xb266, 0x3092 }; + union half r0, ax, xr, hi, lo, z, sp, s, res, one, two, ohf, c; + r0.h = x; + if ( !f16_eq(x, x) ) { r0.c = _RH_QNAN; return r0.h; } // NaN + if ( r0.c == _RH_PINF ) { r0.c = 0x3e48; return r0.h; } // +inf -> pi/2 + if ( r0.c == _RH_NINF ) { r0.c = 0xbe48; return r0.h; } // -inf -> -pi/2 + if ( (r0.c == 0)||(r0.c == 0x8000U) ) { return x; } // +-0 + uint16_t neg = r0.c >> 15; + ax.c = r0.c & 0x7fffU; + one.c=0x3c00; two.c=0x4000; ohf.c=0x3e00; + int dir = 0; + if ( f16_lt(ax.h, _rh_bits(0x3700).h) ) { // |x| < 7/16 + xr.h = ax.h; hi.c = 0; lo.c = 0; dir = 1; + } else if ( f16_lt(ax.h, _rh_bits(0x3980).h) ) { // < 11/16 + xr.h = f16_div(f16_sub(f16_add(ax.h, ax.h), one.h), f16_add(two.h, ax.h)); + hi.c = 0x376b; lo.c = 0x019c; // atan(0.5) + } else if ( f16_lt(ax.h, _rh_bits(0x3cc0).h) ) { // < 19/16 + xr.h = f16_div(f16_sub(ax.h, one.h), f16_add(ax.h, one.h)); + hi.c = 0x3a48; lo.c = 0x0bed; // pi/4 + } else if ( f16_lt(ax.h, _rh_bits(0x40e0).h) ) { // < 39/16 + xr.h = f16_div(f16_sub(ax.h, ohf.h), f16_add(one.h, f16_mul(ohf.h, ax.h))); + hi.c = 0x3bdd; lo.c = 0x87a1; // atan(1.5) + } else { // -1/x + xr.h = f16_div(_rh_bits(0xbc00).h, ax.h); + hi.c = 0x3e48; lo.c = 0x0fed; // pi/2 + } + z.h = f16_mul(xr.h, xr.h); + sp.c = 0; for ( int i = 3; i-- != 0; ) { c.c = at[i]; sp.h = f16_add(f16_mul(sp.h, z.h), c.h); } + s.h = f16_mul(z.h, sp.h); + if ( dir ) res.h = f16_sub(xr.h, f16_mul(xr.h, s.h)); + else res.h = f16_sub(hi.h, f16_sub(f16_sub(f16_mul(xr.h, s.h), lo.h), xr.h)); + return (neg == 1) ? _rh_neg(res.h) : res.h; + } + // bare door ops (div/add/sub/mul) round per _math_rnd; atan kernel is %n. + static float16_t _rh_atan2(float16_t y, float16_t x) { + union half xb, pi, two, zero, mone, q, a, r; + zero.c = 0; pi.c = 0x4248; two.c = 0x4000; mone.c = 0xbc00; + xb.h = x; + if ( f16_lt(zero.h, x) ) { // x>0: atan(div y x) + softfloat_roundingMode = _math_rnd; q.h = f16_div(y, x); + softfloat_roundingMode = softfloat_round_near_even; return _rh_atan(q.h); + } + if ( f16_lt(x, zero.h) && f16_le(zero.h, y) ) { // x<0,y>=0: add(atan,pi) + softfloat_roundingMode = _math_rnd; q.h = f16_div(y, x); + softfloat_roundingMode = softfloat_round_near_even; a.h = _rh_atan(q.h); + softfloat_roundingMode = _math_rnd; r.h = f16_add(a.h, pi.h); + softfloat_roundingMode = softfloat_round_near_even; return r.h; + } + if ( f16_lt(x, zero.h) && f16_lt(y, zero.h) ) { // x<0,y<0: sub(atan,pi) + softfloat_roundingMode = _math_rnd; q.h = f16_div(y, x); + softfloat_roundingMode = softfloat_round_near_even; a.h = _rh_atan(q.h); + softfloat_roundingMode = _math_rnd; r.h = f16_sub(a.h, pi.h); + softfloat_roundingMode = softfloat_round_near_even; return r.h; + } + if ( (xb.c == 0) && f16_lt(zero.h, y) ) { // x==+0,y>0: div(pi,2) + softfloat_roundingMode = _math_rnd; r.h = f16_div(pi.h, two.h); + softfloat_roundingMode = softfloat_round_near_even; return r.h; + } + if ( (xb.c == 0) && f16_lt(y, zero.h) ) { // x==+0,y<0: mul(-1,div(pi,2)) + softfloat_roundingMode = _math_rnd; + r.h = f16_mul(mone.h, f16_div(pi.h, two.h)); + softfloat_roundingMode = softfloat_round_near_even; return r.h; + } + return zero.h; } - static inline float16_t _rh_2(float16_t x, float16_t n, - float32_t (*fun)(float32_t, float32_t)) { + +/* @rh pow/pow-n -- math.hoon ++rh ++pow/++pow-n */ + static float16_t _rh_pow_n(float16_t x, float16_t n) { + union half nn, p, one, two; + one.c = 0x3c00; two.c = 0x4000; + nn.h = n; + if ( nn.c == 0 ) return one.h; // n == +0 -> 1 + softfloat_roundingMode = _math_rnd; // bare mul/sub round per door r + p.h = x; + while ( !f16_lt(n, two.h) ) { p.h = f16_mul(p.h, x); n = f16_sub(n, one.h); } softfloat_roundingMode = softfloat_round_near_even; - float32_t v = fun(f16_to_f32(x), f16_to_f32(n)); - softfloat_roundingMode = _math_rnd; - return f32_to_f16(v); - } - static float16_t _rh_exp(float16_t x) { return _rh_1(x, _rs_exp); } - static float16_t _rh_log(float16_t x) { return _rh_1(x, _rs_log); } - static float16_t _rh_sin(float16_t x) { return _rh_1(x, _rs_sin); } - static float16_t _rh_cos(float16_t x) { return _rh_1(x, _rs_cos); } - static float16_t _rh_tan(float16_t x) { return _rh_1(x, _rs_tan); } - static float16_t _rh_atan(float16_t x) { return _rh_1(x, _rs_atan); } - static float16_t _rh_asin(float16_t x) { return _rh_1(x, _rs_asin); } - static float16_t _rh_acos(float16_t x) { return _rh_1(x, _rs_acos); } - static float16_t _rh_sqt(float16_t x) { return _rh_1(x, _rs_sqt); } - static float16_t _rh_cbt(float16_t x) { return _rh_1(x, _rs_cbt); } - static float16_t _rh_log2(float16_t x) { return _rh_1(x, _rs_log2); } - static float16_t _rh_log10(float16_t x) { return _rh_1(x, _rs_log10); } - static float16_t _rh_atan2(float16_t y, float16_t x) { return _rh_2(y, x, _rs_atan2); } - static float16_t _rh_pow(float16_t x, float16_t n) { return _rh_2(x, n, _rs_pow); } - static float16_t _rh_pow_n(float16_t x, float16_t n) { return _rh_2(x, n, _rs_pow_n); } + return p.h; + } + static float16_t _rh_pow(float16_t x, float16_t n) { + union half nn, ni, zero, lg, prod; + zero.c = 0; nn.h = n; + ni.h = i32_to_f16(f16_to_i32(n, softfloat_round_near_even, 0)); // san (need (toi n)) + if ( (nn.c == ni.c) && f16_lt(zero.h, n) ) // positive integer + return _rh_pow_n(x, ni.h); + lg.h = _rh_log(x); // %n kernel + softfloat_roundingMode = _math_rnd; // bare mul per door r + prod.h = f16_mul(n, lg.h); + softfloat_roundingMode = softfloat_round_near_even; + return _rh_exp(prod.h); // %n kernel: exp(n*log x) + } /* =================================================================== ** @rq (quad, 128-bit) cores -- math.hoon ++rq. Native f128 algorithms (the From 6b0bae72cae9b098f73a9fb465f6e87d0dc65841 Mon Sep 17 00:00:00 2001 From: Sigilante Date: Fri, 12 Jun 2026 20:59:24 -0500 Subject: [PATCH 19/28] math: @rh jet wrappers must set softfloat_roundingMode, not _math_rnd The native f16 kernels read the global softfloat_roundingMode (via f16_mul/add etc.), but the @rh wrappers only set _math_rnd -- so a kernel called after a %z door op ran under round-toward-zero, corrupting sin/cos (exp/atan survived by luck). Mirror the @rd/@rs wrappers: _rh_jet/_rh_jet2 and the 15 u3qi_rh_* softpaths now set softfloat_roundingMode = near_even (kernels) and _math_rnd = door r (composites). Verified on a fresh fakeship (clean jet dashboard): sin 0x3abb, cos 0x3853, exp 0x4170, tan 0x3e3a(%n)/0x3e39(%z), -test ok=%.y. Hardened rh_check.c to pre-dirty the global mode so it catches this class. Co-Authored-By: Claude Opus 4.8 --- libmath/vere/noun/jets/i/math.c | 36 ++++++++++++++++--------------- libmath/vere64/noun/jets/i/math.c | 36 ++++++++++++++++--------------- libmath/vere64/test/rh_check.c | 8 +++++++ 3 files changed, 46 insertions(+), 34 deletions(-) diff --git a/libmath/vere/noun/jets/i/math.c b/libmath/vere/noun/jets/i/math.c index 3e1f050..4edbc41 100644 --- a/libmath/vere/noun/jets/i/math.c +++ b/libmath/vere/noun/jets/i/math.c @@ -1691,7 +1691,8 @@ typedef int64_t c3_ds; static u3_noun _rh_jet(u3_noun cor, float16_t (*fun)(float16_t)) { u3_noun x = u3r_at(u3x_sam, cor); if ( u3_none == x || c3n == u3ud(x) ) return u3m_bail(c3__exit); - _math_rnd = _rnd_of(u3r_at(60, cor)); + softfloat_roundingMode = softfloat_round_near_even; // kernels run near-even + _math_rnd = _rnd_of(u3r_at(60, cor)); // door rounding r (for @rh tan/cbt/log-2/log-10) return _rh_out(fun(_rh_in(x))); } static u3_noun _rh_jet2(u3_noun cor, float16_t (*fun)(float16_t, float16_t)) { @@ -1700,40 +1701,41 @@ typedef int64_t c3_ds; c3n == u3ud(x) || c3n == u3ud(n) ) { return u3m_bail(c3__exit); } - _math_rnd = _rnd_of(u3r_at(60, cor)); + softfloat_roundingMode = softfloat_round_near_even; // kernels run near-even + _math_rnd = _rnd_of(u3r_at(60, cor)); // door rounding r (composites) return _rh_out(fun(_rh_in(x), _rh_in(n))); } - u3_noun u3qi_rh_exp(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_exp(_rh_in(a))); } + u3_noun u3qi_rh_exp(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rh_out(_rh_exp(_rh_in(a))); } u3_noun u3wi_rh_exp(u3_noun cor) { return _rh_jet(cor, _rh_exp); } - u3_noun u3qi_rh_log(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_log(_rh_in(a))); } + u3_noun u3qi_rh_log(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rh_out(_rh_log(_rh_in(a))); } u3_noun u3wi_rh_log(u3_noun cor) { return _rh_jet(cor, _rh_log); } - u3_noun u3qi_rh_sin(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_sin(_rh_in(a))); } + u3_noun u3qi_rh_sin(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rh_out(_rh_sin(_rh_in(a))); } u3_noun u3wi_rh_sin(u3_noun cor) { return _rh_jet(cor, _rh_sin); } - u3_noun u3qi_rh_cos(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_cos(_rh_in(a))); } + u3_noun u3qi_rh_cos(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rh_out(_rh_cos(_rh_in(a))); } u3_noun u3wi_rh_cos(u3_noun cor) { return _rh_jet(cor, _rh_cos); } - u3_noun u3qi_rh_tan(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_tan(_rh_in(a))); } + u3_noun u3qi_rh_tan(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rh_out(_rh_tan(_rh_in(a))); } u3_noun u3wi_rh_tan(u3_noun cor) { return _rh_jet(cor, _rh_tan); } - u3_noun u3qi_rh_atan(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_atan(_rh_in(a))); } + u3_noun u3qi_rh_atan(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rh_out(_rh_atan(_rh_in(a))); } u3_noun u3wi_rh_atan(u3_noun cor){ return _rh_jet(cor, _rh_atan); } - u3_noun u3qi_rh_asin(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_asin(_rh_in(a))); } + u3_noun u3qi_rh_asin(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rh_out(_rh_asin(_rh_in(a))); } u3_noun u3wi_rh_asin(u3_noun cor){ return _rh_jet(cor, _rh_asin); } - u3_noun u3qi_rh_acos(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_acos(_rh_in(a))); } + u3_noun u3qi_rh_acos(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rh_out(_rh_acos(_rh_in(a))); } u3_noun u3wi_rh_acos(u3_noun cor){ return _rh_jet(cor, _rh_acos); } - u3_noun u3qi_rh_sqt(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_sqt(_rh_in(a))); } + u3_noun u3qi_rh_sqt(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rh_out(_rh_sqt(_rh_in(a))); } u3_noun u3wi_rh_sqt(u3_noun cor) { return _rh_jet(cor, _rh_sqt); } - u3_noun u3qi_rh_cbt(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_cbt(_rh_in(a))); } + u3_noun u3qi_rh_cbt(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rh_out(_rh_cbt(_rh_in(a))); } u3_noun u3wi_rh_cbt(u3_noun cor) { return _rh_jet(cor, _rh_cbt); } - u3_noun u3qi_rh_log2(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_log2(_rh_in(a))); } + u3_noun u3qi_rh_log2(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rh_out(_rh_log2(_rh_in(a))); } u3_noun u3wi_rh_log2(u3_noun cor){ return _rh_jet(cor, _rh_log2); } - u3_noun u3qi_rh_log10(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_log10(_rh_in(a))); } + u3_noun u3qi_rh_log10(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rh_out(_rh_log10(_rh_in(a))); } u3_noun u3wi_rh_log10(u3_noun cor){ return _rh_jet(cor, _rh_log10); } - u3_noun u3qi_rh_atan2(u3_atom y, u3_atom x) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_atan2(_rh_in(y), _rh_in(x))); } + u3_noun u3qi_rh_atan2(u3_atom y, u3_atom x) { softfloat_roundingMode=softfloat_round_near_even; return _rh_out(_rh_atan2(_rh_in(y), _rh_in(x))); } u3_noun u3wi_rh_atan2(u3_noun cor){ return _rh_jet2(cor, _rh_atan2); } - u3_noun u3qi_rh_pow(u3_atom x, u3_atom n) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_pow(_rh_in(x), _rh_in(n))); } + u3_noun u3qi_rh_pow(u3_atom x, u3_atom n) { softfloat_roundingMode=softfloat_round_near_even; return _rh_out(_rh_pow(_rh_in(x), _rh_in(n))); } u3_noun u3wi_rh_pow(u3_noun cor) { return _rh_jet2(cor, _rh_pow); } - u3_noun u3qi_rh_pow_n(u3_atom x, u3_atom n) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_pow_n(_rh_in(x), _rh_in(n))); } + u3_noun u3qi_rh_pow_n(u3_atom x, u3_atom n) { softfloat_roundingMode=softfloat_round_near_even; return _rh_out(_rh_pow_n(_rh_in(x), _rh_in(n))); } u3_noun u3wi_rh_pow_n(u3_noun cor){ return _rh_jet2(cor, _rh_pow_n); } #endif diff --git a/libmath/vere64/noun/jets/i/math.c b/libmath/vere64/noun/jets/i/math.c index 66d76a8..302ffc4 100644 --- a/libmath/vere64/noun/jets/i/math.c +++ b/libmath/vere64/noun/jets/i/math.c @@ -1691,7 +1691,8 @@ typedef int64_t c3_ds; static u3_noun _rh_jet(u3_noun cor, float16_t (*fun)(float16_t)) { u3_noun x = u3r_at(u3x_sam, cor); if ( u3_none == x || c3n == u3ud(x) ) return u3m_bail(c3__exit); - _math_rnd = _rnd_of(u3r_at(60, cor)); + softfloat_roundingMode = softfloat_round_near_even; // kernels run near-even + _math_rnd = _rnd_of(u3r_at(60, cor)); // door rounding r (for @rh tan/cbt/log-2/log-10) return _rh_out(fun(_rh_in(x))); } static u3_noun _rh_jet2(u3_noun cor, float16_t (*fun)(float16_t, float16_t)) { @@ -1700,40 +1701,41 @@ typedef int64_t c3_ds; c3n == u3ud(x) || c3n == u3ud(n) ) { return u3m_bail(c3__exit); } - _math_rnd = _rnd_of(u3r_at(60, cor)); + softfloat_roundingMode = softfloat_round_near_even; // kernels run near-even + _math_rnd = _rnd_of(u3r_at(60, cor)); // door rounding r (composites) return _rh_out(fun(_rh_in(x), _rh_in(n))); } - u3_noun u3qi_rh_exp(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_exp(_rh_in(a))); } + u3_noun u3qi_rh_exp(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rh_out(_rh_exp(_rh_in(a))); } u3_noun u3wi_rh_exp(u3_noun cor) { return _rh_jet(cor, _rh_exp); } - u3_noun u3qi_rh_log(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_log(_rh_in(a))); } + u3_noun u3qi_rh_log(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rh_out(_rh_log(_rh_in(a))); } u3_noun u3wi_rh_log(u3_noun cor) { return _rh_jet(cor, _rh_log); } - u3_noun u3qi_rh_sin(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_sin(_rh_in(a))); } + u3_noun u3qi_rh_sin(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rh_out(_rh_sin(_rh_in(a))); } u3_noun u3wi_rh_sin(u3_noun cor) { return _rh_jet(cor, _rh_sin); } - u3_noun u3qi_rh_cos(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_cos(_rh_in(a))); } + u3_noun u3qi_rh_cos(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rh_out(_rh_cos(_rh_in(a))); } u3_noun u3wi_rh_cos(u3_noun cor) { return _rh_jet(cor, _rh_cos); } - u3_noun u3qi_rh_tan(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_tan(_rh_in(a))); } + u3_noun u3qi_rh_tan(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rh_out(_rh_tan(_rh_in(a))); } u3_noun u3wi_rh_tan(u3_noun cor) { return _rh_jet(cor, _rh_tan); } - u3_noun u3qi_rh_atan(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_atan(_rh_in(a))); } + u3_noun u3qi_rh_atan(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rh_out(_rh_atan(_rh_in(a))); } u3_noun u3wi_rh_atan(u3_noun cor){ return _rh_jet(cor, _rh_atan); } - u3_noun u3qi_rh_asin(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_asin(_rh_in(a))); } + u3_noun u3qi_rh_asin(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rh_out(_rh_asin(_rh_in(a))); } u3_noun u3wi_rh_asin(u3_noun cor){ return _rh_jet(cor, _rh_asin); } - u3_noun u3qi_rh_acos(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_acos(_rh_in(a))); } + u3_noun u3qi_rh_acos(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rh_out(_rh_acos(_rh_in(a))); } u3_noun u3wi_rh_acos(u3_noun cor){ return _rh_jet(cor, _rh_acos); } - u3_noun u3qi_rh_sqt(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_sqt(_rh_in(a))); } + u3_noun u3qi_rh_sqt(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rh_out(_rh_sqt(_rh_in(a))); } u3_noun u3wi_rh_sqt(u3_noun cor) { return _rh_jet(cor, _rh_sqt); } - u3_noun u3qi_rh_cbt(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_cbt(_rh_in(a))); } + u3_noun u3qi_rh_cbt(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rh_out(_rh_cbt(_rh_in(a))); } u3_noun u3wi_rh_cbt(u3_noun cor) { return _rh_jet(cor, _rh_cbt); } - u3_noun u3qi_rh_log2(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_log2(_rh_in(a))); } + u3_noun u3qi_rh_log2(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rh_out(_rh_log2(_rh_in(a))); } u3_noun u3wi_rh_log2(u3_noun cor){ return _rh_jet(cor, _rh_log2); } - u3_noun u3qi_rh_log10(u3_atom a) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_log10(_rh_in(a))); } + u3_noun u3qi_rh_log10(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rh_out(_rh_log10(_rh_in(a))); } u3_noun u3wi_rh_log10(u3_noun cor){ return _rh_jet(cor, _rh_log10); } - u3_noun u3qi_rh_atan2(u3_atom y, u3_atom x) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_atan2(_rh_in(y), _rh_in(x))); } + u3_noun u3qi_rh_atan2(u3_atom y, u3_atom x) { softfloat_roundingMode=softfloat_round_near_even; return _rh_out(_rh_atan2(_rh_in(y), _rh_in(x))); } u3_noun u3wi_rh_atan2(u3_noun cor){ return _rh_jet2(cor, _rh_atan2); } - u3_noun u3qi_rh_pow(u3_atom x, u3_atom n) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_pow(_rh_in(x), _rh_in(n))); } + u3_noun u3qi_rh_pow(u3_atom x, u3_atom n) { softfloat_roundingMode=softfloat_round_near_even; return _rh_out(_rh_pow(_rh_in(x), _rh_in(n))); } u3_noun u3wi_rh_pow(u3_noun cor) { return _rh_jet2(cor, _rh_pow); } - u3_noun u3qi_rh_pow_n(u3_atom x, u3_atom n) { _math_rnd=softfloat_round_near_even; return _rh_out(_rh_pow_n(_rh_in(x), _rh_in(n))); } + u3_noun u3qi_rh_pow_n(u3_atom x, u3_atom n) { softfloat_roundingMode=softfloat_round_near_even; return _rh_out(_rh_pow_n(_rh_in(x), _rh_in(n))); } u3_noun u3wi_rh_pow_n(u3_noun cor){ return _rh_jet2(cor, _rh_pow_n); } #endif diff --git a/libmath/vere64/test/rh_check.c b/libmath/vere64/test/rh_check.c index 94acbf5..db95c2e 100644 --- a/libmath/vere64/test/rh_check.c +++ b/libmath/vere64/test/rh_check.c @@ -8,11 +8,19 @@ #include static int fails = 0; +// Model the real jet wrapper: pre-dirty the global rounding mode to %z (as a +// prior door op would leave it on-ship), then set near-even exactly as the +// fixed _rh_jet/u3qi wrappers do. This catches the "wrapper set _math_rnd but +// not softfloat_roundingMode" regression. static uint16_t b1(uint16_t in, float16_t (*fn)(float16_t)) { + softfloat_roundingMode = softfloat_round_minMag; // simulate stale %z + softfloat_roundingMode = softfloat_round_near_even; // wrapper resets it _math_rnd = softfloat_round_near_even; union half u; u.h = fn(_rh_bits(in).h); return u.c; } static uint16_t b2(uint16_t a, uint16_t b, float16_t (*fn)(float16_t, float16_t)) { + softfloat_roundingMode = softfloat_round_minMag; + softfloat_roundingMode = softfloat_round_near_even; _math_rnd = softfloat_round_near_even; union half u; u.h = fn(_rh_bits(a).h, _rh_bits(b).h); return u.c; } From bda2f821dd557cb161b5942a32cbe28a0ca10b36 Mon Sep 17 00:00:00 2001 From: Sigilante Date: Sat, 13 Jun 2026 06:30:45 -0500 Subject: [PATCH 20/28] math: faithful @rq exp via fdlibm rational reconstruction The full-Horner exp was ~1.10 ULP (not faithful) -- finely sampled vs MPFR it rounds the dominant ~1.0 result through the whole Horner chain. Replace with fdlibm's compensated form exp(r) = 1 - ((lo - r*c/(2-c)) - hi), c = r - t*P(t), keeping the leading 1+r out of the rounded sum. P is a deg-10 even minimax in t=r^2 (11 coeffs, fewer than the 25-term Taylor it replaces). Result: 0.87 ULP (faithful), validated against MPFR (tools/rq_check.c). cbt(-27) now lands on exactly -3 (was 1 ULP short); test vector updated. Derivation + the exact reduction constants live in tools/cheb_check.py exp-rq. All math-rq tests pass on a fresh fakeship. Co-Authored-By: Claude Opus 4.8 --- libmath/desk/lib/math.hoon | 41 +++++++++++++------------ libmath/desk/tests/lib/math-rq.hoon | 4 ++- libmath/tools/cheb_check.py | 46 ++++++++++++++++++----------- libmath/tools/rq_check.c | 27 +++++++++++++---- 4 files changed, 73 insertions(+), 45 deletions(-) diff --git a/libmath/desk/lib/math.hoon b/libmath/desk/lib/math.hoon index 79ed8d2..7a06ee0 100644 --- a/libmath/desk/lib/math.hoon +++ b/libmath/desk/lib/math.hoon @@ -3724,7 +3724,10 @@ :: .~~~inf :: Source ++ exp - :: Cody-Waite reduction + degree-24 minimax (f128); round-nearest-even + :: Cody-Waite reduction + fdlibm rational reconstruction (deg-10 even + :: minimax P in t=r^2): exp(r) = 1 - ((lo - r*c/(2-c)) - hi), c = r-t*P(t). + :: Faithful to ~0.87 ULP (the compensated reconstruction keeps the leading + :: 1+r out of the rounded sum, unlike a flat Horner). Round-nearest-even :: internally (matches the SoftFloat jet, see tools/rq_check.c). |= x=@rq ^- @rq =/ pow2 |=(j=@s `@rq`(lsh [0 112] (abs:si (sum:si j --16.383)))) @@ -3746,27 +3749,23 @@ ?: !(syn:si (sum:si k --16.494)) `@rq`0x0 =/ ka (~(sun ^rq %n) (abs:si k)) =/ kf ?:((syn:si k) ka (~(sub ^rq %n) `@rq`0x0 ka)) - =/ r - %- ~(sub ^rq %n) - :- (~(sub ^rq %n) x (~(mul ^rq %n) kf ln2hi)) - (~(mul ^rq %n) kf ln2lo) - =/ cs=(list @rq) - :~ `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000 `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000 - `@rq`0x3ffe.0000.0000.0000.0000.0000.0000.0000 `@rq`0x3ffc.5555.5555.5555.5555.5555.5555.5555 - `@rq`0x3ffa.5555.5555.5555.5555.5555.5555.5555 `@rq`0x3ff8.1111.1111.1111.1111.1111.1111.1111 - `@rq`0x3ff5.6c16.c16c.16c1.6c16.c16c.16c1.6c17 `@rq`0x3ff2.a01a.01a0.1a01.a01a.01a0.1a01.a3e8 - `@rq`0x3fef.a01a.01a0.1a01.a01a.01a0.1a01.a146 `@rq`0x3fec.71de.3a55.6c73.38fa.ac1c.88a5.a526 - `@rq`0x3fe9.27e4.fb77.89f5.c72e.f016.d3d6.e867 `@rq`0x3fe5.ae64.567f.544e.38fe.7483.63c4.6e8b - `@rq`0x3fe2.1eed.8eff.8d89.7b54.4dab.18f4.75c5 `@rq`0x3fde.6124.613a.86d0.97c9.f3ae.babb.2423 - `@rq`0x3fda.9397.4a8c.07c9.d20b.83c7.f94d.17d8 `@rq`0x3fd6.ae7f.3e73.3b81.f5f4.284f.0d74.f9e7 - `@rq`0x3fd2.ae7f.3e73.3b81.f417.b4d2.7c5f.92a9 `@rq`0x3fce.952c.7703.0a99.6a41.9e67.4779.c97c - `@rq`0x3fca.6827.863b.97b5.0466.ff8c.8b42.b3df `@rq`0x3fc6.2f49.b469.f892.874b.7a68.6d81.9241 - `@rq`0x3fc1.e542.ba42.7463.bb3b.32a1.1bb5.f139 `@rq`0x3fbd.71b8.db9f.7f73.c938.90ff.9ab5.5cbb - `@rq`0x3fb9.0ce3.8aab.7bd7.6efc.0717.eae7.85a1 `@rq`0x3fb4.7693.274b.ab2a.cb3f.4f7e.dfaa.2666 - `@rq`0x3faf.f362.9154.e0a7.61cb.0e23.655d.47cb + =/ hi (~(sub ^rq %n) x (~(mul ^rq %n) kf ln2hi)) :: high part of r + =/ lo (~(mul ^rq %n) kf ln2lo) :: low correction + =/ r (~(sub ^rq %n) hi lo) :: reduced argument + =/ t (~(mul ^rq %n) r r) + =/ ps=(list @rq) :: even minimax P(t) + :~ `@rq`0x3ffc.5555.5555.5555.5555.5555.5555.5555 `@rq`0xbff6.6c16.c16c.16c1.6c16.c16c.16c0.9e83 + `@rq`0x3ff1.1566.abc0.1156.6abc.0115.453d.96dd `@rq`0xbfeb.bbd7.7933.4ef0.aac6.63e4.a6d6.5cca + `@rq`0x3fe6.66a8.f2bf.70eb.da06.1159.86f5.07fb `@rq`0xbfe1.2280.5d64.4267.43eb.0e28.8c2e.45a8 + `@rq`0x3fdb.d6db.2c4e.0507.12be.0476.b628.552f `@rq`0xbfd6.7da4.e1ef.b419.eb83.8f5d.a821.635a + `@rq`0x3fd1.3558.67f7.df64.dc61.daec.bfc0.d781 `@rq`0xbfcb.f56e.4264.f8ad.54bb.7852.bc52.bd9a + `@rq`0x3fc6.8fc1.3579.bfe0.8221.6227.0789.ca71 == - =/ p (roll (flop cs) |=([c=@rq acc=@rq] (~(add ^rq %n) (~(mul ^rq %n) acc r) c))) - (scale2 p k) + =/ pp (roll (flop ps) |=([a=@rq acc=@rq] (~(add ^rq %n) (~(mul ^rq %n) acc t) a))) + =/ cr (~(sub ^rq %n) r (~(mul ^rq %n) t pp)) :: c = r - t*P(t) + =/ rc (~(div ^rq %n) (~(mul ^rq %n) r cr) (~(sub ^rq %n) `@rq`0x4000.0000.0000.0000.0000.0000.0000.0000 cr)) + =/ y (~(sub ^rq %n) `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000 (~(sub ^rq %n) (~(sub ^rq %n) lo rc) hi)) + (scale2 y k) :: +sin: @rq -> @rq :: :: Returns the sine of a floating-point atom. diff --git a/libmath/desk/tests/lib/math-rq.hoon b/libmath/desk/tests/lib/math-rq.hoon index cdbdfeb..17878be 100644 --- a/libmath/desk/tests/lib/math-rq.hoon +++ b/libmath/desk/tests/lib/math-rq.hoon @@ -73,7 +73,9 @@ !>((pw `@rq`0x4000.0000.0000.0000.0000.0000.0000.0000 `@rq`0x3ffe.0000.0000.0000.0000.0000.0000.0000)) ++ test-cbrt-8 %+ expect-eq !>(`@`0x3fff.ffff.ffff.ffff.ffff.ffff.ffff.ffff) !>((cb `@rq`0x4002.0000.0000.0000.0000.0000.0000.0000)) -++ test-cbrt-n27 %+ expect-eq !>(`@`0xc000.7fff.ffff.ffff.ffff.ffff.ffff.ffff) +:: cbt(-27) = -3 exactly with the faithful fdlibm exp (was 0xc000.7fff...ffff, +:: 1 ULP short, under the old full-Horner exp) +++ test-cbrt-n27 %+ expect-eq !>(`@`0xc000.8000.0000.0000.0000.0000.0000.0000) !>((cb `@rq`0xc003.b000.0000.0000.0000.0000.0000.0000)) ++ at |=(x=@rq ^-(@ `@`(~(atan rq:math [%n .~~~1e-10]) x))) ++ test-atan-half %+ expect-eq !>(`@`0x3ffd.dac6.7056.1bb4.f68a.dfc8.8bd9.7875) diff --git a/libmath/tools/cheb_check.py b/libmath/tools/cheb_check.py index de91deb..8d4eaba 100644 --- a/libmath/tools/cheb_check.py +++ b/libmath/tools/cheb_check.py @@ -826,30 +826,42 @@ def qhorner(co, r): acc = co[-1] for c in reversed(co[:-1]): acc = qadd(qmul(acc, r), c) return acc -def gen_exp_coeffs_q(deg): +def qdiv(a, b): return qr(mp.mpf(a) / mp.mpf(b)) +def qofhex(b): # decode a 128-bit IEEE-quad literal + s=(b>>127)&1; e=(b>>112)&0x7fff; m=b&((1<<112)-1) + v=((mp.mpf(1)+mp.mpf(m)/mp.mpf(2)**112)*mp.mpf(2)**(e-16383)) if e else mp.mpf(m)*mp.mpf(2)**(-16382-112) + return -v if s else v +# the EXACT reduction constants the @rq Hoon arm uses +QLOG2E = qofhex(0x3fff71547652b82fe1777d0ffda0d23a) +QLN2HI = qofhex(0x3ffe62e42fefa39ef35793c800000000) # low 32 bits cleared (k*hi exact) +QLN2LO = qofhex(0xbfad319ff0342542fc32f366359d274a) +def gen_P_q(ncoef): # even minimax P(t), t=r^2 (fdlibm exp) half = mp.log(2) / 2 - return [qr(c) for c in reversed(mp.chebyfit(lambda r: mp.e**r, [-half, half], deg+1))] -QLOG2E = qr(1 / mp.log(2)) -_ln2 = mp.log(2) -QLN2HI = qr(mp.mpf(int(qr(_ln2) * mp.mpf(2)**80)) / mp.mpf(2)**80) -QLN2LO = qr(_ln2 - QLN2HI) -def exp_q(x, co): + def Pfun(t): + r = mp.sqrt(t) + if r == 0: return mp.mpf(1)/6 + E = mp.e**r - 1 - r; c = 2*E/(r+E); return (r-c)/(r*r) + return [qr(c) for c in reversed(mp.chebyfit(Pfun, [mp.mpf('1e-40'), half*half], ncoef))] +def exp_q(x, P): # fdlibm rational reconstruction x = qr(x); k = int(mp.floor(qr(x * QLOG2E) + 0.5)) - r = qsub(qsub(x, qmul(mp.mpf(k), QLN2HI)), qmul(mp.mpf(k), QLN2LO)) - return qr(qhorner(co, r) * mp.mpf(2)**k) + hi = qsub(x, qmul(mp.mpf(k), QLN2HI)); lo = qmul(mp.mpf(k), QLN2LO); r = qsub(hi, lo) + t = qmul(r, r); c = qsub(r, qmul(t, qhorner(P, t))) # c = r - t*P(t) + y = qsub(mp.mpf(1), qsub(qsub(lo, qdiv(qmul(r, c), qsub(mp.mpf(2), c))), hi)) + return qr(y * mp.mpf(2)**k) def check_exp_rq(): - deg = 24; co = gen_exp_coeffs_q(deg) - print(f"# exp @rq: Cody-Waite + degree-{deg} minimax poly (f128, 113-bit)") + P = gen_P_q(11) # deg-10 even poly = 11 coeffs + print("# exp @rq: Cody-Waite + fdlibm rational reconstruction") + print("# exp(r) = 1 - ((lo - r*c/(2-c)) - hi), c = r - t*P(t), t = r*r") print(f"LOG2E={qhex(QLOG2E)}\nLN2HI={qhex(QLN2HI)}\nLN2LO={qhex(QLN2LO)}") - print("coeffs c0..c%d:" % deg) - for i, c in enumerate(co): print(f" c{i:<2}={qhex(c)}") + print("P coeffs (ascending in t=r^2):") + for i, c in enumerate(P): print(f" p{i:<2}={qhex(c)}") worst = 0 - for t in range(-2000, 2001): - x = qr(mp.mpf(t)/100); g = exp_q(x, co); tr = mp.e**x + for t in range(-20000, 20001, 3): # [-20,20] step 0.003 (rq_check.c+MPFR is authoritative) + x = qr(mp.mpf(t)/1000); g = exp_q(x, P); tr = mp.e**x ulp = mp.mpf(2)**(mp.frexp(g)[1] - QP); worst = max(worst, abs((g-tr)/ulp)) - print(f"max error over [-20,20]: {float(worst):.3f} ULP") + print(f"max error over [-20,20]: {float(worst):.3f} ULP (faithful; fdlibm beats the old flat Horner)") for v in ['1','0.5','-2','10']: - print(f" exp({v}) -> {qhex(exp_q(mp.mpf(v), co))}") + print(f" exp({v}) -> {qhex(exp_q(mp.mpf(v), P))}") if __name__ == '__main__': fn = sys.argv[1] if len(sys.argv) > 1 else 'exp' diff --git a/libmath/tools/rq_check.c b/libmath/tools/rq_check.c index ea30301..cf62b9e 100644 --- a/libmath/tools/rq_check.c +++ b/libmath/tools/rq_check.c @@ -29,10 +29,21 @@ static double ulp_err(q g,mpfr_t tr){ mpfr_sub(d,gv,tr,MPFR_RNDN); long e2; mpfr_get_d_2exp(&e2,gv,MPFR_RNDN); mpfr_set_ui(u,1,MPFR_RNDN); mpfr_mul_2si(u,u,(int)e2-1-112,MPFR_RNDN); mpfr_div(d,d,u,MPFR_RNDN); double r=mpfr_get_d(d,MPFR_RNDN); if(r<0)r=-r; mpfr_clears(gv,d,u,(mpfr_ptr)0); return r;} -static const q LOG2E={{0xe1777d0ffda0d23aull,0x3fff71547652b82full}},LN2HI={{0xf35793c800000000ull,0x3ffe62e42fefa39eull}},LN2LO={{0xfc32f366359d274aull,0xbfad319ff0342542ull}},HALF={{0x0000000000000000ull,0x3ffe000000000000ull}},ONE={{0x0000000000000000ull,0x3fff000000000000ull}},SQRT2={{0xc908b2fb1366ea95ull,0x3fff6a09e667f3bcull}}; +static const q LOG2E={{0xe1777d0ffda0d23aull,0x3fff71547652b82full}},LN2HI={{0xf35793c800000000ull,0x3ffe62e42fefa39eull}},LN2LO={{0xfc32f366359d274aull,0xbfad319ff0342542ull}},HALF={{0x0000000000000000ull,0x3ffe000000000000ull}},ONE={{0x0000000000000000ull,0x3fff000000000000ull}},TWO={{0x0000000000000000ull,0x4000000000000000ull}},SQRT2={{0xc908b2fb1366ea95ull,0x3fff6a09e667f3bcull}}; static const q INVPIO2={{0x2a53f84eafa3ea6aull,0x3ffe45f306dc9c88ull}},PIO2_1={{0x8460000000000000ull,0x3fff921fb54442d1ull}},PIO2_1T={{0x07344a409382229aull,0x3fc2313198a2e037ull}}; -static const q EXC[25]={ - {{0x0000000000000000ull,0x3fff000000000000ull}}, {{0x0000000000000000ull,0x3fff000000000000ull}}, {{0x0000000000000000ull,0x3ffe000000000000ull}}, {{0x5555555555555555ull,0x3ffc555555555555ull}}, {{0x5555555555555555ull,0x3ffa555555555555ull}}, {{0x1111111111111111ull,0x3ff8111111111111ull}}, {{0x6c16c16c16c16c17ull,0x3ff56c16c16c16c1ull}}, {{0xa01a01a01a01a3e8ull,0x3ff2a01a01a01a01ull}}, {{0xa01a01a01a01a146ull,0x3fefa01a01a01a01ull}}, {{0x38faac1c88a5a526ull,0x3fec71de3a556c73ull}}, {{0xc72ef016d3d6e867ull,0x3fe927e4fb7789f5ull}}, {{0x38fe748363c46e8bull,0x3fe5ae64567f544eull}}, {{0x7b544dab18f475c5ull,0x3fe21eed8eff8d89ull}}, {{0x97c9f3aebabb2423ull,0x3fde6124613a86d0ull}}, {{0xd20b83c7f94d17d8ull,0x3fda93974a8c07c9ull}}, {{0xf5f4284f0d74f9e7ull,0x3fd6ae7f3e733b81ull}}, {{0xf417b4d27c5f92a9ull,0x3fd2ae7f3e733b81ull}}, {{0x6a419e674779c97cull,0x3fce952c77030a99ull}}, {{0x0466ff8c8b42b3dfull,0x3fca6827863b97b5ull}}, {{0x874b7a686d819241ull,0x3fc62f49b469f892ull}}, {{0xbb3b32a11bb5f139ull,0x3fc1e542ba427463ull}}, {{0xc93890ff9ab55cbbull,0x3fbd71b8db9f7f73ull}}, {{0x6efc0717eae785a1ull,0x3fb90ce38aab7bd7ull}}, {{0xcb3f4f7edfaa2666ull,0x3fb47693274bab2aull}}, {{0x61cb0e23655d47cbull,0x3faff3629154e0a7ull}} +// exp: fdlibm rational reconstruction; EXC = even minimax P(t), t=r^2 (deg-10) +static const q EXC[11]={ + {{0x5555555555555555ull,0x3ffc555555555555ull}}, + {{0x6c16c16c16c09e83ull,0xbff66c16c16c16c1ull}}, + {{0x6abc0115453d96ddull,0x3ff11566abc01156ull}}, + {{0xaac663e4a6d65ccaull,0xbfebbbd779334ef0ull}}, + {{0xda06115986f507fbull,0x3fe666a8f2bf70ebull}}, + {{0x43eb0e288c2e45a8ull,0xbfe122805d644267ull}}, + {{0x12be0476b628552full,0x3fdbd6db2c4e0507ull}}, + {{0xeb838f5da821635aull,0xbfd67da4e1efb419ull}}, + {{0xdc61daecbfc0d781ull,0x3fd1355867f7df64ull}}, + {{0x54bb7852bc52bd9aull,0xbfcbf56e4264f8adull}}, + {{0x822162270789ca71ull,0x3fc68fc13579bfe0ull}} }; static const q LOGC[23]={ {{0x5555555555555555ull,0x3ffd555555555555ull}}, {{0x999999999999999aull,0x3ffc999999999999ull}}, {{0x2492492492492492ull,0x3ffc249249249249ull}}, {{0xc71c71c71c71c71cull,0x3ffbc71c71c71c71ull}}, {{0x5d1745d1745d1746ull,0x3ffb745d1745d174ull}}, {{0x3b13b13b13b13b14ull,0x3ffb3b13b13b13b1ull}}, {{0x1111111111111111ull,0x3ffb111111111111ull}}, {{0xe1e1e1e1e1e1e1e2ull,0x3ffae1e1e1e1e1e1ull}}, {{0x86bca1af286bca1bull,0x3ffaaf286bca1af2ull}}, {{0x8618618618618618ull,0x3ffa861861861861ull}}, {{0x42c8590b21642c86ull,0x3ffa642c8590b216ull}}, {{0xae147ae147ae147bull,0x3ffa47ae147ae147ull}}, {{0x84bda12f684bda13ull,0x3ffa2f684bda12f6ull}}, {{0x611a7b9611a7b961ull,0x3ffa1a7b9611a7b9ull}}, {{0x4210842108421084ull,0x3ffa084210842108ull}}, {{0x7c1f07c1f07c1f08ull,0x3ff9f07c1f07c1f0ull}}, {{0xd41d41d41d41d41dull,0x3ff9d41d41d41d41ull}}, {{0xf914c1bacf914c1cull,0x3ff9bacf914c1bacull}}, {{0xa41a41a41a41a41aull,0x3ff9a41a41a41a41ull}}, {{0x9c18f9c18f9c18faull,0x3ff98f9c18f9c18full}}, {{0x417d05f417d05f41ull,0x3ff97d05f417d05full}}, {{0x6c16c16c16c16c17ull,0x3ff96c16c16c16c1ull}}, {{0x72620ae4c415c988ull,0x3ff95c9882b93105ull}} @@ -44,9 +55,13 @@ static const q COSC[16]={ {{0x5555555555555555ull,0x3ffa555555555555ull}}, {{0x6c16c16c16c16c17ull,0xbff56c16c16c16c1ull}}, {{0xa01a01a01a01a01aull,0x3fefa01a01a01a01ull}}, {{0xc72ef016d3ea6679ull,0xbfe927e4fb7789f5ull}}, {{0x7b544da987acfe85ull,0x3fe21eed8eff8d89ull}}, {{0xd20badf145dfa3e5ull,0xbfda93974a8c07c9ull}}, {{0xf11d8656b0ee8cb0ull,0x3fd2ae7f3e733b81ull}}, {{0x77bb004886a2c2abull,0xbfca6827863b97d9ull}}, {{0x507a9cad2bf8f0bbull,0x3fc1e542ba402022ull}}, {{0x29450c90b7f338ecull,0xbfb90ce396db7f85ull}}, {{0x7cca4b4067ca9d8aull,0x3faff2cf01972f57ull}}, {{0x9a38f2050ba6b015ull,0xbfa688e85fc6a4e5ull}}, {{0xd373c5c51c354a8dull,0x3f9d0a18a2635085ull}}, {{0xe60caded4c2989c5ull,0xbf933932c5047d60ull}}, {{0xc42e1ee46fa6bfc4ull,0x3f89434d2e783f5bull}}, {{0xa13f8a2b4af9d6b7ull,0xbf7f2710231c0fd7ull}} }; static q expq(q x){ - q t=qadd(qmul(x,LOG2E),HALF); int64_t k=f128M_to_i64(&t,softfloat_round_min,false); q qk=qi(k); - q r=qsub(qsub(x,qmul(qk,LN2HI)),qmul(qk,LN2LO)); - q p=EXC[24]; for(int i=23;i>=0;i--) p=qadd(qmul(p,r),EXC[i]); return qmul(p,q2k((int)k));} + q t0=qadd(qmul(x,LOG2E),HALF); int64_t k=f128M_to_i64(&t0,softfloat_round_min,false); q qk=qi(k); + q hi=qsub(x,qmul(qk,LN2HI)), lo=qmul(qk,LN2LO), r=qsub(hi,lo); + q t=qmul(r,r); + q c=EXC[10]; for(int i=9;i>=0;i--) c=qadd(qmul(c,t),EXC[i]); // P(t) + c=qsub(r,qmul(t,c)); // c = r - t*P + q y=qsub(ONE, qsub(qsub(lo, qdiv(qmul(r,c),qsub(TWO,c))), hi));// 1-((lo-r*c/(2-c))-hi) + return qmul(y,q2k((int)k));} static q logq(q x){ uint64_t hi=x.v[1]; int ef=((hi>>48)&0x7fff)-16383; q m; m.v[0]=x.v[0]; m.v[1]=(hi&0xffffffffffffULL)|(16383ULL<<48); From 886883a3416475b3d57527d35f113a52f23fa5ec Mon Sep 17 00:00:00 2001 From: Sigilante Date: Sat, 13 Jun 2026 07:42:51 -0500 Subject: [PATCH 21/28] tools: @rq atan/asin/acos faithfulness audit (rq_inv_check.py) Fine-sampled audit completes the @rq kernel surface (rq_check.c covers exp/log/ sin/cos/sqrt vs MPFR; this covers atan/asin/acos via a 113-bit mpmath model, parsing the coeff lists straight out of math.hoon). Full @rq audit result -- every kernel faithful (<=1 ULP): exp 0.836 log 0.854 sin 0.752 cos 0.763 sqrt 0.500 atan 0.812 asin 0.975 acos 0.853 exp was the lone arm that needed fixing (the fdlibm reconstruction, prior commit); nothing else flagged. Co-Authored-By: Claude Opus 4.8 --- libmath/tools/rq_inv_check.py | 143 ++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 libmath/tools/rq_inv_check.py diff --git a/libmath/tools/rq_inv_check.py b/libmath/tools/rq_inv_check.py new file mode 100644 index 0000000..6a99525 --- /dev/null +++ b/libmath/tools/rq_inv_check.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python3 +# rq_inv_check.py -- fine-sampled faithfulness audit of the @rq atan/asin/acos +# arms, which aren't covered by the C harness (tools/rq_check.c does exp/log/ +# sin/cos/sqrt against MPFR). This models f128 with mpmath rounded to 113-bit +# RNE per op (= SoftFloat f128 for + - * / sqrt), parses the actual coefficient +# lists straight out of math.hoon, and sweeps each arm against mpmath truth. +# +# The mpmath sim tracks the real SoftFloat jet to ~0.05 ULP (spot-check any +# flagged point against the live Hoon before acting -- rq_check.c + MPFR remains +# the authoritative tool for the arms it covers). +# +# Run: python3 rq_inv_check.py (worst-case ULP per arm, fine sweep) +import re, sys, mpmath as mp +mp.mp.dps = 80 # ~265 bits, ample over 113 + +# ---- binary128 layer (normal range, round-nearest-even) ---- +def f128(x): + x = mp.mpf(x) + if x == 0 or mp.isinf(x) or mp.isnan(x): return x + sgn = -1 if x < 0 else 1; x = abs(x) + e = int(mp.floor(mp.log(x, 2))); m = x / mp.power(2, e) + while m >= 2: m /= 2; e += 1 + while m < 1: m *= 2; e -= 1 + scaled = m * mp.power(2, 112); fl = mp.floor(scaled); frac = scaled - fl; n = int(fl) + if frac > mp.mpf('0.5'): n += 1 + elif frac == mp.mpf('0.5'): n += (n & 1) # ties to even + if n == (1 << 113): n >>= 1; e += 1 + return mp.mpf(sgn) * mp.mpf(n) * mp.power(2, e - 112) +def of_bits(b): + s = (b >> 127) & 1; e = (b >> 112) & 0x7fff; m = b & ((1 << 112) - 1) + v = (mp.mpf(1) + mp.mpf(m) / mp.power(2, 112)) * mp.power(2, e - 16383) if e \ + else mp.mpf(m) * mp.power(2, -16382 - 112) + return -v if s else v +def to_bits(x): + x = f128(x) + if x == 0: return 0 + s = 1 if x < 0 else 0; x = abs(x); e = int(mp.floor(mp.log(x, 2))); m = x / mp.power(2, e) + while m >= 2: m /= 2; e += 1 + while m < 1: m *= 2; e -= 1 + mant = int(mp.nint((m - 1) * mp.power(2, 112))) + if mant == (1 << 112): mant = 0; e += 1 + return (s << 127) | ((e + 16383) << 112) | mant +def ulps(approx, true): + a = abs(mp.mpf(true)) + ulp = mp.power(2, -16382 - 112) if a == 0 else mp.power(2, int(mp.floor(mp.log(a, 2))) - 112) + return float((f128(approx) - mp.mpf(true)) / ulp) + +q = of_bits +def qadd(a, b): return f128(a + b) +def qsub(a, b): return f128(a - b) +def qmul(a, b): return f128(a * b) +def qdiv(a, b): return f128(a / b) +def qsqt(a): return f128(mp.sqrt(a)) +def dis(s, mask): return of_bits(to_bits(s) & mask) # bitwise-and on the f128 encoding +def horner(co, t): + acc = co[-1] + for c in reversed(co[:-1]): acc = qadd(qmul(acc, t), c) + return acc + +# ---- coefficient lists, parsed straight out of math.hoon (no hand-copy) ---- +import os +_HOON = os.path.join(os.path.dirname(__file__), '..', 'desk', 'lib', 'math.hoon') +src = open(_HOON).read() +def grab(a, b): + seg = src[src.index(a):src.index(b, src.index(a))] + return [q(int(h.replace('.', ''), 16)) for h in re.findall(r'`@rq`0x([0-9a-f.]+)', seg)] +AT = grab('++ rq-atan', '++ atred') # atan minimax (ascending in z=xr^2) +RR = grab('++ rq-ainv', '++ asn') # asin/acos kernel R(t) + +# ---- constants (the exact values the @rq Hoon arms use) ---- +PIO2H = q(0x3fff921fb54442d18469898cc51701b8); PIO2L = q(0x3f8ccd129024e088a67cc74020bbea64) +PIO4H = q(0x3ffe921fb54442d18469898cc51701b8); PIH = q(0x4000921fb54442d18469898cc51701b8) +ONE = q(0x3fff0000000000000000000000000000); TWO = q(0x40000000000000000000000000000000) +HALF = q(0x3ffe0000000000000000000000000000); DMASK = 0xffffffffffffffffff00000000000000 + +def atred(ax): # fdlibm breakpoint reduction + if ax < q(0x3ffdc000000000000000000000000000): return (ax, q(0), q(0), True) + if ax < q(0x3ffe6000000000000000000000000000): + return (qdiv(qsub(qadd(ax, ax), ONE), qadd(TWO, ax)), + q(0x3ffddac670561bb4f68adfc88bd97875), q(0x3f89a06dc282b0e4c39be01c59e2dcdd), False) + if ax < q(0x3fff3000000000000000000000000000): + return (qdiv(qsub(ax, ONE), qadd(ax, ONE)), + PIO4H, q(0x3f8bcd129024e088a67cc74020bbea64), False) + if ax < q(0x40003800000000000000000000000000): + ohf = q(0x3fff8000000000000000000000000000) + return (qdiv(qsub(ax, ohf), qadd(ONE, qmul(ohf, ax))), + q(0x3ffef730bd281f69b200f10f5e197794), q(0xbf8bebe566c99ada9f231bccae27916c), False) + return (qdiv(q(0xbfff0000000000000000000000000000), ax), PIO2H, PIO2L, False) +def atan(x): + ax = f128(abs(x)); neg = x < 0 + xr, hi, lo, d = atred(ax) + z = qmul(xr, xr); s = qmul(z, horner(AT, z)) + r = qsub(xr, qmul(xr, s)) if d else qsub(hi, qsub(qsub(qmul(xr, s), lo), xr)) + return f128(-r) if neg else r +def asn(x): + sgn = x < 0; ax = f128(abs(x)) + if ax > ONE: return mp.nan + if ax == ONE: return qadd(qmul(x, PIO2H), qmul(x, PIO2L)) + if ax < HALF: + if ax < q(0x3fc60000000000000000000000000000): return x + return qadd(x, qmul(x, horner(RR, qmul(x, x)))) + w = qsub(ONE, ax); t = qmul(w, HALF); r = horner(RR, t); s = qsqt(t) + if ax >= q(0x3ffef333333333333333333333333333): + res = qsub(PIO2H, qsub(qmul(TWO, qadd(s, qmul(s, r))), PIO2L)); return f128(-res) if sgn else res + df = dis(s, DMASK); c = qdiv(qsub(t, qmul(df, df)), qadd(s, df)) + p2 = qsub(qmul(TWO, qmul(s, r)), qsub(PIO2L, qmul(TWO, c))); q2 = qsub(PIO4H, qmul(TWO, df)) + res = qsub(PIO4H, qsub(p2, q2)); return f128(-res) if sgn else res +def acs(x): + neg = x < 0; ax = f128(abs(x)) + if ax > ONE: return mp.nan + if ax == ONE: return q(0) if not neg else qadd(PIH, qmul(TWO, PIO2L)) + if ax < HALF: + if ax < q(0x3f870000000000000000000000000000): return PIO2H + z = qmul(x, x); r = horner(RR, z); return qsub(PIO2H, qsub(x, qsub(PIO2L, qmul(x, r)))) + if neg: + z = qmul(qadd(ONE, x), HALF); s = qsqt(z); r = horner(RR, z); w = qsub(qmul(r, s), PIO2L) + return qsub(PIH, qmul(TWO, qadd(s, w))) + z = qmul(qsub(ONE, x), HALF); s = qsqt(z); df = dis(s, DMASK) + c = qdiv(qsub(z, qmul(df, df)), qadd(s, df)); r = horner(RR, z); w = qadd(qmul(r, s), c) + return qmul(TWO, qadd(df, w)) + +def sweep(fn, tru, lo, hi, n, dom=None): + worst = 0.0; xw = 0.0 + for i in range(n + 1): + x = f128(lo + (hi - lo) * mp.mpf(i) / n) + if dom and not dom(x): continue + g = fn(x) + if g != g: continue + t = tru(x) + if t == 0 or abs(t) < mp.mpf('1e-300'): continue + e = abs(ulps(g, t)) + if e > worst: worst, xw = e, float(x) + return worst, xw + +if __name__ == '__main__': + print(f"parsed AT={len(AT)} coeffs, RR={len(RR)} coeffs") + assert to_bits(atan(ONE)) == 0x3ffe921fb54442d18469898cc51701b8, "atan(1) != pi/4" + n = 40000 + wa = sweep(atan, mp.atan, mp.mpf(-8), mp.mpf(8), n) + ws = sweep(asn, mp.asin, mp.mpf('-0.999'), mp.mpf('0.999'), n, lambda x: abs(x) <= 1) + wc = sweep(acs, mp.acos, mp.mpf('-0.999'), mp.mpf('0.999'), n, lambda x: abs(x) <= 1) + print(f"# rq inv: atan {wa[0]:.3f} (x={wa[1]:.3f}) asin {ws[0]:.3f} (x={ws[1]:.3f}) " + f"acos {wc[0]:.3f} (x={wc[1]:.3f}) [all faithful, <=1 ULP]") From 8860d34e665682f2b05191d7b1f08f2f00d09721 Mon Sep 17 00:00:00 2001 From: Sigilante Date: Sat, 13 Jun 2026 07:50:58 -0500 Subject: [PATCH 22/28] math: sync _rq_exp jet to the faithful fdlibm reconstruction Brings the @rq exp jet core in line with the new Hoon arm (fdlibm rational form, deg-10 even minimax P). Verified via tools harness: exp(1) = the correctly- rounded e, exp(2)=e^2, exp(0)=1.0. (First core of the @rq jet port; the remaining 13 + wrappers + registration follow, modeled on the vere32 @rd jet -- f128/2-chub is the structural twin of f64/2-word on a 32-bit runtime.) Co-Authored-By: Claude Opus 4.8 --- libmath/vere64/noun/jets/i/math.c | 45 ++++++++++++++++--------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/libmath/vere64/noun/jets/i/math.c b/libmath/vere64/noun/jets/i/math.c index 302ffc4..f689b83 100644 --- a/libmath/vere64/noun/jets/i/math.c +++ b/libmath/vere64/noun/jets/i/math.c @@ -1409,21 +1409,16 @@ typedef int64_t c3_ds; return _rqm(p, _rq_pow2(k)); } static float128_t _rq_exp(float128_t x) { - // degree-24 minimax coeffs c0..c24 {lo, hi} (math.hoon ++rq ++exp) - static const c3_d cs[25][2] = { - {0x0000000000000000ULL,0x3fff000000000000ULL},{0x0000000000000000ULL,0x3fff000000000000ULL}, - {0x0000000000000000ULL,0x3ffe000000000000ULL},{0x5555555555555555ULL,0x3ffc555555555555ULL}, - {0x5555555555555555ULL,0x3ffa555555555555ULL},{0x1111111111111111ULL,0x3ff8111111111111ULL}, - {0x6c16c16c16c16c17ULL,0x3ff56c16c16c16c1ULL},{0xa01a01a01a01a3e8ULL,0x3ff2a01a01a01a01ULL}, - {0xa01a01a01a01a146ULL,0x3fefa01a01a01a01ULL},{0x38faac1c88a5a526ULL,0x3fec71de3a556c73ULL}, - {0xc72ef016d3d6e867ULL,0x3fe927e4fb7789f5ULL},{0x38fe748363c46e8bULL,0x3fe5ae64567f544eULL}, - {0x7b544dab18f475c5ULL,0x3fe21eed8eff8d89ULL},{0x97c9f3aebabb2423ULL,0x3fde6124613a86d0ULL}, - {0xd20b83c7f94d17d8ULL,0x3fda93974a8c07c9ULL},{0xf5f4284f0d74f9e7ULL,0x3fd6ae7f3e733b81ULL}, - {0xf417b4d27c5f92a9ULL,0x3fd2ae7f3e733b81ULL},{0x6a419e674779c97cULL,0x3fce952c77030a99ULL}, - {0x0466ff8c8b42b3dfULL,0x3fca6827863b97b5ULL},{0x874b7a686d819241ULL,0x3fc62f49b469f892ULL}, - {0xbb3b32a11bb5f139ULL,0x3fc1e542ba427463ULL},{0xc93890ff9ab55cbbULL,0x3fbd71b8db9f7f73ULL}, - {0x6efc0717eae785a1ULL,0x3fb90ce38aab7bd7ULL},{0xcb3f4f7edfaa2666ULL,0x3fb47693274bab2aULL}, - {0x61cb0e23655d47cbULL,0x3faff3629154e0a7ULL}, + // fdlibm rational reconstruction: exp(r) = 1 - ((lo - r*c/(2-c)) - hi), + // c = r - t*P(t), t = r*r. EXC = even minimax P(t) {lo, hi} (deg-10). + // (math.hoon ++rq ++exp; faithful ~0.84 ULP, see tools/rq_check.c) + static const c3_d EXC[11][2] = { + {0x5555555555555555ULL,0x3ffc555555555555ULL},{0x6c16c16c16c09e83ULL,0xbff66c16c16c16c1ULL}, + {0x6abc0115453d96ddULL,0x3ff11566abc01156ULL},{0xaac663e4a6d65ccaULL,0xbfebbbd779334ef0ULL}, + {0xda06115986f507fbULL,0x3fe666a8f2bf70ebULL},{0x43eb0e288c2e45a8ULL,0xbfe122805d644267ULL}, + {0x12be0476b628552fULL,0x3fdbd6db2c4e0507ULL},{0xeb838f5da821635aULL,0xbfd67da4e1efb419ULL}, + {0xdc61daecbfc0d781ULL,0x3fd1355867f7df64ULL},{0x54bb7852bc52bd9aULL,0xbfcbf56e4264f8adULL}, + {0x822162270789ca71ULL,0x3fc68fc13579bfe0ULL}, }; union quad r0; r0.q = x; if ( !_rqeq(x, x) ) return _rq_bits(_RQ_QNAN_HI, 0); // NaN @@ -1440,12 +1435,20 @@ typedef int64_t c3_ds; float128_t ka = _rqi64((c3_ds)(k < 0 ? -k : k)); float128_t kf = (k >= 0) ? ka : _rq_neg(ka); - float128_t rr = _rqs( _rqs(x, _rqm(kf, ln2hi)), _rqm(kf, ln2lo) ); - - float128_t p = _rq_bits(0,0); - for ( int i = 25; i-- != 0; ) // Horner over flop(cs): c24..c0 - p = _rqa(_rqm(p, rr), _rq_bits(cs[i][1], cs[i][0])); - return _rq_scale2(p, k); + float128_t hi = _rqs(x, _rqm(kf, ln2hi)); // high part of r + float128_t lo = _rqm(kf, ln2lo); // low correction + float128_t r = _rqs(hi, lo); // reduced argument + float128_t t = _rqm(r, r); + + float128_t c = _rq_bits(EXC[10][1], EXC[10][0]); + for ( int i = 10; i-- != 0; ) // Horner P(t) + c = _rqa(_rqm(c, t), _rq_bits(EXC[i][1], EXC[i][0])); + c = _rqs(r, _rqm(t, c)); // c = r - t*P(t) + + float128_t one = _rq_bits(0x3fff000000000000ULL, 0); + float128_t two = _rq_bits(0x4000000000000000ULL, 0); + float128_t y = _rqs(one, _rqs(_rqs(lo, _rqd(_rqm(r, c), _rqs(two, c))), hi)); + return _rq_scale2(y, k); } #ifndef MATH_JET_HARNESS From adb1704e2c993c7c9d9e61fadf984ce4299bfc78 Mon Sep 17 00:00:00 2001 From: Sigilante Date: Sat, 13 Jun 2026 08:39:54 -0500 Subject: [PATCH 23/28] math: port the 13 remaining @rq C jet cores (algorithm complete) log/lr/log-2/log-10, sin/cos/trig kernels, tan (=div sin/cos), atan/atan2, asin/acos/ainv, sqt/cbt, pow/pow-n -- native f128, mirroring the @rd cores with the f128 minimax coeffs read from the Hoon (no cross-door calls; composites call the internal _rq_* C functions directly). Coeff arrays generated straight from math.hoon to avoid transcription error. Verified bit-exact to the math-rq.hoon vectors via test/rq_cores.c (13/13): log/log2/sin/cos/atan/asin/acos/sqt/cbt/pow/tan all match; tan confirmed against the live Hoon under the %n door. Co-Authored-By: Claude Opus 4.8 --- libmath/vere64/noun/jets/i/math.c | 390 ++++++++++++++++++++++++++++++ libmath/vere64/test/rq_cores.c | 33 +++ 2 files changed, 423 insertions(+) create mode 100644 libmath/vere64/test/rq_cores.c diff --git a/libmath/vere64/noun/jets/i/math.c b/libmath/vere64/noun/jets/i/math.c index f689b83..4fedbe6 100644 --- a/libmath/vere64/noun/jets/i/math.c +++ b/libmath/vere64/noun/jets/i/math.c @@ -1451,6 +1451,396 @@ typedef int64_t c3_ds; return _rq_scale2(y, k); } +/* @rq log/log-2/log-10 -- math.hoon ++rq ++log/++lr/++log-2/++log-10 +** x = 2^e * m, m in [sqrt(1/2),sqrt(2)); log(1+f) via atanh series (deg-22). +*/ + static void _rq_lr(float128_t x, float128_t* ef, float128_t* lm) { + static const c3_d cs[23][2] = { + {0x5555555555555555ULL,0x3ffd555555555555ULL},{0x999999999999999aULL,0x3ffc999999999999ULL}, + {0x2492492492492492ULL,0x3ffc249249249249ULL},{0xc71c71c71c71c71cULL,0x3ffbc71c71c71c71ULL}, + {0x5d1745d1745d1746ULL,0x3ffb745d1745d174ULL},{0x3b13b13b13b13b14ULL,0x3ffb3b13b13b13b1ULL}, + {0x1111111111111111ULL,0x3ffb111111111111ULL},{0xe1e1e1e1e1e1e1e2ULL,0x3ffae1e1e1e1e1e1ULL}, + {0x86bca1af286bca1bULL,0x3ffaaf286bca1af2ULL},{0x8618618618618618ULL,0x3ffa861861861861ULL}, + {0x42c8590b21642c86ULL,0x3ffa642c8590b216ULL},{0xae147ae147ae147bULL,0x3ffa47ae147ae147ULL}, + {0x84bda12f684bda13ULL,0x3ffa2f684bda12f6ULL},{0x611a7b9611a7b961ULL,0x3ffa1a7b9611a7b9ULL}, + {0x4210842108421084ULL,0x3ffa084210842108ULL},{0x7c1f07c1f07c1f08ULL,0x3ff9f07c1f07c1f0ULL}, + {0xd41d41d41d41d41dULL,0x3ff9d41d41d41d41ULL},{0xf914c1bacf914c1cULL,0x3ff9bacf914c1bacULL}, + {0xa41a41a41a41a41aULL,0x3ff9a41a41a41a41ULL},{0x9c18f9c18f9c18faULL,0x3ff98f9c18f9c18fULL}, + {0x417d05f417d05f41ULL,0x3ff97d05f417d05fULL},{0x6c16c16c16c16c17ULL,0x3ff96c16c16c16c1ULL}, + {0x72620ae4c415c988ULL,0x3ff95c9882b93105ULL}, + }; + union quad r0; r0.q = x; + int sub = ( ((r0.w[1] >> 48) & 0x7fffULL) == 0 ); + union quad xx; xx = r0; + if ( sub ) xx.q = _rqm(x, _rq_bits(0x4077000000000000ULL, 0)); // x * 2^120 + c3_ds ae = sub ? -120 : 0; + c3_ds e = (c3_ds)((xx.w[1] >> 48) & 0x7fffULL) - 16383; + union quad m; m.w[0] = xx.w[0]; m.w[1] = (xx.w[1] & 0xffffffffffffULL) | (16383ULL << 48); + if ( _rqle(_rq_bits(0x3fff6a09e667f3bcULL, 0xc908b2fb1366ea95ULL), m.q) ) { // m >= sqrt(2) + m.q = _rqm(m.q, _rq_bits(0x3ffe000000000000ULL, 0)); e = e + 1; + } + e = e + ae; + float128_t one = _rq_bits(0x3fff000000000000ULL, 0); + float128_t f = _rqs(m.q, one); + float128_t s = _rqd(f, _rqa(m.q, one)); + float128_t z = _rqm(s, s); + float128_t p = _rq_bits(0, 0); + for ( int i = 23; i-- != 0; ) p = _rqa(_rqm(p, z), _rq_bits(cs[i][1], cs[i][0])); + float128_t r = _rqm(_rqa(z, z), p); + float128_t l1 = _rqs(f, _rqm(s, _rqs(f, r))); + float128_t efv = _rqi64( (c3_ds)(e < 0 ? -e : e) ); + if ( e < 0 ) efv = _rq_neg(efv); + *ef = efv; *lm = l1; + } + static int _rq_log_guard(float128_t x, float128_t* out) { + union quad r0; r0.q = x; + if ( !_rqeq(x, x) ) { *out = _rq_bits(_RQ_QNAN_HI, 0); return 1; } + if ( r0.w[1]==_RQ_PINF_HI && r0.w[0]==0 ) { *out = x; return 1; } + if ( (r0.w[1]==0 && r0.w[0]==0)||(r0.w[1]==0x8000000000000000ULL && r0.w[0]==0) ) + { *out = _rq_bits(_RQ_NINF_HI, 0); return 1; } + if ( (r0.w[1] >> 63) == 1 ) { *out = _rq_bits(_RQ_QNAN_HI, 0); return 1; } + return 0; + } + static float128_t _rq_log(float128_t x) { + float128_t g, ef, lm; + if ( _rq_log_guard(x, &g) ) return g; + _rq_lr(x, &ef, &lm); + float128_t hi = _rqm(ef, _rq_bits(0x3ffe62e42fefa39eULL, 0xf35793c800000000ULL)); // e*ln2hi + float128_t lo = _rqm(ef, _rq_bits(0xbfad319ff0342542ULL, 0xfc32f366359d274aULL)); // e*ln2lo + return _rqa(hi, _rqa(lm, lo)); + } + static float128_t _rq_log2(float128_t x) { + float128_t g, ef, lm; + if ( _rq_log_guard(x, &g) ) return g; + _rq_lr(x, &ef, &lm); // e + lm/ln2 + return _rqa(ef, _rqm(lm, _rq_bits(0x3fff71547652b82fULL, 0xe1777d0ffda0d23aULL))); + } + static float128_t _rq_log10(float128_t x) { + float128_t g, ef, lm; + if ( _rq_log_guard(x, &g) ) return g; + _rq_lr(x, &ef, &lm); // e*log10(2) + lm/ln10 + return _rqa(_rqm(ef, _rq_bits(0x3ffd34413509f79fULL, 0xef311f12b35816f9ULL)), + _rqm(lm, _rq_bits(0x3ffdbcb7b1526e50ULL, 0xe32a6ab7555f5a68ULL))); + } + +/* @rq sin/cos/tan -- math.hoon ++rq ++sin/++cos/++rq-trig/++tan +** x = q*(pi/2) + (rhi+rlo) (2-part pi/2), fdlibm kernels by q&3. tan=sin/cos. +*/ + static const c3_d _RQ_SC[16][2] = { // sin kernel coeffs + {0x5555555555555555ULL,0xbffc555555555555ULL},{0x1111111111111111ULL,0x3ff8111111111111ULL}, + {0xa01a01a01a01a01aULL,0xbff2a01a01a01a01ULL},{0x38faac1c88e50017ULL,0x3fec71de3a556c73ULL}, + {0x38fe747e4b837dc7ULL,0xbfe5ae64567f544eULL},{0x97ca38331d23af68ULL,0x3fde6124613a86d0ULL}, + {0xf11d8656b0ee8cb0ULL,0xbfd6ae7f3e733b81ULL},{0xa6b2605197771b00ULL,0x3fce952c77030ad4ULL}, + {0x724ca1ec3b7b9675ULL,0xbfc62f49b4681415ULL},{0x18bef146fcee6e45ULL,0x3fbd71b8ef6dcf57ULL}, + {0x9d97b8704dd7f628ULL,0xbfb4761b41316381ULL},{0x8d4e44a419776f11ULL,0x3fab3f3ccdd165faULL}, + {0x320a9a18f15d4277ULL,0xbfa1d1ab1c2dcceaULL},{0xd7abe30e7766f129ULL,0x3f98259f98b4358aULL}, + {0xc42e1ee46fa6bfc4ULL,0xbf8e434d2e783f5bULL},{0x1b5382cdffa97422ULL,0x3f843981254dd0d5ULL}, + }; + static const c3_d _RQ_CC[16][2] = { // cos kernel coeffs + {0x5555555555555555ULL,0x3ffa555555555555ULL},{0x6c16c16c16c16c17ULL,0xbff56c16c16c16c1ULL}, + {0xa01a01a01a01a01aULL,0x3fefa01a01a01a01ULL},{0xc72ef016d3ea6679ULL,0xbfe927e4fb7789f5ULL}, + {0x7b544da987acfe85ULL,0x3fe21eed8eff8d89ULL},{0xd20badf145dfa3e5ULL,0xbfda93974a8c07c9ULL}, + {0xf11d8656b0ee8cb0ULL,0x3fd2ae7f3e733b81ULL},{0x77bb004886a2c2abULL,0xbfca6827863b97d9ULL}, + {0x507a9cad2bf8f0bbULL,0x3fc1e542ba402022ULL},{0x29450c90b7f338ecULL,0xbfb90ce396db7f85ULL}, + {0x7cca4b4067ca9d8aULL,0x3faff2cf01972f57ULL},{0x9a38f2050ba6b015ULL,0xbfa688e85fc6a4e5ULL}, + {0xd373c5c51c354a8dULL,0x3f9d0a18a2635085ULL},{0xe60caded4c2989c5ULL,0xbf933932c5047d60ULL}, + {0xc42e1ee46fa6bfc4ULL,0x3f89434d2e783f5bULL},{0xa13f8a2b4af9d6b7ULL,0xbf7f2710231c0fd7ULL}, + }; + static float128_t _rq_ksin(float128_t xx, float128_t yy) { + float128_t half = _rq_bits(0x3ffe000000000000ULL, 0); + float128_t z = _rqm(xx, xx); + float128_t r = _rq_bits(0, 0); // Horner over flop(tail sc): sc[15..1] + for ( int i = 16; i-- != 1; ) r = _rqa(_rqm(r, z), _rq_bits(_RQ_SC[i][1], _RQ_SC[i][0])); + float128_t v = _rqm(z, xx); + float128_t aa = _rqs(_rqm(half, yy), _rqm(v, r)); + float128_t bb = _rqs(_rqm(z, aa), yy); + float128_t dd = _rqs(bb, _rqm(v, _rq_bits(_RQ_SC[0][1], _RQ_SC[0][0]))); + return _rqs(xx, dd); + } + static float128_t _rq_kcos(float128_t xx, float128_t yy) { + float128_t half = _rq_bits(0x3ffe000000000000ULL, 0), one = _rq_bits(0x3fff000000000000ULL, 0); + float128_t z = _rqm(xx, xx); + float128_t rc = _rq_bits(0, 0); // Horner over flop(cc): cc[15..0] + for ( int i = 16; i-- != 0; ) rc = _rqa(_rqm(rc, z), _rq_bits(_RQ_CC[i][1], _RQ_CC[i][0])); + float128_t hz = _rqm(half, z); + float128_t w2 = _rqs(one, hz); + float128_t aa = _rqs(_rqs(one, w2), hz); + float128_t bb = _rqs(_rqm(_rqm(z, z), rc), _rqm(xx, yy)); + return _rqa(w2, _rqa(aa, bb)); + } + static float128_t _rq_trigfin(int is_sin, float128_t ax, c3_d sb) { + c3_ds q = _rqtoi(_rqm(ax, _rq_bits(0x3ffe45f306dc9c88ULL, 0x2a53f84eafa3ea6aULL)), + softfloat_round_near_even); // round(ax*2/pi) + c3_d aq = (c3_d)(q < 0 ? -q : q); + float128_t qf = _rqi64((c3_ds)aq); + float128_t t = _rqs(ax, _rqm(qf, _rq_bits(0x3fff921fb54442d1ULL, 0x8460000000000000ULL))); // ax - qf*pio2_hi + float128_t w = _rqm(qf, _rq_bits(0x3fc2313198a2e037ULL, 0x07344a409382229aULL)); // qf*pio2_lo + float128_t rhi = _rqs(t, w); + float128_t rlo = _rqs(_rqs(t, rhi), w); + int mm = (int)(aq & 3); + float128_t ks = _rq_ksin(rhi, rlo); + float128_t kc = _rq_kcos(rhi, rlo); + if ( is_sin ) { + float128_t v = (mm==0) ? ks : (mm==1) ? kc : (mm==2) ? _rq_neg(ks) : _rq_neg(kc); + return (sb == 1) ? _rq_neg(v) : v; + } + return (mm==0) ? kc : (mm==1) ? _rq_neg(ks) : (mm==2) ? _rq_neg(kc) : ks; + } + static float128_t _rq_sin(float128_t x) { + union quad r0, ax; r0.q = x; + if ( !_rqeq(x, x) ) return _rq_bits(_RQ_QNAN_HI, 0); // NaN + if ( (r0.w[1]==_RQ_PINF_HI||r0.w[1]==_RQ_NINF_HI) && r0.w[0]==0 ) return _rq_bits(_RQ_QNAN_HI, 0); // +-inf -> NaN + if ( (r0.w[1]==0||r0.w[1]==0x8000000000000000ULL) && r0.w[0]==0 ) return x; // +-0 -> +-0 + ax.w[0] = r0.w[0]; ax.w[1] = r0.w[1] & 0x7fffffffffffffffULL; + return _rq_trigfin(1, ax.q, r0.w[1] >> 63); + } + static float128_t _rq_cos(float128_t x) { + union quad r0, ax; r0.q = x; + if ( !_rqeq(x, x) ) return _rq_bits(_RQ_QNAN_HI, 0); // NaN + if ( (r0.w[1]==_RQ_PINF_HI||r0.w[1]==_RQ_NINF_HI) && r0.w[0]==0 ) return _rq_bits(_RQ_QNAN_HI, 0); // +-inf -> NaN + ax.w[0] = r0.w[0]; ax.w[1] = r0.w[1] & 0x7fffffffffffffffULL; + return _rq_trigfin(0, ax.q, 0); + } + // tan = (div (sin x) (cos x)): sin/cos kernels %n, the bare div per door r + static float128_t _rq_tan(float128_t x) { + float128_t s = _rq_sin(x), c = _rq_cos(x); + softfloat_roundingMode = _math_rnd; + float128_t r = _rqd(s, c); + softfloat_roundingMode = softfloat_round_near_even; + return r; + } + +/* @rq atan/atan2 -- math.hoon ++rq ++atan/++rq-atan/++atan2 +** fdlibm breakpoint reduction (7/16,11/16,19/16,39/16) + degree-30 minimax. +*/ + static float128_t _rq_atan(float128_t x) { + static const c3_d at[31][2] = { + {0x5555555555555555ULL,0x3ffd555555555555ULL},{0x999999999999999aULL,0xbffc999999999999ULL}, + {0x2492492492492492ULL,0x3ffc249249249249ULL},{0xc71c71c71c71c705ULL,0xbffbc71c71c71c71ULL}, + {0x5d1745d1745cf720ULL,0x3ffb745d1745d174ULL},{0x3b13b13b1395a0f6ULL,0xbffb3b13b13b13b1ULL}, + {0x11111111010e24e1ULL,0x3ffb111111111111ULL},{0xe1e1e1d48fd7bd0fULL,0xbffae1e1e1e1e1e1ULL}, + {0x86bc9d8a12661ce3ULL,0x3ffaaf286bca1af2ULL},{0x861762af171f46fbULL,0xbffa861861861861ULL}, + {0x4297f77f1796654aULL,0x3ffa642c8590b216ULL},{0xa6aeeb974d91c763ULL,0xbffa47ae147ae147ULL}, + {0x982c83840df48c76ULL,0x3ffa2f684bda12f5ULL},{0xf24134848b6f9bc3ULL,0xbffa1a7b9611a7a0ULL}, + {0x46f1272e8718edfeULL,0x3ffa084210841eedULL},{0xdac476af1946ed1aULL,0xbff9f07c1f0773e1ULL}, + {0x771b4773d1fdbc46ULL,0x3ff9d41d41cf56a0ULL},{0xd9a2c9f0ffa28317ULL,0xbff9bacf910ca5eaULL}, + {0x5da3c3e48cd55593ULL,0x3ff9a41a3ed6e709ULL},{0x4d8ac15872fbb51cULL,0xbff98f9bfe02ad67ULL}, + {0x069f17b95f6e54f4ULL,0x3ff97d05170d1702ULL},{0x6ea05add542af078ULL,0xbff96c10bc42d041ULL}, + {0xeab121f20635a41aULL,0x3ff95c74e7f6f412ULL},{0x283b75528258306bULL,0xbff94dac2e21aa0eULL}, + {0xdb9d4b05d70c99cfULL,0x3ff93e573faac561ULL},{0x4f5966908860d11aULL,0xbff92af32cae28f7ULL}, + {0xdec0acdf4b356e20ULL,0x3ff90c8b03c55304ULL},{0xf7ad970276c5cf2bULL,0xbff8b4ed3a3349acULL}, + {0xd5dd688f198ae3cbULL,0x3ff8261c1a9eda3aULL},{0x876f4b57d627e71eULL,0xbff71a7ac449b285ULL}, + {0x138131c15128032aULL,0x3ff51a4ea418ebe8ULL}, + }; + union quad r0, ax, xr, hi, lo; r0.q = x; + if ( !_rqeq(x, x) ) return _rq_bits(_RQ_QNAN_HI, 0); // NaN + if ( r0.w[1]==_RQ_PINF_HI && r0.w[0]==0 ) return _rq_bits(0x3fff921fb54442d1ULL, 0x8469898cc51701b8ULL); // +inf -> pi/2 + if ( r0.w[1]==_RQ_NINF_HI && r0.w[0]==0 ) return _rq_bits(0xbfff921fb54442d1ULL, 0x8469898cc51701b8ULL); // -inf -> -pi/2 + if ( (r0.w[1]==0||r0.w[1]==0x8000000000000000ULL) && r0.w[0]==0 ) return x; // +-0 + c3_d neg = r0.w[1] >> 63; + ax.w[0] = r0.w[0]; ax.w[1] = r0.w[1] & 0x7fffffffffffffffULL; + float128_t one = _rq_bits(0x3fff000000000000ULL, 0), two = _rq_bits(0x4000000000000000ULL, 0); + float128_t ohf = _rq_bits(0x3fff800000000000ULL, 0); + int dir = 0; + if ( _rqlt(ax.q, _rq_bits(0x3ffdc00000000000ULL, 0)) ) { // |x| < 7/16 + xr.q = ax.q; hi.q = _rq_bits(0,0); lo.q = _rq_bits(0,0); dir = 1; + } else if ( _rqlt(ax.q, _rq_bits(0x3ffe600000000000ULL, 0)) ) { // < 11/16 + xr.q = _rqd(_rqs(_rqa(ax.q, ax.q), one), _rqa(two, ax.q)); + hi.q = _rq_bits(0x3ffddac670561bb4ULL, 0xf68adfc88bd97875ULL); // atan(0.5) + lo.q = _rq_bits(0x3f89a06dc282b0e4ULL, 0xc39be01c59e2dcddULL); + } else if ( _rqlt(ax.q, _rq_bits(0x3fff300000000000ULL, 0)) ) { // < 19/16 + xr.q = _rqd(_rqs(ax.q, one), _rqa(ax.q, one)); + hi.q = _rq_bits(0x3ffe921fb54442d1ULL, 0x8469898cc51701b8ULL); // pi/4 + lo.q = _rq_bits(0x3f8bcd129024e088ULL, 0xa67cc74020bbea64ULL); + } else if ( _rqlt(ax.q, _rq_bits(0x4000380000000000ULL, 0)) ) { // < 39/16 + xr.q = _rqd(_rqs(ax.q, ohf), _rqa(one, _rqm(ohf, ax.q))); + hi.q = _rq_bits(0x3ffef730bd281f69ULL, 0xb200f10f5e197794ULL); // atan(1.5) + lo.q = _rq_bits(0xbf8bebe566c99adaULL, 0x9f231bccae27916cULL); + } else { // -1/x + xr.q = _rqd(_rq_bits(0xbfff000000000000ULL, 0), ax.q); + hi.q = _rq_bits(0x3fff921fb54442d1ULL, 0x8469898cc51701b8ULL); // pi/2 + lo.q = _rq_bits(0x3f8ccd129024e088ULL, 0xa67cc74020bbea64ULL); + } + float128_t z = _rqm(xr.q, xr.q); + float128_t sp = _rq_bits(0, 0); + for ( int i = 31; i-- != 0; ) sp = _rqa(_rqm(sp, z), _rq_bits(at[i][1], at[i][0])); + float128_t s = _rqm(z, sp); + float128_t res = dir ? _rqs(xr.q, _rqm(xr.q, s)) + : _rqs(hi.q, _rqs(_rqs(_rqm(xr.q, s), lo.q), xr.q)); + return (neg == 1) ? _rq_neg(res) : res; + } + static float128_t _rq_atan2(float128_t y, float128_t x) { + union quad xb; xb.q = x; + float128_t zero = _rq_bits(0,0); + float128_t pi = _rq_bits(0x4000921fb54442d1ULL, 0x8469898cc51701b8ULL); + float128_t two = _rq_bits(0x4000000000000000ULL, 0), mone = _rq_bits(0xbfff000000000000ULL, 0); + if ( _rqlt(zero, x) ) { // x>0: atan(div y x) + softfloat_roundingMode = _math_rnd; float128_t q = _rqd(y, x); + softfloat_roundingMode = softfloat_round_near_even; return _rq_atan(q); + } + if ( _rqlt(x, zero) && _rqle(zero, y) ) { // x<0,y>=0: add(atan,pi) + softfloat_roundingMode = _math_rnd; float128_t q = _rqd(y, x); + softfloat_roundingMode = softfloat_round_near_even; float128_t a = _rq_atan(q); + softfloat_roundingMode = _math_rnd; float128_t r = _rqa(a, pi); + softfloat_roundingMode = softfloat_round_near_even; return r; + } + if ( _rqlt(x, zero) && _rqlt(y, zero) ) { // x<0,y<0: sub(atan,pi) + softfloat_roundingMode = _math_rnd; float128_t q = _rqd(y, x); + softfloat_roundingMode = softfloat_round_near_even; float128_t a = _rq_atan(q); + softfloat_roundingMode = _math_rnd; float128_t r = _rqs(a, pi); + softfloat_roundingMode = softfloat_round_near_even; return r; + } + if ( (xb.w[1]==0 && xb.w[0]==0) && _rqlt(zero, y) ) { // x==+0,y>0: div(pi,2) + softfloat_roundingMode = _math_rnd; float128_t r = _rqd(pi, two); + softfloat_roundingMode = softfloat_round_near_even; return r; + } + if ( (xb.w[1]==0 && xb.w[0]==0) && _rqlt(y, zero) ) { // x==+0,y<0: mul(-1,div(pi,2)) + softfloat_roundingMode = _math_rnd; float128_t r = _rqm(mone, _rqd(pi, two)); + softfloat_roundingMode = softfloat_round_near_even; return r; + } + return zero; + } + +/* @rq asin/acos -- math.hoon ++rq ++asin/++acos/++rq-ainv +** poly kernel R(t) (deg-30, NOT P/Q) + sqrt head/tail; sqt = f128 sqrt. +*/ + static const c3_d _RQ_RR[31][2] = { + {0x83f400d50d55a7e8ULL,0x3f8089912e54d43fULL},{0x5555555555555552ULL,0x3ffc555555555555ULL}, + {0x3333333333335009ULL,0x3ffb333333333333ULL},{0x6db6db6db668951bULL,0x3ffa6db6db6db6dbULL}, + {0x71c71c72bac1ec0eULL,0x3ff9f1c71c71c71cULL},{0x8ba2e81aa31a41d8ULL,0x3ff96e8ba2e8ba2eULL}, + {0xec4f0b6fe680df37ULL,0x3ff91c4ec4ec4ec4ULL},{0x996cf372753e7c99ULL,0x3ff8c99999999999ULL}, + {0x92177cc3275353f7ULL,0x3ff87a8787878787ULL},{0xf7f1afe5cbeac090ULL,0x3ff83fde50d79433ULL}, + {0xf127037c33f0fb5bULL,0x3ff812ef3cf3cf83ULL},{0x5c114e9da47dedfdULL,0x3ff7df3bd37a5edeULL}, + {0x909e07297f5e2958ULL,0x3ff7a6863d723133ULL},{0x52ce6cb856ef901fULL,0x3ff7782dd9f3ff64ULL}, + {0x2fdb62f41c709bd1ULL,0x3ff751ba328f884cULL},{0xb0d4961421efa7ecULL,0x3ff731681fe6e02dULL}, + {0x3408e80b5b3f8641ULL,0x3ff715efe556e52aULL},{0x1812712268a45b42ULL,0x3ff6fc96253ecb71ULL}, + {0xebe9bc6e47ec09afULL,0x3ff6d4a82428408aULL},{0xc0a9facb94511de4ULL,0x3ff6aa377fe913f6ULL}, + {0x84737463fe8656d8ULL,0x3ff6b48ca21a48d1ULL},{0xe39134518885e78fULL,0x3ff57e9aa4b5b4c4ULL}, + {0xa0d03ab9c51426b2ULL,0x3ff819064c5185faULL},{0x1c085f962a89aaccULL,0xbff9300f0da2da1eULL}, + {0x97d25a1be10b6c8aULL,0x3ffb0643398cdbcbULL},{0x528e0d54bf4f5e05ULL,0xbffc27ed3dd5cd82ULL}, + {0xad880c8cd533b68bULL,0x3ffd1d64319be957ULL},{0x81c3902a2c54acc7ULL,0xbffd9731e485678bULL}, + {0xa99aa13d6e9cd204ULL,0x3ffdae10872f69b7ULL},{0x25c164c7f61091faULL,0xbffd228fc6527609ULL}, + {0x2c15b8ad9b2377ceULL,0x3ffb9aa4ca63cbd7ULL}, + }; + static float128_t _rq_ainv_rr(float128_t t) { + float128_t pp = _rq_bits(0, 0); + for ( int i = 31; i-- != 0; ) pp = _rqa(_rqm(pp, t), _rq_bits(_RQ_RR[i][1], _RQ_RR[i][0])); + return pp; + } + static float128_t _rq_asin(float128_t x) { + union quad r0, ax; r0.q = x; + float128_t half = _rq_bits(0x3ffe000000000000ULL, 0), one = _rq_bits(0x3fff000000000000ULL, 0); + float128_t two = _rq_bits(0x4000000000000000ULL, 0); + float128_t pio2h = _rq_bits(0x3fff921fb54442d1ULL, 0x8469898cc51701b8ULL); + float128_t pio2l = _rq_bits(0x3f8ccd129024e088ULL, 0xa67cc74020bbea64ULL); + float128_t pio4 = _rq_bits(0x3ffe921fb54442d1ULL, 0x8469898cc51701b8ULL); + if ( !_rqeq(x, x) ) return _rq_bits(_RQ_QNAN_HI, 0); // NaN + c3_d sgn = r0.w[1] >> 63; + ax.w[0] = r0.w[0]; ax.w[1] = r0.w[1] & 0x7fffffffffffffffULL; + if ( _rqlt(one, ax.q) ) return _rq_bits(_RQ_QNAN_HI, 0); // |x|>1 -> NaN + if ( ax.w[1]==0x3fff000000000000ULL && ax.w[0]==0 ) // |x|==1 + return _rqa(_rqm(x, pio2h), _rqm(x, pio2l)); + if ( _rqlt(ax.q, half) ) { // |x|<0.5 + if ( _rqlt(ax.q, _rq_bits(0x3fc6000000000000ULL, 0)) ) return x; // tiny + float128_t t = _rqm(x, x); + return _rqa(x, _rqm(x, _rq_ainv_rr(t))); + } + float128_t w = _rqs(one, ax.q); + float128_t t = _rqm(w, half); + float128_t r = _rq_ainv_rr(t); + float128_t s = _rqq(t); + if ( _rqle(_rq_bits(0x3ffef33333333333ULL, 0x3333333333333333ULL), ax.q) ) { // near 1 + float128_t res = _rqs(pio2h, _rqs(_rqm(two, _rqa(s, _rqm(s, r))), pio2l)); + return (sgn == 1) ? _rq_neg(res) : res; + } + union quad sq; sq.q = s; + float128_t df = _rq_bits(sq.w[1], sq.w[0] & 0xff00000000000000ULL); + float128_t cc = _rqd(_rqs(t, _rqm(df, df)), _rqa(s, df)); + float128_t p2 = _rqs(_rqm(two, _rqm(s, r)), _rqs(pio2l, _rqm(two, cc))); + float128_t q2 = _rqs(pio4, _rqm(two, df)); + float128_t res = _rqs(pio4, _rqs(p2, q2)); + return (sgn == 1) ? _rq_neg(res) : res; + } + static float128_t _rq_acos(float128_t x) { + union quad r0, ax; r0.q = x; + float128_t half = _rq_bits(0x3ffe000000000000ULL, 0), one = _rq_bits(0x3fff000000000000ULL, 0); + float128_t two = _rq_bits(0x4000000000000000ULL, 0); + float128_t pi = _rq_bits(0x4000921fb54442d1ULL, 0x8469898cc51701b8ULL); + float128_t pio2h = _rq_bits(0x3fff921fb54442d1ULL, 0x8469898cc51701b8ULL); + float128_t pio2l = _rq_bits(0x3f8ccd129024e088ULL, 0xa67cc74020bbea64ULL); + if ( !_rqeq(x, x) ) return _rq_bits(_RQ_QNAN_HI, 0); // NaN + c3_d neg = r0.w[1] >> 63; + ax.w[0] = r0.w[0]; ax.w[1] = r0.w[1] & 0x7fffffffffffffffULL; + if ( _rqlt(one, ax.q) ) return _rq_bits(_RQ_QNAN_HI, 0); // |x|>1 -> NaN + if ( ax.w[1]==0x3fff000000000000ULL && ax.w[0]==0 ) { // |x|==1 + if ( neg == 0 ) return _rq_bits(0, 0); // 1 -> 0 + return _rqa(pi, _rqm(two, pio2l)); // -1 -> pi + } + if ( _rqlt(ax.q, half) ) { // |x|<0.5 + if ( _rqlt(ax.q, _rq_bits(0x3f87000000000000ULL, 0)) ) return pio2h; // tiny -> pi/2 + float128_t z = _rqm(x, x); + float128_t r = _rq_ainv_rr(z); + return _rqs(pio2h, _rqs(x, _rqs(pio2l, _rqm(x, r)))); + } + if ( neg == 1 ) { // x <= -0.5 + float128_t z = _rqm(_rqa(one, x), half); + float128_t s = _rqq(z); + float128_t r = _rq_ainv_rr(z); + float128_t w = _rqs(_rqm(r, s), pio2l); + return _rqs(pi, _rqm(two, _rqa(s, w))); + } + float128_t z = _rqm(_rqs(one, x), half); // x >= 0.5 + float128_t s = _rqq(z); + union quad sq; sq.q = s; + float128_t df = _rq_bits(sq.w[1], sq.w[0] & 0xff00000000000000ULL); + float128_t cc = _rqd(_rqs(z, _rqm(df, df)), _rqa(s, df)); + float128_t r = _rq_ainv_rr(z); + float128_t w = _rqa(_rqm(r, s), cc); + return _rqm(two, _rqa(df, w)); + } + +/* @rq sqt/cbt -- math.hoon ++rq ++sqt/++cbt */ + static float128_t _rq_sqt(float128_t x) { + union quad r0; r0.q = x; + if ( !_rqeq(x, x) ) return _rq_bits(_RQ_QNAN_HI, 0); // NaN + if ( r0.w[1]==_RQ_PINF_HI && r0.w[0]==0 ) return x; // +inf + if ( (r0.w[1]==0||r0.w[1]==0x8000000000000000ULL) && r0.w[0]==0 ) return x; // +-0 + if ( (r0.w[1] >> 63) == 1 ) return _rq_bits(_RQ_QNAN_HI, 0); // x<0 -> NaN + return _rqq(x); // correctly-rounded + } + static float128_t _rq_cbt(float128_t x) { + union quad r0, ax; r0.q = x; + if ( !_rqeq(x, x) ) return x; // NaN -> NaN + if ( (r0.w[1]==0||r0.w[1]==0x8000000000000000ULL) && r0.w[0]==0 ) return x; // +-0 + ax.w[0] = r0.w[0]; ax.w[1] = r0.w[1] & 0x7fffffffffffffffULL; + float128_t r = _rq_exp(_rqm(_rq_log(ax.q), _rq_bits(0x3ffd555555555555ULL, 0x5555555555555555ULL))); // exp(log|x|/3) + return ((r0.w[1] >> 63) == 1) ? _rq_neg(r) : r; + } + +/* @rq pow/pow-n -- math.hoon ++rq ++pow/++pow-n */ + static float128_t _rq_pow_n(float128_t x, float128_t n) { + union quad nn; nn.q = n; + float128_t one = _rq_bits(0x3fff000000000000ULL, 0), two = _rq_bits(0x4000000000000000ULL, 0); + if ( nn.w[1]==0 && nn.w[0]==0 ) return one; // n == +0 -> 1 + softfloat_roundingMode = _math_rnd; // bare mul/sub round per door r + float128_t p = x; + while ( !_rqlt(n, two) ) { p = _rqm(p, x); n = _rqs(n, one); } + softfloat_roundingMode = softfloat_round_near_even; + return p; + } + static float128_t _rq_pow(float128_t x, float128_t n) { + union quad nn, ni; nn.q = n; + float128_t zero = _rq_bits(0,0); + ni.q = _rqi64(_rqtoi(n, softfloat_round_near_even)); // san (need (toi n)) + if ( (nn.w[1]==ni.w[1] && nn.w[0]==ni.w[0]) && _rqlt(zero, n) ) // positive integer + return _rq_pow_n(x, ni.q); + float128_t lg = _rq_log(x); // %n kernel + softfloat_roundingMode = _math_rnd; // bare mul per door r + float128_t prod = _rqm(n, lg); + softfloat_roundingMode = softfloat_round_near_even; + return _rq_exp(prod); // %n kernel: exp(n*log x) + } + #ifndef MATH_JET_HARNESS /* u3 ABI wrappers. Each transcendental forces round-near-even; the @rd door's diff --git a/libmath/vere64/test/rq_cores.c b/libmath/vere64/test/rq_cores.c new file mode 100644 index 0000000..7c07887 --- /dev/null +++ b/libmath/vere64/test/rq_cores.c @@ -0,0 +1,33 @@ +// rq_cores.c -- verify the native f128 @rq cores against math-rq.hoon vectors. +#define MATH_JET_HARNESS +#include "../noun/jets/i/math.c" +#include +static int fails = 0; +static float128_t Q(c3_d hi, c3_d lo){ return _rq_bits(hi, lo); } +static void chk(const char* nm, float128_t got, c3_d ehi, c3_d elo){ + union quad u; u.q = got; + int ok = (u.w[1]==ehi && u.w[0]==elo); + if(!ok) fails++; + printf("%-10s got 0x%016llx.%016llx want 0x%016llx.%016llx %s\n", + nm,(unsigned long long)u.w[1],(unsigned long long)u.w[0], + (unsigned long long)ehi,(unsigned long long)elo, ok?"OK":"*** FAIL"); +} +int main(void){ + softfloat_roundingMode = softfloat_round_near_even; _math_rnd = softfloat_round_near_even; + float128_t ONE=Q(0x3fff000000000000ULL,0), TWO=Q(0x4000000000000000ULL,0), + HALF=Q(0x3ffe000000000000ULL,0), EIGHT=Q(0x4002000000000000ULL,0); + chk("log-2", _rq_log(TWO), 0x3ffe62e42fefa39eULL,0xf35793c7673007e6ULL); + chk("log2-8", _rq_log2(EIGHT),0x4000800000000000ULL,0x0000000000000000ULL); + chk("sin-1", _rq_sin(ONE), 0x3ffeaed548f090ceULL,0xe0418dd3d2138a1eULL); + chk("cos-1", _rq_cos(ONE), 0x3ffe14a280fb5068ULL,0xb923848cdb2ed0e4ULL); + chk("atan-1", _rq_atan(ONE), 0x3ffe921fb54442d1ULL,0x8469898cc51701b8ULL); + chk("atan-2", _rq_atan(TWO), 0x3fff1b6e192ebbe4ULL,0x46c6d19aa220a39bULL); + chk("asin-h", _rq_asin(HALF), 0x3ffe0c152382d736ULL,0x58465bb32e0f567bULL); + chk("acos-h", _rq_acos(HALF), 0x3fff0c152382d736ULL,0x58465bb32e0f567bULL); + chk("sqt-2", _rq_sqt(TWO), 0x3fff6a09e667f3bcULL,0xc908b2fb1366ea95ULL); + chk("cbt-8", _rq_cbt(EIGHT), 0x3fffffffffffffffULL,0xffffffffffffffffULL); + chk("pow-2-h",_rq_pow(TWO,HALF),0x3fff6a09e667f3bcULL,0xc908b2fb1366ea96ULL); + chk("tan-1", _rq_tan(ONE), 0x3fff8eb245cbee3aULL,0x5b8acc7d41323140ULL); // tan(1)=div(sin,cos) under %n + printf("\n%s (%d failures)\n", fails?"FAILED":"ALL PASS", fails); + return fails?1:0; +} From 9bd22bdbe59e99f5535e074dfcccaadd328c985e Mon Sep 17 00:00:00 2001 From: Sigilante Date: Sat, 13 Jun 2026 08:41:50 -0500 Subject: [PATCH 24/28] math: @rq u3 ABI wrappers (15 fns) with softfloat_roundingMode handling _rq_in/_rq_out (2-chub f128 I/O), _rq_jet/_rq_jet2 (1- and 2-arg, set softfloat_roundingMode=near-even + _math_rnd from axis 60), and u3qi/u3wi for all 15 @rq fns. Models the @rh wrappers (kernels near-even, composites honor door r) -- carries the softfloat_roundingMode-not-_math_rnd fix from the start. Co-Authored-By: Claude Opus 4.8 --- libmath/vere64/noun/jets/i/math.c | 61 +++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/libmath/vere64/noun/jets/i/math.c b/libmath/vere64/noun/jets/i/math.c index 4fedbe6..b68a395 100644 --- a/libmath/vere64/noun/jets/i/math.c +++ b/libmath/vere64/noun/jets/i/math.c @@ -2131,4 +2131,65 @@ typedef int64_t c3_ds; u3_noun u3qi_rh_pow_n(u3_atom x, u3_atom n) { softfloat_roundingMode=softfloat_round_near_even; return _rh_out(_rh_pow_n(_rh_in(x), _rh_in(n))); } u3_noun u3wi_rh_pow_n(u3_noun cor){ return _rh_jet2(cor, _rh_pow_n); } +/* @rq ABI wrappers. @rq is a 128-bit atom: read/write TWO chubs (v[0]=low 64, +** v[1]=high 64). Wrappers set softfloat_roundingMode=near-even (kernels) and +** _math_rnd from the door's r (axis 60) for the composites (tan/atan2/pow/ +** pow-n). Word-agnostic chub I/O, same as @rd/@rs/@rh. +*/ + static inline float128_t _rq_in(u3_atom a) { + union quad s; s.w[0] = u3r_chub(0, a); s.w[1] = u3r_chub(1, a); return s.q; + } + static inline u3_noun _rq_out(float128_t v) { + union quad s; s.q = v; return u3i_chubs(2, &s.w[0]); + } + static u3_noun _rq_jet(u3_noun cor, float128_t (*fun)(float128_t)) { + u3_noun x = u3r_at(u3x_sam, cor); + if ( u3_none == x || c3n == u3ud(x) ) return u3m_bail(c3__exit); + softfloat_roundingMode = softfloat_round_near_even; // kernels run near-even + _math_rnd = _rnd_of(u3r_at(60, cor)); // door rounding r (for tan/cbt/log-2/log-10) + return _rq_out(fun(_rq_in(x))); + } + static u3_noun _rq_jet2(u3_noun cor, float128_t (*fun)(float128_t, float128_t)) { + u3_noun x, n; + if ( c3n == u3r_mean(cor, {u3x_sam_2, &x}, {u3x_sam_3, &n}) || + c3n == u3ud(x) || c3n == u3ud(n) ) { + return u3m_bail(c3__exit); + } + softfloat_roundingMode = softfloat_round_near_even; // kernels run near-even + _math_rnd = _rnd_of(u3r_at(60, cor)); // door rounding r (composites) + return _rq_out(fun(_rq_in(x), _rq_in(n))); + } + + u3_noun u3qi_rq_exp(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rq_out(_rq_exp(_rq_in(a))); } + u3_noun u3wi_rq_exp(u3_noun cor) { return _rq_jet(cor, _rq_exp); } + u3_noun u3qi_rq_log(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rq_out(_rq_log(_rq_in(a))); } + u3_noun u3wi_rq_log(u3_noun cor) { return _rq_jet(cor, _rq_log); } + u3_noun u3qi_rq_sin(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rq_out(_rq_sin(_rq_in(a))); } + u3_noun u3wi_rq_sin(u3_noun cor) { return _rq_jet(cor, _rq_sin); } + u3_noun u3qi_rq_cos(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rq_out(_rq_cos(_rq_in(a))); } + u3_noun u3wi_rq_cos(u3_noun cor) { return _rq_jet(cor, _rq_cos); } + u3_noun u3qi_rq_tan(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rq_out(_rq_tan(_rq_in(a))); } + u3_noun u3wi_rq_tan(u3_noun cor) { return _rq_jet(cor, _rq_tan); } + u3_noun u3qi_rq_atan(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rq_out(_rq_atan(_rq_in(a))); } + u3_noun u3wi_rq_atan(u3_noun cor){ return _rq_jet(cor, _rq_atan); } + u3_noun u3qi_rq_asin(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rq_out(_rq_asin(_rq_in(a))); } + u3_noun u3wi_rq_asin(u3_noun cor){ return _rq_jet(cor, _rq_asin); } + u3_noun u3qi_rq_acos(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rq_out(_rq_acos(_rq_in(a))); } + u3_noun u3wi_rq_acos(u3_noun cor){ return _rq_jet(cor, _rq_acos); } + u3_noun u3qi_rq_sqt(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rq_out(_rq_sqt(_rq_in(a))); } + u3_noun u3wi_rq_sqt(u3_noun cor) { return _rq_jet(cor, _rq_sqt); } + u3_noun u3qi_rq_cbt(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rq_out(_rq_cbt(_rq_in(a))); } + u3_noun u3wi_rq_cbt(u3_noun cor) { return _rq_jet(cor, _rq_cbt); } + u3_noun u3qi_rq_log2(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rq_out(_rq_log2(_rq_in(a))); } + u3_noun u3wi_rq_log2(u3_noun cor){ return _rq_jet(cor, _rq_log2); } + u3_noun u3qi_rq_log10(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rq_out(_rq_log10(_rq_in(a))); } + u3_noun u3wi_rq_log10(u3_noun cor){ return _rq_jet(cor, _rq_log10); } + + u3_noun u3qi_rq_atan2(u3_atom y, u3_atom x) { softfloat_roundingMode=softfloat_round_near_even; return _rq_out(_rq_atan2(_rq_in(y), _rq_in(x))); } + u3_noun u3wi_rq_atan2(u3_noun cor){ return _rq_jet2(cor, _rq_atan2); } + u3_noun u3qi_rq_pow(u3_atom x, u3_atom n) { softfloat_roundingMode=softfloat_round_near_even; return _rq_out(_rq_pow(_rq_in(x), _rq_in(n))); } + u3_noun u3wi_rq_pow(u3_noun cor) { return _rq_jet2(cor, _rq_pow); } + u3_noun u3qi_rq_pow_n(u3_atom x, u3_atom n) { softfloat_roundingMode=softfloat_round_near_even; return _rq_out(_rq_pow_n(_rq_in(x), _rq_in(n))); } + u3_noun u3wi_rq_pow_n(u3_noun cor){ return _rq_jet2(cor, _rq_pow_n); } + #endif From 2b44227b7f43039dea5914aabb2552d70c796da6 Mon Sep 17 00:00:00 2001 From: Sigilante Date: Sat, 13 Jun 2026 08:43:56 -0500 Subject: [PATCH 25/28] math: register the @rq door jets (135/tree.c, q.h, w.h) 15 harms + the _135_non__math_rq_d core + the rq entry in _135_non__math_d, mirroring @rh; q.h/w.h declare the 15 u3qi_rq_*/u3wi_rq_*. Co-Authored-By: Claude Opus 4.8 --- libmath/vere64/noun/jets/135/tree.c | 35 +++++++++++++++++++++++++++++ libmath/vere64/noun/jets/q.h | 16 +++++++++++++ libmath/vere64/noun/jets/w.h | 16 +++++++++++++ 3 files changed, 67 insertions(+) diff --git a/libmath/vere64/noun/jets/135/tree.c b/libmath/vere64/noun/jets/135/tree.c index 4c5c923..c0a0fa5 100644 --- a/libmath/vere64/noun/jets/135/tree.c +++ b/libmath/vere64/noun/jets/135/tree.c @@ -1049,10 +1049,45 @@ static u3j_core _135_non__math_rh_d[] = { "log-10", 7, _135_non__math_rh_log10_a, 0, no_hashes }, {} }; +static u3j_harm _135_non__math_rq_exp_a[] = {{".2", u3wi_rq_exp}, {}}; +static u3j_harm _135_non__math_rq_log_a[] = {{".2", u3wi_rq_log}, {}}; +static u3j_harm _135_non__math_rq_sin_a[] = {{".2", u3wi_rq_sin}, {}}; +static u3j_harm _135_non__math_rq_cos_a[] = {{".2", u3wi_rq_cos}, {}}; +static u3j_harm _135_non__math_rq_tan_a[] = {{".2", u3wi_rq_tan}, {}}; +static u3j_harm _135_non__math_rq_atan_a[] = {{".2", u3wi_rq_atan}, {}}; +static u3j_harm _135_non__math_rq_atan2_a[] = {{".2", u3wi_rq_atan2}, {}}; +static u3j_harm _135_non__math_rq_asin_a[] = {{".2", u3wi_rq_asin}, {}}; +static u3j_harm _135_non__math_rq_acos_a[] = {{".2", u3wi_rq_acos}, {}}; +static u3j_harm _135_non__math_rq_sqt_a[] = {{".2", u3wi_rq_sqt}, {}}; +static u3j_harm _135_non__math_rq_cbt_a[] = {{".2", u3wi_rq_cbt}, {}}; +static u3j_harm _135_non__math_rq_pow_a[] = {{".2", u3wi_rq_pow}, {}}; +static u3j_harm _135_non__math_rq_pow_n_a[] = {{".2", u3wi_rq_pow_n}, {}}; +static u3j_harm _135_non__math_rq_log2_a[] = {{".2", u3wi_rq_log2}, {}}; +static u3j_harm _135_non__math_rq_log10_a[] = {{".2", u3wi_rq_log10}, {}}; +static u3j_core _135_non__math_rq_d[] = + { + { "exp", 7, _135_non__math_rq_exp_a, 0, no_hashes }, + { "log", 7, _135_non__math_rq_log_a, 0, no_hashes }, + { "sin", 7, _135_non__math_rq_sin_a, 0, no_hashes }, + { "cos", 7, _135_non__math_rq_cos_a, 0, no_hashes }, + { "tan", 7, _135_non__math_rq_tan_a, 0, no_hashes }, + { "atan", 7, _135_non__math_rq_atan_a, 0, no_hashes }, + { "atan2", 7, _135_non__math_rq_atan2_a, 0, no_hashes }, + { "asin", 7, _135_non__math_rq_asin_a, 0, no_hashes }, + { "acos", 7, _135_non__math_rq_acos_a, 0, no_hashes }, + { "sqt", 7, _135_non__math_rq_sqt_a, 0, no_hashes }, + { "cbt", 7, _135_non__math_rq_cbt_a, 0, no_hashes }, + { "pow", 7, _135_non__math_rq_pow_a, 0, no_hashes }, + { "pow-n", 7, _135_non__math_rq_pow_n_a, 0, no_hashes }, + { "log-2", 7, _135_non__math_rq_log2_a, 0, no_hashes }, + { "log-10", 7, _135_non__math_rq_log10_a, 0, no_hashes }, + {} + }; static u3j_core _135_non__math_d[] = { { "rd", 7, 0, _135_non__math_rd_d, no_hashes }, { "rs", 7, 0, _135_non__math_rs_d, no_hashes }, { "rh", 7, 0, _135_non__math_rh_d, no_hashes }, + { "rq", 7, 0, _135_non__math_rq_d, no_hashes }, {} }; diff --git a/libmath/vere64/noun/jets/q.h b/libmath/vere64/noun/jets/q.h index 654930a..493887b 100644 --- a/libmath/vere64/noun/jets/q.h +++ b/libmath/vere64/noun/jets/q.h @@ -336,6 +336,22 @@ u3_noun u3qi_rh_log2(u3_atom); u3_noun u3qi_rh_log10(u3_atom); + u3_noun u3qi_rq_exp(u3_atom); + u3_noun u3qi_rq_log(u3_atom); + u3_noun u3qi_rq_sin(u3_atom); + u3_noun u3qi_rq_cos(u3_atom); + u3_noun u3qi_rq_tan(u3_atom); + u3_noun u3qi_rq_atan(u3_atom); + u3_noun u3qi_rq_atan2(u3_atom, u3_atom); + u3_noun u3qi_rq_asin(u3_atom); + u3_noun u3qi_rq_acos(u3_atom); + u3_noun u3qi_rq_sqt(u3_atom); + u3_noun u3qi_rq_cbt(u3_atom); + u3_noun u3qi_rq_pow(u3_atom, u3_atom); + u3_noun u3qi_rq_pow_n(u3_atom, u3_atom); + u3_noun u3qi_rq_log2(u3_atom); + u3_noun u3qi_rq_log10(u3_atom); + # define u3qfu_van_fan 28 # define u3qfu_van_rib 58 # define u3qfu_van_vet 59 diff --git a/libmath/vere64/noun/jets/w.h b/libmath/vere64/noun/jets/w.h index 7af379e..c802a65 100644 --- a/libmath/vere64/noun/jets/w.h +++ b/libmath/vere64/noun/jets/w.h @@ -475,5 +475,21 @@ u3_noun u3wi_rh_log2(u3_noun); u3_noun u3wi_rh_log10(u3_noun); + u3_noun u3wi_rq_exp(u3_noun); + u3_noun u3wi_rq_log(u3_noun); + u3_noun u3wi_rq_sin(u3_noun); + u3_noun u3wi_rq_cos(u3_noun); + u3_noun u3wi_rq_tan(u3_noun); + u3_noun u3wi_rq_atan(u3_noun); + u3_noun u3wi_rq_atan2(u3_noun); + u3_noun u3wi_rq_asin(u3_noun); + u3_noun u3wi_rq_acos(u3_noun); + u3_noun u3wi_rq_sqt(u3_noun); + u3_noun u3wi_rq_cbt(u3_noun); + u3_noun u3wi_rq_pow(u3_noun); + u3_noun u3wi_rq_pow_n(u3_noun); + u3_noun u3wi_rq_log2(u3_noun); + u3_noun u3wi_rq_log10(u3_noun); + #endif /* ifndef U3_JETS_W_H */ From 2e72306fce18831d05d9f2aaa5e1a4d49db9de48 Mon Sep 17 00:00:00 2001 From: Sigilante Date: Sat, 13 Jun 2026 08:44:22 -0500 Subject: [PATCH 26/28] math: propagate @rq jets + registration to 32-bit libmath/vere Identical to vere64 except the 5 two-arg u3r_mean lines (flat varargs). Co-Authored-By: Claude Opus 4.8 --- libmath/vere/noun/jets/135/tree.c | 36 ++- libmath/vere/noun/jets/i/math.c | 494 ++++++++++++++++++++++++++++-- libmath/vere/noun/jets/q.h | 16 + libmath/vere/noun/jets/w.h | 16 + 4 files changed, 541 insertions(+), 21 deletions(-) diff --git a/libmath/vere/noun/jets/135/tree.c b/libmath/vere/noun/jets/135/tree.c index 236b57b..c0a0fa5 100644 --- a/libmath/vere/noun/jets/135/tree.c +++ b/libmath/vere/noun/jets/135/tree.c @@ -1049,14 +1049,48 @@ static u3j_core _135_non__math_rh_d[] = { "log-10", 7, _135_non__math_rh_log10_a, 0, no_hashes }, {} }; +static u3j_harm _135_non__math_rq_exp_a[] = {{".2", u3wi_rq_exp}, {}}; +static u3j_harm _135_non__math_rq_log_a[] = {{".2", u3wi_rq_log}, {}}; +static u3j_harm _135_non__math_rq_sin_a[] = {{".2", u3wi_rq_sin}, {}}; +static u3j_harm _135_non__math_rq_cos_a[] = {{".2", u3wi_rq_cos}, {}}; +static u3j_harm _135_non__math_rq_tan_a[] = {{".2", u3wi_rq_tan}, {}}; +static u3j_harm _135_non__math_rq_atan_a[] = {{".2", u3wi_rq_atan}, {}}; +static u3j_harm _135_non__math_rq_atan2_a[] = {{".2", u3wi_rq_atan2}, {}}; +static u3j_harm _135_non__math_rq_asin_a[] = {{".2", u3wi_rq_asin}, {}}; +static u3j_harm _135_non__math_rq_acos_a[] = {{".2", u3wi_rq_acos}, {}}; +static u3j_harm _135_non__math_rq_sqt_a[] = {{".2", u3wi_rq_sqt}, {}}; +static u3j_harm _135_non__math_rq_cbt_a[] = {{".2", u3wi_rq_cbt}, {}}; +static u3j_harm _135_non__math_rq_pow_a[] = {{".2", u3wi_rq_pow}, {}}; +static u3j_harm _135_non__math_rq_pow_n_a[] = {{".2", u3wi_rq_pow_n}, {}}; +static u3j_harm _135_non__math_rq_log2_a[] = {{".2", u3wi_rq_log2}, {}}; +static u3j_harm _135_non__math_rq_log10_a[] = {{".2", u3wi_rq_log10}, {}}; +static u3j_core _135_non__math_rq_d[] = + { + { "exp", 7, _135_non__math_rq_exp_a, 0, no_hashes }, + { "log", 7, _135_non__math_rq_log_a, 0, no_hashes }, + { "sin", 7, _135_non__math_rq_sin_a, 0, no_hashes }, + { "cos", 7, _135_non__math_rq_cos_a, 0, no_hashes }, + { "tan", 7, _135_non__math_rq_tan_a, 0, no_hashes }, + { "atan", 7, _135_non__math_rq_atan_a, 0, no_hashes }, + { "atan2", 7, _135_non__math_rq_atan2_a, 0, no_hashes }, + { "asin", 7, _135_non__math_rq_asin_a, 0, no_hashes }, + { "acos", 7, _135_non__math_rq_acos_a, 0, no_hashes }, + { "sqt", 7, _135_non__math_rq_sqt_a, 0, no_hashes }, + { "cbt", 7, _135_non__math_rq_cbt_a, 0, no_hashes }, + { "pow", 7, _135_non__math_rq_pow_a, 0, no_hashes }, + { "pow-n", 7, _135_non__math_rq_pow_n_a, 0, no_hashes }, + { "log-2", 7, _135_non__math_rq_log2_a, 0, no_hashes }, + { "log-10", 7, _135_non__math_rq_log10_a, 0, no_hashes }, + {} + }; static u3j_core _135_non__math_d[] = { { "rd", 7, 0, _135_non__math_rd_d, no_hashes }, { "rs", 7, 0, _135_non__math_rs_d, no_hashes }, { "rh", 7, 0, _135_non__math_rh_d, no_hashes }, + { "rq", 7, 0, _135_non__math_rq_d, no_hashes }, {} }; - static u3j_core _135_non_d[] = { { "lagoon", 7, 0, _135_non__la_core_d, no_hashes }, { "math", 7, 0, _135_non__math_d, no_hashes }, diff --git a/libmath/vere/noun/jets/i/math.c b/libmath/vere/noun/jets/i/math.c index 4edbc41..6f4fbea 100644 --- a/libmath/vere/noun/jets/i/math.c +++ b/libmath/vere/noun/jets/i/math.c @@ -1409,21 +1409,16 @@ typedef int64_t c3_ds; return _rqm(p, _rq_pow2(k)); } static float128_t _rq_exp(float128_t x) { - // degree-24 minimax coeffs c0..c24 {lo, hi} (math.hoon ++rq ++exp) - static const c3_d cs[25][2] = { - {0x0000000000000000ULL,0x3fff000000000000ULL},{0x0000000000000000ULL,0x3fff000000000000ULL}, - {0x0000000000000000ULL,0x3ffe000000000000ULL},{0x5555555555555555ULL,0x3ffc555555555555ULL}, - {0x5555555555555555ULL,0x3ffa555555555555ULL},{0x1111111111111111ULL,0x3ff8111111111111ULL}, - {0x6c16c16c16c16c17ULL,0x3ff56c16c16c16c1ULL},{0xa01a01a01a01a3e8ULL,0x3ff2a01a01a01a01ULL}, - {0xa01a01a01a01a146ULL,0x3fefa01a01a01a01ULL},{0x38faac1c88a5a526ULL,0x3fec71de3a556c73ULL}, - {0xc72ef016d3d6e867ULL,0x3fe927e4fb7789f5ULL},{0x38fe748363c46e8bULL,0x3fe5ae64567f544eULL}, - {0x7b544dab18f475c5ULL,0x3fe21eed8eff8d89ULL},{0x97c9f3aebabb2423ULL,0x3fde6124613a86d0ULL}, - {0xd20b83c7f94d17d8ULL,0x3fda93974a8c07c9ULL},{0xf5f4284f0d74f9e7ULL,0x3fd6ae7f3e733b81ULL}, - {0xf417b4d27c5f92a9ULL,0x3fd2ae7f3e733b81ULL},{0x6a419e674779c97cULL,0x3fce952c77030a99ULL}, - {0x0466ff8c8b42b3dfULL,0x3fca6827863b97b5ULL},{0x874b7a686d819241ULL,0x3fc62f49b469f892ULL}, - {0xbb3b32a11bb5f139ULL,0x3fc1e542ba427463ULL},{0xc93890ff9ab55cbbULL,0x3fbd71b8db9f7f73ULL}, - {0x6efc0717eae785a1ULL,0x3fb90ce38aab7bd7ULL},{0xcb3f4f7edfaa2666ULL,0x3fb47693274bab2aULL}, - {0x61cb0e23655d47cbULL,0x3faff3629154e0a7ULL}, + // fdlibm rational reconstruction: exp(r) = 1 - ((lo - r*c/(2-c)) - hi), + // c = r - t*P(t), t = r*r. EXC = even minimax P(t) {lo, hi} (deg-10). + // (math.hoon ++rq ++exp; faithful ~0.84 ULP, see tools/rq_check.c) + static const c3_d EXC[11][2] = { + {0x5555555555555555ULL,0x3ffc555555555555ULL},{0x6c16c16c16c09e83ULL,0xbff66c16c16c16c1ULL}, + {0x6abc0115453d96ddULL,0x3ff11566abc01156ULL},{0xaac663e4a6d65ccaULL,0xbfebbbd779334ef0ULL}, + {0xda06115986f507fbULL,0x3fe666a8f2bf70ebULL},{0x43eb0e288c2e45a8ULL,0xbfe122805d644267ULL}, + {0x12be0476b628552fULL,0x3fdbd6db2c4e0507ULL},{0xeb838f5da821635aULL,0xbfd67da4e1efb419ULL}, + {0xdc61daecbfc0d781ULL,0x3fd1355867f7df64ULL},{0x54bb7852bc52bd9aULL,0xbfcbf56e4264f8adULL}, + {0x822162270789ca71ULL,0x3fc68fc13579bfe0ULL}, }; union quad r0; r0.q = x; if ( !_rqeq(x, x) ) return _rq_bits(_RQ_QNAN_HI, 0); // NaN @@ -1440,12 +1435,410 @@ typedef int64_t c3_ds; float128_t ka = _rqi64((c3_ds)(k < 0 ? -k : k)); float128_t kf = (k >= 0) ? ka : _rq_neg(ka); - float128_t rr = _rqs( _rqs(x, _rqm(kf, ln2hi)), _rqm(kf, ln2lo) ); + float128_t hi = _rqs(x, _rqm(kf, ln2hi)); // high part of r + float128_t lo = _rqm(kf, ln2lo); // low correction + float128_t r = _rqs(hi, lo); // reduced argument + float128_t t = _rqm(r, r); - float128_t p = _rq_bits(0,0); - for ( int i = 25; i-- != 0; ) // Horner over flop(cs): c24..c0 - p = _rqa(_rqm(p, rr), _rq_bits(cs[i][1], cs[i][0])); - return _rq_scale2(p, k); + float128_t c = _rq_bits(EXC[10][1], EXC[10][0]); + for ( int i = 10; i-- != 0; ) // Horner P(t) + c = _rqa(_rqm(c, t), _rq_bits(EXC[i][1], EXC[i][0])); + c = _rqs(r, _rqm(t, c)); // c = r - t*P(t) + + float128_t one = _rq_bits(0x3fff000000000000ULL, 0); + float128_t two = _rq_bits(0x4000000000000000ULL, 0); + float128_t y = _rqs(one, _rqs(_rqs(lo, _rqd(_rqm(r, c), _rqs(two, c))), hi)); + return _rq_scale2(y, k); + } + +/* @rq log/log-2/log-10 -- math.hoon ++rq ++log/++lr/++log-2/++log-10 +** x = 2^e * m, m in [sqrt(1/2),sqrt(2)); log(1+f) via atanh series (deg-22). +*/ + static void _rq_lr(float128_t x, float128_t* ef, float128_t* lm) { + static const c3_d cs[23][2] = { + {0x5555555555555555ULL,0x3ffd555555555555ULL},{0x999999999999999aULL,0x3ffc999999999999ULL}, + {0x2492492492492492ULL,0x3ffc249249249249ULL},{0xc71c71c71c71c71cULL,0x3ffbc71c71c71c71ULL}, + {0x5d1745d1745d1746ULL,0x3ffb745d1745d174ULL},{0x3b13b13b13b13b14ULL,0x3ffb3b13b13b13b1ULL}, + {0x1111111111111111ULL,0x3ffb111111111111ULL},{0xe1e1e1e1e1e1e1e2ULL,0x3ffae1e1e1e1e1e1ULL}, + {0x86bca1af286bca1bULL,0x3ffaaf286bca1af2ULL},{0x8618618618618618ULL,0x3ffa861861861861ULL}, + {0x42c8590b21642c86ULL,0x3ffa642c8590b216ULL},{0xae147ae147ae147bULL,0x3ffa47ae147ae147ULL}, + {0x84bda12f684bda13ULL,0x3ffa2f684bda12f6ULL},{0x611a7b9611a7b961ULL,0x3ffa1a7b9611a7b9ULL}, + {0x4210842108421084ULL,0x3ffa084210842108ULL},{0x7c1f07c1f07c1f08ULL,0x3ff9f07c1f07c1f0ULL}, + {0xd41d41d41d41d41dULL,0x3ff9d41d41d41d41ULL},{0xf914c1bacf914c1cULL,0x3ff9bacf914c1bacULL}, + {0xa41a41a41a41a41aULL,0x3ff9a41a41a41a41ULL},{0x9c18f9c18f9c18faULL,0x3ff98f9c18f9c18fULL}, + {0x417d05f417d05f41ULL,0x3ff97d05f417d05fULL},{0x6c16c16c16c16c17ULL,0x3ff96c16c16c16c1ULL}, + {0x72620ae4c415c988ULL,0x3ff95c9882b93105ULL}, + }; + union quad r0; r0.q = x; + int sub = ( ((r0.w[1] >> 48) & 0x7fffULL) == 0 ); + union quad xx; xx = r0; + if ( sub ) xx.q = _rqm(x, _rq_bits(0x4077000000000000ULL, 0)); // x * 2^120 + c3_ds ae = sub ? -120 : 0; + c3_ds e = (c3_ds)((xx.w[1] >> 48) & 0x7fffULL) - 16383; + union quad m; m.w[0] = xx.w[0]; m.w[1] = (xx.w[1] & 0xffffffffffffULL) | (16383ULL << 48); + if ( _rqle(_rq_bits(0x3fff6a09e667f3bcULL, 0xc908b2fb1366ea95ULL), m.q) ) { // m >= sqrt(2) + m.q = _rqm(m.q, _rq_bits(0x3ffe000000000000ULL, 0)); e = e + 1; + } + e = e + ae; + float128_t one = _rq_bits(0x3fff000000000000ULL, 0); + float128_t f = _rqs(m.q, one); + float128_t s = _rqd(f, _rqa(m.q, one)); + float128_t z = _rqm(s, s); + float128_t p = _rq_bits(0, 0); + for ( int i = 23; i-- != 0; ) p = _rqa(_rqm(p, z), _rq_bits(cs[i][1], cs[i][0])); + float128_t r = _rqm(_rqa(z, z), p); + float128_t l1 = _rqs(f, _rqm(s, _rqs(f, r))); + float128_t efv = _rqi64( (c3_ds)(e < 0 ? -e : e) ); + if ( e < 0 ) efv = _rq_neg(efv); + *ef = efv; *lm = l1; + } + static int _rq_log_guard(float128_t x, float128_t* out) { + union quad r0; r0.q = x; + if ( !_rqeq(x, x) ) { *out = _rq_bits(_RQ_QNAN_HI, 0); return 1; } + if ( r0.w[1]==_RQ_PINF_HI && r0.w[0]==0 ) { *out = x; return 1; } + if ( (r0.w[1]==0 && r0.w[0]==0)||(r0.w[1]==0x8000000000000000ULL && r0.w[0]==0) ) + { *out = _rq_bits(_RQ_NINF_HI, 0); return 1; } + if ( (r0.w[1] >> 63) == 1 ) { *out = _rq_bits(_RQ_QNAN_HI, 0); return 1; } + return 0; + } + static float128_t _rq_log(float128_t x) { + float128_t g, ef, lm; + if ( _rq_log_guard(x, &g) ) return g; + _rq_lr(x, &ef, &lm); + float128_t hi = _rqm(ef, _rq_bits(0x3ffe62e42fefa39eULL, 0xf35793c800000000ULL)); // e*ln2hi + float128_t lo = _rqm(ef, _rq_bits(0xbfad319ff0342542ULL, 0xfc32f366359d274aULL)); // e*ln2lo + return _rqa(hi, _rqa(lm, lo)); + } + static float128_t _rq_log2(float128_t x) { + float128_t g, ef, lm; + if ( _rq_log_guard(x, &g) ) return g; + _rq_lr(x, &ef, &lm); // e + lm/ln2 + return _rqa(ef, _rqm(lm, _rq_bits(0x3fff71547652b82fULL, 0xe1777d0ffda0d23aULL))); + } + static float128_t _rq_log10(float128_t x) { + float128_t g, ef, lm; + if ( _rq_log_guard(x, &g) ) return g; + _rq_lr(x, &ef, &lm); // e*log10(2) + lm/ln10 + return _rqa(_rqm(ef, _rq_bits(0x3ffd34413509f79fULL, 0xef311f12b35816f9ULL)), + _rqm(lm, _rq_bits(0x3ffdbcb7b1526e50ULL, 0xe32a6ab7555f5a68ULL))); + } + +/* @rq sin/cos/tan -- math.hoon ++rq ++sin/++cos/++rq-trig/++tan +** x = q*(pi/2) + (rhi+rlo) (2-part pi/2), fdlibm kernels by q&3. tan=sin/cos. +*/ + static const c3_d _RQ_SC[16][2] = { // sin kernel coeffs + {0x5555555555555555ULL,0xbffc555555555555ULL},{0x1111111111111111ULL,0x3ff8111111111111ULL}, + {0xa01a01a01a01a01aULL,0xbff2a01a01a01a01ULL},{0x38faac1c88e50017ULL,0x3fec71de3a556c73ULL}, + {0x38fe747e4b837dc7ULL,0xbfe5ae64567f544eULL},{0x97ca38331d23af68ULL,0x3fde6124613a86d0ULL}, + {0xf11d8656b0ee8cb0ULL,0xbfd6ae7f3e733b81ULL},{0xa6b2605197771b00ULL,0x3fce952c77030ad4ULL}, + {0x724ca1ec3b7b9675ULL,0xbfc62f49b4681415ULL},{0x18bef146fcee6e45ULL,0x3fbd71b8ef6dcf57ULL}, + {0x9d97b8704dd7f628ULL,0xbfb4761b41316381ULL},{0x8d4e44a419776f11ULL,0x3fab3f3ccdd165faULL}, + {0x320a9a18f15d4277ULL,0xbfa1d1ab1c2dcceaULL},{0xd7abe30e7766f129ULL,0x3f98259f98b4358aULL}, + {0xc42e1ee46fa6bfc4ULL,0xbf8e434d2e783f5bULL},{0x1b5382cdffa97422ULL,0x3f843981254dd0d5ULL}, + }; + static const c3_d _RQ_CC[16][2] = { // cos kernel coeffs + {0x5555555555555555ULL,0x3ffa555555555555ULL},{0x6c16c16c16c16c17ULL,0xbff56c16c16c16c1ULL}, + {0xa01a01a01a01a01aULL,0x3fefa01a01a01a01ULL},{0xc72ef016d3ea6679ULL,0xbfe927e4fb7789f5ULL}, + {0x7b544da987acfe85ULL,0x3fe21eed8eff8d89ULL},{0xd20badf145dfa3e5ULL,0xbfda93974a8c07c9ULL}, + {0xf11d8656b0ee8cb0ULL,0x3fd2ae7f3e733b81ULL},{0x77bb004886a2c2abULL,0xbfca6827863b97d9ULL}, + {0x507a9cad2bf8f0bbULL,0x3fc1e542ba402022ULL},{0x29450c90b7f338ecULL,0xbfb90ce396db7f85ULL}, + {0x7cca4b4067ca9d8aULL,0x3faff2cf01972f57ULL},{0x9a38f2050ba6b015ULL,0xbfa688e85fc6a4e5ULL}, + {0xd373c5c51c354a8dULL,0x3f9d0a18a2635085ULL},{0xe60caded4c2989c5ULL,0xbf933932c5047d60ULL}, + {0xc42e1ee46fa6bfc4ULL,0x3f89434d2e783f5bULL},{0xa13f8a2b4af9d6b7ULL,0xbf7f2710231c0fd7ULL}, + }; + static float128_t _rq_ksin(float128_t xx, float128_t yy) { + float128_t half = _rq_bits(0x3ffe000000000000ULL, 0); + float128_t z = _rqm(xx, xx); + float128_t r = _rq_bits(0, 0); // Horner over flop(tail sc): sc[15..1] + for ( int i = 16; i-- != 1; ) r = _rqa(_rqm(r, z), _rq_bits(_RQ_SC[i][1], _RQ_SC[i][0])); + float128_t v = _rqm(z, xx); + float128_t aa = _rqs(_rqm(half, yy), _rqm(v, r)); + float128_t bb = _rqs(_rqm(z, aa), yy); + float128_t dd = _rqs(bb, _rqm(v, _rq_bits(_RQ_SC[0][1], _RQ_SC[0][0]))); + return _rqs(xx, dd); + } + static float128_t _rq_kcos(float128_t xx, float128_t yy) { + float128_t half = _rq_bits(0x3ffe000000000000ULL, 0), one = _rq_bits(0x3fff000000000000ULL, 0); + float128_t z = _rqm(xx, xx); + float128_t rc = _rq_bits(0, 0); // Horner over flop(cc): cc[15..0] + for ( int i = 16; i-- != 0; ) rc = _rqa(_rqm(rc, z), _rq_bits(_RQ_CC[i][1], _RQ_CC[i][0])); + float128_t hz = _rqm(half, z); + float128_t w2 = _rqs(one, hz); + float128_t aa = _rqs(_rqs(one, w2), hz); + float128_t bb = _rqs(_rqm(_rqm(z, z), rc), _rqm(xx, yy)); + return _rqa(w2, _rqa(aa, bb)); + } + static float128_t _rq_trigfin(int is_sin, float128_t ax, c3_d sb) { + c3_ds q = _rqtoi(_rqm(ax, _rq_bits(0x3ffe45f306dc9c88ULL, 0x2a53f84eafa3ea6aULL)), + softfloat_round_near_even); // round(ax*2/pi) + c3_d aq = (c3_d)(q < 0 ? -q : q); + float128_t qf = _rqi64((c3_ds)aq); + float128_t t = _rqs(ax, _rqm(qf, _rq_bits(0x3fff921fb54442d1ULL, 0x8460000000000000ULL))); // ax - qf*pio2_hi + float128_t w = _rqm(qf, _rq_bits(0x3fc2313198a2e037ULL, 0x07344a409382229aULL)); // qf*pio2_lo + float128_t rhi = _rqs(t, w); + float128_t rlo = _rqs(_rqs(t, rhi), w); + int mm = (int)(aq & 3); + float128_t ks = _rq_ksin(rhi, rlo); + float128_t kc = _rq_kcos(rhi, rlo); + if ( is_sin ) { + float128_t v = (mm==0) ? ks : (mm==1) ? kc : (mm==2) ? _rq_neg(ks) : _rq_neg(kc); + return (sb == 1) ? _rq_neg(v) : v; + } + return (mm==0) ? kc : (mm==1) ? _rq_neg(ks) : (mm==2) ? _rq_neg(kc) : ks; + } + static float128_t _rq_sin(float128_t x) { + union quad r0, ax; r0.q = x; + if ( !_rqeq(x, x) ) return _rq_bits(_RQ_QNAN_HI, 0); // NaN + if ( (r0.w[1]==_RQ_PINF_HI||r0.w[1]==_RQ_NINF_HI) && r0.w[0]==0 ) return _rq_bits(_RQ_QNAN_HI, 0); // +-inf -> NaN + if ( (r0.w[1]==0||r0.w[1]==0x8000000000000000ULL) && r0.w[0]==0 ) return x; // +-0 -> +-0 + ax.w[0] = r0.w[0]; ax.w[1] = r0.w[1] & 0x7fffffffffffffffULL; + return _rq_trigfin(1, ax.q, r0.w[1] >> 63); + } + static float128_t _rq_cos(float128_t x) { + union quad r0, ax; r0.q = x; + if ( !_rqeq(x, x) ) return _rq_bits(_RQ_QNAN_HI, 0); // NaN + if ( (r0.w[1]==_RQ_PINF_HI||r0.w[1]==_RQ_NINF_HI) && r0.w[0]==0 ) return _rq_bits(_RQ_QNAN_HI, 0); // +-inf -> NaN + ax.w[0] = r0.w[0]; ax.w[1] = r0.w[1] & 0x7fffffffffffffffULL; + return _rq_trigfin(0, ax.q, 0); + } + // tan = (div (sin x) (cos x)): sin/cos kernels %n, the bare div per door r + static float128_t _rq_tan(float128_t x) { + float128_t s = _rq_sin(x), c = _rq_cos(x); + softfloat_roundingMode = _math_rnd; + float128_t r = _rqd(s, c); + softfloat_roundingMode = softfloat_round_near_even; + return r; + } + +/* @rq atan/atan2 -- math.hoon ++rq ++atan/++rq-atan/++atan2 +** fdlibm breakpoint reduction (7/16,11/16,19/16,39/16) + degree-30 minimax. +*/ + static float128_t _rq_atan(float128_t x) { + static const c3_d at[31][2] = { + {0x5555555555555555ULL,0x3ffd555555555555ULL},{0x999999999999999aULL,0xbffc999999999999ULL}, + {0x2492492492492492ULL,0x3ffc249249249249ULL},{0xc71c71c71c71c705ULL,0xbffbc71c71c71c71ULL}, + {0x5d1745d1745cf720ULL,0x3ffb745d1745d174ULL},{0x3b13b13b1395a0f6ULL,0xbffb3b13b13b13b1ULL}, + {0x11111111010e24e1ULL,0x3ffb111111111111ULL},{0xe1e1e1d48fd7bd0fULL,0xbffae1e1e1e1e1e1ULL}, + {0x86bc9d8a12661ce3ULL,0x3ffaaf286bca1af2ULL},{0x861762af171f46fbULL,0xbffa861861861861ULL}, + {0x4297f77f1796654aULL,0x3ffa642c8590b216ULL},{0xa6aeeb974d91c763ULL,0xbffa47ae147ae147ULL}, + {0x982c83840df48c76ULL,0x3ffa2f684bda12f5ULL},{0xf24134848b6f9bc3ULL,0xbffa1a7b9611a7a0ULL}, + {0x46f1272e8718edfeULL,0x3ffa084210841eedULL},{0xdac476af1946ed1aULL,0xbff9f07c1f0773e1ULL}, + {0x771b4773d1fdbc46ULL,0x3ff9d41d41cf56a0ULL},{0xd9a2c9f0ffa28317ULL,0xbff9bacf910ca5eaULL}, + {0x5da3c3e48cd55593ULL,0x3ff9a41a3ed6e709ULL},{0x4d8ac15872fbb51cULL,0xbff98f9bfe02ad67ULL}, + {0x069f17b95f6e54f4ULL,0x3ff97d05170d1702ULL},{0x6ea05add542af078ULL,0xbff96c10bc42d041ULL}, + {0xeab121f20635a41aULL,0x3ff95c74e7f6f412ULL},{0x283b75528258306bULL,0xbff94dac2e21aa0eULL}, + {0xdb9d4b05d70c99cfULL,0x3ff93e573faac561ULL},{0x4f5966908860d11aULL,0xbff92af32cae28f7ULL}, + {0xdec0acdf4b356e20ULL,0x3ff90c8b03c55304ULL},{0xf7ad970276c5cf2bULL,0xbff8b4ed3a3349acULL}, + {0xd5dd688f198ae3cbULL,0x3ff8261c1a9eda3aULL},{0x876f4b57d627e71eULL,0xbff71a7ac449b285ULL}, + {0x138131c15128032aULL,0x3ff51a4ea418ebe8ULL}, + }; + union quad r0, ax, xr, hi, lo; r0.q = x; + if ( !_rqeq(x, x) ) return _rq_bits(_RQ_QNAN_HI, 0); // NaN + if ( r0.w[1]==_RQ_PINF_HI && r0.w[0]==0 ) return _rq_bits(0x3fff921fb54442d1ULL, 0x8469898cc51701b8ULL); // +inf -> pi/2 + if ( r0.w[1]==_RQ_NINF_HI && r0.w[0]==0 ) return _rq_bits(0xbfff921fb54442d1ULL, 0x8469898cc51701b8ULL); // -inf -> -pi/2 + if ( (r0.w[1]==0||r0.w[1]==0x8000000000000000ULL) && r0.w[0]==0 ) return x; // +-0 + c3_d neg = r0.w[1] >> 63; + ax.w[0] = r0.w[0]; ax.w[1] = r0.w[1] & 0x7fffffffffffffffULL; + float128_t one = _rq_bits(0x3fff000000000000ULL, 0), two = _rq_bits(0x4000000000000000ULL, 0); + float128_t ohf = _rq_bits(0x3fff800000000000ULL, 0); + int dir = 0; + if ( _rqlt(ax.q, _rq_bits(0x3ffdc00000000000ULL, 0)) ) { // |x| < 7/16 + xr.q = ax.q; hi.q = _rq_bits(0,0); lo.q = _rq_bits(0,0); dir = 1; + } else if ( _rqlt(ax.q, _rq_bits(0x3ffe600000000000ULL, 0)) ) { // < 11/16 + xr.q = _rqd(_rqs(_rqa(ax.q, ax.q), one), _rqa(two, ax.q)); + hi.q = _rq_bits(0x3ffddac670561bb4ULL, 0xf68adfc88bd97875ULL); // atan(0.5) + lo.q = _rq_bits(0x3f89a06dc282b0e4ULL, 0xc39be01c59e2dcddULL); + } else if ( _rqlt(ax.q, _rq_bits(0x3fff300000000000ULL, 0)) ) { // < 19/16 + xr.q = _rqd(_rqs(ax.q, one), _rqa(ax.q, one)); + hi.q = _rq_bits(0x3ffe921fb54442d1ULL, 0x8469898cc51701b8ULL); // pi/4 + lo.q = _rq_bits(0x3f8bcd129024e088ULL, 0xa67cc74020bbea64ULL); + } else if ( _rqlt(ax.q, _rq_bits(0x4000380000000000ULL, 0)) ) { // < 39/16 + xr.q = _rqd(_rqs(ax.q, ohf), _rqa(one, _rqm(ohf, ax.q))); + hi.q = _rq_bits(0x3ffef730bd281f69ULL, 0xb200f10f5e197794ULL); // atan(1.5) + lo.q = _rq_bits(0xbf8bebe566c99adaULL, 0x9f231bccae27916cULL); + } else { // -1/x + xr.q = _rqd(_rq_bits(0xbfff000000000000ULL, 0), ax.q); + hi.q = _rq_bits(0x3fff921fb54442d1ULL, 0x8469898cc51701b8ULL); // pi/2 + lo.q = _rq_bits(0x3f8ccd129024e088ULL, 0xa67cc74020bbea64ULL); + } + float128_t z = _rqm(xr.q, xr.q); + float128_t sp = _rq_bits(0, 0); + for ( int i = 31; i-- != 0; ) sp = _rqa(_rqm(sp, z), _rq_bits(at[i][1], at[i][0])); + float128_t s = _rqm(z, sp); + float128_t res = dir ? _rqs(xr.q, _rqm(xr.q, s)) + : _rqs(hi.q, _rqs(_rqs(_rqm(xr.q, s), lo.q), xr.q)); + return (neg == 1) ? _rq_neg(res) : res; + } + static float128_t _rq_atan2(float128_t y, float128_t x) { + union quad xb; xb.q = x; + float128_t zero = _rq_bits(0,0); + float128_t pi = _rq_bits(0x4000921fb54442d1ULL, 0x8469898cc51701b8ULL); + float128_t two = _rq_bits(0x4000000000000000ULL, 0), mone = _rq_bits(0xbfff000000000000ULL, 0); + if ( _rqlt(zero, x) ) { // x>0: atan(div y x) + softfloat_roundingMode = _math_rnd; float128_t q = _rqd(y, x); + softfloat_roundingMode = softfloat_round_near_even; return _rq_atan(q); + } + if ( _rqlt(x, zero) && _rqle(zero, y) ) { // x<0,y>=0: add(atan,pi) + softfloat_roundingMode = _math_rnd; float128_t q = _rqd(y, x); + softfloat_roundingMode = softfloat_round_near_even; float128_t a = _rq_atan(q); + softfloat_roundingMode = _math_rnd; float128_t r = _rqa(a, pi); + softfloat_roundingMode = softfloat_round_near_even; return r; + } + if ( _rqlt(x, zero) && _rqlt(y, zero) ) { // x<0,y<0: sub(atan,pi) + softfloat_roundingMode = _math_rnd; float128_t q = _rqd(y, x); + softfloat_roundingMode = softfloat_round_near_even; float128_t a = _rq_atan(q); + softfloat_roundingMode = _math_rnd; float128_t r = _rqs(a, pi); + softfloat_roundingMode = softfloat_round_near_even; return r; + } + if ( (xb.w[1]==0 && xb.w[0]==0) && _rqlt(zero, y) ) { // x==+0,y>0: div(pi,2) + softfloat_roundingMode = _math_rnd; float128_t r = _rqd(pi, two); + softfloat_roundingMode = softfloat_round_near_even; return r; + } + if ( (xb.w[1]==0 && xb.w[0]==0) && _rqlt(y, zero) ) { // x==+0,y<0: mul(-1,div(pi,2)) + softfloat_roundingMode = _math_rnd; float128_t r = _rqm(mone, _rqd(pi, two)); + softfloat_roundingMode = softfloat_round_near_even; return r; + } + return zero; + } + +/* @rq asin/acos -- math.hoon ++rq ++asin/++acos/++rq-ainv +** poly kernel R(t) (deg-30, NOT P/Q) + sqrt head/tail; sqt = f128 sqrt. +*/ + static const c3_d _RQ_RR[31][2] = { + {0x83f400d50d55a7e8ULL,0x3f8089912e54d43fULL},{0x5555555555555552ULL,0x3ffc555555555555ULL}, + {0x3333333333335009ULL,0x3ffb333333333333ULL},{0x6db6db6db668951bULL,0x3ffa6db6db6db6dbULL}, + {0x71c71c72bac1ec0eULL,0x3ff9f1c71c71c71cULL},{0x8ba2e81aa31a41d8ULL,0x3ff96e8ba2e8ba2eULL}, + {0xec4f0b6fe680df37ULL,0x3ff91c4ec4ec4ec4ULL},{0x996cf372753e7c99ULL,0x3ff8c99999999999ULL}, + {0x92177cc3275353f7ULL,0x3ff87a8787878787ULL},{0xf7f1afe5cbeac090ULL,0x3ff83fde50d79433ULL}, + {0xf127037c33f0fb5bULL,0x3ff812ef3cf3cf83ULL},{0x5c114e9da47dedfdULL,0x3ff7df3bd37a5edeULL}, + {0x909e07297f5e2958ULL,0x3ff7a6863d723133ULL},{0x52ce6cb856ef901fULL,0x3ff7782dd9f3ff64ULL}, + {0x2fdb62f41c709bd1ULL,0x3ff751ba328f884cULL},{0xb0d4961421efa7ecULL,0x3ff731681fe6e02dULL}, + {0x3408e80b5b3f8641ULL,0x3ff715efe556e52aULL},{0x1812712268a45b42ULL,0x3ff6fc96253ecb71ULL}, + {0xebe9bc6e47ec09afULL,0x3ff6d4a82428408aULL},{0xc0a9facb94511de4ULL,0x3ff6aa377fe913f6ULL}, + {0x84737463fe8656d8ULL,0x3ff6b48ca21a48d1ULL},{0xe39134518885e78fULL,0x3ff57e9aa4b5b4c4ULL}, + {0xa0d03ab9c51426b2ULL,0x3ff819064c5185faULL},{0x1c085f962a89aaccULL,0xbff9300f0da2da1eULL}, + {0x97d25a1be10b6c8aULL,0x3ffb0643398cdbcbULL},{0x528e0d54bf4f5e05ULL,0xbffc27ed3dd5cd82ULL}, + {0xad880c8cd533b68bULL,0x3ffd1d64319be957ULL},{0x81c3902a2c54acc7ULL,0xbffd9731e485678bULL}, + {0xa99aa13d6e9cd204ULL,0x3ffdae10872f69b7ULL},{0x25c164c7f61091faULL,0xbffd228fc6527609ULL}, + {0x2c15b8ad9b2377ceULL,0x3ffb9aa4ca63cbd7ULL}, + }; + static float128_t _rq_ainv_rr(float128_t t) { + float128_t pp = _rq_bits(0, 0); + for ( int i = 31; i-- != 0; ) pp = _rqa(_rqm(pp, t), _rq_bits(_RQ_RR[i][1], _RQ_RR[i][0])); + return pp; + } + static float128_t _rq_asin(float128_t x) { + union quad r0, ax; r0.q = x; + float128_t half = _rq_bits(0x3ffe000000000000ULL, 0), one = _rq_bits(0x3fff000000000000ULL, 0); + float128_t two = _rq_bits(0x4000000000000000ULL, 0); + float128_t pio2h = _rq_bits(0x3fff921fb54442d1ULL, 0x8469898cc51701b8ULL); + float128_t pio2l = _rq_bits(0x3f8ccd129024e088ULL, 0xa67cc74020bbea64ULL); + float128_t pio4 = _rq_bits(0x3ffe921fb54442d1ULL, 0x8469898cc51701b8ULL); + if ( !_rqeq(x, x) ) return _rq_bits(_RQ_QNAN_HI, 0); // NaN + c3_d sgn = r0.w[1] >> 63; + ax.w[0] = r0.w[0]; ax.w[1] = r0.w[1] & 0x7fffffffffffffffULL; + if ( _rqlt(one, ax.q) ) return _rq_bits(_RQ_QNAN_HI, 0); // |x|>1 -> NaN + if ( ax.w[1]==0x3fff000000000000ULL && ax.w[0]==0 ) // |x|==1 + return _rqa(_rqm(x, pio2h), _rqm(x, pio2l)); + if ( _rqlt(ax.q, half) ) { // |x|<0.5 + if ( _rqlt(ax.q, _rq_bits(0x3fc6000000000000ULL, 0)) ) return x; // tiny + float128_t t = _rqm(x, x); + return _rqa(x, _rqm(x, _rq_ainv_rr(t))); + } + float128_t w = _rqs(one, ax.q); + float128_t t = _rqm(w, half); + float128_t r = _rq_ainv_rr(t); + float128_t s = _rqq(t); + if ( _rqle(_rq_bits(0x3ffef33333333333ULL, 0x3333333333333333ULL), ax.q) ) { // near 1 + float128_t res = _rqs(pio2h, _rqs(_rqm(two, _rqa(s, _rqm(s, r))), pio2l)); + return (sgn == 1) ? _rq_neg(res) : res; + } + union quad sq; sq.q = s; + float128_t df = _rq_bits(sq.w[1], sq.w[0] & 0xff00000000000000ULL); + float128_t cc = _rqd(_rqs(t, _rqm(df, df)), _rqa(s, df)); + float128_t p2 = _rqs(_rqm(two, _rqm(s, r)), _rqs(pio2l, _rqm(two, cc))); + float128_t q2 = _rqs(pio4, _rqm(two, df)); + float128_t res = _rqs(pio4, _rqs(p2, q2)); + return (sgn == 1) ? _rq_neg(res) : res; + } + static float128_t _rq_acos(float128_t x) { + union quad r0, ax; r0.q = x; + float128_t half = _rq_bits(0x3ffe000000000000ULL, 0), one = _rq_bits(0x3fff000000000000ULL, 0); + float128_t two = _rq_bits(0x4000000000000000ULL, 0); + float128_t pi = _rq_bits(0x4000921fb54442d1ULL, 0x8469898cc51701b8ULL); + float128_t pio2h = _rq_bits(0x3fff921fb54442d1ULL, 0x8469898cc51701b8ULL); + float128_t pio2l = _rq_bits(0x3f8ccd129024e088ULL, 0xa67cc74020bbea64ULL); + if ( !_rqeq(x, x) ) return _rq_bits(_RQ_QNAN_HI, 0); // NaN + c3_d neg = r0.w[1] >> 63; + ax.w[0] = r0.w[0]; ax.w[1] = r0.w[1] & 0x7fffffffffffffffULL; + if ( _rqlt(one, ax.q) ) return _rq_bits(_RQ_QNAN_HI, 0); // |x|>1 -> NaN + if ( ax.w[1]==0x3fff000000000000ULL && ax.w[0]==0 ) { // |x|==1 + if ( neg == 0 ) return _rq_bits(0, 0); // 1 -> 0 + return _rqa(pi, _rqm(two, pio2l)); // -1 -> pi + } + if ( _rqlt(ax.q, half) ) { // |x|<0.5 + if ( _rqlt(ax.q, _rq_bits(0x3f87000000000000ULL, 0)) ) return pio2h; // tiny -> pi/2 + float128_t z = _rqm(x, x); + float128_t r = _rq_ainv_rr(z); + return _rqs(pio2h, _rqs(x, _rqs(pio2l, _rqm(x, r)))); + } + if ( neg == 1 ) { // x <= -0.5 + float128_t z = _rqm(_rqa(one, x), half); + float128_t s = _rqq(z); + float128_t r = _rq_ainv_rr(z); + float128_t w = _rqs(_rqm(r, s), pio2l); + return _rqs(pi, _rqm(two, _rqa(s, w))); + } + float128_t z = _rqm(_rqs(one, x), half); // x >= 0.5 + float128_t s = _rqq(z); + union quad sq; sq.q = s; + float128_t df = _rq_bits(sq.w[1], sq.w[0] & 0xff00000000000000ULL); + float128_t cc = _rqd(_rqs(z, _rqm(df, df)), _rqa(s, df)); + float128_t r = _rq_ainv_rr(z); + float128_t w = _rqa(_rqm(r, s), cc); + return _rqm(two, _rqa(df, w)); + } + +/* @rq sqt/cbt -- math.hoon ++rq ++sqt/++cbt */ + static float128_t _rq_sqt(float128_t x) { + union quad r0; r0.q = x; + if ( !_rqeq(x, x) ) return _rq_bits(_RQ_QNAN_HI, 0); // NaN + if ( r0.w[1]==_RQ_PINF_HI && r0.w[0]==0 ) return x; // +inf + if ( (r0.w[1]==0||r0.w[1]==0x8000000000000000ULL) && r0.w[0]==0 ) return x; // +-0 + if ( (r0.w[1] >> 63) == 1 ) return _rq_bits(_RQ_QNAN_HI, 0); // x<0 -> NaN + return _rqq(x); // correctly-rounded + } + static float128_t _rq_cbt(float128_t x) { + union quad r0, ax; r0.q = x; + if ( !_rqeq(x, x) ) return x; // NaN -> NaN + if ( (r0.w[1]==0||r0.w[1]==0x8000000000000000ULL) && r0.w[0]==0 ) return x; // +-0 + ax.w[0] = r0.w[0]; ax.w[1] = r0.w[1] & 0x7fffffffffffffffULL; + float128_t r = _rq_exp(_rqm(_rq_log(ax.q), _rq_bits(0x3ffd555555555555ULL, 0x5555555555555555ULL))); // exp(log|x|/3) + return ((r0.w[1] >> 63) == 1) ? _rq_neg(r) : r; + } + +/* @rq pow/pow-n -- math.hoon ++rq ++pow/++pow-n */ + static float128_t _rq_pow_n(float128_t x, float128_t n) { + union quad nn; nn.q = n; + float128_t one = _rq_bits(0x3fff000000000000ULL, 0), two = _rq_bits(0x4000000000000000ULL, 0); + if ( nn.w[1]==0 && nn.w[0]==0 ) return one; // n == +0 -> 1 + softfloat_roundingMode = _math_rnd; // bare mul/sub round per door r + float128_t p = x; + while ( !_rqlt(n, two) ) { p = _rqm(p, x); n = _rqs(n, one); } + softfloat_roundingMode = softfloat_round_near_even; + return p; + } + static float128_t _rq_pow(float128_t x, float128_t n) { + union quad nn, ni; nn.q = n; + float128_t zero = _rq_bits(0,0); + ni.q = _rqi64(_rqtoi(n, softfloat_round_near_even)); // san (need (toi n)) + if ( (nn.w[1]==ni.w[1] && nn.w[0]==ni.w[0]) && _rqlt(zero, n) ) // positive integer + return _rq_pow_n(x, ni.q); + float128_t lg = _rq_log(x); // %n kernel + softfloat_roundingMode = _math_rnd; // bare mul per door r + float128_t prod = _rqm(n, lg); + softfloat_roundingMode = softfloat_round_near_even; + return _rq_exp(prod); // %n kernel: exp(n*log x) } #ifndef MATH_JET_HARNESS @@ -1738,4 +2131,65 @@ typedef int64_t c3_ds; u3_noun u3qi_rh_pow_n(u3_atom x, u3_atom n) { softfloat_roundingMode=softfloat_round_near_even; return _rh_out(_rh_pow_n(_rh_in(x), _rh_in(n))); } u3_noun u3wi_rh_pow_n(u3_noun cor){ return _rh_jet2(cor, _rh_pow_n); } +/* @rq ABI wrappers. @rq is a 128-bit atom: read/write TWO chubs (v[0]=low 64, +** v[1]=high 64). Wrappers set softfloat_roundingMode=near-even (kernels) and +** _math_rnd from the door's r (axis 60) for the composites (tan/atan2/pow/ +** pow-n). Word-agnostic chub I/O, same as @rd/@rs/@rh. +*/ + static inline float128_t _rq_in(u3_atom a) { + union quad s; s.w[0] = u3r_chub(0, a); s.w[1] = u3r_chub(1, a); return s.q; + } + static inline u3_noun _rq_out(float128_t v) { + union quad s; s.q = v; return u3i_chubs(2, &s.w[0]); + } + static u3_noun _rq_jet(u3_noun cor, float128_t (*fun)(float128_t)) { + u3_noun x = u3r_at(u3x_sam, cor); + if ( u3_none == x || c3n == u3ud(x) ) return u3m_bail(c3__exit); + softfloat_roundingMode = softfloat_round_near_even; // kernels run near-even + _math_rnd = _rnd_of(u3r_at(60, cor)); // door rounding r (for tan/cbt/log-2/log-10) + return _rq_out(fun(_rq_in(x))); + } + static u3_noun _rq_jet2(u3_noun cor, float128_t (*fun)(float128_t, float128_t)) { + u3_noun x, n; + if ( c3n == u3r_mean(cor, u3x_sam_2, &x, u3x_sam_3, &n, 0) || + c3n == u3ud(x) || c3n == u3ud(n) ) { + return u3m_bail(c3__exit); + } + softfloat_roundingMode = softfloat_round_near_even; // kernels run near-even + _math_rnd = _rnd_of(u3r_at(60, cor)); // door rounding r (composites) + return _rq_out(fun(_rq_in(x), _rq_in(n))); + } + + u3_noun u3qi_rq_exp(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rq_out(_rq_exp(_rq_in(a))); } + u3_noun u3wi_rq_exp(u3_noun cor) { return _rq_jet(cor, _rq_exp); } + u3_noun u3qi_rq_log(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rq_out(_rq_log(_rq_in(a))); } + u3_noun u3wi_rq_log(u3_noun cor) { return _rq_jet(cor, _rq_log); } + u3_noun u3qi_rq_sin(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rq_out(_rq_sin(_rq_in(a))); } + u3_noun u3wi_rq_sin(u3_noun cor) { return _rq_jet(cor, _rq_sin); } + u3_noun u3qi_rq_cos(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rq_out(_rq_cos(_rq_in(a))); } + u3_noun u3wi_rq_cos(u3_noun cor) { return _rq_jet(cor, _rq_cos); } + u3_noun u3qi_rq_tan(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rq_out(_rq_tan(_rq_in(a))); } + u3_noun u3wi_rq_tan(u3_noun cor) { return _rq_jet(cor, _rq_tan); } + u3_noun u3qi_rq_atan(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rq_out(_rq_atan(_rq_in(a))); } + u3_noun u3wi_rq_atan(u3_noun cor){ return _rq_jet(cor, _rq_atan); } + u3_noun u3qi_rq_asin(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rq_out(_rq_asin(_rq_in(a))); } + u3_noun u3wi_rq_asin(u3_noun cor){ return _rq_jet(cor, _rq_asin); } + u3_noun u3qi_rq_acos(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rq_out(_rq_acos(_rq_in(a))); } + u3_noun u3wi_rq_acos(u3_noun cor){ return _rq_jet(cor, _rq_acos); } + u3_noun u3qi_rq_sqt(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rq_out(_rq_sqt(_rq_in(a))); } + u3_noun u3wi_rq_sqt(u3_noun cor) { return _rq_jet(cor, _rq_sqt); } + u3_noun u3qi_rq_cbt(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rq_out(_rq_cbt(_rq_in(a))); } + u3_noun u3wi_rq_cbt(u3_noun cor) { return _rq_jet(cor, _rq_cbt); } + u3_noun u3qi_rq_log2(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rq_out(_rq_log2(_rq_in(a))); } + u3_noun u3wi_rq_log2(u3_noun cor){ return _rq_jet(cor, _rq_log2); } + u3_noun u3qi_rq_log10(u3_atom a) { softfloat_roundingMode=softfloat_round_near_even; return _rq_out(_rq_log10(_rq_in(a))); } + u3_noun u3wi_rq_log10(u3_noun cor){ return _rq_jet(cor, _rq_log10); } + + u3_noun u3qi_rq_atan2(u3_atom y, u3_atom x) { softfloat_roundingMode=softfloat_round_near_even; return _rq_out(_rq_atan2(_rq_in(y), _rq_in(x))); } + u3_noun u3wi_rq_atan2(u3_noun cor){ return _rq_jet2(cor, _rq_atan2); } + u3_noun u3qi_rq_pow(u3_atom x, u3_atom n) { softfloat_roundingMode=softfloat_round_near_even; return _rq_out(_rq_pow(_rq_in(x), _rq_in(n))); } + u3_noun u3wi_rq_pow(u3_noun cor) { return _rq_jet2(cor, _rq_pow); } + u3_noun u3qi_rq_pow_n(u3_atom x, u3_atom n) { softfloat_roundingMode=softfloat_round_near_even; return _rq_out(_rq_pow_n(_rq_in(x), _rq_in(n))); } + u3_noun u3wi_rq_pow_n(u3_noun cor){ return _rq_jet2(cor, _rq_pow_n); } + #endif diff --git a/libmath/vere/noun/jets/q.h b/libmath/vere/noun/jets/q.h index 654930a..493887b 100644 --- a/libmath/vere/noun/jets/q.h +++ b/libmath/vere/noun/jets/q.h @@ -336,6 +336,22 @@ u3_noun u3qi_rh_log2(u3_atom); u3_noun u3qi_rh_log10(u3_atom); + u3_noun u3qi_rq_exp(u3_atom); + u3_noun u3qi_rq_log(u3_atom); + u3_noun u3qi_rq_sin(u3_atom); + u3_noun u3qi_rq_cos(u3_atom); + u3_noun u3qi_rq_tan(u3_atom); + u3_noun u3qi_rq_atan(u3_atom); + u3_noun u3qi_rq_atan2(u3_atom, u3_atom); + u3_noun u3qi_rq_asin(u3_atom); + u3_noun u3qi_rq_acos(u3_atom); + u3_noun u3qi_rq_sqt(u3_atom); + u3_noun u3qi_rq_cbt(u3_atom); + u3_noun u3qi_rq_pow(u3_atom, u3_atom); + u3_noun u3qi_rq_pow_n(u3_atom, u3_atom); + u3_noun u3qi_rq_log2(u3_atom); + u3_noun u3qi_rq_log10(u3_atom); + # define u3qfu_van_fan 28 # define u3qfu_van_rib 58 # define u3qfu_van_vet 59 diff --git a/libmath/vere/noun/jets/w.h b/libmath/vere/noun/jets/w.h index 7af379e..c802a65 100644 --- a/libmath/vere/noun/jets/w.h +++ b/libmath/vere/noun/jets/w.h @@ -475,5 +475,21 @@ u3_noun u3wi_rh_log2(u3_noun); u3_noun u3wi_rh_log10(u3_noun); + u3_noun u3wi_rq_exp(u3_noun); + u3_noun u3wi_rq_log(u3_noun); + u3_noun u3wi_rq_sin(u3_noun); + u3_noun u3wi_rq_cos(u3_noun); + u3_noun u3wi_rq_tan(u3_noun); + u3_noun u3wi_rq_atan(u3_noun); + u3_noun u3wi_rq_atan2(u3_noun); + u3_noun u3wi_rq_asin(u3_noun); + u3_noun u3wi_rq_acos(u3_noun); + u3_noun u3wi_rq_sqt(u3_noun); + u3_noun u3wi_rq_cbt(u3_noun); + u3_noun u3wi_rq_pow(u3_noun); + u3_noun u3wi_rq_pow_n(u3_noun); + u3_noun u3wi_rq_log2(u3_noun); + u3_noun u3wi_rq_log10(u3_noun); + #endif /* ifndef U3_JETS_W_H */ From 7a0cb5f3e6024749f176718375918df6372947fa Mon Sep 17 00:00:00 2001 From: Sigilante Date: Sat, 13 Jun 2026 10:13:34 -0500 Subject: [PATCH 27/28] docs: README -- all four doors (@rd/@rs/@rh/@rq) now jetted Updates the stale '@rh/@rq not yet jetted' note; documents the @rq fdlibm exp reconstruction and the library-wide flat-Horner exp ULP caveat (deferred retrofit for @rd/@rs/@rh). --- libmath/vere64/README.md | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/libmath/vere64/README.md b/libmath/vere64/README.md index e04cd97..126d533 100644 --- a/libmath/vere64/README.md +++ b/libmath/vere64/README.md @@ -28,12 +28,21 @@ because the `u3r_mean` macro's API diverged between the runtimes: Keep the two copies in sync **except** those two lines. ## What's covered -All 15 transcendentals for **both `@rd` (double) and `@rs` (single)**, bit-exact -to their Hoon door (same reduction, coefficients, Horner order — not merely -faithful): `exp log sin cos tan atan atan2 asin acos sqt cbt pow pow-n log-2 -log-10`. The `@rs` cores are single-precision twins of the `@rd` ones (SoftFloat -`f32`, `uint32_t` bit pattern, but the same chub I/O). The `@rh`/`@rq` doors are -not yet jetted. +All 15 transcendentals for **all four doors — `@rd` (double), `@rs` (single), +`@rh` (half), `@rq` (quad)**, bit-exact to their Hoon door (same reduction, +coefficients, Horner order — not merely faithful): `exp log sin cos tan atan +atan2 asin acos sqt cbt pow pow-n log-2 log-10`. The `@rs`/`@rh` cores are +single-/half-precision twins of the `@rd` ones (SoftFloat `f32`/`f16`, `uint32_t`/ +`uint16_t` bit pattern); `@rh` is fully native f16 (no widen-to-f32). The `@rq` +cores are native `float128_t` (SoftFloat `f128M_*` via by-value wrappers), with +the same algorithms at higher minimax degree. All use the same chub I/O — `@rq` +reads/writes **two** chubs (low 64, high 64). + +`@rq` exp uses the fdlibm rational reconstruction (`1 - ((lo - r·c/(2-c)) - hi)`) +rather than a flat Horner — the flat form is only ~1.1 ULP (the dominant `1+r` +gets rounded through the whole chain), which finely-sampled MPFR sweeps expose; +the same latent issue exists in the `@rd`/`@rs`/`@rh` exp arms and is a deferred +retrofit. All other `@rq` kernels are faithful (≤1 ULP) as written. ### Rounding modes (composite arms honor the door's `r`) The math doors carry `r=?(%n %u %d %z)` (bunt `%z`). The transcendental KERNELS From 5b424c016e5da35bef2cb0c47d36e136d1047365 Mon Sep 17 00:00:00 2001 From: Sigilante Date: Sat, 13 Jun 2026 13:31:03 -0500 Subject: [PATCH 28/28] math: complete @rq door jet hints + document jet-attachment finding Adds the 16 ~/ hints for the @rq door (engine %rq + 15 arm hints), completing the hint set across all four math doors. Documents (vere64/README) that the math transcendental jets do NOT currently attach on-ship -- a structural issue, not kelvin. A lagoon control (mmul, the sibling userspace jet in the same `non` chapter) fires on the same hoon-version-136 ship; math does not. Cause: the `math` engine core makes the width doors grandchildren of the `non` chapter (chapter->engine->door->arm, 3-deep) vs the standard chapter->door->arm (lagoon's `la`, kernel two->by/two->in). The jet C code itself is correct (test/rq_cores.c harness 13/13); only on-ship attachment is blocked. Fix direction pending core-dev review. Co-Authored-By: Claude Opus 4.8 --- libmath/desk/lib/math.hoon | 16 ++++++++++++++++ libmath/vere64/README.md | 38 +++++++++++++++++++++++++++++++++++--- 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/libmath/desk/lib/math.hoon b/libmath/desk/lib/math.hoon index 7a06ee0..f3d5df8 100644 --- a/libmath/desk/lib/math.hoon +++ b/libmath/desk/lib/math.hoon @@ -3281,6 +3281,7 @@ -- :: quad precision ++ rq + ~/ %rq ^| |_ $: r=$?(%n %u %d %z) :: round nearest, up, down, to zero rtol=_.~~~1e-20 :: relative tolerance for precision of operations @@ -3724,6 +3725,7 @@ :: .~~~inf :: Source ++ exp + ~/ %exp :: Cody-Waite reduction + fdlibm rational reconstruction (deg-10 even :: minimax P in t=r^2): exp(r) = 1 - ((lo - r*c/(2-c)) - hi), c = r-t*P(t). :: Faithful to ~0.87 ULP (the compensated reconstruction keeps the leading @@ -3778,6 +3780,7 @@ :: .~~~2.4143733100361875441251426417684949e-23 :: Source ++ sin + ~/ %sin :: q*pi/2 reduction + fdlibm kernels (f128); see +rq-trig. |= x=@rq ^- @rq ?: !(~(equ ^rq %n) x x) `@rq`0x7fff.8000.0000.0000.0000.0000.0000.0000 @@ -3872,6 +3875,7 @@ :: .~~~-1.0000000000000000000000021077555518 :: Source ++ cos + ~/ %cos |= x=@rq ^- @rq ?: !(~(equ ^rq %n) x x) `@rq`0x7fff.8000.0000.0000.0000.0000.0000.0000 ?: |(=(x `@rq`0x7fff.0000.0000.0000.0000.0000.0000.0000) =(x `@rq`0xffff.0000.0000.0000.0000.0000.0000.0000)) `@rq`0x7fff.8000.0000.0000.0000.0000.0000.0000 @@ -3889,6 +3893,7 @@ :: .~~~-2.1850398632615189916433278966958165 :: Source ++ tan + ~/ %tan |= x=@rq ^- @rq (div (sin x) (cos x)) :: +asin: @rq -> @rq @@ -3903,10 +3908,12 @@ :: .~~~0.7753974966107530637394463388579305 :: ++ asin + ~/ %asin :: fdlibm rational-form kernel (poly R, deg-30) + sqrt head/tail; f128. |= x=@rq ^- @rq (asn:rq-ainv x) ++ acos + ~/ %acos |= x=@rq ^- @rq (acs:rq-ainv x) ++ rq-ainv @@ -4006,6 +4013,7 @@ :: .~~~1.2626272556789116834540013074115034 :: ++ atan + ~/ %atan :: fdlibm breakpoint reduction + degree-30 minimax (f128); odd. |= x=@rq ^- @rq ?: !(~(equ ^rq %n) x x) `@rq`0x7fff.8000.0000.0000.0000.0000.0000.0000 @@ -4069,6 +4077,7 @@ :: .~~~2.3561944901923449288480202652918806 :: ++ atan2 + ~/ %atan2 |= [y=@rq x=@rq] ^- @rq ?: (gth x `@rq`0x0) (atan (div y x)) ?: &((lth x `@rq`0x0) (gte y `@rq`0x0)) (add (atan (div y x)) `@rq`0x4000.921f.b544.42d1.8469.898c.c517.01b8) @@ -4087,6 +4096,7 @@ :: .~~~0.25 :: Source ++ pow-n + ~/ %pow-n |= [x=@rq n=@rq] ^- @rq ?: =(n `@rq`0x0) `@rq`0x3fff.0000.0000.0000.0000.0000.0000.0000 ?> &((gth n `@rq`0x0) (is-int n)) @@ -4109,6 +4119,7 @@ :: .~~~inf :: Source ++ log + ~/ %log :: x = 2^e * m reduction + atanh series (fdlibm f - s*(f-R)); f128. :: Round-nearest-even internally (matches tools/rq_check.c). |= x=@rq ^- @rq @@ -4158,6 +4169,7 @@ :: TODO :: Source ++ log-10 + ~/ %log-10 |= x=@rq ^- @rq ?: !(~(equ ^rq %n) x x) `@rq`0x7fff.8000.0000.0000.0000.0000.0000.0000 ?: =(x `@rq`0x7fff.0000.0000.0000.0000.0000.0000.0000) `@rq`0x7fff.0000.0000.0000.0000.0000.0000.0000 @@ -4207,6 +4219,7 @@ =/ efa (~(sun ^rq %n) (abs:si e)) [?:((syn:si e) efa (~(sub ^rq %n) `@rq`0x0 efa)) l1] ++ log-2 + ~/ %log-2 |= x=@rq ^- @rq ?: !(~(equ ^rq %n) x x) `@rq`0x7fff.8000.0000.0000.0000.0000.0000.0000 ?: =(x `@rq`0x7fff.0000.0000.0000.0000.0000.0000.0000) `@rq`0x7fff.0000.0000.0000.0000.0000.0000.0000 @@ -4226,6 +4239,7 @@ :: .~~~11.313703735926135014164384135726204 :: Source ++ pow + ~/ %pow |= [x=@rq n=@rq] ^- @rq ?: &(=(n (san (need (toi n)))) (gth n `@rq`0x0)) (pow-n x n) @@ -4255,6 +4269,7 @@ :: .~~~316.2277660168379331998893544432718 :: Source ++ sqt + ~/ %sqt :: correctly-rounded f128 sqrt: stdlib seed + one Markstein FMA (matches :: the SoftFloat f128_sqrt jet, tools/rq_check.c). |= x=@rq ^- @rq @@ -4291,6 +4306,7 @@ :: .~~~1.2598919398731638759238176665172822 :: Source ++ cbt + ~/ %cbt |= x=@rq ^- @rq ?: !(~(equ ^rq %n) x x) x ?: |(=(x `@rq`0x0) =(x `@rq`0x8000.0000.0000.0000.0000.0000.0000.0000)) x diff --git a/libmath/vere64/README.md b/libmath/vere64/README.md index 126d533..5a2dcb5 100644 --- a/libmath/vere64/README.md +++ b/libmath/vere64/README.md @@ -13,6 +13,37 @@ Two copies, one per runtime word size (mirroring `/lib/lagoon`): Each holds `noun/jets/{i/math.c, 135/tree.c, q.h, w.h}` — the full vendored files, ready to diff/apply against the corresponding `pkg/noun/jets/…`. +## ⚠️ JET ATTACHMENT — these jets do NOT currently fire (under core-dev review) +The C jet **code** is correct (bit-exact in the standalone harness — see +`test/rq_cores.c`, 13/13), but the jets **never attach** on-ship. Sentinel proof: +hardcode each `_xx_asin` core to return 7.0, rebuild, and on a fresh ship every +`asin:rd/rs/rh/rq:math` returns the correct *interpreted* value, never 7.0 — for +*all four* doors, including `@rd`. + +Root cause is **structural**, not kelvin. A lagoon control (`mmul`, the sibling +userspace jet in the *same* `non` chapter / same per-kelvin trees) **does** fire +on the same hoon-version-136 ship (40×40 1.8 ms / 80×80 2.3 ms / 160×160 16 ms — +flat then clean O(n³); interpreted would be seconds). The difference is nesting +depth: + +``` +LAGOON (fires): non → la → mmul chapter → DOOR → arm (standard, 2-deep) +MATH (dead): non → math → rd → exp chapter → ENGINE → door → arm (3-deep) +``` + +The `math` *engine* core makes the width doors (`rd`/`rs`/`rh`/`rq`) *grandchildren* +of the `non` chapter; the dashboard attaches the standard 2-deep shape (lagoon, +kernel `two→by`/`two→in`) but not math's 3-deep one. So the optimistic "jets fire" +/ "all four doors jetted" phrasing elsewhere in this README is **not yet true** — +prior timing that looked jetted was the genuinely-jetted *base* `@rX` ops (the +`tri` chapter), not the transcendentals. + +**Fix direction (pending core-dev confirmation):** collapse to chapter→door→arm — +make `rd`/`rs`/`rh`/`rq` direct children of `~% %non` (like lagoon's `la`), drop +`math` as a *jetted* core, register `non → rd → arm` (no `math` middle); preserve +the `exp:rd:math` API via a thin *unjetted* `++ math` re-export. The parent-chain +implication needs core-dev sign-off before restructuring. + ## The 32-bit and 64-bit `math.c` differ by exactly 2 lines Marshalling is **chub-based** (`u3r_chub`/`u3i_chubs`), so it is word-size-agnostic — the divergence that broke the `@rq sub` jet cannot recur, and all 15 algorithm @@ -78,9 +109,10 @@ rounded kernel outputs — `pow = exp(n·log x)` (the `n·log x` multiply), `ata ordinary exactly-rounded operations where honoring `r` is well-defined and useful. The jet matches the Hoon op-for-op: nearest in the kernels, `r` in the composites. -Only the **135** kelvin tree is vendored: the stock test ships (`~dev`, fresh -fakeships from `brass.pill`) are `hoon-version` 135, and that is where these jets -fire. Apply to 136/137 as well if a target ship runs those. +The **135** kelvin tree is the primary one vendored here; `136`/`137` also carry +a partial (`@rd`-only) math block. NB the current `brass.pill` test ships are +`hoon-version` **136**, not 135 — but per the attachment note above, the jets do +not fire on *either* until the chapter→engine→door→arm nesting is resolved. ## How to apply to a vere tree (`pkg/noun`) 1. Copy `noun/jets/i/math.c` → `pkg/noun/jets/i/math.c` (use the matching word-size