17 impl division_struct Q#
23 impl module_struct Q# -> Z#
28 generic Qfrom : (p : @a, q : @a -> std.result(Q#, byte[:])) :: numeric,integral @a
29 generic QfromZ : (n : @a -> Q#) :: numeric,integral @a
30 generic QfromS : (n : byte[:], d : byte[:] -> std.result(Q#, byte[:]))
31 const QfromFlt : (f : flt64 -> std.result(Q#, byte[:]))
32 const fltfromQ : (q : Q# -> flt64)
34 generic eqQ : (q : Q#, n : @i, d : @i -> bool) :: numeric,integral @i
35 const reduceQ : (q : Q# -> void)
41 std.fmtinstall(std.typeof(q), qfmt)
44 const qfmt = {sb, ap, opts
45 var q : Q# = std.vanext(ap)
46 std.sbfmt(sb, "{}", q.p)
47 if !std.bigeqi(q.q, 1)
49 std.sbfmt(sb, "{}", q.q)
54 TODO: Every invocation of this should be replaced with "std.free".
55 Typechecking issues that Ori will fix soon.
57 const freewrap = { a : Q#
58 std.bytefree((a : byte#), sizeof(Q))
63 var ap : std.bigint# = (a.p : std.bigint#)
64 var aq : std.bigint# = (a.q : std.bigint#)
72 impl group_struct Q# =
73 gadd_ip = {a : Q#, b : Q#
74 /* Be careful in case a == b */
75 var t : std.bigint# = std.bigdup(b.p)
85 gadd = {a : Q#, b : Q#
99 var p : std.bigint# = std.mkbigint(0)
100 var q : std.bigint# = std.mkbigint(1)
101 var ret : Q = [ .p = p, .q = q]
102 -> (std.mk(ret) : Q#) // TODO: Cast shouldn't be necessary.
106 -> std.bigiszero(r.p)
110 impl ring_struct Q# =
112 var p : std.bigint# = std.mkbigint(1)
113 var q : std.bigint# = std.mkbigint(1)
114 var ret : Q = [ .p = p, .q = q]
115 -> (std.mk(ret) : Q#) // TODO: Cast shouldn't be necessary
129 impl division_struct Q# =
132 | `std.Some bi: -> `std.Some rmul(a, bi)
133 | `std.None: -> `std.None
138 impl field_struct Q# =
140 if std.bigiszero(a.p)
143 var q : Q = [ .p = std.bigdup(a.q), .q = std.bigdup(a.p) ]
144 -> `std.Some (std.mk(q) : Q#) // TODO: Cast shouldn't be necessary
149 abs_ip = {q; abs_ip(q.p)}
156 var b : std.bigint# = (q.p : std.bigint#)
168 gcd = {a : Q#, b : Q#
170 Let Thomae's function f(p/q) = 1/q, for p and q
171 coprime. Then gcd(a,b) = a f(b/a) when a != 0, and b
183 x.p = std.mkbigint(1)
194 impl real_struct Q# =
196 compconj = {q; -> t.dup(q)}
199 impl module_struct Q# -> Z# =
200 phi_ip = {z : Z#, q : Q#
201 q.p = std.bigmul(q.p, (z : std.bigint#))
211 impl std.equatable Q# =
213 var m = std.bigdup(a.p)
214 var n = std.bigdup(b.p)
217 var eq = std.bigeq(m, n)
224 impl t.comparable Q# =
242 var q : Q = [ .p = std.bigdup(a.p), .q = std.bigdup(a.q) ]
243 -> (std.mk(q) : Q#) // TODO: Cast shouldn't be necessary
253 if std.bigiszero(q.p)
254 if !std.bigeqi(q.q, 1)
255 std.bigsteal(q.q, std.mkbigint(1))
261 var d : Z# = auto gcd((q.p : Z#), (q.q : Z#))
262 std.bigdiv(q.p, (d : std.bigint#))
263 std.bigdiv(q.q, (d : std.bigint#))
266 generic eqQ = {q, n, d
271 var l : std.bigint# = std.bigdup(q.p)
272 l = std.bigmuli(l, d)
273 var r : std.bigint# = std.bigdup(q.q)
274 r = std.bigmuli(r, n)
276 var ret = std.bigeq(l, r)
284 var pp : std.bigint# = std.mkbigint(p)
285 var qq : std.bigint# = std.mkbigint(q)
289 -> `std.Err(std.fmt("Denominator is zero"))
291 var a = std.mk([ .p = pp, .q = qq ])
297 var pp : std.bigint# = std.mkbigint(p)
298 var qq : std.bigint# = std.mkbigint(1)
299 var a = std.mk([ .p = pp, .q = qq ])
304 generic QfromS = {ps, qs
305 match std.bigparse(ps)
307 match std.bigparse(qs)
310 -> `std.Err std.fmt("Denominator is zero")
312 var qbase : Q = [ .p = p, .q = q ]
313 -> `std.Ok std.mk(qbase)
314 | `std.None: -> `std.Err std.fmt("Unparsable denominator")
316 | `std.None: -> `std.Err std.fmt("Unparsable numerator")
321 var b = std.flt64bits(f)
323 if (b >> 52) & 0x7fful == 0x7fful
324 -> `std.Err std.fmt("Cannot convert infinity or NaN to rational")
327 var isneg : bool = (b >> 63 & 0x1) == 0x1
329 b = b & 0x7fffffffffffffff
330 f = std.flt64frombits(b)
333 if b >= 0x4340000000000000
335 This is ~2^53, certainly an integer. If we go much
336 higher, we can't store the rounding in an int64, so
337 this should be handled specially. We don't need any
338 continued fractions, since this is certainly an
339 integer. Since f = s * 2^(e - 52), build it up.
341 (_, e, s) = std.flt64explode(f)
342 var n : std.bigint# = std.mkbigint(s)
343 var p : std.bigint# = bigpowtwoi(e - 52)
351 var ret : Q = [ .p = n, .q = std.mkbigint(1) ]
352 -> `std.Ok (std.mk(ret) : Q#)
356 It will be useful to assume later that 0 < a < 1. We can save
357 this off safely because of the check for large numbers above
359 var a0f : flt64 = math.floor(f)
360 var a0 : int64 = math.rn(a0f)
362 (_, e, s) = std.flt64explode(f)
365 var ret : Q = [ .p = std.mkbigint(a0), .q = std.mkbigint(1) ]
369 -> `std.Ok (std.mk(ret) : Q#)
373 Now f = s * 2^(e - 52) for 0 < s < 2 and e < 0. We think of f
374 as really representing the range (m, M), where
376 f- = floating point number immediately below f
377 f+ = floating point number immediately above f
381 We will construct a "best rational approximation" for f as
382 follows: begin to compute, in order, the continued fractions
383 [ a0; a1, a2, ... ] for each of m (coefficients ai) and M
384 (coefficients Ai). One of the following will happen first.
386 - If we obtain a k for which ak != Ak, then the best
387 rational approximation for f has continued fraction
389 [ a0; a1, a2, ... a{k-1}, min(ak, Ak) + 1 ]
391 We augment this slightly by, when building up the
392 continued fraction, ignoring entries when we can prove
393 that the relative error is below 2^-53. In this case,
395 - If we obtain a k for which ak or Ak are ambiguous (this
396 will happen at some point, since m and M are rational
397 numbers), we give up and return the exact value of f,
398 which is s/2^(52 - e) or something similar.
400 It is known that, were we to resolve the ambiguity in both
401 directions for both m and M, one of the four combinations of
402 continued fraction pairs would yield the best rational
403 approximation of f. However, that is tedious to calculate and
404 doesn't feel like the "right" algorithm.
408 First, get f-, f+, m, and M. Since we've restricted the range
409 of f, we can just add and subtract bits to f to get f- and
410 f+. Irritatingly, we then have to go to bigints to get the
411 numerators and denominators for m and M.
413 var fQ : Q# = naiveQfromFlt(f)
415 var fminus : Q# = auto naiveQfromFlt(std.flt64frombits(std.flt64bits(f) - 1))
416 var fplus : Q# = auto naiveQfromFlt(std.flt64frombits(std.flt64bits(f) + 1))
417 var half : Q# = auto std.mk([ .p = std.mkbigint(1), .q = std.mkbigint(2) ])
418 var m : Q# = auto yakmo.gadd(fminus, fQ)
419 var M : Q# = auto yakmo.gadd(fplus, fQ)
420 yakmo.rmul_ip(m, half)
421 yakmo.rmul_ip(M, half)
423 /* Now, start computing the continued fractions for m and M */
430 m = p/q = 1/(a + epsilon) with epsilon in [0, 1]
433 We let a = floor(q / p) and epsilon = (q % p) / p.
434 Then setting m = epsilon allows computing the next
437 If q % p == 0, then the choice is ambiguous: either
438 (a, 0) or (a - 1, 1) would work. There should be a
439 way to figure out what the correct choice is, but I
440 really don't have time right now, so we bail and
443 var ak, mpnext, Ak, Mpnext
444 (ak, mpnext) = std.bigdivmod(m.q, m.p)
445 if std.bigiszero(mpnext)
455 (Ak, Mpnext) = std.bigdivmod(M.q, M.p)
456 if std.bigiszero(Mpnext)
465 match std.bigcmp(ak, Ak)
468 std.bigaddi(a[a.len - 1], 1)
469 ret = buildCFrac(a0, a)
472 std.bigaddi(A[A.len - 1], 1)
473 ret = buildCFrac(a0, A)
479 var ipart = std.mkbigint(a0)
480 std.bigmul(ipart, fQ.q)
481 std.bigadd(fQ.p, ipart)
489 for var k = 0; k < a.len; ++k
494 for var k = 0; k < A.len; ++k
506 const naiveQfromFlt = {f
507 /* We assume 0 < f < 1 */
509 (_, e, s) = std.flt64explode(f)
511 var ret : Q = [ .p = std.mkbigint(s), .q = bigpowtwoi(52 - e) ]
512 var retp : Q# = std.mk(ret)
517 const bigpowtwoi = {e
518 var ret : std.bigint# = std.mkbigint(1)
523 const buildCFrac = {a0 : int64, a : std.bigint#[:]
524 var q : Q# = std.mk([ .p = std.mkbigint(1), .q = std.mkbigint(1) ])
525 var old_q : Q# = std.mk([ .p = std.mkbigint(2), .q = std.mkbigint(1) ])
528 First, figure out the maximum error that a floating point
529 number could detect. If a0 ~ 2^e is not 0, then we can ignore
530 errors up to 2^(e - 53).
532 But if a0 == 0, we guess based on a1. The number we're
533 approximating is not less than 1/(a1 + 1), so we can pull the
534 exponent off that, then subtract 53.
538 var a0f = (a0 : flt64)
540 (n, e, s) = std.flt64explode(a0f)
541 detectable_exp = 52 - e
544 a1 is a bigint, so we have to be sloppy. If
545 a1.dig.len > 1, pretend a1 = 2^32. If a1.dig.len ==
546 1, use a1 = a1.dig[0]
550 a1if = 1.0 / (a[0].dig[0] : flt64)
552 a1if = 0.00000000023283064365386962890625
556 (n, e, s) = std.flt64explode(a1if)
557 detectable_exp = 52 - e
559 if detectable_exp < 0
563 var two = std.mkbigint(2)
564 std.bigshli(two, detectable_exp)
566 for var j = 1; j <= a.len; ++j
567 /* Try and build the continued fraction using the first j terms */
572 var qbody : Q = [ .p = std.mkbigint(1), .q = std.bigdup(ares[ares.len - 1]) ]
575 for var k = ares.len - 2; k >= 0; --k
576 /* convert p/q to 1/( ares[k] + p/q ) = q / (ares[k]*q + p) */
577 var newq = std.bigdup(ares[k])
578 std.bigmul(newq, q.q)
579 std.bigadd(newq, q.p)
581 q.p = std.bigdup(q.q)
586 Was that a detectable improvement? If |q - old_q| <
587 1/2^detectable_exp, then we should return old_q.
589 var qdiff = auto gneg(q)
590 gadd_ip(qdiff, old_q)
591 std.bigmul(qdiff.p, two)
592 match std.bigcmpabs(qdiff.p, qdiff.q)
594 /* std.swap(&q, &old_q) */
606 var ipart : std.bigint# = std.bigdup(q.q)
607 std.bigmuli(ipart, a0)
608 std.bigadd(q.p, ipart)
618 var p : std.bigint# = std.bigdup(r.p)
619 var is_neg : bool = false
628 var q : std.bigint# = std.bigdup(r.q)
633 r = p/q = (1 + (s + eps)/2^52) * 2^e
635 where eps in [0, 1), s in [0, 2^52), and e an integer. This
636 will allow us to construct the significand out of s + eps and
637 u5e e as the exponent. First, calculate e. Luckily, we can
638 calculate this in terms of the shifting offset to make p and
639 q have the same number of digits.
641 There are much fancier ways to get the highest bit of a
642 32-bit number, I know.
644 var digits_p = 32 * (p.dig.len - 1)
645 for var t = p.dig[p.dig.len - 1]; t != 0; t >>= 1
648 var digits_q = 32 * (q.dig.len - 1)
649 for var t = q.dig[q.dig.len - 1]; t != 0; t >>= 1
653 /* Get p and q to have the same order of magnitude */
654 var e : int64 = digits_p - digits_q
661 /* Now, are we looking at something like 1.01 / 1.02, or 1.02 / 1.01? */
663 /* I'm pretty sure this only takes one pass. */
664 match std.bigcmp(p, q)
673 Now that we know e, we may construct
675 s + eps = ((r * 2^-e) - 1) * 2^52
679 for e' = (p' % q') / q', so floor(p'/q') in [0, 2^52), and eps'
680 in [0, 1). We can then round based on eps'.
686 (sb, eps_p) = std.bigdivmod(p, q)
689 s_m_1 += (sb.dig[0] : uint64)
691 s_m_1 += ((sb.dig[1] : uint64) << 32)
696 Now, we have to check whether eps_p / q is large enough to
697 deserve rounding s up or not. To do so, compare eps_p*2 to q.
699 var was_roundup = false
700 std.bigshli(eps_p, 1)
701 match std.bigcmp(eps_p, q)
707 if s_m_1 & 0x1 == 0x1
714 If we increased s so that it is now 2^52, then
715 (1 + s/2^52) * 2^e = (1 + 0) * 2^(e + 1)
717 if s_m_1 == 4503599627370496
721 var s : uint64 = s_m_1 | (1 << 52)
723 /* If e is large enough, clean out all the NaN bits to give Inf */
730 Finally, we have to handle subnormals. If e is low enough, we
731 should truncate s. However, this may require us to do another
732 rounding check, and this time we have to compensate for a
733 possible previous rounding.
736 /* This must round to 0 */
749 The significand of a subnormal number is
757 We'll shift s to the right by e - (-1022), then set e to -1023
759 var rshift = ((-1022 - e) : uint64)
760 var new_s = s >> rshift
762 var firstcut = s & (1 << (rshift - 1))
763 var restcut = s & ((1 << (rshift - 1)) - 1)
764 var lastkept = s & (1 << (rshift))
765 var roundup = firstcut != 0 && (lastkept != 0 || restcut != 0)
766 if roundup && !was_roundup
768 if new_s & (1 << 52) != 0
779 -> std.flt64assem(is_neg, e, s)