1use 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
29pub fn isqrt_i64(n: i64) -> (r: i64)
42 requires
43 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 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 let mut y: i64 = (n + 1) / 2;
70 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 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 y = (x + n / x) / 2;
94 }
95 let mut r: i64 = x;
98 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 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 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
176pub 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 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
206pub 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 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
229pub 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 assert(k * k < (k + 1) * (k + 1)) by (nonlinear_arith)
241 requires
242 0 <= k,
243 ;
244 theorem_isqrt_unique(k * k, r, k);
246}
247
248fn 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 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 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 = Q::div(Q::add(y, Q::div(q, y)), two);
318 i = i + 1;
319 }
320 y
321 }
322 },
323 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
334const SERIES_TERMS: u32 = 20;
353
354
355const TRIG_TERMS: u32 = 11;
358
359const SQRT_ITERS: u32 = 7;
362
363
364const EXP_ARG_LIMIT: i64 = 44;
368
369const HYP_ARG_LIMIT: i64 = 22;
372
373pub const PI_NUM: i64 = 1_811_004_864_519_280_709;
375pub const PI_DEN: i64 = 576_460_752_303_423_488;
376
377pub 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
395pub 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
440pub 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
500pub 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
565pub 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
593fn 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
639pub 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
679pub 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
717pub 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#[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
843fn 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
881fn 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
902fn 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 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(num as i64, 1i64 << 61)
942}
943
944impl Q {
945 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 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 let xg: i128 = fx_to_grid(x);
1005 let (t, m) = crate::fx::fx_exp_reduced(xg);
1006 if m >= 62 {
1008 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 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 let mant = Q::new(fx_quarter(t), 1i64 << 61);
1056 Q::mul(pow2_q(m), mant)
1057 }
1058 },
1059 }
1060 }
1061}
1062
1063const MAX_BINARY_SHIFTS: u32 = 64;
1069
1070fn 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
1097pub 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
1128pub fn e() -> (r: Q)
1145 ensures
1146 r.wf(),
1147{
1148 Q::new(3133965575612453543, 1152921504606846976)
1149}
1150
1151pub 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
1172pub fn ln2() -> (r: Q)
1186 ensures
1187 r.wf(),
1188{
1189 Q::new(399572145162582989, 576460752303423488)
1190}
1191
1192impl Q {
1193 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 let (mn, md): (i64, i64) = match m {
1257 Q::Number(r) => (r.numerator(), r.denominator()),
1258 _ => {
1263 return Q::Nan;
1264 },
1265 };
1266 proof {
1267 crate::model::lemma_max_mag_pow2();
1268 }
1269 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 Q::mul(Q::new(2, 1), fx_small_to_q(crate::fx::fx_atanh_series(zg)))
1294 };
1295 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 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 let n: i64 = -(e as i64);
1323 self.pow_u32(n as u32).recip()
1324 }
1325 }
1326}
1327
1328const ATAN_TERMS: u32 = 30;
1331
1332const TRIG_ARG_LIMIT: i64 = 1 << 20;
1336
1337fn 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
1371pub 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
1390pub fn pi() -> (r: Q)
1407 ensures
1408 r.wf(),
1409{
1410 Q::new(PI_NUM, PI_DEN)
1411}
1412
1413pub fn half_pi() -> (r: Q)
1422 ensures
1423 r.wf(),
1424{
1425 Q::div(pi(), Q::new(2, 1))
1426}
1427
1428fn 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
1451fn 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 let kk: i64 = k as i64;
1472 assert(1 <= kk <= TRIG_TERMS as i64);
1473 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
1491fn 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 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 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 let p = pi();
1561 let quarter_pi = Q::div(p, Q::new(4, 1));
1562 let big = Q::gt(q.abs(), one);
1563 let base = if big {
1565 Q::div(one, q)
1566 } else {
1567 q
1568 };
1569 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 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 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 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 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 let m = ((n % 4) + 4) % 4;
1651 let idx = if want_cos {
1652 (m + 1) % 4
1653 } else {
1654 m
1655 };
1656 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 _ => Q::Nan,
1671 }
1672 }
1673
1674 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
1697pub fn ln10_series() -> (r: Q)
1710 ensures
1711 r.wf(),
1712{
1713 Q::new(10, 1).ln()
1714}
1715
1716pub fn ln10() -> (r: Q)
1729 ensures
1730 r.wf(),
1731{
1732 Q::new(2654699869899991811, 1152921504606846976)
1733}
1734
1735
1736fn 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
1766fn 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
1795fn 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 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 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 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 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 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 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 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 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 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 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 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 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 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 let denom = Q::sub(one, Q::mul(q, q)).sqrt();
2332 Q::div(q, denom).atan()
2333 },
2334 _ => Q::Nan,
2336 }
2337 }
2338
2339 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 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} #[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}