1use crate::defs::WORD_BIT_SIZE;
4use crate::Consts;
5use crate::ExactNum;
6use crate::RoundingMode;
7use alloc::vec::Vec;
8
9pub const QUADRATURE_MAX_NODES: usize = 64;
11
12pub const TANH_SINH_LEVELS_MAX: usize = 8;
14
15const QUADRATURE_NEWTON_MAX: usize = 64;
17
18const QUADRATURE_BRACKET_MUL: usize = 8;
20
21const QUADRATURE_BISECT_STEPS: usize = 16;
23
24const TANH_SINH_K_MAX: usize = 512;
26
27fn work_p(p: usize) -> usize {
28 p.saturating_add(WORD_BIT_SIZE)
29}
30
31fn work_p_de(p: usize) -> usize {
34 p.saturating_mul(2).saturating_add(WORD_BIT_SIZE)
35}
36
37fn finite(x: &ExactNum) -> bool {
38 !x.is_nan() && !x.is_inf()
39}
40
41fn tiny(p: usize, extra: i32) -> ExactNum {
42 let e = (p as i32).saturating_sub(extra).saturating_neg();
43 ExactNum::from_u8(1, p).ldexp(e, p, RoundingMode::ToEven)
44}
45
46fn below(x: &ExactNum, bound: &ExactNum) -> bool {
47 x.is_zero() || x.cmp(bound) == Some(-1)
48}
49
50fn factorial(n: usize, p: usize, rm: RoundingMode) -> ExactNum {
51 let mut acc = ExactNum::from_u8(1, p);
52 for k in 2..=n {
53 acc = acc.mul(&ExactNum::from_u32(k as u32, p), p, rm);
54 }
55 acc
56}
57
58fn newton<F, D>(
60 mut f: F,
61 mut df: D,
62 x0: ExactNum,
63 p: usize,
64 rm: RoundingMode,
65 cc: &mut Consts,
66) -> Option<ExactNum>
67where
68 F: FnMut(&ExactNum, usize, RoundingMode, &mut Consts) -> ExactNum,
69 D: FnMut(&ExactNum, usize, RoundingMode, &mut Consts) -> ExactNum,
70{
71 let guard = tiny(p, 8);
72 let mut x = x0;
73 for _ in 0..QUADRATURE_NEWTON_MAX {
74 let y = f(&x, p, rm, cc);
75 let d = df(&x, p, rm, cc);
76 if !finite(&y) || !finite(&d) || d.is_zero() {
77 return None;
78 }
79 let step = y.div(&d, p, rm);
80 x = x.sub(&step, p, rm);
81 if !finite(&x) {
82 return None;
83 }
84 if below(&step.abs(), &guard) {
85 return Some(x);
86 }
87 }
88 None
89}
90
91fn bisect_zero<F>(
92 mut f: F,
93 mut a: ExactNum,
94 mut b: ExactNum,
95 p: usize,
96 rm: RoundingMode,
97 cc: &mut Consts,
98) -> Option<ExactNum>
99where
100 F: FnMut(&ExactNum, usize, RoundingMode, &mut Consts) -> ExactNum,
101{
102 let fa0 = f(&a, p, rm, cc);
103 let fb0 = f(&b, p, rm, cc);
104 if !finite(&fa0) || !finite(&fb0) {
105 return None;
106 }
107 if fa0.is_zero() {
108 return Some(a);
109 }
110 if fb0.is_zero() {
111 return Some(b);
112 }
113 if fa0.is_positive() == fb0.is_positive() {
114 return None;
115 }
116 let two = ExactNum::from_u8(2, p);
117 for _ in 0..QUADRATURE_BISECT_STEPS {
118 let m = a.add(&b, p, rm).div(&two, p, rm);
119 let fm = f(&m, p, rm, cc);
120 if !finite(&fm) {
121 return None;
122 }
123 if fm.is_zero() {
124 return Some(m);
125 }
126 if fm.is_positive() == fa0.is_positive() {
127 a = m;
128 } else {
129 b = m;
130 }
131 }
132 Some(a.add(&b, p, rm).div(&two, p, rm))
133}
134
135fn isolate_positive<F>(
136 mut f: F,
137 lo: &ExactNum,
138 hi: &ExactNum,
139 want: usize,
140 p: usize,
141 rm: RoundingMode,
142 cc: &mut Consts,
143) -> Option<Vec<(ExactNum, ExactNum)>>
144where
145 F: FnMut(&ExactNum, usize, RoundingMode, &mut Consts) -> ExactNum,
146{
147 if want == 0 {
148 return Some(Vec::new());
149 }
150 let n_grid = want
151 .saturating_mul(QUADRATURE_BRACKET_MUL)
152 .saturating_add(4);
153 let step = hi
154 .sub(lo, p, rm)
155 .div(&ExactNum::from_u32(n_grid as u32, p), p, rm);
156 let mut prev_x = lo.clone();
157 let mut prev_f = f(lo, p, rm, cc);
158 if !finite(&prev_f) {
159 return None;
160 }
161 let mut out = Vec::new();
162 for i in 1..=n_grid {
163 let x = if i == n_grid {
164 hi.clone()
165 } else {
166 lo.add(&step.mul(&ExactNum::from_u32(i as u32, p), p, rm), p, rm)
167 };
168 let y = f(&x, p, rm, cc);
169 if !finite(&y) {
170 return None;
171 }
172 if prev_f.is_zero() {
173 out.push((prev_x.clone(), x.clone()));
174 } else if y.is_zero() || prev_f.is_positive() != y.is_positive() {
175 out.push((prev_x, x.clone()));
176 }
177 if out.len() == want {
178 return Some(out);
179 }
180 prev_x = x;
181 prev_f = y;
182 }
183 if out.len() == want {
184 Some(out)
185 } else {
186 None
187 }
188}
189
190fn map_ab(xi: &ExactNum, a: &ExactNum, b: &ExactNum, p: usize, rm: RoundingMode) -> ExactNum {
191 let two = ExactNum::from_u8(2, p);
192 let mid = a.add(b, p, rm).div(&two, p, rm);
193 let half = b.sub(a, p, rm).div(&two, p, rm);
194 mid.add(&half.mul(xi, p, rm), p, rm)
195}
196
197fn gauss_legendre_nodes(
198 n: usize,
199 p: usize,
200 _rm: RoundingMode,
201 cc: &mut Consts,
202) -> Option<Vec<(ExactNum, ExactNum)>> {
203 if n == 0 || n > QUADRATURE_MAX_NODES {
204 return None;
205 }
206 let wrk = work_p(p);
207 let nu = n as u32;
208 let pi = cc.pi(wrk, RoundingMode::None);
209 let den = ExactNum::from_u32((4 * n + 2) as u32, wrk);
210 let n_f = ExactNum::from_u32(nu, wrk);
211 let one = ExactNum::from_u8(1, wrk);
212 let two = ExactNum::from_u8(2, wrk);
213 let mut nodes = Vec::with_capacity(n);
214 for k in 1..=n {
215 let num = ExactNum::from_u32((4 * k - 1) as u32, wrk);
216 let theta = pi
217 .mul(&num, wrk, RoundingMode::None)
218 .div(&den, wrk, RoundingMode::None);
219 let x0 = theta.cos(wrk, RoundingMode::None, cc);
220 let x = newton(
221 |x, p, rm, _cc| x.legendre_p(nu, p, rm),
222 |x, p, rm, _cc| {
223 let pn = x.legendre_p(nu, p, rm);
224 let pnm = if nu == 0 { ExactNum::new(p) } else { x.legendre_p(nu - 1, p, rm) };
225 let d = one.sub(&x.mul(x, p, rm), p, rm);
226 n_f.mul(&pnm.sub(&x.mul(&pn, p, rm), p, rm), p, rm)
227 .div(&d, p, rm)
228 },
229 x0,
230 wrk,
231 RoundingMode::None,
232 cc,
233 )?;
234 let pn = x.legendre_p(nu, wrk, RoundingMode::None);
235 let pnm = if nu == 0 {
236 ExactNum::new(wrk)
237 } else {
238 x.legendre_p(nu - 1, wrk, RoundingMode::None)
239 };
240 let d = one.sub(&x.mul(&x, wrk, RoundingMode::None), wrk, RoundingMode::None);
241 let dp = n_f
242 .mul(
243 &pnm.sub(
244 &x.mul(&pn, wrk, RoundingMode::None),
245 wrk,
246 RoundingMode::None,
247 ),
248 wrk,
249 RoundingMode::None,
250 )
251 .div(&d, wrk, RoundingMode::None);
252 let w = two.div(
253 &d.mul(
254 &dp.mul(&dp, wrk, RoundingMode::None),
255 wrk,
256 RoundingMode::None,
257 ),
258 wrk,
259 RoundingMode::None,
260 );
261 if !finite(&x) || !finite(&w) {
262 return None;
263 }
264 nodes.push((x, w));
265 }
266 Some(nodes)
267}
268
269pub fn gauss_legendre<F>(
276 mut f: F,
277 a: &ExactNum,
278 b: &ExactNum,
279 n: usize,
280 p: usize,
281 rm: RoundingMode,
282 cc: &mut Consts,
283) -> Option<ExactNum>
284where
285 F: FnMut(&ExactNum, usize, RoundingMode, &mut Consts) -> ExactNum,
286{
287 if !finite(a) || !finite(b) || a.cmp(b) != Some(-1) {
288 return None;
289 }
290 let wrk = work_p(p);
291 let nodes = gauss_legendre_nodes(n, wrk, RoundingMode::None, cc)?;
292 let two = ExactNum::from_u8(2, wrk);
293 let half = b
294 .sub(a, wrk, RoundingMode::None)
295 .div(&two, wrk, RoundingMode::None);
296 let mut acc = ExactNum::new(wrk);
297 for (xi, wi) in &nodes {
298 let x = map_ab(xi, a, b, wrk, RoundingMode::None);
299 let y = f(&x, wrk, RoundingMode::None, cc);
300 if !finite(&y) {
301 return None;
302 }
303 acc = acc.add(
304 &wi.mul(&y, wrk, RoundingMode::None),
305 wrk,
306 RoundingMode::None,
307 );
308 }
309 let mut out = half.mul(&acc, wrk, RoundingMode::None);
310 let _ = out.set_precision(p, rm);
311 Some(out)
312}
313
314fn tanh_sinh_sum<F>(
315 mut f: F,
316 a: &ExactNum,
317 b: &ExactNum,
318 h: &ExactNum,
319 p: usize,
320 rm: RoundingMode,
321 cc: &mut Consts,
322) -> Option<ExactNum>
323where
324 F: FnMut(&ExactNum, usize, RoundingMode, &mut Consts) -> ExactNum,
325{
326 let wrk = work_p_de(p);
327 let two = ExactNum::from_u8(2, wrk);
328 let half = b
329 .sub(a, wrk, RoundingMode::None)
330 .div(&two, wrk, RoundingMode::None);
331 let mid = a
332 .add(b, wrk, RoundingMode::None)
333 .div(&two, wrk, RoundingMode::None);
334 let pi = cc.pi(wrk, RoundingMode::None);
335 let half_pi = pi.div(&two, wrk, RoundingMode::None);
336 let wmin = tiny(wrk, 8);
337 let mut acc = ExactNum::new(wrk);
338 for k in 0..TANH_SINH_K_MAX {
339 let t = h.mul(&ExactNum::from_u32(k as u32, wrk), wrk, RoundingMode::None);
340 let (sh, ch) = t.sinh_cosh(wrk, RoundingMode::None, cc);
341 let u = half_pi.mul(&sh, wrk, RoundingMode::None);
342 let (su, cu) = u.sinh_cosh(wrk, RoundingMode::None, cc);
343 if !finite(&cu) || cu.is_zero() {
344 break;
345 }
346 let xi = su.div(&cu, wrk, RoundingMode::None);
347 let w = half_pi.mul(&ch, wrk, RoundingMode::None).div(
348 &cu.mul(&cu, wrk, RoundingMode::None),
349 wrk,
350 RoundingMode::None,
351 );
352 if !finite(&w) {
353 break;
354 }
355 if k > 0 && below(&w.abs(), &wmin) {
356 break;
357 }
358 let mut eval = |s: &ExactNum| {
359 let x = mid.add(
360 &half.mul(s, wrk, RoundingMode::None),
361 wrk,
362 RoundingMode::None,
363 );
364 f(&x, wrk, RoundingMode::None, cc)
365 };
366 let y0 = eval(&xi);
367 if !finite(&y0) {
368 if k == 0 {
369 return None;
370 }
371 break;
372 }
373 acc = acc.add(
374 &w.mul(&y0, wrk, RoundingMode::None),
375 wrk,
376 RoundingMode::None,
377 );
378 if k > 0 {
379 let y1 = eval(&xi.neg());
380 if finite(&y1) {
381 acc = acc.add(
382 &w.mul(&y1, wrk, RoundingMode::None),
383 wrk,
384 RoundingMode::None,
385 );
386 }
387 }
388 }
389 let mut out = half
390 .mul(h, wrk, RoundingMode::None)
391 .mul(&acc, wrk, RoundingMode::None);
392 let _ = out.set_precision(p, rm);
393 Some(out)
394}
395
396pub fn tanh_sinh<F>(
402 mut f: F,
403 a: &ExactNum,
404 b: &ExactNum,
405 p: usize,
406 rm: RoundingMode,
407 cc: &mut Consts,
408) -> Option<ExactNum>
409where
410 F: FnMut(&ExactNum, usize, RoundingMode, &mut Consts) -> ExactNum,
411{
412 if !finite(a) || !finite(b) || a.cmp(b) != Some(-1) {
413 return None;
414 }
415 let wrk = work_p(p);
416 let two = ExactNum::from_u8(2, wrk);
417 let pi = cc.pi(wrk, RoundingMode::None);
418 let ln2 = cc.ln_2(wrk, RoundingMode::None);
419 let p_f = ExactNum::from_u32(p as u32, wrk);
420 let h0 = two.mul(&pi, wrk, RoundingMode::None).div(
421 &p_f.mul(&ln2, wrk, RoundingMode::None),
422 wrk,
423 RoundingMode::None,
424 );
425 let guard = tiny(p, 8);
426 let mut prev: Option<ExactNum> = None;
427 let mut best = None;
428 let two_wrk = ExactNum::from_u8(2, wrk);
429 let mut h = h0;
430 for level in 0..TANH_SINH_LEVELS_MAX {
431 if level > 0 {
432 h = h.div(&two_wrk, wrk, RoundingMode::None);
433 }
434 let s = tanh_sinh_sum(&mut f, a, b, &h, p, rm, cc)?;
435 if let Some(pr) = &prev {
436 let err = s.sub(pr, p, rm).abs();
437 if below(&err, &guard) {
438 return Some(s);
439 }
440 }
441 prev = Some(s.clone());
442 best = Some(s);
443 }
444 best
445}
446
447fn gauss_laguerre_nodes(
448 n: usize,
449 p: usize,
450 _rm: RoundingMode,
451 cc: &mut Consts,
452) -> Option<Vec<(ExactNum, ExactNum)>> {
453 if n == 0 || n > QUADRATURE_MAX_NODES {
454 return None;
455 }
456 let wrk = work_p(p);
457 let nu = n as u32;
458 let zero = ExactNum::new(wrk);
459 let hi = ExactNum::from_u32((4 * n + 4) as u32, wrk);
460 let brackets = isolate_positive(
461 |x, p, rm, _cc| x.laguerre(n, p, rm),
462 &zero,
463 &hi,
464 n,
465 wrk,
466 RoundingMode::None,
467 cc,
468 )?;
469 let n_f = ExactNum::from_u32(nu, wrk);
470 let np1 = ExactNum::from_u32((n + 1) as u32, wrk);
471 let np1sq = np1.mul(&np1, wrk, RoundingMode::None);
472 let mut nodes = Vec::with_capacity(n);
473 for (a, b) in brackets {
474 let x0 = bisect_zero(
475 |x, p, rm, _cc| x.laguerre(n, p, rm),
476 a,
477 b,
478 wrk,
479 RoundingMode::None,
480 cc,
481 )?;
482 let x = newton(
483 |x, p, rm, _cc| x.laguerre(n, p, rm),
484 |x, p, rm, _cc| {
485 if x.is_zero() {
486 return ExactNum::nan(None);
487 }
488 let ln = x.laguerre(n, p, rm);
489 let lnm = if n == 0 { ExactNum::new(p) } else { x.laguerre(n - 1, p, rm) };
490 n_f.mul(&ln.sub(&lnm, p, rm), p, rm).div(x, p, rm)
491 },
492 x0,
493 wrk,
494 RoundingMode::None,
495 cc,
496 )?;
497 let ln1 = x.laguerre(n + 1, wrk, RoundingMode::None);
498 let w = x.div(
499 &np1sq.mul(
500 &ln1.mul(&ln1, wrk, RoundingMode::None),
501 wrk,
502 RoundingMode::None,
503 ),
504 wrk,
505 RoundingMode::None,
506 );
507 if !finite(&x) || !finite(&w) {
508 return None;
509 }
510 nodes.push((x, w));
511 }
512 Some(nodes)
513}
514
515pub fn gauss_laguerre<F>(
520 mut f: F,
521 n: usize,
522 p: usize,
523 rm: RoundingMode,
524 cc: &mut Consts,
525) -> Option<ExactNum>
526where
527 F: FnMut(&ExactNum, usize, RoundingMode, &mut Consts) -> ExactNum,
528{
529 let wrk = work_p(p);
530 let nodes = gauss_laguerre_nodes(n, wrk, RoundingMode::None, cc)?;
531 let mut acc = ExactNum::new(wrk);
532 for (xi, wi) in &nodes {
533 let y = f(xi, wrk, RoundingMode::None, cc);
534 if !finite(&y) {
535 return None;
536 }
537 acc = acc.add(
538 &wi.mul(&y, wrk, RoundingMode::None),
539 wrk,
540 RoundingMode::None,
541 );
542 }
543 let _ = acc.set_precision(p, rm);
544 Some(acc)
545}
546
547fn gauss_hermite_nodes(
548 n: usize,
549 p: usize,
550 _rm: RoundingMode,
551 cc: &mut Consts,
552) -> Option<Vec<(ExactNum, ExactNum)>> {
553 if n == 0 || n > QUADRATURE_MAX_NODES {
554 return None;
555 }
556 let wrk = work_p(p);
557 let nu = n as u32;
558 let two = ExactNum::from_u8(2, wrk);
559 let hi = ExactNum::from_u32((4 * n + 2) as u32, wrk).sqrt(wrk, RoundingMode::None);
560 let zero = ExactNum::new(wrk);
561 let want_pos = n / 2;
562 let brackets = isolate_positive(
563 |x, p, rm, _cc| x.hermite_h(n, p, rm),
564 &zero,
565 &hi,
566 want_pos,
567 wrk,
568 RoundingMode::None,
569 cc,
570 )?;
571 let n_f = ExactNum::from_u32(nu, wrk);
572 let nsq = n_f.mul(&n_f, wrk, RoundingMode::None);
573 let fact = factorial(n, wrk, RoundingMode::None);
574 let pi = cc.pi(wrk, RoundingMode::None);
575 let sqrt_pi = pi.sqrt(wrk, RoundingMode::None);
576 let two_pow = ExactNum::from_u8(1, wrk).ldexp((n as i32) - 1, wrk, RoundingMode::None);
577 let scale = two_pow
578 .mul(&fact, wrk, RoundingMode::None)
579 .mul(&sqrt_pi, wrk, RoundingMode::None);
580 let weight = |x: &ExactNum| {
581 let hm = if n == 0 {
582 ExactNum::from_u8(1, wrk)
583 } else {
584 x.hermite_h(n - 1, wrk, RoundingMode::None)
585 };
586 scale.div(
587 &nsq.mul(
588 &hm.mul(&hm, wrk, RoundingMode::None),
589 wrk,
590 RoundingMode::None,
591 ),
592 wrk,
593 RoundingMode::None,
594 )
595 };
596 let mut nodes = Vec::with_capacity(n);
597 if n % 2 == 1 {
598 let w0 = weight(&zero);
599 if !finite(&w0) {
600 return None;
601 }
602 nodes.push((zero.clone(), w0));
603 }
604 for (a, b) in brackets {
605 let x0 = bisect_zero(
606 |x, p, rm, _cc| x.hermite_h(n, p, rm),
607 a,
608 b,
609 wrk,
610 RoundingMode::None,
611 cc,
612 )?;
613 let x = newton(
614 |x, p, rm, _cc| x.hermite_h(n, p, rm),
615 |x, p, rm, _cc| {
616 if n == 0 {
617 return ExactNum::new(p);
618 }
619 two.mul(&n_f, p, rm).mul(&x.hermite_h(n - 1, p, rm), p, rm)
620 },
621 x0,
622 wrk,
623 RoundingMode::None,
624 cc,
625 )?;
626 let w = weight(&x);
627 if !finite(&x) || !finite(&w) {
628 return None;
629 }
630 nodes.push((x.clone(), w.clone()));
631 nodes.push((x.neg(), w));
632 }
633 if nodes.len() != n {
634 return None;
635 }
636 Some(nodes)
637}
638
639pub fn gauss_hermite<F>(
645 mut f: F,
646 n: usize,
647 p: usize,
648 rm: RoundingMode,
649 cc: &mut Consts,
650) -> Option<ExactNum>
651where
652 F: FnMut(&ExactNum, usize, RoundingMode, &mut Consts) -> ExactNum,
653{
654 let wrk = work_p(p);
655 let nodes = gauss_hermite_nodes(n, wrk, RoundingMode::None, cc)?;
656 let mut acc = ExactNum::new(wrk);
657 for (xi, wi) in &nodes {
658 let y = f(xi, wrk, RoundingMode::None, cc);
659 if !finite(&y) {
660 return None;
661 }
662 acc = acc.add(
663 &wi.mul(&y, wrk, RoundingMode::None),
664 wrk,
665 RoundingMode::None,
666 );
667 }
668 let _ = acc.set_precision(p, rm);
669 Some(acc)
670}
671
672#[cfg(test)]
673mod tests {
674 use super::*;
675 use crate::Consts;
676
677 fn gold_p() -> (usize, RoundingMode) {
678 (256, RoundingMode::ToEven)
679 }
680
681 #[test]
682 fn quadrature_gl_tanh_laguerre_hermite() {
683 let (p, rm) = gold_p();
684 let mut cc = Consts::new().expect("consts");
685 let a = ExactNum::from_i64(-1, p);
686 let b = ExactNum::from_u8(1, p);
687 let two = ExactNum::from_u8(2, p);
688 let three = ExactNum::from_u8(3, p);
689
690 let gl = gauss_legendre(|x, p, rm, _cc| x.mul(x, p, rm), &a, &b, 10, p, rm, &mut cc)
691 .expect("gl x^2");
692 let two_thirds = two.div(&three, p, rm);
693 assert_eq!(gl.cmp(&two_thirds), Some(0));
694
695 const GL_EXACT_DEG: u32 = 38;
696 const GL_EXACT_NODES: usize = 20;
697 let gl38 = gauss_legendre(
698 |x, p, rm, _cc| {
699 let mut y = ExactNum::from_u8(1, p);
700 for _ in 0..GL_EXACT_DEG {
701 y = y.mul(x, p, rm);
702 }
703 y
704 },
705 &a,
706 &b,
707 GL_EXACT_NODES,
708 p,
709 rm,
710 &mut cc,
711 )
712 .expect("gl x^38");
713 let thirty_nine = ExactNum::from_u32(GL_EXACT_DEG + 1, p);
714 let two_over = two.div(&thirty_nine, p, rm);
715 assert_eq!(gl38.cmp(&two_over), Some(0));
716
717 let ts = tanh_sinh(
718 |x, p, rm, _cc| {
719 let one = ExactNum::from_u8(1, p);
720 one.sub(&x.mul(x, p, rm), p, rm)
721 .sqrt(p, rm)
722 .reciprocal(p, rm)
723 },
724 &a,
725 &b,
726 p,
727 rm,
728 &mut cc,
729 )
730 .expect("tanh-sinh arcsine");
731 let pi = cc.pi(p, rm);
732 assert_eq!(ts.cmp(&pi), Some(0));
733
734 let lag = gauss_laguerre(|x, p, rm, _cc| x.mul(x, p, rm), 10, p, rm, &mut cc)
735 .expect("laguerre x^2");
736 assert_eq!(lag.cmp(&two), Some(0));
737
738 let gh = gauss_hermite(|_x, p, _rm, _cc| ExactNum::from_u8(1, p), 1, p, rm, &mut cc)
739 .expect("hermite 1");
740 let sqrt_pi = pi.sqrt(p, rm);
741 assert_eq!(gh.cmp(&sqrt_pi), Some(0));
742
743 assert!(gauss_legendre(|x, _p, _rm, _cc| x.clone(), &b, &a, 4, p, rm, &mut cc).is_none());
744 assert!(gauss_legendre(|x, _p, _rm, _cc| x.clone(), &a, &b, 0, p, rm, &mut cc).is_none());
745 }
746}