1use crate::Float;
10use crate::InnerFloat::{Finite, NaN};
11use crate::conversion::rational_from_float::RationalFromFloatError;
12use core::cmp::Ordering::{self, *};
13use core::cmp::max;
14use core::mem::swap;
15use core::ops::{Add, Mul, Shr, ShrAssign};
16use malachite_base::num::arithmetic::traits::{CeilingLogBase2, Parity, Sqrt, SqrtAssign};
17use malachite_base::num::basic::integers::PrimitiveInt;
18use malachite_base::num::basic::traits::Zero;
19use malachite_base::num::conversion::traits::{ExactFrom, SaturatingInto};
20use malachite_base::num::logic::traits::SignificantBits;
21use malachite_base::rounding_modes::RoundingMode::{self, *};
22use malachite_nz::natural::arithmetic::float_extras::float_can_round;
23use malachite_nz::natural::arithmetic::float_sub::exponent_shift_compare;
24use malachite_nz::platform::Limb;
25use malachite_q::Rational;
26
27pub_crate_test_struct! {
28#[derive(Clone)]
29ExtendedFloat {
30 pub(crate) x: Float,
31 exp: i64,
32}}
33
34impl ExtendedFloat {
35 fn is_valid(&self) -> bool {
36 if self.x == 0u32 && self.exp != 0 {
37 return false;
38 }
39 let exp = self.x.get_exponent();
40 exp.is_none() || exp == Some(0)
41 }
42
43 fn from_rational_prec_round(value: Rational, prec: u64, rm: RoundingMode) -> (Self, Ordering) {
44 if value == 0 {
45 return (
46 Self {
47 x: Float::ZERO,
48 exp: 0,
49 },
50 Equal,
51 );
52 }
53 let exp = value.floor_log_base_2_abs() + 1;
54 let (x, o) = Float::from_rational_prec_round(value >> exp, prec, rm);
55 let new_exp = x.get_exponent().unwrap();
56 (
57 Self {
58 x: x >> new_exp,
59 exp: i64::from(new_exp) + exp,
60 },
61 o,
62 )
63 }
64
65 pub(crate) fn from_rational_prec_round_ref(
66 value: &Rational,
67 prec: u64,
68 rm: RoundingMode,
69 ) -> (Self, Ordering) {
70 if *value == 0 {
71 return (
72 Self {
73 x: Float::ZERO,
74 exp: 0,
75 },
76 Equal,
77 );
78 }
79 let exp = value.floor_log_base_2_abs() + 1;
80 if exp >= i64::from(Float::MIN_EXPONENT) && exp <= i64::from(Float::MAX_EXPONENT) {
81 let (x, o) = Float::from_rational_prec_round_ref(value, prec, rm);
82 let exp = x.get_exponent().unwrap();
83 return (
84 Self {
85 x: x >> exp,
86 exp: i64::from(exp),
87 },
88 o,
89 );
90 }
91 let (x, o) = Float::from_rational_prec_round(value >> exp, prec, rm);
92 let new_exp = x.get_exponent().unwrap();
93 (
94 Self {
95 x: x >> new_exp,
96 exp: i64::from(new_exp) + exp,
97 },
98 o,
99 )
100 }
101
102 fn add_prec_ref_ref(&self, other: &Self, prec: u64) -> (Self, Ordering) {
103 assert!(self.is_valid());
104 assert!(other.is_valid());
105 assert!(self.x.is_normal());
106 assert!(other.x.is_normal());
107 Self::from_rational_prec_round(
108 Rational::exact_from(self) + Rational::exact_from(other),
109 prec,
110 Nearest,
111 )
112 }
113
114 fn sub_prec_ref_ref(&self, other: &Self, prec: u64) -> (Self, Ordering) {
115 assert!(self.is_valid());
116 assert!(other.is_valid());
117 assert!(self.x.is_normal());
118 assert!(other.x.is_normal());
119 Self::from_rational_prec_round(
120 Rational::exact_from(self) - Rational::exact_from(other),
121 prec,
122 Nearest,
123 )
124 }
125
126 fn sub_prec(self, other: Self, prec: u64) -> (Self, Ordering) {
127 assert!(self.is_valid());
128 assert!(other.is_valid());
129 assert!(self.x.is_normal());
130 assert!(other.x.is_normal());
131 Self::from_rational_prec_round(
132 Rational::exact_from(self) - Rational::exact_from(other),
133 prec,
134 Nearest,
135 )
136 }
137
138 fn mul_prec_ref_ref(&self, other: &Self, prec: u64) -> (Self, Ordering) {
139 assert!(self.is_valid());
140 assert!(other.is_valid());
141 assert!(self.x.is_normal());
142 assert!(other.x.is_normal());
143 let (mut product, o) = self.x.mul_prec_ref_ref(&other.x, prec);
144 let mut product_exp = self.exp + other.exp;
145 let extra_exp = product.get_exponent().unwrap();
146 product >>= extra_exp;
147 product_exp = product_exp.checked_add(i64::from(extra_exp)).unwrap();
148 (
149 Self {
150 x: product,
151 exp: product_exp,
152 },
153 o,
154 )
155 }
156
157 fn div_prec_val_ref(self, other: &Self, prec: u64) -> (Self, Ordering) {
158 assert!(self.is_valid());
159 assert!(other.is_valid());
160 assert!(self.x.is_normal());
161 assert!(other.x.is_normal());
162 let (mut quotient, o) = self.x.div_prec_ref_ref(&other.x, prec);
163 let mut quotient_exp = self.exp - other.exp;
164 let extra_exp = quotient.get_exponent().unwrap();
165 quotient >>= extra_exp;
166 quotient_exp = quotient_exp.checked_add(i64::from(extra_exp)).unwrap();
167 (
168 Self {
169 x: quotient,
170 exp: quotient_exp,
171 },
172 o,
173 )
174 }
175
176 fn div_prec_assign_ref(&mut self, other: &Self, prec: u64) -> Ordering {
177 let mut x = Self {
178 x: Float::ZERO,
179 exp: 0,
180 };
181 swap(self, &mut x);
182 let (q, o) = x.div_prec_val_ref(other, prec);
183 *self = q;
184 o
185 }
186
187 fn square_round_assign(&mut self, rm: RoundingMode) -> Ordering {
188 let mut x = Self {
189 x: Float::ZERO,
190 exp: 0,
191 };
192 swap(self, &mut x);
193 let (mut square, o) = x.x.square_round(rm);
194 let mut square_exp = x.exp << 1;
195 let extra_exp = square.get_exponent().unwrap();
196 square >>= extra_exp;
197 square_exp = square_exp.checked_add(i64::from(extra_exp)).unwrap();
198 *self = Self {
199 x: square,
200 exp: square_exp,
201 };
202 o
203 }
204
205 fn from_extended_float_prec_round(x: Self, prec: u64, rm: RoundingMode) -> (Self, Ordering) {
206 if let Ok(x) = Rational::try_from(&x) {
207 Self::from_rational_prec_round(x, prec, rm)
208 } else {
209 (x, Equal)
210 }
211 }
212
213 pub_crate_test! {from_extended_float_prec_round_ref(
214 x: &Self,
215 prec: u64,
216 rm: RoundingMode,
217 ) -> (Self, Ordering) {
218 if let Ok(x) = Rational::try_from(x) {
219 Self::from_rational_prec_round(x, prec, rm)
220 } else {
221 (x.clone(), Equal)
222 }
223 }}
224
225 fn shr_prec_round<T: PrimitiveInt>(
226 self,
227 bits: T,
228 prec: u64,
229 rm: RoundingMode,
230 ) -> (Self, Ordering) {
231 let (out_x, o) = Self::from_extended_float_prec_round(self, prec, rm);
233 let out_exp =
234 i64::exact_from(i128::from(out_x.exp) - SaturatingInto::<i128>::saturating_into(bits));
235 (
236 Self {
237 x: out_x.x,
238 exp: out_exp,
239 },
240 o,
241 )
242 }
243
244 fn shr_round_assign<T: PrimitiveInt>(&mut self, bits: T, _rm: RoundingMode) -> Ordering {
245 if self.x.is_normal() {
247 let out_exp = i64::exact_from(
248 i128::from(self.exp) - SaturatingInto::<i128>::saturating_into(bits),
249 );
250 self.exp = out_exp;
251 }
252 Equal
253 }
254
255 pub(crate) fn into_float_helper(
256 mut self,
257 prec: u64,
258 rm: RoundingMode,
259 previous_o: Ordering,
260 ) -> (Float, Ordering) {
261 let o = self
262 .x
263 .shl_prec_round_assign_helper(self.exp, prec, rm, previous_o);
264 (self.x, o)
265 }
266
267 pub(crate) fn increment(&mut self) {
268 self.x.increment();
269 if let Some(exp) = self.x.get_exponent()
270 && exp == 1
271 {
272 self.x >>= 1u32;
273 self.exp = 0;
274 }
275 }
276}
277
278impl From<Float> for ExtendedFloat {
279 fn from(value: Float) -> Self {
280 if let Some(exp) = value.get_exponent() {
281 Self {
282 x: value >> exp,
283 exp: i64::from(exp),
284 }
285 } else {
286 Self { x: value, exp: 0 }
287 }
288 }
289}
290
291impl TryFrom<ExtendedFloat> for Rational {
292 type Error = RationalFromFloatError;
293
294 fn try_from(value: ExtendedFloat) -> Result<Self, Self::Error> {
295 Self::try_from(value.x).map(|x| x << value.exp)
296 }
297}
298
299impl<'a> TryFrom<&'a ExtendedFloat> for Rational {
300 type Error = RationalFromFloatError;
301
302 fn try_from(value: &'a ExtendedFloat) -> Result<Self, Self::Error> {
303 Self::try_from(&value.x).map(|x| x << value.exp)
304 }
305}
306
307impl PartialEq for ExtendedFloat {
308 fn eq(&self, other: &Self) -> bool {
309 self.x == other.x && self.exp == other.exp
310 }
311}
312
313impl PartialOrd for ExtendedFloat {
314 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
315 assert!(self.is_valid());
316 assert!(other.is_valid());
317 let self_sign = self.x > 0u32;
318 let other_sign = other.x > 0u32;
319 match self_sign.cmp(&other_sign) {
320 Greater => Some(Greater),
321 Less => Some(Less),
322 Equal => match self.exp.cmp(&other.exp) {
323 Greater => Some(if self_sign { Greater } else { Less }),
324 Less => Some(if self_sign { Less } else { Greater }),
325 Equal => self.x.partial_cmp(&other.x),
326 },
327 }
328 }
329}
330
331impl Add<&ExtendedFloat> for &ExtendedFloat {
332 type Output = ExtendedFloat;
333
334 fn add(self, other: &ExtendedFloat) -> Self::Output {
335 let prec = max(self.x.significant_bits(), other.x.significant_bits());
336 self.add_prec_ref_ref(other, prec).0
337 }
338}
339
340impl Mul<&ExtendedFloat> for &ExtendedFloat {
341 type Output = ExtendedFloat;
342
343 fn mul(self, other: &ExtendedFloat) -> Self::Output {
344 let prec = max(self.x.significant_bits(), other.x.significant_bits());
345 self.mul_prec_ref_ref(other, prec).0
346 }
347}
348
349impl SqrtAssign for ExtendedFloat {
350 fn sqrt_assign(&mut self) {
351 if self.exp.odd() {
352 self.x <<= 1;
353 self.exp = self.exp.checked_sub(1).unwrap();
354 }
355 self.x.sqrt_assign();
356 self.exp >>= 1;
357 if let Some(new_exp) = self.x.get_exponent() {
358 self.exp = self.exp.checked_add(i64::from(new_exp)).unwrap();
359 self.x >>= new_exp;
360 }
361 assert!(self.is_valid());
362 }
363}
364
365impl Sqrt for ExtendedFloat {
366 type Output = Self;
367
368 fn sqrt(mut self) -> Self::Output {
369 self.sqrt_assign();
370 self
371 }
372}
373
374impl Shr<u32> for ExtendedFloat {
375 type Output = Self;
376
377 fn shr(mut self, bits: u32) -> Self::Output {
378 self.shr_round_assign(bits, Nearest);
379 self
380 }
381}
382
383impl ShrAssign<u32> for ExtendedFloat {
384 fn shr_assign(&mut self, bits: u32) {
385 self.shr_round_assign(bits, Nearest);
386 }
387}
388
389fn cmp2_helper_extended(b: &ExtendedFloat, c: &ExtendedFloat, cancel: &mut u64) -> Ordering {
390 match (&b.x, &c.x) {
391 (
392 Float(Finite {
393 precision: x_prec,
394 significand: x,
395 ..
396 }),
397 Float(Finite {
398 precision: y_prec,
399 significand: y,
400 ..
401 }),
402 ) => {
403 let (o, c) = exponent_shift_compare(
404 x.as_limbs_asc(),
405 b.exp,
406 *x_prec,
407 y.as_limbs_asc(),
408 c.exp,
409 *y_prec,
410 );
411 *cancel = c;
412 o
413 }
414 _ => panic!(),
415 }
416}
417
418pub(crate) fn agm_prec_round_normal_extended(
419 mut a: ExtendedFloat,
420 mut b: ExtendedFloat,
421 prec: u64,
422 rm: RoundingMode,
423) -> (ExtendedFloat, Ordering) {
424 if a.x < 0u32 || b.x < 0u32 {
425 return (
426 ExtendedFloat {
427 x: float_nan!(),
428 exp: 0,
429 },
430 Equal,
431 );
432 }
433 let q = prec;
434 let mut working_prec = q + q.ceiling_log_base_2() + 15;
435 match a.partial_cmp(&b).unwrap() {
437 Equal => return ExtendedFloat::from_extended_float_prec_round(a, prec, rm),
438 Greater => swap(&mut a, &mut b),
439 _ => {}
440 }
441 let mut increment = Limb::WIDTH;
442 let mut v;
443 let mut scaleit;
444 loop {
445 let mut err: u64 = 0;
446 let mut u = a.mul_prec_ref_ref(&b, working_prec).0;
447 v = a.add_prec_ref_ref(&b, working_prec).0;
448 u.sqrt_assign();
449 v >>= 1u32;
450 scaleit = 0;
451 let mut n: u64 = 1;
452 let mut eq = 0;
453 while cmp2_helper_extended(&u, &v, &mut eq) != Equal && eq <= working_prec - 2 {
454 let mut vf;
455 vf = (&u + &v) >> 1;
456 if eq > working_prec >> 2 {
458 let low_p = (working_prec + 1) >> 1;
460 let mut w = v.sub_prec_ref_ref(&u, low_p).0; w.square_round_assign(Nearest); w.shr_round_assign(4, Nearest); w.div_prec_assign_ref(&vf, low_p); let vf_exp = vf.exp;
465 v = vf.sub_prec(w, working_prec).0;
466 err = u64::exact_from(vf_exp - v.exp);
468 break;
469 }
470 let uf = &u * &v;
471 u = uf.sqrt();
472 swap(&mut v, &mut vf);
473 n += 1;
474 }
475 err += (18 * n + 51).ceiling_log_base_2();
480 if (n + 2).ceiling_log_base_2() <= working_prec >> 2
482 && float_can_round(v.x.significand_ref().unwrap(), working_prec - err, q, rm)
483 {
484 break;
485 }
486 working_prec += increment;
487 increment = working_prec >> 1;
488 }
489 v.shr_prec_round(scaleit, prec, rm)
490}
491
492pub_crate_test! {agm_prec_round_normal_ref_ref_extended<'a>(
493 mut a: &'a ExtendedFloat,
494 mut b: &'a ExtendedFloat,
495 prec: u64,
496 rm: RoundingMode,
497) -> (ExtendedFloat, Ordering) {
498 if a.x < 0u32 || b.x < 0u32 {
499 return (
500 ExtendedFloat {
501 x: float_nan!(),
502 exp: 0,
503 },
504 Equal,
505 );
506 }
507 let q = prec;
508 let mut working_prec = q + q.ceiling_log_base_2() + 15;
509 match a.partial_cmp(b).unwrap() {
511 Equal => return ExtendedFloat::from_extended_float_prec_round_ref(a, prec, rm),
512 Greater => swap(&mut a, &mut b),
513 _ => {}
514 }
515 let mut increment = Limb::WIDTH;
516 let mut v;
517 let mut scaleit;
518 loop {
519 let mut err: u64 = 0;
520 let mut u = a.mul_prec_ref_ref(b, working_prec).0;
521 v = a.add_prec_ref_ref(b, working_prec).0;
522 u.sqrt_assign();
523 v >>= 1u32;
524 scaleit = 0;
525 let mut n: u64 = 1;
526 let mut eq = 0;
527 while cmp2_helper_extended(&u, &v, &mut eq) != Equal && eq <= working_prec - 2 {
528 let mut vf;
529 vf = (&u + &v) >> 1;
530 if eq > working_prec >> 2 {
532 let low_p = (working_prec + 1) >> 1;
534 let mut w = v.sub_prec_ref_ref(&u, low_p).0; assert!(w.is_valid());
536 assert!(w.x.is_normal());
537 w.square_round_assign(Nearest); assert!(w.is_valid());
539 assert!(w.x.is_normal());
540 w.shr_round_assign(4, Nearest); assert!(w.is_valid());
542 assert!(w.x.is_normal());
543 w.div_prec_assign_ref(&vf, low_p); let vf_exp = vf.exp;
545 v = vf.sub_prec(w, working_prec).0;
546 err = u64::exact_from(vf_exp - v.exp);
548 break;
549 }
550 let uf = &u * &v;
551 u = uf.sqrt();
552 swap(&mut v, &mut vf);
553 n += 1;
554 }
555 err += (18 * n + 51).ceiling_log_base_2();
560 if (n + 2).ceiling_log_base_2() <= working_prec >> 2
562 && float_can_round(v.x.significand_ref().unwrap(), working_prec - err, q, rm)
563 {
564 break;
565 }
566 working_prec += increment;
567 increment = working_prec >> 1;
568 }
569 v.shr_prec_round(scaleit, prec, rm)
570}}