boostvoronoi_ext/
extended_exp_fpt.rs

1// Boost.Polygon library detail/voronoi_structures.hpp header file
2
3//          Copyright Andrii Sydorchuk 2010-2012.
4// Distributed under the Boost Software License, Version 1.0.
5//    (See accompanying file LICENSE_1_0.txt or copy at
6//          http://www.boost.org/LICENSE_1_0.txt)
7
8// See http://www.boost.org for updates, documentation, and revision history of C++ code..
9
10// Ported from C++ boost 1.76.0 to Rust in 2020/2021 by Eadf (github.com/eadf)
11
12//! Utilities for extended float. Supports 63 bit mantissa with 32 bit exponent.
13use crate::extended_int as EI;
14use num_traits::Float as OutputType;
15use std::fmt;
16use std::ops;
17
18/// Floating point type wrapper. Allows to extend exponent boundaries to the
19/// integer type range. This class does not handle division by zero, subnormal
20/// numbers or NaNs.
21/// Ported from the class extended_exponent_fpt in voronoi_ctypes.hpp
22#[derive(Copy, Clone)]
23pub struct ExtendedExponentFpt<F: OutputType> {
24    val_: F,
25    exp_: i32,
26}
27
28const MAX_SIGNIFICANT_EXP_DIF_F64: i32 = 54;
29
30impl From<&EI::ExtendedInt> for ExtendedExponentFpt<f64> {
31    #[inline]
32    /// Converts to ExtendedExponentFpt::<f64> from &ExtendedInt
33    /// ```
34    /// # use boostvoronoi_ext::extended_int::ExtendedInt;
35    /// # use boostvoronoi_ext::extended_exp_fpt::ExtendedExponentFpt;
36    ///
37    /// let aa = 41232131332_f64;
38    /// let a = ExtendedInt::from(aa as i64);
39    /// let e = ExtendedExponentFpt::from(&a);
40    /// approx::assert_ulps_eq!(e.d(), aa);
41    /// ```
42    fn from(that: &EI::ExtendedInt) -> Self {
43        let p = that.p();
44        Self::new(p.0, p.1)
45    }
46}
47
48impl From<EI::ExtendedInt> for ExtendedExponentFpt<f64> {
49    #[inline]
50    /// Converts to `ExtendedExponentFpt::<f64>` from `ExtendedInt`
51    /// ```
52    /// # use boostvoronoi_ext::extended_int::ExtendedInt;
53    /// # use boostvoronoi_ext::extended_exp_fpt::ExtendedExponentFpt;
54    ///
55    /// let aa = 41232131332_f64;
56    /// let a = ExtendedInt::from(aa as i64);
57    /// let e = ExtendedExponentFpt::from(a);
58    /// approx::assert_ulps_eq!(e.d(), aa);
59    /// ```
60    fn from(that: EI::ExtendedInt) -> Self {
61        let p = that.p();
62        Self::new(p.0, p.1)
63    }
64}
65
66impl From<ExtendedExponentFpt<f64>> for f64 {
67    #[inline]
68    /// Converts from `ExtendedExponentFpt<f64>` to `f64`
69    /// ```
70    /// # use boostvoronoi_ext::extended_exp_fpt::ExtendedExponentFpt;
71    ///
72    /// let f1 = 345345345453_f64;
73    /// let e = ExtendedExponentFpt::from(f1);
74    /// let f2 = f64::from(e);
75    /// approx::assert_ulps_eq!(f1, f2);
76    /// ```
77    fn from(that: ExtendedExponentFpt<f64>) -> f64 {
78        that.d()
79    }
80}
81
82impl From<f64> for ExtendedExponentFpt<f64> {
83    #[inline]
84    /// Converts from `f64` to `ExtendedExponentFpt<f64>`
85    /// ```
86    /// # use boostvoronoi_ext::extended_exp_fpt::ExtendedExponentFpt;
87    ///
88    /// let f1 = 345345345453_f64;
89    /// let e = ExtendedExponentFpt::from(f1);
90    /// let f2 = f64::from(e);
91    /// approx::assert_ulps_eq!(f1, f2);
92    /// ```
93    fn from(that: f64) -> ExtendedExponentFpt<f64> {
94        let rv = libm::frexp(that);
95        Self::new(rv.0, rv.1)
96    }
97}
98
99#[allow(dead_code)]
100impl ExtendedExponentFpt<f64> {
101    #[inline]
102    /// Constructor with value and exponent as arguments.
103    /// The value of this number is 'val_' * 2^ 'exp_'
104    /// ```
105    /// # use boostvoronoi_ext::extended_exp_fpt::ExtendedExponentFpt;
106    ///
107    /// let a = ExtendedExponentFpt::<f64>::new(1.0, 12);
108    /// approx::assert_ulps_eq!(a.d(), 4096.0);
109    /// ```
110    pub fn new(val: f64, exp: i32) -> Self {
111        let fr = libm::frexp(val);
112        Self {
113            val_: fr.0,
114            exp_: exp + fr.1,
115        }
116    }
117
118    /// Is positive method.
119    /// IMPORTANT!!!!! in the c++ boost voronoi implementation zero values can't be positive.
120    /// ```
121    /// # use boostvoronoi_ext::extended_exp_fpt::ExtendedExponentFpt;
122    ///
123    /// let aa:f64 = 0_f64;
124    /// let a = ExtendedExponentFpt::<f64>::from(aa);
125    /// assert_eq!(a.is_pos(), false);
126    ///
127    /// let aa:f64 = -0_f64;
128    /// let a = ExtendedExponentFpt::<f64>::from(aa);
129    /// assert_eq!(a.is_pos(), false);
130    ///
131    /// let aa:f64 = f64::MIN_POSITIVE;
132    /// let a = ExtendedExponentFpt::<f64>::from(aa);
133    /// assert_eq!(a.is_pos(), aa.is_sign_positive());
134    /// ```
135    #[inline]
136    pub fn is_pos(&self) -> bool {
137        self.val_ > 0.0
138    }
139
140    /// Is negative method.
141    /// IMPORTANT!!!!! in the c++ boost voronoi implementation zero values can't be negative.
142    /// ```
143    /// # use boostvoronoi_ext::extended_exp_fpt;
144    ///
145    /// let aa:f64 = 0_f64;
146    /// let a = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(aa);
147    /// assert_eq!(a.is_neg(), aa.is_sign_negative());
148    ///
149    /// let aa:f64 = -0_f64;
150    /// let a = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(aa);
151    /// assert_eq!(a.is_neg(), false);
152    /// ```
153    #[inline]
154    pub fn is_neg(&self) -> bool {
155        self.val_ < 0.0
156    }
157
158    /// Is zero method.
159    /// ```
160    /// # use boostvoronoi_ext::extended_exp_fpt;
161    /// # use num_traits::identities::Zero;
162    ///
163    /// let aa:f64 = 0_f64;
164    /// let a = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(aa);
165    /// assert_eq!(a.is_zero(), aa.is_zero());
166    ///
167    /// let aa:f64 = -0_f64;
168    /// let a = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(aa);
169    /// assert_eq!(a.is_zero(), aa.is_zero());
170    ///
171    /// let aa:f64 = f64::MIN_POSITIVE;
172    /// let a = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(aa);
173    /// assert_eq!(a.is_zero(), aa.is_zero());
174    ///
175    /// let aa:f64 = -f64::MIN_POSITIVE;
176    /// let a = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(aa);
177    /// assert_eq!(a.is_zero(), aa.is_zero());
178    /// ```
179    #[inline]
180    pub fn is_zero(&self) -> bool {
181        self.val_ == 0.0
182    }
183
184    /// Square root method.
185    /// ```
186    /// # use boostvoronoi_ext::extended_exp_fpt;
187    ///
188    /// let aa:f64 = f64::MAX;
189    /// let a = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(aa);
190    /// approx::assert_ulps_eq!(a.d(), aa);
191    /// let a = a.sqrt();
192    /// approx::assert_ulps_eq!(a.d(), aa.sqrt());
193    /// ```
194    #[inline]
195    pub fn sqrt(&self) -> Self {
196        let mut val = self.val_;
197        let mut exp = self.exp_;
198        if (exp & 1) != 0 {
199            val *= 2.0;
200            exp -= 1;
201        }
202
203        Self::new(val.sqrt(), exp >> 1)
204    }
205
206    /// A to-float operation.
207    /// ```
208    /// # use boostvoronoi_ext::extended_exp_fpt;
209    ///
210    /// let aa:f64 = 1000000000.0;
211    /// let a = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(aa);
212    /// approx::assert_ulps_eq!(a.d(), aa);
213    /// let a = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(-aa);
214    /// approx::assert_ulps_eq!(a.d(), -aa);
215    /// ```
216    pub fn d(&self) -> f64 {
217        libm::ldexp(self.val_, self.exp_)
218    }
219
220    pub fn val(&self) -> f64 {
221        self.val_
222    }
223
224    pub fn exp(&self) -> i32 {
225        self.exp_
226    }
227}
228
229impl ops::Neg for ExtendedExponentFpt<f64> {
230    type Output = Self;
231
232    /// ```
233    /// # use boostvoronoi_ext::extended_exp_fpt;
234    ///
235    /// let a = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(1_f64);
236    ///
237    /// approx::assert_ulps_eq!(a.d(), 1_f64);
238    /// let c = -a;
239    /// approx::assert_ulps_eq!(c.d(), -1_f64);
240    /// let a = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(1000000000_f64);
241    /// approx::assert_ulps_eq!(a.d(), 1000000000_f64);
242    /// let c = -a;
243    /// approx::assert_ulps_eq!(c.d(), -1000000000_f64);
244    /// ```
245    fn neg(self) -> Self {
246        Self {
247            val_: -self.val_,
248            exp_: self.exp_,
249        }
250    }
251}
252
253impl ops::Add for ExtendedExponentFpt<f64> {
254    type Output = Self;
255
256    /// ```
257    /// # use boostvoronoi_ext::extended_exp_fpt;
258    ///
259    /// let a = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(1_f64);
260    /// let b = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(2_f64);
261    ///
262    /// approx::assert_ulps_eq!(a.d(), 1_f64);
263    /// approx::assert_ulps_eq!(b.d(), 2_f64);
264    /// let c = a + b;
265    /// approx::assert_ulps_eq!(c.d(), 3_f64);
266    /// let c = c + b;
267    /// approx::assert_ulps_eq!(c.d(), 5_f64);
268    /// let a = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(1000000000_f64);
269    /// let b = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(2000000000_f64);
270    /// approx::assert_ulps_eq!(a.d(), 1000000000_f64);
271    /// approx::assert_ulps_eq!(b.d(), 2000000000_f64);
272    /// let c = a + b;
273    /// approx::assert_ulps_eq!(c.d(), 3000000000_f64);
274    /// ```
275    fn add(self, that: Self) -> Self {
276        if self.val_ == 0.0 || that.exp_ > self.exp_ + MAX_SIGNIFICANT_EXP_DIF_F64 {
277            return that;
278        }
279        if that.val_ == 0.0 || self.exp_ > that.exp_ + MAX_SIGNIFICANT_EXP_DIF_F64 {
280            return self;
281        }
282        if self.exp_ >= that.exp_ {
283            let exp_dif = self.exp_ - that.exp_;
284            let val = libm::ldexp(self.val_, exp_dif) + that.val_;
285            Self::new(val, that.exp_)
286        } else {
287            let exp_dif = that.exp_ - self.exp_;
288            let val = libm::ldexp(that.val_, exp_dif) + self.val_;
289            Self::new(val, self.exp_)
290        }
291    }
292}
293
294impl ops::Sub for ExtendedExponentFpt<f64> {
295    type Output = Self;
296    /// ```
297    /// # use boostvoronoi_ext::extended_exp_fpt;
298    ///
299    /// let a = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(1_f64);
300    /// let b = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(-2_f64);
301    ///
302    /// approx::assert_ulps_eq!(a.d(), 1_f64);
303    /// approx::assert_ulps_eq!(b.d(), -2_f64);
304    /// let c = a - b;
305    /// approx::assert_ulps_eq!(c.d(), 3_f64);
306    /// let c = c - b;
307    /// approx::assert_ulps_eq!(c.d(), 5_f64);
308    /// let a = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(1000000000_f64);
309    /// let b = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(-3000000000_f64);
310    /// approx::assert_ulps_eq!(a.d(), 1000000000_f64);
311    /// approx::assert_ulps_eq!(b.d(), -3000000000_f64);
312    /// let c = a - b;
313    /// approx::assert_ulps_eq!(c.d(), 1000000000_f64-(-3000000000.0));
314    /// ```
315    fn sub(self, that: Self) -> Self {
316        if self.val_ == 0.0 || that.exp_ > self.exp_ + MAX_SIGNIFICANT_EXP_DIF_F64 {
317            return Self::new(-that.val_, that.exp_);
318        }
319        if that.val_ == 0.0 || self.exp_ > that.exp_ + MAX_SIGNIFICANT_EXP_DIF_F64 {
320            return self;
321        }
322        if self.exp_ >= that.exp_ {
323            let exp_dif = self.exp_ - that.exp_;
324            let val = libm::ldexp(self.val_, exp_dif) - that.val_;
325            Self::new(val, that.exp_)
326        } else {
327            let exp_dif = that.exp_ - self.exp_;
328            let val = libm::ldexp(-that.val_, exp_dif) + self.val_;
329            Self::new(val, self.exp_)
330        }
331    }
332}
333
334impl ops::Mul for ExtendedExponentFpt<f64> {
335    type Output = Self;
336    /// ```
337    /// # use boostvoronoi_ext::extended_exp_fpt;
338    ///
339    /// let a = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(1_f64);
340    /// let b = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(2_f64);
341    ///
342    /// approx::assert_ulps_eq!(a.d(), 1_f64);
343    /// approx::assert_ulps_eq!(b.d(), 2_f64);
344    /// let c = a * b;
345    /// approx::assert_ulps_eq!(c.d(), 2_f64);
346    /// let a = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(1000000000_f64);
347    /// let b = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(2000000000_f64);
348    /// approx::assert_ulps_eq!(a.d(), 1000000000_f64);
349    /// approx::assert_ulps_eq!(b.d(), 2000000000_f64);
350    /// let c = a * b;
351    /// approx::assert_ulps_eq!(c.d(), 1000000000_f64*2000000000_f64);
352    /// ```
353    fn mul(self, that: Self) -> Self {
354        let val = self.val_ * that.val_;
355        let exp = self.exp_ + that.exp_;
356        Self::new(val, exp)
357    }
358}
359
360impl ops::Mul<f64> for ExtendedExponentFpt<f64> {
361    type Output = Self;
362    /// ```
363    /// # use boostvoronoi_ext::extended_exp_fpt;
364    ///
365    /// let a = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(7_f64);
366    /// let b = 2_f64;
367    ///
368    /// approx::assert_ulps_eq!(a.d(), 7_f64);
369    /// approx::assert_ulps_eq!(b, 2_f64);
370    /// let c = a * b;
371    /// approx::assert_ulps_eq!(c.d(), 7_f64*2_f64);
372    /// let a = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(1234567890_f64);
373    /// let b = 2000000000_f64;
374    /// approx::assert_ulps_eq!(a.d(), 1234567890_f64);
375    /// approx::assert_ulps_eq!(b, 2000000000_f64);
376    /// let c = a * b;
377    /// approx::assert_ulps_eq!(c.d(), 1234567890_f64*2000000000_f64);
378    /// ```
379    fn mul(self, that: f64) -> Self {
380        let that = Self::from(that);
381        self * that
382    }
383}
384
385impl ops::Div for ExtendedExponentFpt<f64> {
386    type Output = Self;
387    /// ```
388    /// # use boostvoronoi_ext::extended_exp_fpt;
389    ///
390    /// let a = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(1_f64);
391    /// let b = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(2_f64);
392    ///
393    /// approx::assert_ulps_eq!(a.d(), 1_f64);
394    /// approx::assert_ulps_eq!(b.d(), 2_f64);
395    /// let c = a / b;
396    /// approx::assert_ulps_eq!(c.d(), 1.0/2.0);
397    /// let a = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(2000000000_f64);
398    /// let b = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(-2000000000_f64);
399    /// approx::assert_ulps_eq!(a.d(),  2000000000_f64);
400    /// approx::assert_ulps_eq!(b.d(), -2000000000_f64);
401    /// let c = a / b;
402    /// approx::assert_ulps_eq!(c.d(), -1f64);
403    /// ```
404    fn div(self, that: Self) -> Self {
405        let val = self.val_ / that.val_;
406        let exp = self.exp_ - that.exp_;
407        Self::new(val, exp)
408    }
409}
410
411impl ops::Div<f64> for ExtendedExponentFpt<f64> {
412    type Output = Self;
413    /// ```
414    /// # use boostvoronoi_ext::extended_exp_fpt;
415    ///
416    /// let a = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(1_f64);
417    /// let b = 2_f64;
418    ///
419    /// approx::assert_ulps_eq!(a.d(), 1_f64);
420    /// let c = a / b;
421    /// approx::assert_ulps_eq!(c.d(), 1.0/2.0);
422    /// let a = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(2000000000_f64);
423    /// let b = -2000000000_f64;
424    /// approx::assert_ulps_eq!(a.d(),  2000000000_f64);
425    /// let c = a / b;
426    /// approx::assert_ulps_eq!(c.d(), -1f64);
427    /// ```
428    fn div(self, that: f64) -> Self {
429        let that = Self::from(that);
430        let val = self.val_ / that.val_;
431        let exp = self.exp_ - that.exp_;
432        Self::new(val, exp)
433    }
434}
435
436impl ops::AddAssign for ExtendedExponentFpt<f64> {
437    /// ```
438    /// # use boostvoronoi_ext::extended_exp_fpt;
439    ///
440    /// let mut a = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(1_f64);
441    /// let b = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(2_f64);
442    ///
443    /// approx::assert_ulps_eq!(a.d(), 1_f64);
444    /// approx::assert_ulps_eq!(b.d(), 2_f64);
445    /// a += b;
446    /// approx::assert_ulps_eq!(a.d(), 3_f64);
447    /// a += b;
448    /// approx::assert_ulps_eq!(a.d(), 5_f64);
449    /// let mut a = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(1000000000_f64);
450    /// let b = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(2000000000_f64);
451    /// approx::assert_ulps_eq!(a.d(), 1000000000_f64);
452    /// approx::assert_ulps_eq!(b.d(), 2000000000_f64);
453    /// a += b;
454    /// approx::assert_ulps_eq!(a.d(), 3000000000_f64);
455    /// ```
456    fn add_assign(&mut self, that: Self) {
457        if self.val_ == 0.0 || that.exp_ > self.exp_ + MAX_SIGNIFICANT_EXP_DIF_F64 {
458            self.val_ = that.val_;
459            self.exp_ = that.exp_;
460        }
461        if that.val_ == 0.0 || self.exp_ > that.exp_ + MAX_SIGNIFICANT_EXP_DIF_F64 {
462            // do nothing
463            return;
464        }
465        if self.exp_ >= that.exp_ {
466            let exp_dif = self.exp_ - that.exp_;
467            let val = libm::ldexp(self.val_, exp_dif) + that.val_;
468            self.val_ = val;
469            self.exp_ = that.exp_;
470        } else {
471            let exp_dif = that.exp_ - self.exp_;
472            let val = libm::ldexp(that.val_, exp_dif) + self.val_;
473            self.val_ = val;
474            //self.exp_ = self.exp;
475        }
476    }
477}
478
479impl ops::SubAssign for ExtendedExponentFpt<f64> {
480    /// ```
481    /// # use boostvoronoi_ext::extended_exp_fpt;
482    ///
483    /// let mut a = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(1_f64);
484    /// let b = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(-2_f64);
485    ///
486    /// approx::assert_ulps_eq!(a.d(), 1_f64);
487    /// approx::assert_ulps_eq!(b.d(), -2_f64);
488    /// a -= b;
489    /// approx::assert_ulps_eq!(a.d(), 3_f64);
490    /// a -= b;
491    /// approx::assert_ulps_eq!(a.d(), 5_f64);
492    /// let mut a = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(1000000000_f64);
493    /// let b = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(-3000000000_f64);
494    /// approx::assert_ulps_eq!(a.d(), 1000000000_f64);
495    /// approx::assert_ulps_eq!(b.d(), -3000000000_f64);
496    /// a -= b;
497    /// approx::assert_ulps_eq!(a.d(), 1000000000_f64-(-3000000000.0));
498    /// ```
499    fn sub_assign(&mut self, that: Self) {
500        if self.val_ == 0.0 || that.exp_ > self.exp_ + MAX_SIGNIFICANT_EXP_DIF_F64 {
501            self.val_ = -that.val_;
502            self.exp_ = that.exp_;
503        }
504        if that.val_ == 0.0 || self.exp_ > that.exp_ + MAX_SIGNIFICANT_EXP_DIF_F64 {
505            return;
506        }
507        if self.exp_ >= that.exp_ {
508            let exp_dif = self.exp_ - that.exp_;
509            let val = libm::ldexp(self.val_, exp_dif) - that.val_;
510            self.val_ = val;
511            self.exp_ = that.exp_;
512        } else {
513            let exp_dif = that.exp_ - self.exp_;
514            let val = libm::ldexp(-that.val_, exp_dif) + self.val_;
515            self.val_ = val;
516            //self.exp_ = self.exp_;
517        }
518    }
519}
520
521impl ops::MulAssign for ExtendedExponentFpt<f64> {
522    /// ```
523    /// # use boostvoronoi_ext::extended_exp_fpt;
524    ///
525    /// let mut a = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(1_f64);
526    /// let b = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(2_f64);
527    ///
528    /// approx::assert_ulps_eq!(a.d(), 1_f64);
529    /// approx::assert_ulps_eq!(b.d(), 2_f64);
530    /// a *= b;
531    /// approx::assert_ulps_eq!(a.d(), 2_f64);
532    /// let mut a = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(1000000000_f64);
533    /// let     b = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(2000000000_f64);
534    /// approx::assert_ulps_eq!(a.d(), 1000000000_f64);
535    /// approx::assert_ulps_eq!(b.d(), 2000000000_f64);
536    /// a *= b;
537    /// approx::assert_ulps_eq!(a.d(), 1000000000_f64*2000000000_f64);
538    /// ```
539    fn mul_assign(&mut self, that: Self) {
540        self.val_ *= that.val_;
541        self.exp_ += that.exp_;
542    }
543}
544
545impl ops::DivAssign for ExtendedExponentFpt<f64> {
546    /// ```
547    /// # use boostvoronoi_ext::extended_exp_fpt;
548    ///
549    /// let mut a = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(1_f64);
550    /// let b = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(2_f64);
551    ///
552    /// approx::assert_ulps_eq!(a.d(), 1_f64);
553    /// approx::assert_ulps_eq!(b.d(), 2_f64);
554    /// a /= b;
555    /// approx::assert_ulps_eq!(a.d(), 1.0/2.0);
556    /// let mut a = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(2000000000_f64);
557    /// let b = extended_exp_fpt::ExtendedExponentFpt::<f64>::from(-2000000000_f64);
558    /// approx::assert_ulps_eq!(a.d(),  2000000000_f64);
559    /// approx::assert_ulps_eq!(b.d(), -2000000000_f64);
560    /// a /= b;
561    /// approx::assert_ulps_eq!(a.d(), -1f64);
562    /// ```
563    fn div_assign(&mut self, that: Self) {
564        self.val_ /= that.val_;
565        self.exp_ -= that.exp_;
566    }
567}
568
569impl fmt::Debug for ExtendedExponentFpt<f64> {
570    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
571        write!(f, "{}^{}", self.val_, self.exp_)
572    }
573}