Skip to main content

the_q/
transcendental.rs

1//! Roots and transcendental functions on [`Q`].
2//!
3//! None of these is rational-closed, so each returns a nearby representable
4//! rational. Every series and iteration runs a fixed number of steps chosen so
5//! the truncation tail is below the `2^-61` grid; the term counts are derived
6//! beside each constant. Termination is therefore structural, and Verus proves
7//! totality and well-formedness of every result. Accuracy is measured, not
8//! proven: `README.md` has the table, from two independent oracles.
9//!
10//! The dominant error is rounding of intermediates, and it is absolute below
11//! 1 (R3), so relative accuracy falls off for small results. Special values
12//! follow the denotations in issue #26: a result is sound only if its
13//! denotation contains the true image of the operand's. That is why
14//! `sqrt(PosSat)`, `ln(PosSat)` and `atan(PosSat)` are `Nan` — the image of
15//! `(MAX_MAG, ∞)` under each reaches back inside the budget.
16
17use verus_builtin_macros::verus;
18
19#[allow(unused_imports)]
20use verus_builtin::*;
21#[allow(unused_imports)]
22use vstd::prelude::*;
23
24use crate::ext::{Q, Sign};
25use crate::types::Rat;
26
27verus! {
28
29/// Integer square root, `r*r <= n < (r+1)*(r+1)`; `0` for `n < 0`. Newton on
30/// integers, then a bounded correction whose exit conditions establish the
31/// postcondition directly (Newton alone would need AM-GM over integer
32/// division).
33///
34/// Public only because Verus's visibility rules require it; not part of the
35/// semver-stable API.
36///
37/// ```
38/// assert_eq!(the_q::transcendental::isqrt_i64(10), 3);
39/// assert_eq!(the_q::transcendental::isqrt_i64(16), 4);
40/// ```
41pub fn isqrt_i64(n: i64) -> (r: i64)
42    requires
43        // Every caller passes a `Rat` component, which the type invariant
44        // already bounds by `MAX_MAG`. The bound is load-bearing rather than
45        // decorative: it is what keeps `x + n/x` inside `i64`, since that sum
46        // is at most `2n` and `2 · MAX_MAG == i64::MAX - 1`.
47        0 <= n <= crate::types::MAX_MAG,
48    ensures
49        r >= 0,
50        (r as int) * (r as int) <= n as int,
51        ((r as int) + 1) * ((r as int) + 1) > n as int,
52{
53    if n < 2 {
54        proof {
55            // `n` is 0 or 1, and both are their own integer square root.
56            assert((n as int) * (n as int) <= n as int) by (nonlinear_arith)
57                requires
58                    0 <= n as int <= 1,
59            ;
60            assert(((n as int) + 1) * ((n as int) + 1) > n as int) by (nonlinear_arith)
61                requires
62                    0 <= n as int <= 1,
63            ;
64        }
65        return n;
66    }
67    let mut x: i64 = n;
68    // `(n + 1) / 2`, *not* `n / 2 + 1` — see the note above.
69    let mut y: i64 = (n + 1) / 2;
70    // `y < x` is the decreasing test; `x` is the measure.
71    while y < x
72        invariant
73            x >= 1,
74            y >= 1,
75            x <= n,
76            n <= crate::types::MAX_MAG,
77        decreases x,
78    {
79        x = y;
80        proof {
81            // `1 <= x <= n` gives `n/x >= n/n == 1`, which is what keeps the
82            // next estimate positive. Integer division does not give the
83            // prover this for free.
84            vstd::arithmetic::div_mod::lemma_div_is_ordered_by_denominator(
85                n as int,
86                x as int,
87                n as int,
88            );
89            vstd::arithmetic::div_mod::lemma_div_by_self(n as int);
90        }
91        // `x <= n` and `n / x <= n`, so the sum is at most `2n <= 2 · MAX_MAG`,
92        // which is `i64::MAX - 1`.
93        y = (x + n / x) / 2;
94    }
95    // Correction, in `i128` so the squares cannot overflow: `r <= n <= 2^62`
96    // gives `r*r <= 2^124`.
97    let mut r: i64 = x;
98    // The squares are in variables and not in the loop guards, for two reasons.
99    // First, `r*r` fits `i128` only as a nonlinear fact, which the prover
100    // reaches only in a proof block. Second, the negation of a `while` guard
101    // carries the postcondition out of the loop, and a `loop`/`break` form
102    // discards that negation.
103    proof {
104        assert(0 <= (r as int) * (r as int) <= (crate::types::MAX_MAG as int) * (crate::types::MAX_MAG as int))
105            by (nonlinear_arith)
106            requires
107                0 <= r as int <= crate::types::MAX_MAG as int,
108        ;
109    }
110    let mut sq: i128 = (r as i128) * (r as i128);
111    while r > 0 && sq > n as i128
112        invariant
113            0 <= r <= n,
114            2 <= n <= crate::types::MAX_MAG,
115            sq as int == (r as int) * (r as int),
116        decreases r,
117    {
118        r = r - 1;
119        proof {
120            assert(0 <= (r as int) * (r as int) <= (crate::types::MAX_MAG as int) * (crate::types::MAX_MAG as int))
121                by (nonlinear_arith)
122                requires
123                    0 <= r as int <= crate::types::MAX_MAG as int,
124            ;
125        }
126        sq = (r as i128) * (r as i128);
127    }
128    proof {
129        // Exiting means `r == 0` or `r*r <= n`, and `0*0 == 0 <= n`, so the
130        // defining lower bound holds either way.
131        assert((r as int) * (r as int) <= n as int) by (nonlinear_arith)
132            requires
133                0 <= r as int,
134                2 <= n as int,
135                r as int == 0 || (r as int) * (r as int) <= n as int,
136        ;
137    }
138    proof {
139        assert(0 <= ((r as int) + 1) * ((r as int) + 1) <= ((crate::types::MAX_MAG as int) + 1) * (
140        (crate::types::MAX_MAG as int) + 1)) by (nonlinear_arith)
141            requires
142                0 <= r as int <= crate::types::MAX_MAG as int,
143        ;
144    }
145    let mut nxt: i128 = ((r as i128) + 1) * ((r as i128) + 1);
146    while nxt <= n as i128
147        invariant
148            0 <= r <= n,
149            2 <= n <= crate::types::MAX_MAG,
150            (r as int) * (r as int) <= n as int,
151            nxt as int == ((r as int) + 1) * ((r as int) + 1),
152        decreases n - r,
153    {
154        proof {
155            // `(r+1)^2 <= n` with `r >= 0` forces `r + 1 <= n`, which keeps the
156            // measure decreasing and `r` inside the budget.
157            assert((r as int) + 1 <= n as int) by (nonlinear_arith)
158                requires
159                    0 <= r as int,
160                    ((r as int) + 1) * ((r as int) + 1) <= n as int,
161            ;
162        }
163        r = r + 1;
164        proof {
165            assert(0 <= ((r as int) + 1) * ((r as int) + 1) <= ((crate::types::MAX_MAG as int) + 1) * (
166            (crate::types::MAX_MAG as int) + 1)) by (nonlinear_arith)
167                requires
168                    0 <= r as int <= crate::types::MAX_MAG as int,
169            ;
170        }
171        nxt = ((r as i128) + 1) * ((r as i128) + 1);
172    }
173    r
174}
175
176/// The `isqrt` contract admits exactly one value.
177pub proof fn theorem_isqrt_unique(n: int, r1: int, r2: int)
178    requires
179        0 <= r1,
180        r1 * r1 <= n,
181        n < (r1 + 1) * (r1 + 1),
182        0 <= r2,
183        r2 * r2 <= n,
184        n < (r2 + 1) * (r2 + 1),
185    ensures
186        r1 == r2,
187{
188    // If the roots differed, the smaller one's successor square would be
189    // trapped: (r1+1)^2 <= r2^2 <= n contradicts n < (r1+1)^2.
190    if r1 < r2 {
191        assert((r1 + 1) * (r1 + 1) <= r2 * r2) by (nonlinear_arith)
192            requires
193                0 <= r1 + 1,
194                r1 + 1 <= r2,
195        ;
196    }
197    if r2 < r1 {
198        assert((r2 + 1) * (r2 + 1) <= r1 * r1) by (nonlinear_arith)
199            requires
200                0 <= r2 + 1,
201                r2 + 1 <= r1,
202        ;
203    }
204}
205
206/// `isqrt` is monotone, stated on the contract.
207pub proof fn theorem_isqrt_monotone(n1: int, n2: int, r1: int, r2: int)
208    requires
209        n1 <= n2,
210        0 <= r1,
211        r1 * r1 <= n1,
212        n1 < (r1 + 1) * (r1 + 1),
213        0 <= r2,
214        r2 * r2 <= n2,
215        n2 < (r2 + 1) * (r2 + 1),
216    ensures
217        r1 <= r2,
218{
219    // Otherwise n2 < (r2+1)^2 <= r1^2 <= n1 <= n2.
220    if r2 < r1 {
221        assert((r2 + 1) * (r2 + 1) <= r1 * r1) by (nonlinear_arith)
222            requires
223                0 <= r2 + 1,
224                r2 + 1 <= r1,
225        ;
226    }
227}
228
229/// On a perfect square `k·k` the contract forces `k`.
230pub proof fn theorem_isqrt_of_square(k: int, r: int)
231    requires
232        0 <= k,
233        0 <= r,
234        r * r <= k * k,
235        k * k < (r + 1) * (r + 1),
236    ensures
237        r == k,
238{
239    // k itself satisfies the contract for n == k·k...
240    assert(k * k < (k + 1) * (k + 1)) by (nonlinear_arith)
241        requires
242            0 <= k,
243    ;
244    // ...and the contract pins its answer.
245    theorem_isqrt_unique(k * k, r, k);
246}
247
248/// A first approximation to `sqrt(num/den)`, as a `Q`.
249///
250/// `isqrt(num) / isqrt(den)` is within a factor of two of the true root, which
251/// is close enough that six Newton steps reach the grid. Starting from `x`
252/// itself would need about thirty, and every extra step is another rounding.
253fn sqrt_seed(x: Rat) -> (r: Q)
254    requires
255        x.wf(),
256        x.n() > 0,
257    ensures
258        r.wf(),
259{
260    let rn = isqrt_i64(x.numerator());
261    let rd = isqrt_i64(x.denominator());
262    // `isqrt` of a positive value is at least 1, so this denominator is safe;
263    // `Q::new` is total regardless.
264    Q::new(if rn < 1 {
265        1
266    } else {
267        rn
268    }, if rd < 1 {
269        1
270    } else {
271        rd
272    })
273}
274
275impl Q {
276    /// The square root. Negative → `Nan`; `PosSat` → `Nan` (its image reaches
277    /// below `MAX_MAG`); `PosInf` → `PosInf`. Seven Newton steps from the
278    /// integer-root seed.
279    ///
280    /// ```
281    /// use the_q::Q;
282    ///
283    /// assert_eq!(Q::new(4, 1).sqrt(), Q::new(2, 1));
284    /// assert_eq!(Q::PosSat.sqrt(), Q::Nan);
285    /// ```
286    pub fn sqrt(self) -> (r: Q)
287        requires
288            self.wf(),
289        ensures
290            r.wf(),
291            self.spec_is_nan() ==> r.spec_is_nan(),
292            self.spec_is_zero() ==> r.spec_is_zero(),
293    {
294        match self {
295            Q::Number(x) => {
296                let s = x.signum();
297                if s < 0 {
298                    Q::Nan
299                } else if s == 0 {
300                    Q::zero()
301                } else {
302                    let two = Q::new(2, 1);
303                    let mut y = sqrt_seed(x);
304                    let q = Q::Number(x);
305                    let mut i: u32 = 0;
306                    while i < SQRT_ITERS
307                        invariant
308                            y.wf(),
309                            q.wf(),
310                            two.wf(),
311                            i <= SQRT_ITERS,
312                        decreases SQRT_ITERS - i,
313                    {
314                        // y <- (y + x/y) / 2. A zero or special `y` gives a
315                        // division that reports the state and does not trap.
316                        // The result stays a value.
317                        y = Q::div(Q::add(y, Q::div(q, y)), two);
318                        i = i + 1;
319                    }
320                    y
321                }
322            },
323            // The image of (MAX_MAG, inf) under sqrt is (2^31, inf), which
324            // extends far below MAX_MAG. No saturation state is thus sound.
325            Q::PosSat => Q::Nan,
326            Q::NegSat => Q::Nan,
327            Q::PosInf => Q::PosInf,
328            Q::NegInf => Q::Nan,
329            Q::Nan => Q::Nan,
330        }
331    }
332}
333
334// ---------------------------------------------------------------------------
335// Series lengths
336//
337// Each series has its own count. The count comes from the tail bound of that
338// series against the grid resolution `2^-61`, which is approximately
339// `4.34e-19`. A shared count is wrong in two directions at the same time. It is
340// too short for `atan`, whose coefficients are `1/(2k+1)`. It is almost twice
341// the necessary length for `sin`, whose coefficients are `1/(2k+1)!`.
342//
343// Each count is a constant and does not come from a convergence test. Thus
344// termination is structural and the cost of a call is constant.
345// ---------------------------------------------------------------------------
346
347/// Terms of the `atanh` series, whose argument is reduced to `|z| <= 1/3`.
348///
349/// The tail at `k` is `3^-(2k+1)/(2k+1)`; `k = 18` gives `6.0e-20`, under the
350/// grid, while `k = 17` gives `5.7e-19`, over it. The loop covers `k` up to
351/// `SERIES_TERMS - 1 = 19`, one past what is needed.
352const SERIES_TERMS: u32 = 20;
353
354
355/// Terms of the `sin`/`cos` series on `|z| <= π/4`: the tail at `k = 9` is
356/// `8.4e-20`, under the grid; at `k = 8`, `4.6e-17`.
357const TRIG_TERMS: u32 = 11;
358
359/// Newton iterations in [`Q::sqrt`]: the seed is within a factor of two and
360/// the error squares each step, so six reach the grid; seven is margin.
361const SQRT_ITERS: u32 = 7;
362
363
364/// Beyond `|x| > 44`, `exp(x)` leaves the budget in one direction or the other:
365/// `exp(44) > 2^63` and `exp(-44) < 2^-63`. Both are decided without summing
366/// anything.
367const EXP_ARG_LIMIT: i64 = 44;
368
369/// Beyond `|x| > 22`, `e^-|x| < 2^-62 · e^|x|`, so the hyperbolic functions
370/// are a single exponential to within the rounding contract.
371const HYP_ARG_LIMIT: i64 = 22;
372
373/// Canonical bounded-rational approximation of π used throughout this module.
374pub const PI_NUM: i64 = 1_811_004_864_519_280_709;
375pub const PI_DEN: i64 = 576_460_752_303_423_488;
376
377/// Quotient/remainder decomposition used by [`fx_to_grid`].
378pub proof fn lemma_fx_to_grid_decomposition(m: int, d: int, q: int, rem: int)
379    requires
380        0 <= m,
381        0 < d,
382        q == (m * crate::fx::FX_ONE as int) / d,
383        rem == (m * crate::fx::FX_ONE as int) % d,
384    ensures
385        m * crate::fx::FX_ONE as int == q * d + rem,
386        0 <= rem < d,
387{
388    vstd::arithmetic::div_mod::lemma_fundamental_div_mod(
389        m * crate::fx::FX_ONE as int,
390        d,
391    );
392    vstd::arithmetic::div_mod::lemma_mod_bound(m * crate::fx::FX_ONE as int, d);
393}
394
395/// The selected grid point is within half a grid cell of the exact scaled
396/// value.
397pub proof fn lemma_fx_to_grid_nearest(
398    m: int,
399    d: int,
400    q: int,
401    rem: int,
402    rounded: int,
403)
404    requires
405        0 <= m,
406        0 < d,
407        m * crate::fx::FX_ONE as int == q * d + rem,
408        0 <= rem < d,
409        rounded == if 2 * rem > d || (2 * rem == d && q % 2 == 1) {
410            q + 1
411        } else {
412            q
413        },
414    ensures
415        2 * crate::model::abs_int(rounded * d - m * crate::fx::FX_ONE as int) <= d,
416{
417    let scaled = m * crate::fx::FX_ONE as int;
418    assert(scaled == q * d + rem);
419    if 2 * rem > d || (2 * rem == d && q % 2 == 1) {
420        assert(rounded == q + 1);
421        assert(2 * rem >= d);
422        assert(rounded * d == (q + 1) * d) by (nonlinear_arith)
423            requires
424                rounded == q + 1,
425        ;
426        assert((q + 1) * d == q * d + d) by (nonlinear_arith);
427        assert(rounded * d - scaled == d - rem);
428        assert(0 <= d - rem);
429        assert(crate::model::abs_int(d - rem) == d - rem);
430        assert(2 * (d - rem) <= d);
431    } else {
432        assert(rounded == q);
433        assert(2 * rem <= d);
434        assert(rounded * d == q * d);
435        assert(rounded * d - scaled == -rem);
436        assert(crate::model::abs_int(-rem) == rem);
437    }
438}
439
440/// An exact half-cell case selects an even grid integer.
441pub proof fn lemma_fx_to_grid_ties_even(
442    m: int,
443    d: int,
444    q: int,
445    rem: int,
446    rounded: int,
447)
448    requires
449        0 <= m,
450        0 < d,
451        m * crate::fx::FX_ONE as int == q * d + rem,
452        0 <= rem < d,
453        rounded == if 2 * rem > d || (2 * rem == d && q % 2 == 1) {
454            q + 1
455        } else {
456            q
457        },
458    ensures
459        2 * crate::model::abs_int(rounded * d - m * crate::fx::FX_ONE as int) == d
460            ==> rounded % 2 == 0,
461{
462    let scaled = m * crate::fx::FX_ONE as int;
463    assert(scaled == q * d + rem);
464    vstd::arithmetic::div_mod::lemma_mod_bound(q, 2);
465    if 2 * rem > d || (2 * rem == d && q % 2 == 1) {
466        assert(rounded == q + 1);
467        assert(2 * rem >= d);
468        assert(rounded * d == (q + 1) * d) by (nonlinear_arith)
469            requires
470                rounded == q + 1,
471        ;
472        assert((q + 1) * d == q * d + d) by (nonlinear_arith);
473        assert(rounded * d - scaled == d - rem);
474        assert(crate::model::abs_int(d - rem) == d - rem);
475        if 2 * crate::model::abs_int(rounded * d - m * crate::fx::FX_ONE as int) == d {
476            assert(2 * rem == d);
477            assert(q % 2 == 1);
478            vstd::arithmetic::div_mod::lemma_fundamental_div_mod(q, 2);
479            vstd::arithmetic::div_mod::lemma_fundamental_div_mod_converse(
480                q + 1,
481                2,
482                q / 2 + 1,
483                0,
484            );
485        }
486    } else {
487        assert(rounded == q);
488        assert(2 * rem <= d);
489        assert(rounded * d == q * d);
490        assert(rounded * d - scaled == -rem);
491        assert(crate::model::abs_int(-rem) == rem);
492        if 2 * crate::model::abs_int(rounded * d - m * crate::fx::FX_ONE as int) == d {
493            assert(2 * rem == d);
494            assert(q % 2 != 1);
495            assert(q % 2 == 0);
496        }
497    }
498}
499
500/// Rounding the supported input range cannot exceed the fixed-point engine's
501/// input budget.
502pub proof fn lemma_fx_to_grid_bound(
503    m: int,
504    d: int,
505    q: int,
506    rem: int,
507    rounded: int,
508    neg: bool,
509)
510    requires
511        0 <= m,
512        0 < d,
513        m * crate::fx::FX_ONE as int == q * d + rem,
514        0 <= rem < d,
515        rounded == if 2 * rem > d || (2 * rem == d && q % 2 == 1) {
516            q + 1
517        } else {
518            q
519        },
520        m * crate::fx::FX_ONE as int <= 405828369621610135552int * d,
521    ensures
522        crate::model::abs_int(if neg { -rounded } else { rounded })
523            <= 406000000000000000000int,
524{
525    let scaled = m * crate::fx::FX_ONE as int;
526    vstd::arithmetic::mul::lemma_mul_nonnegative(m, crate::fx::FX_ONE as int);
527    assert(scaled >= 0);
528    assert(scaled == q * d + rem);
529    if q < 0 {
530        assert(q <= -1);
531        assert(q * d <= -d) by (nonlinear_arith)
532            requires
533                q <= -1,
534                d > 0,
535        ;
536        assert(scaled < 0);
537        assert(false);
538    }
539    assert(q * d <= scaled);
540    assert(q * d <= 405828369621610135552int * d);
541    if q > 405828369621610135552int {
542        assert(q >= 405828369621610135553int);
543        assert(q * d >= 405828369621610135553int * d) by (nonlinear_arith)
544            requires
545                q >= 405828369621610135553int,
546                d > 0,
547        ;
548        assert(q * d > 405828369621610135552int * d) by (nonlinear_arith)
549            requires
550                d > 0,
551                q * d >= 405828369621610135553int * d,
552        ;
553        assert(false);
554    }
555    assert(q <= rounded <= q + 1);
556    assert(rounded <= 405828369621610135553int);
557    assert(405828369621610135553int <= 406000000000000000000int) by (compute);
558    if neg {
559        assert(crate::model::abs_int(-rounded) == rounded);
560    } else {
561        assert(crate::model::abs_int(rounded) == rounded);
562    }
563}
564
565/// Exact rounded target for the four cases where both `atan2` coordinates are
566/// infinite. Other inputs map to zero so the model remains total.
567pub open spec fn atan2_inf_target(y: Q, x: Q) -> Rat {
568    match (y, x) {
569        (Q::PosInf, Q::PosInf) => crate::round::round_frac(
570            PI_NUM as int,
571            4 * PI_DEN as int,
572            crate::types::Dir::Nearest,
573        ),
574        (Q::PosInf, Q::NegInf) => crate::round::round_frac(
575            3 * PI_NUM as int,
576            4 * PI_DEN as int,
577            crate::types::Dir::Nearest,
578        ),
579        (Q::NegInf, Q::PosInf) => crate::round::round_frac(
580            -(PI_NUM as int),
581            4 * PI_DEN as int,
582            crate::types::Dir::Nearest,
583        ),
584        (Q::NegInf, Q::NegInf) => crate::round::round_frac(
585            -(3 * PI_NUM as int),
586            4 * PI_DEN as int,
587            crate::types::Dir::Nearest,
588        ),
589        _ => crate::round::round_frac(0, 1, crate::types::Dir::Nearest),
590    }
591}
592
593/// Executable counterpart of [`atan2_inf_target`].
594fn atan2_inf_target_exec(y: Q, x: Q) -> (r: Rat)
595    requires
596        y.wf(),
597        x.wf(),
598    ensures
599        r == atan2_inf_target(y, x),
600        r.wf(),
601{
602    proof {
603        crate::model::lemma_pow2_126();
604        crate::model::lemma_pow2_124();
605    }
606    match (y, x) {
607        (Q::PosInf, Q::PosInf) => {
608            crate::round::round_frac_exec(
609                PI_NUM as i128,
610                4 * PI_DEN as i128,
611                crate::types::Dir::Nearest,
612            )
613        },
614        (Q::PosInf, Q::NegInf) => {
615            crate::round::round_frac_exec(
616                3 * PI_NUM as i128,
617                4 * PI_DEN as i128,
618                crate::types::Dir::Nearest,
619            )
620        },
621        (Q::NegInf, Q::PosInf) => {
622            crate::round::round_frac_exec(
623                -(PI_NUM as i128),
624                4 * PI_DEN as i128,
625                crate::types::Dir::Nearest,
626            )
627        },
628        (Q::NegInf, Q::NegInf) => {
629            crate::round::round_frac_exec(
630                -(3 * PI_NUM as i128),
631                4 * PI_DEN as i128,
632                crate::types::Dir::Nearest,
633            )
634        },
635        _ => crate::round::round_frac_exec(0, 1, crate::types::Dir::Nearest),
636    }
637}
638
639/// Every infinity-pair target satisfies the bounded-rational invariant.
640pub proof fn lemma_atan2_inf_target_wf(y: Q, x: Q)
641    ensures
642        atan2_inf_target(y, x).wf(),
643{
644    match (y, x) {
645        (Q::PosInf, Q::PosInf) => {
646            crate::round::lemma_round_frac_wf(
647                PI_NUM as int,
648                4 * PI_DEN as int,
649                crate::types::Dir::Nearest,
650            );
651        },
652        (Q::PosInf, Q::NegInf) => {
653            crate::round::lemma_round_frac_wf(
654                3 * PI_NUM as int,
655                4 * PI_DEN as int,
656                crate::types::Dir::Nearest,
657            );
658        },
659        (Q::NegInf, Q::PosInf) => {
660            crate::round::lemma_round_frac_wf(
661                -(PI_NUM as int),
662                4 * PI_DEN as int,
663                crate::types::Dir::Nearest,
664            );
665        },
666        (Q::NegInf, Q::NegInf) => {
667            crate::round::lemma_round_frac_wf(
668                -(3 * PI_NUM as int),
669                4 * PI_DEN as int,
670                crate::types::Dir::Nearest,
671            );
672        },
673        _ => {
674            crate::round::lemma_round_frac_wf(0, 1, crate::types::Dir::Nearest);
675        },
676    }
677}
678
679/// The infinite-coordinate \`atan2\` targets have the sign of the vertical coordinate.
680pub proof fn lemma_atan2_inf_target_sign(y: Q, x: Q)
681    requires
682        y.spec_is_infinite(),
683        x.spec_is_infinite(),
684    ensures
685        y == Q::PosInf ==> atan2_inf_target(y, x).n() > 0,
686        y == Q::NegInf ==> atan2_inf_target(y, x).n() < 0,
687{
688    match (y, x) {
689        (Q::PosInf, Q::PosInf) => {
690            Rat::lemma_from_raw_spec_components(1_811_004_864_519_280_709, 2_305_843_009_213_693_952);
691            assert(crate::round::round_frac(PI_NUM as int, 4 * PI_DEN as int, crate::types::Dir::Nearest)
692                == Rat::from_raw_spec(1_811_004_864_519_280_709, 2_305_843_009_213_693_952)) by (compute);
693            assert(crate::round::round_frac(PI_NUM as int, 4 * PI_DEN as int, crate::types::Dir::Nearest).n() > 0) by (compute);
694        },
695        (Q::PosInf, Q::NegInf) => {
696            Rat::lemma_from_raw_spec_components(339_563_412_097_365_133, 144_115_188_075_855_872);
697            assert(crate::round::round_frac(3 * PI_NUM as int, 4 * PI_DEN as int, crate::types::Dir::Nearest)
698                == Rat::from_raw_spec(339_563_412_097_365_133, 144_115_188_075_855_872)) by (compute);
699            assert(crate::round::round_frac(3 * PI_NUM as int, 4 * PI_DEN as int, crate::types::Dir::Nearest).n() > 0) by (compute);
700        },
701        (Q::NegInf, Q::PosInf) => {
702            Rat::lemma_from_raw_spec_components(-1_811_004_864_519_280_709i64, 2_305_843_009_213_693_952);
703            assert(crate::round::round_frac(-(PI_NUM as int), 4 * PI_DEN as int, crate::types::Dir::Nearest)
704                == Rat::from_raw_spec(-1_811_004_864_519_280_709i64, 2_305_843_009_213_693_952)) by (compute);
705            assert(crate::round::round_frac(-(PI_NUM as int), 4 * PI_DEN as int, crate::types::Dir::Nearest).n() < 0) by (compute);
706        },
707        (Q::NegInf, Q::NegInf) => {
708            Rat::lemma_from_raw_spec_components(-339_563_412_097_365_133i64, 144_115_188_075_855_872);
709            assert(crate::round::round_frac(-(3 * PI_NUM as int), 4 * PI_DEN as int, crate::types::Dir::Nearest)
710                == Rat::from_raw_spec(-339_563_412_097_365_133i64, 144_115_188_075_855_872)) by (compute);
711            assert(crate::round::round_frac(-(3 * PI_NUM as int), 4 * PI_DEN as int, crate::types::Dir::Nearest).n() < 0) by (compute);
712        },
713        _ => assert(false),
714    }
715}
716
717/// The infinite-coordinate \`atan2\` targets lie in their mathematical quadrants.
718pub proof fn lemma_atan2_inf_target_quadrant(y: Q, x: Q)
719    requires
720        y.spec_is_infinite(),
721        x.spec_is_infinite(),
722    ensures
723        y == Q::PosInf && x == Q::PosInf ==> crate::model::q_lt_frac(atan2_inf_target(y, x), PI_NUM as int, 2 * PI_DEN as int),
724        y == Q::PosInf && x == Q::NegInf ==> crate::model::q_lt_frac(atan2_inf_target(y, x), PI_NUM as int, PI_DEN as int)
725            && crate::model::q_ge_frac(atan2_inf_target(y, x), PI_NUM as int, 2 * PI_DEN as int),
726        y == Q::NegInf && x == Q::PosInf ==> crate::model::q_ge_frac(atan2_inf_target(y, x), -(PI_NUM as int), 2 * PI_DEN as int),
727        y == Q::NegInf && x == Q::NegInf ==> crate::model::q_lt_frac(atan2_inf_target(y, x), -(PI_NUM as int), 2 * PI_DEN as int)
728            && crate::model::q_ge_frac(atan2_inf_target(y, x), -(PI_NUM as int), PI_DEN as int),
729{
730    match (y, x) {
731        (Q::PosInf, Q::PosInf) => {
732            Rat::lemma_from_raw_spec_components(1_811_004_864_519_280_709, 2_305_843_009_213_693_952);
733            assert(crate::round::round_frac(PI_NUM as int, 4 * PI_DEN as int, crate::types::Dir::Nearest)
734                == Rat::from_raw_spec(1_811_004_864_519_280_709, 2_305_843_009_213_693_952)) by (compute);
735            assert(crate::model::q_lt_frac(
736                crate::round::round_frac(PI_NUM as int, 4 * PI_DEN as int, crate::types::Dir::Nearest), PI_NUM as int, 2 * PI_DEN as int)) by (compute);
737        },
738        (Q::PosInf, Q::NegInf) => {
739            Rat::lemma_from_raw_spec_components(339_563_412_097_365_133, 144_115_188_075_855_872);
740            assert(crate::round::round_frac(3 * PI_NUM as int, 4 * PI_DEN as int, crate::types::Dir::Nearest)
741                == Rat::from_raw_spec(339_563_412_097_365_133, 144_115_188_075_855_872)) by (compute);
742            assert(crate::model::q_lt_frac(crate::round::round_frac(3 * PI_NUM as int, 4 * PI_DEN as int, crate::types::Dir::Nearest), PI_NUM as int, PI_DEN as int)) by (compute);
743            assert(crate::model::q_ge_frac(crate::round::round_frac(3 * PI_NUM as int, 4 * PI_DEN as int, crate::types::Dir::Nearest), PI_NUM as int, 2 * PI_DEN as int)) by (compute);
744        },
745        (Q::NegInf, Q::PosInf) => {
746            Rat::lemma_from_raw_spec_components(-1_811_004_864_519_280_709i64, 2_305_843_009_213_693_952);
747            assert(crate::round::round_frac(-(PI_NUM as int), 4 * PI_DEN as int, crate::types::Dir::Nearest)
748                == Rat::from_raw_spec(-1_811_004_864_519_280_709i64, 2_305_843_009_213_693_952)) by (compute);
749            assert(crate::model::q_ge_frac(
750                crate::round::round_frac(-(PI_NUM as int), 4 * PI_DEN as int, crate::types::Dir::Nearest), -(PI_NUM as int), 2 * PI_DEN as int)) by (compute);
751        },
752        (Q::NegInf, Q::NegInf) => {
753            Rat::lemma_from_raw_spec_components(-339_563_412_097_365_133i64, 144_115_188_075_855_872);
754            assert(crate::round::round_frac(-(3 * PI_NUM as int), 4 * PI_DEN as int, crate::types::Dir::Nearest)
755                == Rat::from_raw_spec(-339_563_412_097_365_133i64, 144_115_188_075_855_872)) by (compute);
756            assert(crate::model::q_lt_frac(crate::round::round_frac(-(3 * PI_NUM as int), 4 * PI_DEN as int, crate::types::Dir::Nearest), -(PI_NUM as int), 2 * PI_DEN as int)) by (compute);
757            assert(crate::model::q_ge_frac(crate::round::round_frac(-(3 * PI_NUM as int), 4 * PI_DEN as int, crate::types::Dir::Nearest), -(PI_NUM as int), PI_DEN as int)) by (compute);
758        },
759        _ => assert(false),
760    }
761}
762
763/// `round(num · 2^63 / den)`, for `|x| <= EXP_ARG_LIMIT`; fits `i128`.
764#[allow(unused_variables)]
765fn fx_to_grid(x: Rat) -> (r: i128)
766    requires
767        x.wf(),
768        crate::model::abs_int(x.n()) <= (EXP_ARG_LIMIT as int) * x.d(),
769    ensures
770        crate::model::abs_int(r as int) <= 406000000000000000000i128 as int,
771{
772    proof {
773        crate::model::lemma_max_mag_pow2();
774        crate::model::lemma_pow2_125();
775        crate::model::lemma_pow2_63();
776        assert(crate::model::abs_int((x.n()) * (crate::fx::FX_ONE as int)) <= 405828369621610135552
777            * (x.d())) by (nonlinear_arith)
778            requires
779                crate::model::abs_int(x.n()) <= (EXP_ARG_LIMIT as int) * x.d(),
780                x.d() > 0,
781                (crate::fx::FX_ONE as int) == 9223372036854775808,
782                (EXP_ARG_LIMIT as int) == 44,
783        ;
784    }
785    let raw: i128 = x.numerator() as i128;
786    let d: i128 = x.denominator() as i128;
787    let neg: bool = raw < 0;
788    let m: i128 = if neg {
789        0 - raw
790    } else {
791        raw
792    };
793    let scaled: i128 = m * crate::fx::FX_ONE;
794    let q: i128 = scaled / d;
795    let rem: i128 = scaled % d;
796    proof {
797        assert(m as int >= 0);
798        lemma_fx_to_grid_decomposition(m as int, d as int, q as int, rem as int);
799        assert((q as int) <= 405828369621610135552) by (nonlinear_arith)
800            requires
801                (m as int) * (crate::fx::FX_ONE as int)
802                    == (q as int) * (d as int) + (rem as int),
803                (rem as int) >= 0,
804                (d as int) >= 1,
805                (m as int) * (crate::fx::FX_ONE as int)
806                    <= 405828369621610135552 * (d as int),
807        ;
808        assert((rem as int) * 2 < 9223372036854775808) by (nonlinear_arith)
809            requires
810                (rem as int) < (d as int),
811                (d as int) <= crate::model::max_mag(),
812                crate::model::max_mag() < 4611686018427387904,
813        ;
814    }
815    let twice_rem: i128 = rem * 2;
816    let round_up: bool = twice_rem > d || (twice_rem == d && q % 2 == 1);
817    let rounded: i128 = if round_up { q + 1 } else { q };
818    proof {
819        assert((rounded as int) == if 2 * (rem as int) > (d as int)
820            || (2 * (rem as int) == (d as int) && (q as int) % 2 == 1) {
821            (q as int) + 1
822        } else {
823            q as int
824        });
825        lemma_fx_to_grid_nearest(m as int, d as int, q as int, rem as int, rounded as int);
826        lemma_fx_to_grid_ties_even(m as int, d as int, q as int, rem as int, rounded as int);
827        lemma_fx_to_grid_bound(
828            m as int,
829            d as int,
830            q as int,
831            rem as int,
832            rounded as int,
833            neg,
834        );
835    }
836    if neg {
837        0 - rounded
838    } else {
839        rounded
840    }
841}
842
843/// `t / 4`, rounded, which brings the fixed-point mantissa inside `i64`.
844///
845/// The mantissa is at most `1.6 · 2^63`. A quarter of that is `1.6 · 2^61`,
846/// which is below `MAX_MAG`, and the denominator becomes `2^61`.
847fn fx_quarter(t: i128) -> (r: i64)
848    requires
849        crate::model::abs_int(t as int) <= crate::fx::FX_T_MAX as int,
850    ensures
851        crate::model::abs_int(r as int) <= crate::model::max_mag(),
852{
853    proof {
854        crate::model::lemma_max_mag_pow2();
855    }
856    let neg: bool = t < 0;
857    let m: i128 = if neg {
858        0 - t
859    } else {
860        t
861    };
862    let q: i128 = (m + 2) / 4;
863    proof {
864        vstd::arithmetic::div_mod::lemma_fundamental_div_mod((m as int) + 2, 4int);
865        vstd::arithmetic::div_mod::lemma_mod_bound((m as int) + 2, 4int);
866        assert((q as int) <= crate::model::max_mag()) by (nonlinear_arith)
867            requires
868                ((m as int) + 2) == 4 * (q as int) + (((m as int) + 2) % 4),
869                (((m as int) + 2) % 4) >= 0,
870                (m as int) <= 14757395258967641292,
871                crate::model::max_mag() == 4611686018427387903,
872        ;
873    }
874    if neg {
875        (0 - q) as i64
876    } else {
877        q as i64
878    }
879}
880
881/// `2^m` as a `Q`, saturating where the exponent leaves the budget.
882///
883/// `|m| <= 66`, and `2^62` is already past `MAX_MAG`, thus an exponent at or
884/// above `62` saturates and one at or below `-62` underflows to zero. Both are
885/// the same answers the argument limit gives for `exp` itself.
886fn pow2_q(m: i32) -> (r: Q)
887    ensures
888        r.wf(),
889{
890    if m >= 62 {
891        Q::PosSat
892    } else if m <= -62 {
893        Q::zero()
894    } else if m >= 0 {
895        Q::new(1i64 << (m as u32), 1)
896    } else {
897        Q::new(1, 1i64 << ((0 - m) as u32))
898    }
899}
900
901
902/// A small grid value as a `Q`: `v · 2^-63`, for `|v| <= 2^63`.
903///
904/// The mantissa logarithm is at most `ln 2 / 2` in magnitude, so a shift of two
905/// brings it inside `i64` with the denominator at `2^61`, and the pair is then
906/// an ordinary `Rat`.
907fn fx_small_to_q(v: i128) -> (r: Q)
908    requires
909        crate::model::abs_int(v as int) <= 10350000000000000000i128 as int,
910    ensures
911        r.wf(),
912{
913    proof {
914        crate::model::lemma_max_mag_pow2();
915    }
916    let neg: bool = v < 0;
917    let m: i128 = if neg {
918        0 - v
919    } else {
920        v
921    };
922    // Round to the `2^-61` grid, which is where the crate's own contract sits.
923    let q: i128 = (m + 2) / 4;
924    proof {
925        vstd::arithmetic::div_mod::lemma_fundamental_div_mod((m as int) + 2, 4int);
926        vstd::arithmetic::div_mod::lemma_mod_bound((m as int) + 2, 4int);
927        assert((q as int) <= 2600000000000000000) by (nonlinear_arith)
928            requires
929                ((m as int) + 2) == 4 * (q as int) + (((m as int) + 2) % 4),
930                (((m as int) + 2) % 4) >= 0,
931                (m as int) <= 10350000000000000000,
932        ;
933    }
934    let num: i128 = if neg {
935        0 - q
936    } else {
937        q
938    };
939    // `Q::new` is total: a numerator past the budget saturates rather than
940    // failing, and this one is inside it whenever the caller's bound holds.
941    Q::new(num as i64, 1i64 << 61)
942}
943
944impl Q {
945    /// `e^self`. `PosSat` above `43.67` (where `e^x > MAX_MAG`), `0` below
946    /// `-44`; `exp(NegSat)` is `Nan` because the image `(0, e^-MAX_MAG)` does
947    /// not contain zero, whereas underflow of a `Number` is inside R3.
948    /// Evaluated by [`crate::fx::fx_exp_reduced`] and reassembled here; the
949    /// `m >= 62` branch keeps results between `2^61` and `MAX_MAG` numeric.
950    ///
951    /// Accuracy is measured, not proven.
952    ///
953    /// ```
954    /// use the_q::Q;
955    ///
956    /// let e2 = Q::new(2, 1).exp();
957    /// if let Q::Number(x) = e2 {
958    ///     assert!((the_q::to_f64(x) - 7.38905609893065).abs() < 1e-9);
959    /// } else {
960    ///     panic!("expected a number");
961    /// }
962    /// assert_eq!(Q::new(100, 1).exp(), Q::PosSat);
963    /// ```
964    pub fn exp(self) -> (r: Q)
965        requires
966            self.wf(),
967        ensures
968            r.wf(),
969            self.spec_is_nan() ==> r.spec_is_nan(),
970    {
971        match self {
972            Q::PosSat => Q::PosSat,
973            Q::NegSat => Q::Nan,
974            Q::PosInf => Q::PosInf,
975            Q::NegInf => Q::zero(),
976            Q::Nan => Q::Nan,
977            Q::Number(x) => {
978                // The argument limit, tested on the components rather than
979                // through the order. The conversion below needs the bound in
980                // exactly this form, and `|num| <= 44 · den` *is* `|x| <= 44`
981                // for a positive denominator.
982                proof {
983                    crate::model::lemma_max_mag_pow2();
984                    assert(44int * x.d() <= 202914184810805067732) by (nonlinear_arith)
985                        requires
986                            x.d() <= 4611686018427387903,
987                    ;
988                }
989                let lim: i128 = (EXP_ARG_LIMIT as i128) * (x.denominator() as i128);
990                let axn: i128 = if x.numerator() < 0 {
991                    0 - (x.numerator() as i128)
992                } else {
993                    x.numerator() as i128
994                };
995                if axn > lim {
996                    return if x.numerator() > 0 {
997                        Q::PosSat
998                    } else {
999                        Q::zero()
1000                    };
1001                }
1002                // The argument on the fixed-point grid. `|x| <= 44` and
1003                // `x.den >= 1`, thus the scaled numerator is inside `i128`.
1004                let xg: i128 = fx_to_grid(x);
1005                let (t, m) = crate::fx::fx_exp_reduced(xg);
1006                // The value is `t · 2^(m-63)` with `|t| <= 1.6 · 2^63`.
1007                if m >= 62 {
1008                    // `2^m` alone is outside the budget, but the value may
1009                    // not be: assemble it as an integer and let the budget
1010                    // decide. `m <= 66`, so the multiplier is at most 8.
1011                    let v: i128 = if m == 62 {
1012                        (t + 1) / 2
1013                    } else {
1014                        let pow: i128 = if m == 63 {
1015                            1
1016                        } else if m == 64 {
1017                            2
1018                        } else if m == 65 {
1019                            4
1020                        } else {
1021                            8
1022                        };
1023                        proof {
1024                            assert(crate::model::abs_int((t as int) * (pow as int))
1025                                <= 8 * (crate::fx::FX_T_MAX as int)) by (nonlinear_arith)
1026                                requires
1027                                    crate::model::abs_int(t as int) <= crate::fx::FX_T_MAX as int,
1028                                    1 <= pow as int <= 8,
1029                            ;
1030                        }
1031                        t * pow
1032                    };
1033                    let mm: i128 = crate::types::MAX_MAG as i128;
1034                    if v > mm {
1035                        Q::PosSat
1036                    } else if v < 0 - mm {
1037                        Q::NegSat
1038                    } else {
1039                        Q::new(v as i64, 1)
1040                    }
1041                } else if m <= -62 {
1042                    // Below `2^-62` everything rounds to zero. At `m == -62`
1043                    // the value is `fx_quarter(t) · 2^-123`, which rounds to
1044                    // `2^-61` exactly when `fx_quarter(t) > 2^61` (a tie at
1045                    // `2^61` goes to the even neighbour, zero).
1046                    let q4: i64 = fx_quarter(t);
1047                    if m == -62 && q4 > (1i64 << 61) {
1048                        Q::new(1, 1i64 << 61)
1049                    } else {
1050                        Q::zero()
1051                    }
1052                } else {
1053                    // A shift of two brings `t` inside the budget with the
1054                    // denominator at `2^61`.
1055                    let mant = Q::new(fx_quarter(t), 1i64 << 61);
1056                    Q::mul(pow2_q(m), mant)
1057                }
1058            },
1059        }
1060    }
1061}
1062
1063/// Bound on the binary range reduction in [`Q::ln`].
1064///
1065/// Every representable value lies in `[1/MAX_MAG, MAX_MAG]`, and `MAX_MAG` is
1066/// below `2^62`, so sixty-three doublings or halvings always reach `[1/2, 2]`.
1067/// Sixty-four is carried for margin and makes the loops trivially terminating.
1068const MAX_BINARY_SHIFTS: u32 = 64;
1069
1070/// `atanh(z)` for `|z| <= 1/3`; the twentieth term at `1/3` is `3e-21`, below
1071/// the grid.
1072fn atanh_series(z: Q) -> (r: Q)
1073    requires
1074        z.wf(),
1075    ensures
1076        r.wf(),
1077{
1078    let z2 = Q::mul(z, z);
1079    let mut term = z;
1080    let mut sum = z;
1081    let mut k: u32 = 1;
1082    while k < SERIES_TERMS
1083        invariant
1084            term.wf(),
1085            sum.wf(),
1086            z2.wf(),
1087            1 <= k <= SERIES_TERMS,
1088        decreases SERIES_TERMS - k,
1089    {
1090        term = Q::mul(term, z2);
1091        sum = Q::add(sum, Q::div(term, Q::new((2 * k + 1) as i64, 1)));
1092        k = k + 1;
1093    }
1094    sum
1095}
1096
1097/// `e` by `Σ 1/n!`, independently of `exp`; the derivation of [`e`].
1098///
1099/// Public only because Verus's visibility rules require it; not part of the
1100/// semver-stable API. Bit-identical to [`e`] (see `e_is_the_series_value`).
1101///
1102/// ```
1103/// use the_q::transcendental::{e, e_series};
1104///
1105/// assert_eq!(e_series(), e());
1106/// ```
1107pub fn e_series() -> (r: Q)
1108    ensures
1109        r.wf(),
1110{
1111    let mut term = Q::one();
1112    let mut sum = Q::one();
1113    let mut i: u32 = 1;
1114    while i <= SERIES_TERMS
1115        invariant
1116            term.wf(),
1117            sum.wf(),
1118            1 <= i <= SERIES_TERMS + 1,
1119        decreases SERIES_TERMS + 1 - i,
1120    {
1121        term = Q::div(term, Q::new(i as i64, 1));
1122        sum = Q::add(sum, term);
1123        i = i + 1;
1124    }
1125    sum
1126}
1127
1128/// `e`, the base of the natural logarithm.
1129///
1130/// The literal is the value that [`e_series`] computes. The test
1131/// `e_is_the_series_value` asserts that the two are bit-identical. See [`ln2`]
1132/// for the reason to use a checked literal instead of a series call.
1133///
1134/// ```
1135/// use the_q::Q;
1136/// use the_q::transcendental::e;
1137///
1138/// if let Q::Number(x) = e() {
1139///     assert!((the_q::to_f64(x) - std::f64::consts::E).abs() < 1e-9);
1140/// } else {
1141///     panic!("expected a number");
1142/// }
1143/// ```
1144pub fn e() -> (r: Q)
1145    ensures
1146        r.wf(),
1147{
1148    Q::new(3133965575612453543, 1152921504606846976)
1149}
1150
1151/// `ln(2)`, by the series `2·atanh(1/3)`.
1152///
1153/// This function is the derivation of [`ln2`], which returns the same value as
1154/// a literal. Twenty series terms on each call dominate the cost of each
1155/// caller, thus [`ln2`] uses the literal.
1156///
1157/// Public only because Verus's visibility rules require it; not part of the
1158/// semver-stable API. Bit-identical to [`ln2`] (see `ln2_is_the_series_value`).
1159///
1160/// ```
1161/// use the_q::transcendental::{ln2, ln2_series};
1162///
1163/// assert_eq!(ln2_series(), ln2());
1164/// ```
1165pub fn ln2_series() -> (r: Q)
1166    ensures
1167        r.wf(),
1168{
1169    Q::mul(Q::new(2, 1), atanh_series(Q::new(1, 3)))
1170}
1171
1172/// `ln 2` as a literal; `ln2_is_the_series_value` checks it against
1173/// [`ln2_series`] bit for bit.
1174///
1175/// ```
1176/// use the_q::Q;
1177/// use the_q::transcendental::ln2;
1178///
1179/// if let Q::Number(x) = ln2() {
1180///     assert!((the_q::to_f64(x) - std::f64::consts::LN_2).abs() < 1e-9);
1181/// } else {
1182///     panic!("expected a number");
1183/// }
1184/// ```
1185pub fn ln2() -> (r: Q)
1186    ensures
1187        r.wf(),
1188{
1189    Q::new(399572145162582989, 576460752303423488)
1190}
1191
1192impl Q {
1193    /// The natural logarithm. `ln(0)` is `NegInf`; negative and `PosSat` are
1194    /// `Nan`. Binary reduction to `m ∈ [1/2, 2]`, then
1195    /// `ln(m) = 2·atanh((m-1)/(m+1))` with `|argument| <= 1/3`, plus `k·ln 2`.
1196    ///
1197    /// ```
1198    /// use the_q::Q;
1199    ///
1200    /// assert_eq!(Q::one().ln(), Q::zero());
1201    /// assert_eq!(Q::zero().ln(), Q::NegInf);
1202    /// assert_eq!(Q::new(-1, 1).ln(), Q::Nan);
1203    /// ```
1204    pub fn ln(self) -> (r: Q)
1205        requires
1206            self.wf(),
1207        ensures
1208            r.wf(),
1209            self.spec_is_nan() ==> r.spec_is_nan(),
1210    {
1211        match self {
1212            Q::PosSat => Q::Nan,
1213            Q::NegSat => Q::Nan,
1214            Q::PosInf => Q::PosInf,
1215            Q::NegInf => Q::Nan,
1216            Q::Nan => Q::Nan,
1217            Q::Number(x) => {
1218                let s = x.signum();
1219                if s < 0 {
1220                    return Q::Nan;
1221                }
1222                if s == 0 {
1223                    return Q::NegInf;
1224                }
1225                let two = Q::new(2, 1);
1226                let half = Q::new(1, 2);
1227                let mut m = Q::Number(x);
1228                let mut up: u32 = 0;
1229                while up < MAX_BINARY_SHIFTS && Q::gt(m, two)
1230                    invariant
1231                        m.wf(),
1232                        two.wf(),
1233                        half.wf(),
1234                        up <= MAX_BINARY_SHIFTS,
1235                    decreases MAX_BINARY_SHIFTS - up,
1236                {
1237                    m = Q::div(m, two);
1238                    up = up + 1;
1239                }
1240                let mut down: u32 = 0;
1241                while down < MAX_BINARY_SHIFTS && Q::lt(m, half)
1242                    invariant
1243                        m.wf(),
1244                        two.wf(),
1245                        half.wf(),
1246                        down <= MAX_BINARY_SHIFTS,
1247                    decreases MAX_BINARY_SHIFTS - down,
1248                {
1249                    m = Q::mul(m, two);
1250                    down = down + 1;
1251                }
1252                // z = (m - 1) / (m + 1), in [-1/3, 1/3] for m in [1/2, 2].
1253                //
1254                // Integers, not a quantised mantissa: near one the difference cancels the
1255                // leading bits, and a quantised mantissa has nothing under them.
1256                let (mn, md): (i64, i64) = match m {
1257                    Q::Number(r) => (r.numerator(), r.denominator()),
1258                    // Unreachable: halving and doubling a positive number
1259                    // toward `[1/2, 2]` cannot leave the representable range.
1260                    // Answering `Nan` keeps the function total without a proof
1261                    // about the loops above.
1262                    _ => {
1263                        return Q::Nan;
1264                    },
1265                };
1266                proof {
1267                    crate::model::lemma_max_mag_pow2();
1268                }
1269                // The near-one branch.
1270                //
1271                // The kernel's error is `2^-63` absolute, which is a large relative error
1272                // for a result near zero; within `2^-8` of one the exact rational path keeps
1273                // the low bits (see README for measured accuracy).
1274                let diff: i128 = (mn as i128) - (md as i128);
1275                let adiff: i128 = if diff < 0 {
1276                    0 - diff
1277                } else {
1278                    diff
1279                };
1280                let near_one: bool = up == 0 && down == 0 && adiff * 256 < (md as i128);
1281                let ln_m = if near_one {
1282                    let one = Q::one();
1283                    let z = Q::div(Q::sub(m, one), Q::add(m, one));
1284                    Q::mul(Q::new(2, 1), atanh_series(z))
1285                } else {
1286                    if mn <= 0 {
1287                        return Q::Nan;
1288                    }
1289                    let zg: i128 = crate::fx::fx_ratio_z(mn as i128, md as i128);
1290                    // `ln(m) = 2·atanh(z)`. The doubling happens in `Q` rather
1291                    // than on the grid, so the grid value stays inside the
1292                    // budget of the `Rat` it becomes.
1293                    Q::mul(Q::new(2, 1), fx_small_to_q(crate::fx::fx_atanh_series(zg)))
1294                };
1295                // k is the net number of doublings undone; `up` and `down` are
1296                // never both nonzero, so this cannot overflow an i64.
1297                let k = Q::sub(Q::new(up as i64, 1), Q::new(down as i64, 1));
1298                Q::add(ln_m, Q::mul(k, ln2()))
1299            },
1300        }
1301    }
1302
1303    /// `self^e`; `pow_i32(a, -n)` is `recip(pow_u32(a, n))`, so `pow_i32(0, -1)`
1304    /// is `PosInf`.
1305    ///
1306    /// ```
1307    /// use the_q::Q;
1308    ///
1309    /// assert_eq!(Q::new(2, 1).pow_i32(3), Q::new(8, 1));
1310    /// assert_eq!(Q::zero().pow_i32(-1), Q::PosInf);
1311    /// ```
1312    pub fn pow_i32(self, e: i32) -> (r: Q)
1313        requires
1314            self.wf(),
1315        ensures
1316            r.wf(),
1317    {
1318        if e >= 0 {
1319            self.pow_u32(e as u32)
1320        } else {
1321            // `-e` for `e == i32::MIN` would overflow, so widen first.
1322            let n: i64 = -(e as i64);
1323            self.pow_u32(n as u32).recip()
1324        }
1325    }
1326}
1327
1328/// Terms of the `atan` series on `|z| <= 1/2`: the tail at `k = 28` is
1329/// `1.2e-19`, below the grid; the series converges only geometrically.
1330const ATAN_TERMS: u32 = 30;
1331
1332/// Largest `|x|` that `sin`, `cos`, `tan` accept; beyond it they return `Nan`.
1333/// The reduction `x mod π/2` uses one word of `π`, so the reduced argument has
1334/// absolute error about `|x| · 2^-60`: `2^-40` at the limit, measured.
1335const TRIG_ARG_LIMIT: i64 = 1 << 20;
1336
1337/// `atan(z) = z − z³/3 + z⁵/5 − …`, for `|z| <= 1/2`.
1338///
1339/// This series is the alternating form of [`atanh_series`]. Subtraction and
1340/// addition alternate between terms.
1341fn atan_series(z: Q) -> (r: Q)
1342    requires
1343        z.wf(),
1344    ensures
1345        r.wf(),
1346{
1347    let z2 = Q::mul(z, z);
1348    let mut term = z;
1349    let mut sum = z;
1350    let mut k: u32 = 1;
1351    while k < ATAN_TERMS
1352        invariant
1353            term.wf(),
1354            sum.wf(),
1355            z2.wf(),
1356            1 <= k <= ATAN_TERMS,
1357        decreases ATAN_TERMS - k,
1358    {
1359        term = Q::mul(term, z2);
1360        let piece = Q::div(term, Q::new((2 * k + 1) as i64, 1));
1361        sum = if k % 2 == 1 {
1362            Q::sub(sum, piece)
1363        } else {
1364            Q::add(sum, piece)
1365        };
1366        k = k + 1;
1367    }
1368    sum
1369}
1370
1371/// `π` by Machin, `16·atan(1/5) − 4·atan(1/239)`; the derivation of [`pi`].
1372///
1373/// Public only because Verus's visibility rules require it; not part of the
1374/// semver-stable API. Bit-identical to [`pi`] (see `pi_is_the_series_value`).
1375///
1376/// ```
1377/// use the_q::transcendental::{pi, pi_series};
1378///
1379/// assert_eq!(pi_series(), pi());
1380/// ```
1381pub fn pi_series() -> (r: Q)
1382    ensures
1383        r.wf(),
1384{
1385    let a = Q::mul(Q::new(16, 1), atan_series(Q::new(1, 5)));
1386    let b = Q::mul(Q::new(4, 1), atan_series(Q::new(1, 239)));
1387    Q::sub(a, b)
1388}
1389
1390/// `π`.
1391///
1392/// The literal is the value that [`pi_series`] computes. The test
1393/// `pi_is_the_series_value` asserts that the two are bit-identical. See [`ln2`]
1394/// for the reason to use a checked literal.
1395///
1396/// ```
1397/// use the_q::Q;
1398/// use the_q::transcendental::pi;
1399///
1400/// if let Q::Number(x) = pi() {
1401///     assert!((the_q::to_f64(x) - std::f64::consts::PI).abs() < 1e-9);
1402/// } else {
1403///     panic!("expected a number");
1404/// }
1405/// ```
1406pub fn pi() -> (r: Q)
1407    ensures
1408        r.wf(),
1409{
1410    Q::new(PI_NUM, PI_DEN)
1411}
1412
1413/// `π/2`.
1414///
1415/// ```
1416/// use the_q::Q;
1417/// use the_q::transcendental::{half_pi, pi};
1418///
1419/// assert_eq!(half_pi(), Q::div(pi(), Q::new(2, 1)));
1420/// ```
1421pub fn half_pi() -> (r: Q)
1422    ensures
1423        r.wf(),
1424{
1425    Q::div(pi(), Q::new(2, 1))
1426}
1427
1428/// Nearest integer to a `Q`, ties away from zero; `0` for any special.
1429///
1430/// Only used on values already known to be small, so the `i64` arithmetic
1431/// cannot overflow: `|num| <= MAX_MAG` and `den/2 <= MAX_MAG/2` make the sum at
1432/// most `1.5 · MAX_MAG`.
1433fn round_to_int(q: Q) -> (r: i64)
1434    requires
1435        q.wf(),
1436{
1437    match q {
1438        Q::Number(x) => {
1439            let n = x.numerator();
1440            let d = x.denominator();
1441            if n >= 0 {
1442                (n + d / 2) / d
1443            } else {
1444                (n - d / 2) / d
1445            }
1446        },
1447        _ => 0,
1448    }
1449}
1450
1451/// `sin(z)` by Maclaurin series, for `|z| <= π/4`.
1452fn sin_series(z: Q) -> (r: Q)
1453    requires
1454        z.wf(),
1455    ensures
1456        r.wf(),
1457{
1458    let z2 = Q::mul(z, z);
1459    let mut term = z;
1460    let mut sum = z;
1461    let mut k: u32 = 1;
1462    while k < TRIG_TERMS
1463        invariant
1464            term.wf(),
1465            sum.wf(),
1466            z2.wf(),
1467            1 <= k <= TRIG_TERMS,
1468        decreases TRIG_TERMS - k,
1469    {
1470        // term_{k} = term_{k-1} · z² / ((2k)(2k+1))
1471        let kk: i64 = k as i64;
1472        assert(1 <= kk <= TRIG_TERMS as i64);
1473        // `kk <= 20`, so the product is at most `40 * 41`. The prover needs
1474        // this spelled out: a product of two bounded terms is nonlinear.
1475        assert(2 * kk * (2 * kk + 1) <= 40 * 41) by (nonlinear_arith)
1476            requires
1477                1 <= kk <= 11,
1478        ;
1479        let d = Q::new(2 * kk * (2 * kk + 1), 1);
1480        term = Q::div(Q::mul(term, z2), d);
1481        sum = if k % 2 == 1 {
1482            Q::sub(sum, term)
1483        } else {
1484            Q::add(sum, term)
1485        };
1486        k = k + 1;
1487    }
1488    sum
1489}
1490
1491/// `cos(z)` by Maclaurin series, for `|z| <= π/4`.
1492fn cos_series(z: Q) -> (r: Q)
1493    requires
1494        z.wf(),
1495    ensures
1496        r.wf(),
1497{
1498    let z2 = Q::mul(z, z);
1499    let mut term = Q::one();
1500    let mut sum = Q::one();
1501    let mut k: u32 = 1;
1502    while k < TRIG_TERMS
1503        invariant
1504            term.wf(),
1505            sum.wf(),
1506            z2.wf(),
1507            1 <= k <= TRIG_TERMS,
1508        decreases TRIG_TERMS - k,
1509    {
1510        // term_{k} = term_{k-1} · z² / ((2k-1)(2k))
1511        let kk: i64 = k as i64;
1512        assert(1 <= kk <= TRIG_TERMS as i64);
1513        assert((2 * kk - 1) * (2 * kk) <= 39 * 40) by (nonlinear_arith)
1514            requires
1515                1 <= kk <= 11,
1516        ;
1517        let d = Q::new((2 * kk - 1) * (2 * kk), 1);
1518        term = Q::div(Q::mul(term, z2), d);
1519        sum = if k % 2 == 1 {
1520            Q::sub(sum, term)
1521        } else {
1522            Q::add(sum, term)
1523        };
1524        k = k + 1;
1525    }
1526    sum
1527}
1528
1529impl Q {
1530    /// The arctangent in `(-π/2, π/2)`; `atan(±∞) = ±π/2`, `atan(PosSat)` is
1531    /// `Nan`. Reduced by `|x| > 1 → π/2 − atan(1/x)` and
1532    /// `|x| > 1/2 → π/4 + atan((x−1)/(x+1))` to `|x| <= 1/2` before the series.
1533    ///
1534    /// ```
1535    /// use the_q::Q;
1536    /// use the_q::transcendental::half_pi;
1537    ///
1538    /// assert_eq!(Q::PosInf.atan(), half_pi());
1539    /// assert_eq!(Q::PosSat.atan(), Q::Nan);
1540    /// ```
1541    pub fn atan(self) -> (r: Q)
1542        requires
1543            self.wf(),
1544        ensures
1545            r.wf(),
1546            self.spec_is_nan() ==> r.spec_is_nan(),
1547    {
1548        match self {
1549            Q::Nan => Q::Nan,
1550            Q::PosSat => Q::Nan,
1551            Q::NegSat => Q::Nan,
1552            Q::PosInf => half_pi(),
1553            Q::NegInf => half_pi().neg(),
1554            Q::Number(x) => {
1555                let q = Q::Number(x);
1556                let one = Q::one();
1557                let half = Q::new(1, 2);
1558                // One `pi()` for both uses below; the reduction needs a quarter
1559                // and the reciprocal branch needs a half.
1560                let p = pi();
1561                let quarter_pi = Q::div(p, Q::new(4, 1));
1562                let big = Q::gt(q.abs(), one);
1563                // Reduce |x| > 1 by reciprocation.
1564                let base = if big {
1565                    Q::div(one, q)
1566                } else {
1567                    q
1568                };
1569                // Reduce |base| > 1/2 by the tangent addition formula.
1570                let (core, shift) = if Q::gt(base, half) {
1571                    (Q::div(Q::sub(base, one), Q::add(base, one)), quarter_pi)
1572                } else if Q::lt(base, half.neg()) {
1573                    (Q::div(Q::add(base, one), Q::sub(one, base)), quarter_pi.neg())
1574                } else {
1575                    (base, Q::zero())
1576                };
1577                let inner = Q::add(atan_series(core), shift);
1578                if big {
1579                    // atan(x) = sign(x)·π/2 − atan(1/x)
1580                    let hp = Q::div(p, Q::new(2, 1));
1581                    if Q::gt(q, Q::zero()) {
1582                        Q::sub(hp, inner)
1583                    } else {
1584                        Q::sub(hp.neg(), inner)
1585                    }
1586                } else {
1587                    inner
1588                }
1589            },
1590        }
1591    }
1592
1593    /// The sine. `Nan` for `|x| > 2^20` and for every special. Reduction
1594    /// `r = x − round(x / (π/2)) · π/2`, then the series selected by `n mod 4`.
1595    ///
1596    /// ```
1597    /// use the_q::Q;
1598    ///
1599    /// assert_eq!(Q::zero().sin(), Q::zero());
1600    /// assert_eq!(Q::new((1i64 << 20) + 1, 1).sin(), Q::Nan);
1601    /// ```
1602    pub fn sin(self) -> (r: Q)
1603        requires
1604            self.wf(),
1605        ensures
1606            r.wf(),
1607    {
1608        Q::sin_cos(self, false)
1609    }
1610
1611    /// The cosine. Same domain and method as [`Q::sin`].
1612    ///
1613    /// ```
1614    /// use the_q::Q;
1615    ///
1616    /// assert_eq!(Q::zero().cos(), Q::one());
1617    /// assert_eq!(Q::new((1i64 << 20) + 1, 1).cos(), Q::Nan);
1618    /// ```
1619    pub fn cos(self) -> (r: Q)
1620        requires
1621            self.wf(),
1622        ensures
1623            r.wf(),
1624    {
1625        Q::sin_cos(self, true)
1626    }
1627
1628    /// The shared reduction for [`Q::sin`] and [`Q::cos`].
1629    ///
1630    /// `want_cos` selects the function to return. Both functions need the same
1631    /// argument reduction. One shared reduction keeps them consistent, which
1632    /// the identity `sin(x)² + cos(x)² == 1` needs.
1633    fn sin_cos(self, want_cos: bool) -> (r: Q)
1634        requires
1635            self.wf(),
1636        ensures
1637            r.wf(),
1638    {
1639        match self {
1640            Q::Number(x) => {
1641                let q = Q::Number(x);
1642                let limit = Q::new(TRIG_ARG_LIMIT, 1);
1643                if Q::gt(q.abs(), limit) {
1644                    return Q::Nan;
1645                }
1646                let hp = half_pi();
1647                let n = round_to_int(Q::div(q, hp));
1648                let r = Q::sub(q, Q::mul(Q::new(n, 1), hp));
1649                // `n mod 4`, normalised into 0..3 for negative `n` too.
1650                let m = ((n % 4) + 4) % 4;
1651                let idx = if want_cos {
1652                    (m + 1) % 4
1653                } else {
1654                    m
1655                };
1656                // sin(r + k·π/2) cycles sin, cos, −sin, −cos; cos is the same
1657                // cycle one quarter-turn ahead, which is what `idx` encodes.
1658                if idx == 0 {
1659                    sin_series(r)
1660                } else if idx == 1 {
1661                    cos_series(r)
1662                } else if idx == 2 {
1663                    sin_series(r).neg()
1664                } else {
1665                    cos_series(r).neg()
1666                }
1667            },
1668            // sin and cos have no limit at infinity, and no saturation state
1669            // can bound a value that oscillates in [-1, 1].
1670            _ => Q::Nan,
1671        }
1672    }
1673
1674    /// The tangent, as `sin/cos`.
1675    ///
1676    /// At an odd multiple of `π/2` the cosine is near zero. The quotient then
1677    /// saturates or gives an infinity, and does not trap. `tan` has a pole at
1678    /// those points.
1679    ///
1680    /// ```
1681    /// use the_q::Q;
1682    ///
1683    /// assert_eq!(Q::zero().tan(), Q::zero());
1684    /// assert_eq!(Q::new((1i64 << 20) + 1, 1).tan(), Q::Nan);
1685    /// ```
1686    pub fn tan(self) -> (r: Q)
1687        requires
1688            self.wf(),
1689        ensures
1690            r.wf(),
1691    {
1692        Q::div(self.sin(), self.cos())
1693    }
1694}
1695
1696
1697/// `ln(10)`, by applying [`Q::ln`] to ten.
1698///
1699/// The derivation of [`ln10`]; see [`ln2`] for why the value is pinned.
1700///
1701/// Public only because Verus's visibility rules require it; not part of the
1702/// semver-stable API. Bit-identical to [`ln10`] (see `ln10_is_the_series_value`).
1703///
1704/// ```
1705/// use the_q::transcendental::{ln10, ln10_series};
1706///
1707/// assert_eq!(ln10_series(), ln10());
1708/// ```
1709pub fn ln10_series() -> (r: Q)
1710    ensures
1711        r.wf(),
1712{
1713    Q::new(10, 1).ln()
1714}
1715
1716/// `ln 10` as a literal, checked against [`ln10_series`] by test.
1717///
1718/// ```
1719/// use the_q::Q;
1720/// use the_q::transcendental::ln10;
1721///
1722/// if let Q::Number(x) = ln10() {
1723///     assert!((the_q::to_f64(x) - std::f64::consts::LN_10).abs() < 1e-9);
1724/// } else {
1725///     panic!("expected a number");
1726/// }
1727/// ```
1728pub fn ln10() -> (r: Q)
1729    ensures
1730        r.wf(),
1731{
1732    Q::new(2654699869899991811, 1152921504606846976)
1733}
1734
1735
1736/// The `k <= 62` with `n == 2^k`, by comparison against the verified power
1737/// table (`round::pow2_i128`); `None` when there is none. Sixty-three
1738/// comparisons at most, so constant cost like the rest of this module.
1739fn pow2_exponent_i64(n: i64) -> (r: Option<u8>)
1740    ensures
1741        r.is_some() ==> r.unwrap() <= 62 && n == crate::model::pow2(r.unwrap() as nat),
1742        r.is_none() ==> forall|k: nat| k <= 62 ==> n != crate::model::pow2(k),
1743{
1744    let mut k: u32 = 0;
1745    let mut found: bool = false;
1746    while k <= 62 && !found
1747        invariant
1748            k <= 63,
1749            !found ==> forall|j: nat| j < k ==> n != crate::model::pow2(j),
1750            found ==> k <= 62 && n == crate::model::pow2(k as nat),
1751        decreases 63 - k + (if found { 0int } else { 1int }),
1752    {
1753        if crate::round::pow2_i128(k) == n as i128 {
1754            found = true;
1755        } else {
1756            k = k + 1;
1757        }
1758    }
1759    if found {
1760        Some(k as u8)
1761    } else {
1762        None
1763    }
1764}
1765
1766/// The `k <= 18` with `n == 10^k`, by comparison against the verified power
1767/// table (`q::pow10_i64`); `None` when there is none.
1768fn pow10_exponent_i64(n: i64) -> (r: Option<u8>)
1769    ensures
1770        r.is_some() ==> r.unwrap() <= 18 && n == crate::model::pow10(r.unwrap() as nat),
1771        r.is_none() ==> forall|k: nat| k <= 18 ==> n != crate::model::pow10(k),
1772{
1773    let mut k: u8 = 0;
1774    let mut found: bool = false;
1775    while k <= 18 && !found
1776        invariant
1777            k <= 19,
1778            !found ==> forall|j: nat| j < k ==> n != crate::model::pow10(j),
1779            found ==> k <= 18 && n == crate::model::pow10(k as nat),
1780        decreases 19 - k + (if found { 0int } else { 1int }),
1781    {
1782        if crate::q::pow10_i64(k) == n {
1783            found = true;
1784        } else {
1785            k = k + 1;
1786        }
1787    }
1788    if found {
1789        Some(k)
1790    } else {
1791        None
1792    }
1793}
1794
1795/// A small integer as a `Q`, with its value pinned. `Rat::from_int` cannot
1796/// fail below the budget, which `|i| <= 62` is far inside.
1797fn small_int_q(i: i64) -> (r: Q)
1798    requires
1799        -62 <= i <= 62,
1800    ensures
1801        r.wf(),
1802        r.spec_is_value(i as int, 1),
1803{
1804    match Rat::from_int(i) {
1805        Some(x) => Q::Number(x),
1806        None => {
1807            proof {
1808                assert(false);
1809            }
1810            Q::Nan
1811        },
1812    }
1813}
1814
1815impl Q {
1816    /// The base-2 logarithm. Exact at `2^k` and `1 / 2^k` for every power of
1817    /// two a `Rat` holds (`k <= 61`; `MAX_MAG` is `2^62 - 1`), where it
1818    /// returns the integer `k` (or `-k`); otherwise
1819    /// `ln(self) / ln(2)`, whose accuracy is measured, not proven.
1820    ///
1821    /// Without the exact path `log2(8)` is a rational within `2^-59` of `3`,
1822    /// not `3`: `ln(8)` mixes the runtime series value of `ln 2` with the
1823    /// stored `ln2()` literal, and the two differ by one grid unit. The
1824    /// exponent is found by comparison against the verified power table, so
1825    /// the exactness is a proven postcondition, not an accident of rounding.
1826    ///
1827    /// ```
1828    /// use the_q::Q;
1829    ///
1830    /// assert_eq!(Q::new(8, 1).log2(), Q::new(3, 1));
1831    /// assert_eq!(Q::new(1, 1024).log2(), Q::new(-10, 1));
1832    /// assert_eq!(Q::one().log2(), Q::zero());
1833    ///
1834    /// // Off the powers of two it is a series result near the true value.
1835    /// let Q::Number(x) = Q::new(10, 1).log2() else { panic!() };
1836    /// assert!((the_q::to_f64(x) - 10f64.log2()).abs() < 1e-15);
1837    /// assert_eq!(Q::zero().log2(), Q::NegInf);
1838    /// ```
1839    pub fn log2(self) -> (r: Q)
1840        requires
1841            self.wf(),
1842        ensures
1843            r.wf(),
1844            forall|k: nat| #![trigger crate::model::pow2(k)]
1845                k <= 62 && self.spec_is_value(crate::model::pow2(k), 1)
1846                    ==> r.spec_is_value(k as int, 1),
1847            forall|k: nat| #![trigger crate::model::pow2(k)]
1848                k <= 62 && self.spec_is_value(1, crate::model::pow2(k))
1849                    ==> r.spec_is_value(-(k as int), 1),
1850    {
1851        match self {
1852            Q::Number(x) => {
1853                let n = x.numerator();
1854                let d = x.denominator();
1855                if d == 1 {
1856                    if n >= 1 {
1857                        match pow2_exponent_i64(n) {
1858                            Some(k) => {
1859                                proof {
1860                                    assert forall|k2: nat| #![trigger crate::model::pow2(k2)]
1861                                        k2 <= 62 && self.spec_is_value(crate::model::pow2(k2), 1)
1862                                            implies k2 == k as nat by {
1863                                        crate::model::lemma_pow2_injective(k2, k as nat);
1864                                    }
1865                                    assert forall|k2: nat| #![trigger crate::model::pow2(k2)]
1866                                        k2 <= 62 && self.spec_is_value(1, crate::model::pow2(k2))
1867                                            implies k2 == 0 && k == 0 by {
1868                                        crate::model::lemma_pow2_injective(k2, 0);
1869                                        crate::model::lemma_pow2_injective(k as nat, 0);
1870                                    }
1871                                }
1872                                return small_int_q(k as i64);
1873                            },
1874                            None => {
1875                                proof {
1876                                    // `1 == 2^k` forces `k == 0`, and then `n == 1 == 2^0`
1877                                    // would have been found.
1878                                    assert forall|k2: nat| #![trigger crate::model::pow2(k2)]
1879                                        k2 <= 62 implies !self.spec_is_value(1, crate::model::pow2(k2)) by {
1880                                        if self.spec_is_value(1, crate::model::pow2(k2)) {
1881                                            crate::model::lemma_pow2_injective(k2, 0);
1882                                        }
1883                                    }
1884                                }
1885                            },
1886                        }
1887                    } else {
1888                        proof {
1889                            assert forall|k2: nat| #![trigger crate::model::pow2(k2)]
1890                                k2 <= 62 implies !self.spec_is_value(crate::model::pow2(k2), 1) by {
1891                                crate::model::lemma_pow2_pos(k2);
1892                            }
1893                        }
1894                    }
1895                } else if n == 1 {
1896                    match pow2_exponent_i64(d) {
1897                        Some(k) => {
1898                            proof {
1899                                assert forall|k2: nat| #![trigger crate::model::pow2(k2)]
1900                                    k2 <= 62 && self.spec_is_value(1, crate::model::pow2(k2))
1901                                        implies k2 == k as nat by {
1902                                    crate::model::lemma_pow2_injective(k2, k as nat);
1903                                }
1904                            }
1905                            return small_int_q(0 - (k as i64));
1906                        },
1907                        None => {},
1908                    }
1909                }
1910            },
1911            _ => {},
1912        }
1913        Q::div(self.ln(), ln2())
1914    }
1915
1916    /// The base-10 logarithm. Exact at `10^k` and `1 / 10^k` for `k <= 18`
1917    /// (`10^18` is the largest power of ten a `Rat` holds), where it returns
1918    /// the integer `k` (or `-k`); otherwise `ln(self) / ln(10)`, whose
1919    /// accuracy is measured, not proven. See `log2` for why the exact path
1920    /// exists.
1921    ///
1922    /// ```
1923    /// use the_q::Q;
1924    ///
1925    /// assert_eq!(Q::new(1000, 1).log10(), Q::new(3, 1));
1926    /// assert_eq!(Q::new(1, 100).log10(), Q::new(-2, 1));
1927    /// assert_eq!(Q::one().log10(), Q::zero());
1928    ///
1929    /// let Q::Number(x) = Q::new(2, 1).log10() else { panic!() };
1930    /// assert!((the_q::to_f64(x) - 2f64.log10()).abs() < 1e-15);
1931    /// ```
1932    pub fn log10(self) -> (r: Q)
1933        requires
1934            self.wf(),
1935        ensures
1936            r.wf(),
1937            forall|k: nat| #![trigger crate::model::pow10(k)]
1938                k <= 18 && self.spec_is_value(crate::model::pow10(k), 1)
1939                    ==> r.spec_is_value(k as int, 1),
1940            forall|k: nat| #![trigger crate::model::pow10(k)]
1941                k <= 18 && self.spec_is_value(1, crate::model::pow10(k))
1942                    ==> r.spec_is_value(-(k as int), 1),
1943    {
1944        match self {
1945            Q::Number(x) => {
1946                let n = x.numerator();
1947                let d = x.denominator();
1948                if d == 1 {
1949                    if n >= 1 {
1950                        match pow10_exponent_i64(n) {
1951                            Some(k) => {
1952                                proof {
1953                                    assert forall|k2: nat| #![trigger crate::model::pow10(k2)]
1954                                        k2 <= 18 && self.spec_is_value(crate::model::pow10(k2), 1)
1955                                            implies k2 == k as nat by {
1956                                        crate::model::lemma_pow10_injective(k2, k as nat);
1957                                    }
1958                                    assert forall|k2: nat| #![trigger crate::model::pow10(k2)]
1959                                        k2 <= 18 && self.spec_is_value(1, crate::model::pow10(k2))
1960                                            implies k2 == 0 && k == 0 by {
1961                                        crate::model::lemma_pow10_injective(k2, 0);
1962                                        crate::model::lemma_pow10_injective(k as nat, 0);
1963                                    }
1964                                }
1965                                return small_int_q(k as i64);
1966                            },
1967                            None => {
1968                                proof {
1969                                    assert forall|k2: nat| #![trigger crate::model::pow10(k2)]
1970                                        k2 <= 18 implies !self.spec_is_value(1, crate::model::pow10(k2)) by {
1971                                        if self.spec_is_value(1, crate::model::pow10(k2)) {
1972                                            crate::model::lemma_pow10_injective(k2, 0);
1973                                        }
1974                                    }
1975                                }
1976                            },
1977                        }
1978                    } else {
1979                        proof {
1980                            assert forall|k2: nat| #![trigger crate::model::pow10(k2)]
1981                                k2 <= 18 implies !self.spec_is_value(crate::model::pow10(k2), 1) by {
1982                                crate::model::lemma_pow10_pos(k2);
1983                            }
1984                        }
1985                    }
1986                } else if n == 1 {
1987                    match pow10_exponent_i64(d) {
1988                        Some(k) => {
1989                            proof {
1990                                assert forall|k2: nat| #![trigger crate::model::pow10(k2)]
1991                                    k2 <= 18 && self.spec_is_value(1, crate::model::pow10(k2))
1992                                        implies k2 == k as nat by {
1993                                    crate::model::lemma_pow10_injective(k2, k as nat);
1994                                }
1995                            }
1996                            return small_int_q(0 - (k as i64));
1997                        },
1998                        None => {},
1999                    }
2000                }
2001            },
2002            _ => {},
2003        }
2004        Q::div(self.ln(), ln10())
2005    }
2006
2007    /// The logarithm in an arbitrary base: `log2` when `base` is exactly `2`,
2008    /// `log10` when it is exactly `10` (so their exact paths apply), and
2009    /// `ln(self) / ln(base)` otherwise.
2010    ///
2011    /// A base of `1` gives a zero denominator, thus an infinity or `Nan`. The
2012    /// function `log_1` is undefined.
2013    ///
2014    /// ```
2015    /// use the_q::Q;
2016    ///
2017    /// assert_eq!(Q::new(8, 1).log(Q::new(2, 1)), Q::new(3, 1));
2018    /// assert_eq!(Q::new(1000, 1).log(Q::new(10, 1)), Q::new(3, 1));
2019    /// let Q::Number(x) = Q::new(9, 1).log(Q::new(3, 1)) else { panic!() };
2020    /// assert!((the_q::to_f64(x) - 2.0).abs() < 1e-15);
2021    /// assert_eq!(Q::new(8, 1).log(Q::one()), Q::PosInf);
2022    /// ```
2023    pub fn log(self, base: Q) -> (r: Q)
2024        requires
2025            self.wf(),
2026            base.wf(),
2027        ensures
2028            r.wf(),
2029            forall|k: nat| #![trigger crate::model::pow2(k)]
2030                base.spec_is_value(2, 1) && k <= 62 && self.spec_is_value(crate::model::pow2(k), 1)
2031                    ==> r.spec_is_value(k as int, 1),
2032            forall|k: nat| #![trigger crate::model::pow2(k)]
2033                base.spec_is_value(2, 1) && k <= 62 && self.spec_is_value(1, crate::model::pow2(k))
2034                    ==> r.spec_is_value(-(k as int), 1),
2035            forall|k: nat| #![trigger crate::model::pow10(k)]
2036                base.spec_is_value(10, 1) && k <= 18 && self.spec_is_value(crate::model::pow10(k), 1)
2037                    ==> r.spec_is_value(k as int, 1),
2038            forall|k: nat| #![trigger crate::model::pow10(k)]
2039                base.spec_is_value(10, 1) && k <= 18 && self.spec_is_value(1, crate::model::pow10(k))
2040                    ==> r.spec_is_value(-(k as int), 1),
2041    {
2042        match base {
2043            Q::Number(b) => {
2044                let bn = b.numerator();
2045                let bd = b.denominator();
2046                if bd == 1 && bn == 2 {
2047                    return self.log2();
2048                }
2049                if bd == 1 && bn == 10 {
2050                    return self.log10();
2051                }
2052            },
2053            _ => {},
2054        }
2055        Q::div(self.ln(), base.ln())
2056    }
2057
2058    /// `2^self`, as `exp(self · ln 2)`.
2059    ///
2060    /// Accuracy is measured, not proven; the result need not be the exact
2061    /// rational power.
2062    ///
2063    /// ```
2064    /// use the_q::Q;
2065    ///
2066    /// let r = Q::new(3, 1).exp2();
2067    /// if let Q::Number(x) = r {
2068    ///     assert!((the_q::to_f64(x) - 8.0).abs() < 1e-9);
2069    /// } else {
2070    ///     panic!("expected a number");
2071    /// }
2072    /// ```
2073    pub fn exp2(self) -> (r: Q)
2074        requires
2075            self.wf(),
2076        ensures
2077            r.wf(),
2078    {
2079        Q::mul(self, ln2()).exp()
2080    }
2081
2082    /// `self^exponent` as `exp(exponent · ln(self))`: `Nan` for a negative base
2083    /// (use [`Q::pow_i32`] for integer exponents); `0^0` is `1`.
2084    ///
2085    /// ```
2086    /// use the_q::Q;
2087    ///
2088    /// let r = Q::new(2, 1).powf(Q::new(3, 1));
2089    /// if let Q::Number(x) = r {
2090    ///     assert!((the_q::to_f64(x) - 8.0).abs() < 1e-9);
2091    /// } else {
2092    ///     panic!("expected a number");
2093    /// }
2094    /// assert_eq!(Q::new(-1, 1).powf(Q::new(2, 1)), Q::Nan);
2095    /// ```
2096    pub fn powf(self, exponent: Q) -> (r: Q)
2097        requires
2098            self.wf(),
2099            exponent.wf(),
2100        ensures
2101            r.wf(),
2102            exponent.spec_is_zero() ==> r.spec_is_value(1, 1),
2103            self.spec_is_zero() && exponent.spec_signum() == Some(Sign::Positive)
2104                ==> r.spec_is_value(0, 1),
2105            self.spec_is_zero() && exponent.spec_signum() == Some(Sign::Negative)
2106                ==> r == Q::PosInf,
2107            self.spec_is_zero() && exponent.spec_is_nan() ==> r == Q::Nan,
2108    {
2109        if exponent.is_zero() {
2110            return Q::one();
2111        }
2112        if self.is_zero() {
2113            return match exponent.signum() {
2114                Some(Sign::Positive) => Q::zero(),
2115                Some(Sign::Negative) => Q::PosInf,
2116                Some(Sign::Zero) => Q::one(),
2117                None => Q::Nan,
2118            };
2119        }
2120        Q::mul(exponent, self.ln()).exp()
2121    }
2122
2123    /// The cube root on the whole real line, as `±exp(ln|x| / 3)`.
2124    ///
2125    /// Accuracy is measured, not proven.
2126    ///
2127    /// ```
2128    /// use the_q::Q;
2129    ///
2130    /// let r = Q::new(8, 1).cbrt();
2131    /// if let Q::Number(x) = r {
2132    ///     assert!((the_q::to_f64(x) - 2.0).abs() < 1e-9);
2133    /// } else {
2134    ///     panic!("expected a number");
2135    /// }
2136    /// assert_eq!(Q::PosSat.cbrt(), Q::Nan);
2137    /// ```
2138    pub fn cbrt(self) -> (r: Q)
2139        requires
2140            self.wf(),
2141        ensures
2142            r.wf(),
2143            self.spec_is_nan() ==> r.spec_is_nan(),
2144    {
2145        match self {
2146            Q::Nan => Q::Nan,
2147            Q::PosInf => Q::PosInf,
2148            Q::NegInf => Q::NegInf,
2149            // Same argument as `sqrt(PosSat)`: the image of `(MAX_MAG, inf)`
2150            // under a root reaches far below `MAX_MAG`.
2151            Q::PosSat => Q::Nan,
2152            Q::NegSat => Q::Nan,
2153            Q::Number(x) => {
2154                let s = x.signum();
2155                if s == 0 {
2156                    return Q::zero();
2157                }
2158                let mag = Q::Number(x).abs();
2159                let root = Q::div(mag.ln(), Q::new(3, 1)).exp();
2160                if s < 0 {
2161                    root.neg()
2162                } else {
2163                    root
2164                }
2165            },
2166        }
2167    }
2168
2169    /// `sqrt(self² + other²)` as `|a|·sqrt(1 + (b/a)²)` with `a` the larger, so
2170    /// the square stays representable when `a² + b²` does not.
2171    ///
2172    /// ```
2173    /// use the_q::Q;
2174    ///
2175    /// assert_eq!(Q::new(3, 1).hypot(Q::new(4, 1)), Q::new(5, 1));
2176    /// assert_eq!(Q::zero().hypot(Q::zero()), Q::zero());
2177    /// ```
2178    pub fn hypot(self, other: Q) -> (r: Q)
2179        requires
2180            self.wf(),
2181            other.wf(),
2182        ensures
2183            r.wf(),
2184    {
2185        let a = self.abs();
2186        let b = other.abs();
2187        let (big, small) = if Q::ge(a, b) {
2188            (a, b)
2189        } else {
2190            (b, a)
2191        };
2192        if big.is_zero() {
2193            return Q::zero();
2194        }
2195        let ratio = Q::div(small, big);
2196        Q::mul(big, Q::add(Q::one(), Q::mul(ratio, ratio)).sqrt())
2197    }
2198
2199    /// `(e^x − e^-x) / 2`; beyond `|x| > 22` it is `±e^(|x| − ln 2)` to within the
2200    /// grid, which saturates cleanly instead of dividing a `PosSat` by two.
2201    ///
2202    /// ```
2203    /// use the_q::Q;
2204    ///
2205    /// assert_eq!(Q::zero().sinh(), Q::zero());
2206    /// assert_eq!(Q::new(100, 1).sinh(), Q::PosSat);
2207    /// ```
2208    pub fn sinh(self) -> (r: Q)
2209        requires
2210            self.wf(),
2211        ensures
2212            r.wf(),
2213    {
2214        match self {
2215            Q::Nan => Q::Nan,
2216            Q::PosInf => Q::PosInf,
2217            Q::NegInf => Q::NegInf,
2218            Q::PosSat => Q::PosSat,
2219            Q::NegSat => Q::NegSat,
2220            Q::Number(_) => {
2221                let lim = Q::new(HYP_ARG_LIMIT, 1);
2222                if Q::gt(self, lim) {
2223                    Q::sub(self, ln2()).exp()
2224                } else if Q::lt(self, lim.neg()) {
2225                    Q::sub(self.neg(), ln2()).exp().neg()
2226                } else {
2227                    Q::div(Q::sub(self.exp(), self.neg().exp()), Q::new(2, 1))
2228                }
2229            },
2230        }
2231    }
2232
2233    /// The hyperbolic cosine, `(e^x + e^-x) / 2`, with the same large-argument
2234    /// path as [`Q::sinh`].
2235    ///
2236    /// ```
2237    /// use the_q::Q;
2238    ///
2239    /// assert_eq!(Q::zero().cosh(), Q::one());
2240    /// assert_eq!(Q::new(100, 1).cosh(), Q::PosSat);
2241    /// ```
2242    pub fn cosh(self) -> (r: Q)
2243        requires
2244            self.wf(),
2245        ensures
2246            r.wf(),
2247    {
2248        match self {
2249            Q::Nan => Q::Nan,
2250            Q::PosInf | Q::NegInf => Q::PosInf,
2251            Q::PosSat | Q::NegSat => Q::PosSat,
2252            Q::Number(_) => {
2253                let lim = Q::new(HYP_ARG_LIMIT, 1);
2254                if Q::gt(self.abs(), lim) {
2255                    Q::sub(self.abs(), ln2()).exp()
2256                } else {
2257                    Q::div(Q::add(self.exp(), self.neg().exp()), Q::new(2, 1))
2258                }
2259            },
2260        }
2261    }
2262
2263    /// `sinh / cosh`; `±1` beyond `|x| >= 22` (where `1 − |tanh x| < 2^-62`) and
2264    /// for the infinite and saturated states.
2265    ///
2266    /// ```
2267    /// use the_q::Q;
2268    ///
2269    /// assert_eq!(Q::zero().tanh(), Q::zero());
2270    /// assert_eq!(Q::new(100, 1).tanh(), Q::one());
2271    /// assert_eq!(Q::PosInf.tanh(), Q::one());
2272    /// ```
2273    pub fn tanh(self) -> (r: Q)
2274        requires
2275            self.wf(),
2276        ensures
2277            r.wf(),
2278    {
2279        match self {
2280            Q::Nan => Q::Nan,
2281            Q::PosInf | Q::PosSat => Q::one(),
2282            Q::NegInf | Q::NegSat => Q::one().neg(),
2283            Q::Number(_) => {
2284                let lim = Q::new(HYP_ARG_LIMIT, 1);
2285                if Q::ge(self, lim) {
2286                    Q::one()
2287                } else if Q::le(self, lim.neg()) {
2288                    Q::one().neg()
2289                } else {
2290                    Q::div(self.sinh(), self.cosh())
2291                }
2292            },
2293        }
2294    }
2295
2296    /// The arcsine, in `[-π/2, π/2]`.
2297    ///
2298    /// The result is `Nan` outside `[-1, 1]`, where there is no real answer.
2299    /// The function computes the endpoints directly. The identity below divides
2300    /// by zero at those two points.
2301    ///
2302    /// ```
2303    /// use the_q::Q;
2304    /// use the_q::transcendental::half_pi;
2305    ///
2306    /// assert_eq!(Q::one().asin(), half_pi());
2307    /// assert_eq!(Q::new(2, 1).asin(), Q::Nan);
2308    /// ```
2309    pub fn asin(self) -> (r: Q)
2310        requires
2311            self.wf(),
2312        ensures
2313            r.wf(),
2314    {
2315        match self {
2316            Q::Number(x) => {
2317                let q = Q::Number(x);
2318                let one = Q::one();
2319                if Q::gt(q.abs(), one) {
2320                    return Q::Nan;
2321                }
2322                if q.abs() == one {
2323                    let hp = Q::div(pi(), Q::new(2, 1));
2324                    return if Q::gt(q, Q::zero()) {
2325                        hp
2326                    } else {
2327                        hp.neg()
2328                    };
2329                }
2330                // asin(x) = atan(x / sqrt(1 - x²))
2331                let denom = Q::sub(one, Q::mul(q, q)).sqrt();
2332                Q::div(q, denom).atan()
2333            },
2334            // Every special lies outside [-1, 1] or carries no information.
2335            _ => Q::Nan,
2336        }
2337    }
2338
2339    /// The arccosine, in `[0, π]`, as `π/2 - asin(self)`.
2340    ///
2341    /// ```
2342    /// use the_q::Q;
2343    ///
2344    /// assert_eq!(Q::one().acos(), Q::zero());
2345    /// let r = Q::zero().acos();
2346    /// if let Q::Number(x) = r {
2347    ///     assert!((the_q::to_f64(x) - std::f64::consts::FRAC_PI_2).abs() < 1e-9);
2348    /// } else {
2349    ///     panic!("expected a number");
2350    /// }
2351    /// ```
2352    pub fn acos(self) -> (r: Q)
2353        requires
2354            self.wf(),
2355        ensures
2356            r.wf(),
2357    {
2358        Q::sub(Q::div(pi(), Q::new(2, 1)), self.asin())
2359    }
2360
2361    /// The angle of `(x, y)` in `(-π, π]`; `atan2(0, 0)` is `Nan`.
2362    ///
2363    /// ```
2364    /// use the_q::Q;
2365    ///
2366    /// assert_eq!(Q::zero().atan2(Q::one()), Q::zero());
2367    /// assert_eq!(Q::zero().atan2(Q::zero()), Q::Nan);
2368    /// ```
2369    pub fn atan2(self, x: Q) -> (r: Q)
2370        requires
2371            self.wf(),
2372            x.wf(),
2373        ensures
2374            r.wf(),
2375            self.spec_is_infinite() && x.spec_is_infinite()
2376                ==> r == Q::Number(atan2_inf_target(self, x)),
2377    {
2378        let y = self;
2379        let zero = Q::zero();
2380        let p = pi();
2381        let hp = Q::div(p, Q::new(2, 1));
2382        if y.is_nan() || x.is_nan() {
2383            return Q::Nan;
2384        }
2385        if y.is_infinite() && x.is_infinite() {
2386            return Q::Number(atan2_inf_target_exec(y, x));
2387        }
2388        if x.is_zero() && y.is_zero() {
2389            return Q::Nan;
2390        }
2391        if x.is_zero() {
2392            return if Q::gt(y, zero) {
2393                hp
2394            } else {
2395                hp.neg()
2396            };
2397        }
2398        let base = Q::div(y, x).atan();
2399        if Q::gt(x, zero) {
2400            base
2401        } else if Q::ge(y, zero) {
2402            Q::add(base, p)
2403        } else {
2404            Q::sub(base, p)
2405        }
2406    }
2407}
2408
2409} // verus!
2410
2411#[cfg(test)]
2412mod tests {
2413    use super::fx_to_grid;
2414    use crate::Rat;
2415
2416    #[test]
2417    fn fx_to_grid_rounds_nearest_ties_even() {
2418        assert_eq!(fx_to_grid(Rat::zero()), 0);
2419        assert_eq!(fx_to_grid(Rat::one()), 9_223_372_036_854_775_808);
2420        assert_eq!(fx_to_grid(Rat::neg_one()), -9_223_372_036_854_775_808);
2421        assert_eq!(
2422            fx_to_grid(Rat::new(1, 2).unwrap()),
2423            4_611_686_018_427_387_904
2424        );
2425        assert_eq!(
2426            fx_to_grid(Rat::new(1, 3).unwrap()),
2427            3_074_457_345_618_258_603
2428        );
2429        assert_eq!(
2430            fx_to_grid(Rat::new(-1, 3).unwrap()),
2431            -3_074_457_345_618_258_603
2432        );
2433    }
2434}