silo:std.math

Source src/silo:std.math

1##! Numeric helpers — generic `Ord` ops, integer arithmetic, and float transcendentals.
2##!
3##! The `MinMax` trait supplies `.min` / `.max` / `.clamp` on any
4##! `Ord` type. Integer bit-manipulation and ilog helpers live as free
5##! `:fn`s backed by host intrinsics. Float transcendentals (`fsqrt`,
6##! `fpow`, `fln`, trig, hyperbolics, rounding, classification, IEEE-754
7##! helpers) are also free `:fn`s typed `AnyFloat -> AnyFloat` —
8##! operator specialisation must land before they can move to trait
9##! methods.
10
11:use
12  :open core AnyInt AnyUInt AnyFloat Bool Str Ordering Result
13  :open traits Ord
14:end
15
16# si[impl stdlib.math.min]
17# si[impl stdlib.math.max]
18# si[impl stdlib.math.clamp]
19:trait(pub) MinMax
20  .min ( Self Self -> Self )
21  .max ( Self Self -> Self )
22  .clamp ( Self Self Self -> Self )
23:end
24
25:impl MinMax AnyInt
26  .min ( AnyInt AnyInt -> AnyInt )
27    dup/2 .< :if drop :else nip :end ;
28  .max ( AnyInt AnyInt -> AnyInt )
29    dup/2 .> :if drop :else nip :end ;
30  .clamp ( AnyInt AnyInt AnyInt -> AnyInt )
31    pop-> val pop-> hi pop-> lo
32    val lo .max hi .min ;
33:end
34
35:impl MinMax AnyFloat
36  .min ( AnyFloat AnyFloat -> AnyFloat )
37    dup/2 .< :if drop :else nip :end ;
38  .max ( AnyFloat AnyFloat -> AnyFloat )
39    dup/2 .> :if drop :else nip :end ;
40  .clamp ( AnyFloat AnyFloat AnyFloat -> AnyFloat )
41    pop-> val pop-> hi pop-> lo
42    val lo .max hi .min ;
43:end
44
45# Int-specific arithmetic helpers.
46# si[impl stdlib.math.int.abs]
47# si[impl stdlib.math.int.signum]
48# si[impl stdlib.math.int.gcd]
49# si[impl stdlib.math.int.lcm]
50# si[impl stdlib.math.int.pow]
51:trait(pub) IntMath
52  .abs ( Self -> Self )
53  .signum ( Self -> Self )
54  .gcd ( Self Self -> Self )
55  .lcm ( Self Self -> Self )
56  .pow ( Self Self -> Self )
57:end
58
59:impl IntMath AnyInt
60  .abs ( AnyInt -> AnyInt )
61    dup 0 .< :if neg :end ;
62
63  .signum ( AnyInt -> AnyInt )
64    dup 0 .< :if drop -1
65    :else dup 0 .> :if drop 1
66    :else drop 0
67    :end :end ;
68
69  .gcd ( AnyInt AnyInt -> AnyInt )
70    .abs swap .abs swap
71    :loop
72      dup 0 .= :if drop :break :end
73      swap over mod
74    :end ;
75
76  .lcm ( AnyInt AnyInt -> AnyInt )
77    dup/2 .gcd pop-> g
78    .* .abs g ./ ;
79
80  .pow ( AnyInt AnyInt -> AnyInt )
81    pop-> exp pop-> base
82    1 pop-> acc
83    :loop
84      exp 0 .= :if :break :end
85      acc base .* pop-> acc
86      exp 1 .- pop-> exp
87    :end acc ;
88:end
89
90# Int bit ops — free fns until trait-constrained specialisation lands.
91# si[impl stdlib.math.int.count-ones]
92:fn(pub) icount-ones ( AnyInt -> AnyInt ) int-count-ones :end
93# si[impl stdlib.math.int.leading-zeros]
94:fn(pub) ileading-zeros ( AnyInt -> AnyInt ) int-leading-zeros :end
95# si[impl stdlib.math.int.trailing-zeros]
96:fn(pub) itrailing-zeros ( AnyInt -> AnyInt ) int-trailing-zeros :end
97# si[impl stdlib.math.int.is-power-of-two]
98:fn(pub) is-power-of-two ( AnyInt -> Bool ) int-is-power-of-two :end
99# si[impl stdlib.math.int.next-power-of-two]
100:fn(pub) inext-power-of-two ( AnyInt -> AnyInt ) int-next-power-of-two :end
101# si[impl stdlib.math.int.ilog2]
102:fn(pub) ilog2 ( AnyInt -> AnyInt ) int-ilog2 :end
103# si[impl stdlib.math.int.ilog10]
104:fn(pub) ilog10 ( AnyInt -> AnyInt ) int-ilog10 :end
105
106# ---------------------------------------------------------------------------
107# F64 transcendentals, rounding, classification, IEEE-754 helpers.
108# Free `:fn` wrappers over host intrinsics (trait-method form blocked on
109# Phase 1b specialisation). Typed `AnyFloat -> AnyFloat` to accept any
110# float kind at call sites.
111# ---------------------------------------------------------------------------
112
113# si[impl stdlib.math.float.sqrt]
114:fn(pub) fsqrt ( AnyFloat -> AnyFloat ) float-sqrt :end
115# si[impl stdlib.math.float.cbrt]
116:fn(pub) fcbrt ( AnyFloat -> AnyFloat ) float-cbrt :end
117# si[impl stdlib.math.float.pow]
118:fn(pub) fpow ( AnyFloat AnyFloat -> AnyFloat ) float-pow :end
119# si[impl stdlib.math.float.exp]
120:fn(pub) fexp ( AnyFloat -> AnyFloat ) float-exp :end
121# si[impl stdlib.math.float.ln]
122:fn(pub) fln ( AnyFloat -> AnyFloat ) float-ln :end
123# si[impl stdlib.math.float.log2]
124:fn(pub) flog2 ( AnyFloat -> AnyFloat ) float-log2 :end
125# si[impl stdlib.math.float.log10]
126:fn(pub) flog10 ( AnyFloat -> AnyFloat ) float-log10 :end
127# si[impl stdlib.math.float.log]
128:fn(pub) flog ( AnyFloat AnyFloat -> AnyFloat ) float-log-base :end
129
130# si[impl stdlib.math.float.sin]
131:fn(pub) fsin ( AnyFloat -> AnyFloat ) float-sin :end
132# si[impl stdlib.math.float.cos]
133:fn(pub) fcos ( AnyFloat -> AnyFloat ) float-cos :end
134# si[impl stdlib.math.float.tan]
135:fn(pub) ftan ( AnyFloat -> AnyFloat ) float-tan :end
136# si[impl stdlib.math.float.asin]
137:fn(pub) fasin ( AnyFloat -> AnyFloat ) float-asin :end
138# si[impl stdlib.math.float.acos]
139:fn(pub) facos ( AnyFloat -> AnyFloat ) float-acos :end
140# si[impl stdlib.math.float.atan]
141:fn(pub) fatan ( AnyFloat -> AnyFloat ) float-atan :end
142# si[impl stdlib.math.float.atan2]
143:fn(pub) fatan2 ( AnyFloat AnyFloat -> AnyFloat ) float-atan2 :end
144# si[impl stdlib.math.float.sin-cos]
145:fn(pub) fsin-cos ( AnyFloat -> AnyFloat AnyFloat ) float-sin-cos :end
146
147# si[impl stdlib.math.float.floor]
148:fn(pub) ffloor ( AnyFloat -> AnyFloat ) float-floor :end
149# si[impl stdlib.math.float.ceil]
150:fn(pub) fceil ( AnyFloat -> AnyFloat ) float-ceil :end
151# si[impl stdlib.math.float.round]
152:fn(pub) fround ( AnyFloat -> AnyFloat ) float-round :end
153# si[impl stdlib.math.float.round-ties-away]
154:fn(pub) fround-ties-away ( AnyFloat -> AnyFloat ) float-round-ties-away :end
155# si[impl stdlib.math.float.trunc]
156:fn(pub) ftrunc ( AnyFloat -> AnyFloat ) float-trunc :end
157# si[impl stdlib.math.float.fract]
158:fn(pub) ffract ( AnyFloat -> AnyFloat ) float-fract :end
159
160# si[impl stdlib.math.float.is-nan]
161:fn(pub) fis-nan ( AnyFloat -> Bool ) float-is-nan :end
162# si[impl stdlib.math.float.is-inf]
163:fn(pub) fis-inf ( AnyFloat -> Bool ) float-is-inf :end
164# si[impl stdlib.math.float.is-finite]
165:fn(pub) fis-finite ( AnyFloat -> Bool ) float-is-finite :end
166
167# si[impl stdlib.math.float.hypot]
168:fn(pub) fhypot ( AnyFloat AnyFloat -> AnyFloat ) float-hypot :end
169# si[impl stdlib.math.float.mul-add]
170:fn(pub) fmul-add ( AnyFloat AnyFloat AnyFloat -> AnyFloat ) float-mul-add :end
171# si[impl stdlib.math.float.copy-sign]
172:fn(pub) fcopy-sign ( AnyFloat AnyFloat -> AnyFloat ) float-copy-sign :end
173# si[impl stdlib.math.float.next-up]
174:fn(pub) fnext-up ( AnyFloat -> AnyFloat ) float-next-up :end
175# si[impl stdlib.math.float.next-down]
176:fn(pub) fnext-down ( AnyFloat -> AnyFloat ) float-next-down :end
177# si[impl stdlib.math.float.total-cmp]
178:fn(pub) ftotal-cmp ( AnyFloat AnyFloat -> Ordering ) float-total-cmp :end
179# si[impl stdlib.math.float.to-bits]
180:fn(pub) fto-bits ( AnyFloat -> AnyInt ) float-to-bits :end
181# si[impl stdlib.math.float.from-bits]
182:fn(pub) from-bits ( AnyInt -> AnyFloat ) float-from-bits :end
183
184# ---------------------------------------------------------------------------
185# Integer radix conversion.
186# ---------------------------------------------------------------------------
187
188:impl (Int range)
189  # si[impl stdlib.math.int.to-str-radix+1]
190  ## `.to-str-radix` — render the integer in the given radix (2..=36).
191  ## Stack effect: `value radix .to-str-radix`.
192  .to-str-radix ( (Int range) AnyInt -> Str )
193    int-to-str-radix ;
194:end
195
196# si[impl stdlib.math.int.from-str-radix]
197## Constructor: parse a string as an integer in the given radix. Free fn
198## because the receiver is a Str (not the produced Int).
199:fn(pub) from-str-radix ( Str AnyInt -> (Result AnyInt Str) )
200  int-from-str-radix
201:end
202
203# ---------------------------------------------------------------------------
204# Numeric constants.
205# ---------------------------------------------------------------------------
206
207# si[impl stdlib.math.const.pi]
208:fn(pub) pi ( -> AnyFloat ) const-pi :end
209# si[impl stdlib.math.const.tau]
210:fn(pub) tau ( -> AnyFloat ) const-tau :end
211# si[impl stdlib.math.const.e]
212:fn(pub) f-e ( -> AnyFloat ) const-e :end
213# si[impl stdlib.math.const.inf]
214:fn(pub) inf ( -> AnyFloat ) const-inf :end
215# si[impl stdlib.math.const.neg-inf]
216:fn(pub) neg-inf ( -> AnyFloat ) const-neg-inf :end
217# si[impl stdlib.math.const.nan]
218:fn(pub) nan ( -> AnyFloat ) const-nan :end
219# si[impl stdlib.math.float.epsilon]
220:fn(pub) epsilon ( -> AnyFloat ) const-epsilon :end
221# si[impl stdlib.math.float.min-positive]
222:fn(pub) min-positive ( -> AnyFloat ) const-min-positive :end
223# si[impl stdlib.math.float.max-float]
224:fn(pub) max-float ( -> AnyFloat ) const-max-float :end