spec/math/f64.bend
bend-collections-laws-crypto@1.0.0.0 · 592 lines · 124 definitions
1import Base
2import bend-collections-laws-crypto@1.0.0.0/spec/lib/common.bend as C
3import bend-collections-laws-crypto@1.0.0.0/src/math/f64.bend as F
4import bend-collections-laws-crypto@1.0.0.0/src/math/natural.bend as M
5import bend-collections-laws-crypto@1.0.0.0/src/math/u64.bend as WU
6import bend-collections-laws-crypto@1.0.0.0/src/math/num.bend as N
7import bend-collections-laws-crypto@1.0.0.0/spec/math/w64.bend as SW
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70def hi_nat(x: F.F64) -> Nat:
71 U32.to_nat(F.word_hi(x))
72
73def lo_nat(x: F.F64) -> Nat:
74 U32.to_nat(F.word_lo(x))
75
76
77def sign(+x: F.F64) -> Bool:
78 Bool.not(C.fits(31n, hi_nat(x)))
79
80def efield(+x: F.F64) -> Nat:
81 C.low(11n, C.high(20n, hi_nat(x)))
82
83def frac(+x: F.F64) -> Nat:
84 Nat.add(lo_nat(x), C.shift(32n, C.low(20n, hi_nat(x))))
85
86def b2n(b: Bool) -> Nat:
87 match b:
88 case True{}:
89 1n
90 case False{}:
91 0n
92
93
94
95def encode(+s: Bool, +ef: Nat, +f: Nat) -> F.F64:
96 F.Bits{U32.from_nat(C.low(32n, f)), U32.from_nat(Nat.add(C.high(32n, f), C.shift(20n, Nat.add(ef, C.shift(11n, b2n(s))))))}
97
98def pick(-T: Data, c: Bool, +a: T, +b: T) -> T:
99 match c:
100 case True{}:
101 a
102 case False{}:
103 b
104
105
106def pickt(-T: Type, c: Bool, a: T, b: T) -> T:
107 match c:
108 case True{}:
109 a
110 case False{}:
111 b
112
113
114def qnan() -> F.F64:
115 F.Bits{0, 2146959360}
116
117def inf(+s: Bool) -> F.F64:
118 pick(F.F64, s, F.Bits{0, 4293918720}, F.Bits{0, 2146435072})
119
120def zero(+s: Bool) -> F.F64:
121 pick(F.F64, s, F.Bits{0, 2147483648}, F.Bits{0, 0})
122
123def is_nan(+x: F.F64) -> Bool:
124 Bool.and(Nat.is_eq(efield(x), 2047n), Bool.not(Nat.is_eq(frac(x), 0n)))
125
126def is_inf(+x: F.F64) -> Bool:
127 Bool.and(Nat.is_eq(efield(x), 2047n), Nat.is_eq(frac(x), 0n))
128
129def is_zero(+x: F.F64) -> Bool:
130 Bool.and(Nat.is_eq(efield(x), 0n), Nat.is_eq(frac(x), 0n))
131
132
133
134
135
136def zb() -> Nat:
137 3000n
138
139
140def mant(+x: F.F64) -> Nat:
141 Nat.add(frac(x), C.shift(52n, b2n(Bool.not(Nat.is_eq(efield(x), 0n)))))
142
143def xexp(+x: F.F64) -> Nat:
144 pick(Nat, Nat.is_eq(efield(x), 0n), Nat.sub(zb(), 1074n), Nat.sub(Nat.add(efield(x), zb()), 1075n))
145
146
147
148
149
150def rne_up(+q: Nat, +r: Nat, +h: Nat) -> Nat:
151 Nat.add(q, b2n(Bool.or(Nat.is_lt(h, r), Bool.and(Nat.is_eq(r, h), Nat.is_eq(Nat.mod(q, 2n), 1n)))))
152
153def rne(+m: Nat, +k: Nat) -> Nat:
154 match k:
155 case 0n:
156 m
157 case 1n+ +j:
158 rne_up(C.high(1n+j, m), C.low(1n+j, m), C.shift(j, 1n))
159
160
161def pack_e(+s: Bool, +ef: Nat, +f: Nat) -> F.F64:
162 pick(F.F64, Nat.is_le(2047n, ef), inf(s), encode(s, ef, f))
163
164
165def pack_n(+s: Bool, +q: Nat, +u: Nat) -> F.F64:
166 pick(F.F64, C.fits(52n, q), encode(s, 0n, q), pack_e(s, Nat.sub(Nat.add(u, 1075n), zb()), C.low(52n, q)))
167
168
169
170
171def pack(+s: Bool, +q: Nat, +u: Nat) -> F.F64:
172 pick(F.F64, C.fits(53n, q), pack_n(s, q, u), pack_e(s, Nat.sub(Nat.add(1n+u, 1075n), zb()), 0n))
173
174
175
176def round_u(+s: Bool, +m: Nat, +x: Nat, +u: Nat) -> F.F64:
177 pack(s, pick(Nat, Nat.is_le(x, u), rne(m, Nat.sub(u, x)), C.shift(Nat.sub(x, u), m)), u)
178
179def round(+s: Bool, +m: Nat, +x: Nat) -> F.F64:
180 pick(F.F64, Nat.is_eq(m, 0n), zero(s), round_u(s, m, x, Nat.max(Nat.sub(Nat.add(x, M.bit_length(m)), 53n), Nat.sub(zb(), 1074n))))
181
182
183
184
185
186def sub_mag(+sa: Bool, +a: Nat, +sb: Bool, +b: Nat, +x: Nat, c: Cmp) -> F.F64:
187 match c:
188 case GT{}:
189 round(sa, Nat.sub(a, b), x)
190 case LT{}:
191 round(sb, Nat.sub(b, a), x)
192 case EQ{}:
193 zero(False{})
194
195def add_mag(+sa: Bool, +a: Nat, +sb: Bool, +b: Nat, +x: Nat) -> F.F64:
196 pick(F.F64, Bool.not(Bool.xor(sa, sb)), round(sa, Nat.add(a, b), x), sub_mag(sa, a, sb, b, x, Nat.cmp(a, b)))
197
198def add_fin(+x: F.F64, +y: F.F64) -> F.F64:
199 add_mag(sign(x), C.shift(Nat.sub(xexp(x), Nat.min(xexp(x), xexp(y))), mant(x)), sign(y), C.shift(Nat.sub(xexp(y), Nat.min(xexp(x), xexp(y))), mant(y)), Nat.min(xexp(x), xexp(y)))
200
201def add_inf(+x: F.F64, +y: F.F64) -> F.F64:
202 pick(F.F64, is_inf(x), pick(F.F64, Bool.and(is_inf(y), Bool.not(Bool.not(Bool.xor(sign(x), sign(y))))), qnan(), x), pick(F.F64, is_inf(y), y, add_fin(x, y)))
203
204def add(+x: F.F64, +y: F.F64) -> F.F64:
205 pick(F.F64, Bool.or(is_nan(x), is_nan(y)), qnan(), add_inf(x, y))
206
207
208def neg(+x: F.F64) -> F.F64:
209 encode(Bool.not(sign(x)), efield(x), frac(x))
210
211def mul_inf(+x: F.F64, +y: F.F64, +s: Bool) -> F.F64:
212 pick(F.F64, Bool.or(is_inf(x), is_inf(y)), pick(F.F64, Bool.or(is_zero(x), is_zero(y)), qnan(), inf(s)), round(s, Nat.mul(mant(x), mant(y)), Nat.sub(Nat.add(xexp(x), xexp(y)), zb())))
213
214def mul(+x: F.F64, +y: F.F64) -> F.F64:
215 pick(F.F64, Bool.or(is_nan(x), is_nan(y)), qnan(), mul_inf(x, y, Bool.xor(sign(x), sign(y))))
216
217
218def kq() -> Nat:
219 200n
220
221def div_fin(+x: F.F64, +y: F.F64, +s: Bool) -> F.F64:
222 round(s, Nat.add(Nat.mul(2n, Nat.div(C.shift(kq(), mant(x)), mant(y))), Nat.min(Nat.mod(C.shift(kq(), mant(x)), mant(y)), 1n)), Nat.sub(Nat.add(xexp(x), zb()), Nat.add(Nat.add(xexp(y), kq()), 1n)))
223
224def div_cls(+x: F.F64, +y: F.F64, +s: Bool) -> F.F64:
225 pick(F.F64, is_inf(x), pick(F.F64, is_inf(y), qnan(), inf(s)), pick(F.F64, is_inf(y), zero(s), pick(F.F64, is_zero(y), pick(F.F64, is_zero(x), qnan(), inf(s)), div_fin(x, y, s))))
226
227def div(+x: F.F64, +y: F.F64) -> F.F64:
228 pick(F.F64, Bool.or(is_nan(x), is_nan(y)), qnan(), div_cls(x, y, Bool.xor(sign(x), sign(y))))
229
230
231
232def kr() -> Nat:
233 100n
234
235def sqrt_even(+m: Nat, +x: Nat) -> F.F64:
236 round(False{}, Nat.add(Nat.mul(2n, M.isqrt(C.shift(Nat.mul(2n, kr()), m))), b2n(Bool.not(Nat.is_eq(Nat.pow(M.isqrt(C.shift(Nat.mul(2n, kr()), m)), 2n), C.shift(Nat.mul(2n, kr()), m))))), Nat.sub(Nat.add(Nat.div(x, 2n), Nat.div(zb(), 2n)), Nat.add(kr(), 1n)))
237
238def sqrt_fin(+x: F.F64) -> F.F64:
239 pick(F.F64, Nat.is_eq(Nat.mod(xexp(x), 2n), 0n), sqrt_even(mant(x), xexp(x)), sqrt_even(Nat.mul(2n, mant(x)), Nat.sub(xexp(x), 1n)))
240
241def sqrt_cls(+x: F.F64) -> F.F64:
242 pick(F.F64, is_zero(x), x, pick(F.F64, sign(x), qnan(), pick(F.F64, is_inf(x), x, sqrt_fin(x))))
243
244def sqrt(+x: F.F64) -> F.F64:
245 pick(F.F64, is_nan(x), qnan(), sqrt_cls(x))
246
247
248
249
250def mag_cmp(+x: F.F64, +y: F.F64) -> Cmp:
251 pick(Cmp, is_inf(x), pick(Cmp, is_inf(y), EQ{}, GT{}), pick(Cmp, is_inf(y), LT{}, Nat.cmp(C.shift(Nat.sub(xexp(x), Nat.min(xexp(x), xexp(y))), mant(x)), C.shift(Nat.sub(xexp(y), Nat.min(xexp(x), xexp(y))), mant(y)))))
252
253def flip(c: Cmp) -> Cmp:
254 match c:
255 case LT{}:
256 GT{}
257 case EQ{}:
258 EQ{}
259 case GT{}:
260 LT{}
261
262def ord(+x: F.F64, +y: F.F64) -> Cmp:
263 pick(Cmp, Bool.and(is_zero(x), is_zero(y)), EQ{}, pick(Cmp, Bool.not(Bool.xor(sign(x), sign(y))), pick(Cmp, sign(x), flip(mag_cmp(x, y)), mag_cmp(x, y)), pick(Cmp, sign(x), LT{}, GT{})))
264
265def ordered(+x: F.F64, +y: F.F64) -> Bool:
266 Bool.not(Bool.or(is_nan(x), is_nan(y)))
267
268
269
270def Add.value(+x: F.F64, +y: F.F64) -> Type:
271 {F.add(x, y) == add(x, y) : F.F64}
272
273
274def Sub.value(+x: F.F64, +y: F.F64) -> Type:
275 {F.sub(x, y) == add(x, neg(y)) : F.F64}
276
277def Mul.value(+x: F.F64, +y: F.F64) -> Type:
278 {F.mul(x, y) == mul(x, y) : F.F64}
279
280def Div.value(+x: F.F64, +y: F.F64) -> Type:
281 {F.div(x, y) == div(x, y) : F.F64}
282
283def Sqrt.value(+x: F.F64) -> Type:
284 {F.sqrt(x) == sqrt(x) : F.F64}
285
286def Lt.value(+x: F.F64, +y: F.F64) -> Type:
287 {F.lt(x, y) == Bool.and(ordered(x, y), Cmp.is_lt(ord(x, y))) : Bool}
288
289def Le.value(+x: F.F64, +y: F.F64) -> Type:
290 {F.le(x, y) == Bool.and(ordered(x, y), Cmp.is_le(ord(x, y))) : Bool}
291
292def Eq.value(+x: F.F64, +y: F.F64) -> Type:
293 {F.eq(x, y) == Bool.and(ordered(x, y), Cmp.is_eq(ord(x, y))) : Bool}
294
295def Neg.value(+x: F.F64) -> Type:
296 {F.neg(x) == neg(x) : F.F64}
297
298def Abs.value(+x: F.F64) -> Type:
299 {F.abs(x) == encode(False{}, efield(x), frac(x)) : F.F64}
300
301def Copysign.value(+x: F.F64, +y: F.F64) -> Type:
302 {F.copysign(x, y) == encode(sign(y), efield(x), frac(x)) : F.F64}
303
304def IsNan.value(+x: F.F64) -> Type:
305 {F.is_nan(x) == is_nan(x) : Bool}
306
307def IsInf.value(+x: F.F64) -> Type:
308 {F.is_inf(x) == is_inf(x) : Bool}
309
310def IsFinite.value(+x: F.F64) -> Type:
311 {F.is_finite(x) == Bool.not(Nat.is_eq(efield(x), 2047n)) : Bool}
312
313def IsZero.value(+x: F.F64) -> Type:
314 {F.is_zero(x) == is_zero(x) : Bool}
315
316def Signbit.value(+x: F.F64) -> Type:
317 {F.signbit(x) == sign(x) : Bool}
318
319
320def OfNat.value(+n: Nat) -> Type:
321 {F.of_nat(n) == round(False{}, n, zb()) : F.F64}
322
323
324
325
326
327
328
329def integral(m: F.RMode, +s: Bool, +n: Nat, +k: Nat) -> Nat:
330 match m:
331 case F.Trunc{}:
332 C.high(k, n)
333 case F.Floor{}:
334 Nat.add(C.high(k, n), b2n(Bool.and(s, Bool.not(Nat.is_eq(C.low(k, n), 0n)))))
335 case F.Ceil{}:
336 Nat.add(C.high(k, n), b2n(Bool.and(Bool.not(s), Bool.not(Nat.is_eq(C.low(k, n), 0n)))))
337 case F.Even{}:
338 rne(n, k)
339
340
341
342
343def to_integral(m: F.RMode, +x: F.F64) -> F.F64:
344 pick(F.F64, is_nan(x), qnan(), pick(F.F64, Bool.or(is_inf(x), Nat.is_le(zb(), xexp(x))), x, round(sign(x), integral(m, sign(x), mant(x), Nat.sub(zb(), xexp(x))), zb())))
345
346def Trunc.value(+x: F.F64) -> Type:
347 {F.trunc(x) == to_integral(F.Trunc{}, x) : F.F64}
348
349def Floor.value(+x: F.F64) -> Type:
350 {F.floor(x) == to_integral(F.Floor{}, x) : F.F64}
351
352def Ceil.value(+x: F.F64) -> Type:
353 {F.ceil(x) == to_integral(F.Ceil{}, x) : F.F64}
354
355def Round.value(+x: F.F64) -> Type:
356 {F.round(x) == to_integral(F.Even{}, x) : F.F64}
357
358
359
360
361def int_part(+x: F.F64) -> Nat:
362 pick(Nat, Nat.is_le(zb(), xexp(x)), C.shift(Nat.sub(xexp(x), zb()), mant(x)), C.high(Nat.sub(zb(), xexp(x)), mant(x)))
363
364
365
366
367def to_nat(+x: F.F64, +w: Nat) -> Result<&2, &2, N.NumError, Nat>:
368 pick(Result<&2, &2, N.NumError, Nat>, is_nan(x), Fail{N.BadDomain{}}, pick(Result<&2, &2, N.NumError, Nat>, Bool.or(is_inf(x), Bool.or(Bool.and(sign(x), Bool.not(Nat.is_eq(int_part(x), 0n))), Bool.not(C.fits(w, int_part(x))))), Fail{N.Overflow{}}, Done{int_part(x)}))
369
370def rv64(r: Result<&2, &2, N.NumError, WU.U64>) -> Result<&2, &2, N.NumError, Nat>:
371 match r:
372 case Fail{e}:
373 Fail{e}
374 case Done{w}:
375 Done{SW.value(w)}
376
377def rv32(r: Result<&2, &2, N.NumError, U32>) -> Result<&2, &2, N.NumError, Nat>:
378 match r:
379 case Fail{e}:
380 Fail{e}
381 case Done{u}:
382 Done{U32.to_nat(u)}
383
384def ToU64.value(+x: F.F64) -> Type:
385 {rv64(F.to_u64(x)) == to_nat(x, 64n) : Result<&2, &2, N.NumError, Nat>}
386
387def ToU32.value(+x: F.F64) -> Type:
388 {rv32(F.to_u32(x)) == to_nat(x, 32n) : Result<&2, &2, N.NumError, Nat>}
389
390def FloorU64.value(+x: F.F64) -> Type:
391 {rv64(F.floor_u64(x)) == to_nat(to_integral(F.Floor{}, x), 64n) : Result<&2, &2, N.NumError, Nat>}
392
393def CeilU64.value(+x: F.F64) -> Type:
394 {rv64(F.ceil_u64(x)) == to_nat(to_integral(F.Ceil{}, x), 64n) : Result<&2, &2, N.NumError, Nat>}
395
396def RoundU64.value(+x: F.F64) -> Type:
397 {rv64(F.round_u64(x)) == to_nat(to_integral(F.Even{}, x), 64n) : Result<&2, &2, N.NumError, Nat>}
398
399
400def OfU64.value(+w: WU.U64) -> Type:
401 {F.of_u64(w) == round(False{}, SW.value(w), zb()) : F.F64}
402
403def OfU32.value(+u: U32) -> Type:
404 {F.of_u32(u) == round(False{}, U32.to_nat(u), zb()) : F.F64}
405
406
407
408
409def exp_of(+t: Nat) -> F.Exp:
410 pick(F.Exp, Nat.is_le(zb(), t), F.Exp{False{}, Nat.sub(t, zb())}, F.Exp{True{}, Nat.sub(zb(), t)})
411
412
413
414
415def frexp(+x: F.F64) -> F.F64 & F.Exp:
416 pickt(F.F64 & F.Exp, is_nan(x), (qnan(), F.Exp{False{}, 0n}), pickt(F.F64 & F.Exp, Bool.or(is_inf(x), is_zero(x)), (x, F.Exp{False{}, 0n}), (round(sign(x), mant(x), Nat.sub(zb(), M.bit_length(mant(x)))), exp_of(Nat.add(xexp(x), M.bit_length(mant(x)))))))
417
418def Frexp.value(+x: F.F64) -> Type:
419 {F.frexp(x) == frexp(x) : F.F64 & F.Exp}
420
421
422
423
424def ldexp(+x: F.F64, +neg: Bool, +k: Nat) -> F.F64:
425 pick(F.F64, is_nan(x), qnan(), pick(F.F64, Bool.or(is_inf(x), is_zero(x)), x, round(sign(x), mant(x), pick(Nat, neg, Nat.sub(xexp(x), k), Nat.add(xexp(x), k)))))
426
427def Ldexp.value(+x: F.F64, +neg: Bool, +k: Nat) -> Type:
428 {F.ldexp(x, F.Exp{neg, k}) == ldexp(x, neg, k) : F.F64}
429
430
431
432def Ulp.value(+x: F.F64) -> Type:
433 {F.ulp(x) == pick(F.F64, is_nan(x), qnan(), pick(F.F64, is_inf(x), inf(False{}), round(False{}, 1n, xexp(x)))) : F.F64}
434
435
436
437
438def pat(+x: F.F64) -> Nat:
439 Nat.add(frac(x), C.shift(52n, efield(x)))
440
441def of_pat(+s: Bool, +p: Nat) -> F.F64:
442 encode(s, C.high(52n, p), C.low(52n, p))
443
444
445
446
447
448
449def nextafter(+x: F.F64, +y: F.F64) -> F.F64:
450 pick(F.F64, Bool.not(ordered(x, y)), qnan(), pick(F.F64, Cmp.is_eq(ord(x, y)), y, pick(F.F64, is_zero(x), encode(sign(y), 0n, 1n), of_pat(sign(x), pick(Nat, Bool.xor(Cmp.is_lt(ord(x, y)), sign(x)), Nat.add(pat(x), 1n), Nat.sub(pat(x), 1n))))))
451
452def Nextafter.value(+x: F.F64, +y: F.F64) -> Type:
453 {F.nextafter(x, y) == nextafter(x, y) : F.F64}
454
455
456
457def fmin(+x: F.F64, +y: F.F64) -> F.F64:
458 pick(F.F64, is_nan(x), pick(F.F64, is_nan(y), qnan(), y), pick(F.F64, is_nan(y), x, pick(F.F64, Bool.and(is_zero(x), is_zero(y)), zero(Bool.or(sign(x), sign(y))), pick(F.F64, Cmp.is_lt(ord(x, y)), x, y))))
459
460def fmax(+x: F.F64, +y: F.F64) -> F.F64:
461 pick(F.F64, is_nan(x), pick(F.F64, is_nan(y), qnan(), y), pick(F.F64, is_nan(y), x, pick(F.F64, Bool.and(is_zero(x), is_zero(y)), zero(Bool.and(sign(x), sign(y))), pick(F.F64, Cmp.is_lt(ord(y, x)), x, y))))
462
463def Fmin.value(+x: F.F64, +y: F.F64) -> Type:
464 {F.fmin(x, y) == fmin(x, y) : F.F64}
465
466def Fmax.value(+x: F.F64, +y: F.F64) -> Type:
467 {F.fmax(x, y) == fmax(x, y) : F.F64}
468
469
470
471def IsNormal.value(+x: F.F64) -> Type:
472 {F.is_normal(x) == Bool.and(Bool.not(Nat.is_eq(efield(x), 0n)), Nat.is_lt(efield(x), 2047n)) : Bool}
473
474def IsSubnormal.value(+x: F.F64) -> Type:
475 {F.is_subnormal(x) == Bool.and(Nat.is_eq(efield(x), 0n), Bool.not(Nat.is_eq(frac(x), 0n))) : Bool}
476
477
478def Bits.value(+x: F.F64) -> Type:
479 {SW.value(F.to_bits(x)) == Nat.add(pat(x), C.shift(63n, b2n(sign(x)))) : Nat}
480
481def Bits.roundtrip(+x: F.F64) -> Type:
482 {F.of_bits64(F.to_bits(x)) == x : F.F64}
483
484def Bits.inverse(+w: WU.U64) -> Type:
485 {F.to_bits(F.of_bits64(w)) == w : WU.U64}
486
487
488def IsInteger.value(+x: F.F64) -> Type:
489 {F.is_integer(x) == Bool.and(Nat.is_lt(efield(x), 2047n), Bool.or(Nat.is_le(zb(), xexp(x)), Nat.is_eq(C.low(Nat.sub(zb(), xexp(x)), mant(x)), 0n))) : Bool}
490
491
492
493
494
495def modf(+x: F.F64) -> F.F64 & F.F64:
496 pickt(F.F64 & F.F64, is_nan(x), (qnan(), qnan()), pickt(F.F64 & F.F64, Bool.or(is_inf(x), Nat.is_le(zb(), xexp(x))), (zero(sign(x)), x), (round(sign(x), C.low(Nat.sub(zb(), xexp(x)), mant(x)), xexp(x)), to_integral(F.Trunc{}, x))))
497
498def Modf.value(+x: F.F64) -> Type:
499 {F.modf(x) == modf(x) : F.F64 & F.F64}
500
501
502def rsc(+x: F.F64, +y: F.F64) -> Nat:
503 Nat.min(xexp(x), xexp(y))
504
505def ra(+x: F.F64, +y: F.F64) -> Nat:
506 C.shift(Nat.sub(xexp(x), rsc(x, y)), mant(x))
507
508def rb(+x: F.F64, +y: F.F64) -> Nat:
509 C.shift(Nat.sub(xexp(y), rsc(x, y)), mant(y))
510
511def rbad(+x: F.F64, +y: F.F64) -> Bool:
512 Bool.or(Bool.or(Bool.not(ordered(x, y)), is_inf(x)), is_zero(y))
513
514
515
516
517def fmod(+x: F.F64, +y: F.F64) -> F.F64:
518 pick(F.F64, rbad(x, y), qnan(), pick(F.F64, is_inf(y), x, round(sign(x), Nat.mod(ra(x, y), rb(x, y)), rsc(x, y))))
519
520def Fmod.value(+x: F.F64, +y: F.F64) -> Type:
521 {F.fmod(x, y) == fmod(x, y) : F.F64}
522
523
524
525
526
527def rflip(+r: Nat, +b: Nat, +q: Nat) -> Bool:
528 Bool.or(Nat.is_lt(b, Nat.add(r, r)), Bool.and(Nat.is_eq(Nat.add(r, r), b), Nat.is_eq(Nat.mod(q, 2n), 1n)))
529
530def rnear(+s: Bool, +r: Nat, +b: Nat, +q: Nat, +u: Nat) -> F.F64:
531 pick(F.F64, rflip(r, b, q), round(Bool.not(s), Nat.sub(b, r), u), round(s, r, u))
532
533def remainder(+x: F.F64, +y: F.F64) -> F.F64:
534 pick(F.F64, rbad(x, y), qnan(), pick(F.F64, is_inf(y), x, rnear(sign(x), Nat.mod(ra(x, y), rb(x, y)), rb(x, y), Nat.div(ra(x, y), rb(x, y)), rsc(x, y))))
535
536def Remainder.value(+x: F.F64, +y: F.F64) -> Type:
537 {F.remainder(x, y) == remainder(x, y) : F.F64}
538
539
540
541def lt_s(+x: F.F64, +y: F.F64) -> Bool:
542 Bool.and(ordered(x, y), Cmp.is_lt(ord(x, y)))
543
544def le_s(+x: F.F64, +y: F.F64) -> Bool:
545 Bool.and(ordered(x, y), Cmp.is_le(ord(x, y)))
546
547def eq_s(+x: F.F64, +y: F.F64) -> Bool:
548 Bool.and(ordered(x, y), Cmp.is_eq(ord(x, y)))
549
550def fabs(+x: F.F64) -> F.F64:
551 encode(False{}, efield(x), frac(x))
552
553
554
555
556def ic_near(+a: F.F64, +b: F.F64, +rel: F.F64, +at: F.F64, +d: F.F64) -> Bool:
557 Bool.or(Bool.or(le_s(d, fabs(mul(rel, b))), le_s(d, fabs(mul(rel, a)))), le_s(d, at))
558
559def isclose(+a: F.F64, +b: F.F64, +rel: F.F64, +at: F.F64) -> Result<&2, &2, N.NumError, Bool>:
560 pick(Result<&2, &2, N.NumError, Bool>, Bool.or(lt_s(rel, zero(False{})), lt_s(at, zero(False{}))), Fail{N.BadDomain{}}, Done{pick(Bool, eq_s(a, b), True{}, pick(Bool, Bool.or(is_inf(a), is_inf(b)), False{}, ic_near(a, b, rel, at, fabs(add(b, neg(a))))))})
561
562def IsClose.value(+a: F.F64, +b: F.F64, +rel: F.F64, +at: F.F64) -> Type:
563 {F.isclose(a, b, rel, at) == isclose(a, b, rel, at) : Result<&2, &2, N.NumError, Bool>}
564
565
566def tz(fuel: Nat, +n: Nat) -> Nat:
567 match fuel:
568 case 0n:
569 0n
570 case 1n+f:
571 pick(Nat, Nat.is_eq(Nat.mod(n, 2n), 1n), 0n, 1n+tz(f, Nat.div(n, 2n)))
572
573
574type Rat is Data:
575 Rat{neg: Bool, num: Nat, den: Nat}
576
577def rtriple(r: Result<&2, &2, N.NumError, F.Ratio>) -> Result<&2, &2, N.NumError, Rat>:
578 match r:
579 case Fail{e}:
580 Fail{e}
581 case Done{F.Ratio{neg, num, den}}:
582 Done{Rat{neg, SW.value(num), den}}
583
584
585
586
587
588def as_ratio(+x: F.F64) -> Result<&2, &2, N.NumError, Rat>:
589 pick(Result<&2, &2, N.NumError, Rat>, is_nan(x), Fail{N.BadDomain{}}, pick(Result<&2, &2, N.NumError, Rat>, is_inf(x), Fail{N.Overflow{}}, pick(Result<&2, &2, N.NumError, Rat>, is_zero(x), Done{Rat{False{}, 0n, 0n}}, pick(Result<&2, &2, N.NumError, Rat>, Nat.is_le(zb(), xexp(x)), pick(Result<&2, &2, N.NumError, Rat>, C.fits(64n, int_part(x)), Done{Rat{sign(x), int_part(x), 0n}}, Fail{N.Overflow{}}), Done{Rat{sign(x), C.high(Nat.min(tz(64n, mant(x)), Nat.sub(zb(), xexp(x))), mant(x)), Nat.sub(Nat.sub(zb(), xexp(x)), Nat.min(tz(64n, mant(x)), Nat.sub(zb(), xexp(x))))}}))))
590
591def AsIntegerRatio.value(+x: F.F64) -> Type:
592 {rtriple(F.as_integer_ratio(x)) == as_ratio(x) : Result<&2, &2, N.NumError, Rat>}