1use core::cmp::Ordering;
2
3use dashu_base::{
4 Approximation::{self, *},
5 BitTest, ConversionError, DivRem, FloatEncoding, PowerOfTwo, Sign, UnsignedAbs,
6};
7use dashu_int::{IBig, UBig};
8
9use crate::{
10 rbig::{RBig, Relaxed},
11 repr::Repr,
12};
13
14impl From<UBig> for Repr {
15 #[inline]
16 fn from(v: UBig) -> Self {
17 Repr {
18 numerator: v.into(),
19 denominator: UBig::ONE,
20 }
21 }
22}
23
24impl From<IBig> for Repr {
25 #[inline]
26 fn from(v: IBig) -> Self {
27 Repr {
28 numerator: v,
29 denominator: UBig::ONE,
30 }
31 }
32}
33
34impl TryFrom<Repr> for UBig {
35 type Error = ConversionError;
36 #[inline]
37 fn try_from(value: Repr) -> Result<Self, Self::Error> {
38 let (sign, mag) = value.numerator.into_parts();
39 if sign == Sign::Negative {
40 Err(ConversionError::OutOfBounds)
41 } else if mag.is_one() {
42 Ok(mag)
43 } else {
44 Err(ConversionError::LossOfPrecision)
45 }
46 }
47}
48
49impl TryFrom<Repr> for IBig {
50 type Error = ConversionError;
51 #[inline]
52 fn try_from(value: Repr) -> Result<Self, Self::Error> {
53 if value.denominator.is_one() {
54 Ok(value.numerator)
55 } else {
56 Err(ConversionError::LossOfPrecision)
57 }
58 }
59}
60
61macro_rules! forward_conversion_to_repr {
62 ($from:ty => $t:ident) => {
63 impl From<$from> for $t {
64 #[inline]
65 fn from(v: $from) -> Self {
66 $t(Repr::from(v))
67 }
68 }
69 impl TryFrom<$t> for $from {
70 type Error = ConversionError;
71 #[inline]
72 fn try_from(value: $t) -> Result<Self, Self::Error> {
73 Self::try_from(value.0)
74 }
75 }
76 };
77}
78forward_conversion_to_repr!(UBig => RBig);
79forward_conversion_to_repr!(IBig => RBig);
80forward_conversion_to_repr!(UBig => Relaxed);
81forward_conversion_to_repr!(IBig => Relaxed);
82
83macro_rules! impl_conversion_for_prim_ints {
84 ($($t:ty)*) => {$(
85 impl From<$t> for Repr {
86 #[inline]
87 fn from(v: $t) -> Repr {
88 Repr {
89 numerator: v.into(),
90 denominator: UBig::ONE
91 }
92 }
93 }
94
95 impl TryFrom<Repr> for $t {
96 type Error = ConversionError;
97 #[inline]
98 fn try_from(value: Repr) -> Result<Self, Self::Error> {
99 let int: IBig = value.try_into()?;
100 int.try_into()
101 }
102 }
103
104 forward_conversion_to_repr!($t => RBig);
105 forward_conversion_to_repr!($t => Relaxed);
106 )*};
107}
108impl_conversion_for_prim_ints!(u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize);
109
110macro_rules! impl_conversion_from_float {
111 ($t:ty) => {
112 impl TryFrom<$t> for Repr {
113 type Error = ConversionError;
114
115 fn try_from(value: $t) -> Result<Self, Self::Error> {
116 if value == 0. {
118 return Ok(Repr::zero());
119 }
120
121 match value.decode() {
122 Ok((man, exp)) => {
123 let repr = if exp >= 0 {
126 Repr {
127 numerator: IBig::from(man) << exp as usize,
128 denominator: UBig::ONE,
129 }
130 } else {
131 let mut denominator = UBig::ZERO;
132 denominator.set_bit((-exp) as _);
133 Repr {
134 numerator: IBig::from(man),
135 denominator,
136 }
137 };
138 Ok(repr)
139 }
140 Err(_) => Err(ConversionError::OutOfBounds),
141 }
142 }
143 }
144
145 impl TryFrom<$t> for RBig {
146 type Error = ConversionError;
147 #[inline]
148 fn try_from(value: $t) -> Result<Self, Self::Error> {
149 Repr::try_from(value).map(|repr| RBig(repr.reduce2()))
150 }
151 }
152 impl TryFrom<$t> for Relaxed {
153 type Error = ConversionError;
154 #[inline]
155 fn try_from(value: $t) -> Result<Self, Self::Error> {
156 Repr::try_from(value).map(|repr| Relaxed(repr.reduce2()))
157 }
158 }
159 };
160}
161impl_conversion_from_float!(f32);
162impl_conversion_from_float!(f64);
163
164macro_rules! impl_conversion_to_float {
165 ($t:ty [$lb:literal, $ub:literal]) => {
166 impl TryFrom<RBig> for $t {
167 type Error = ConversionError;
168
169 fn try_from(value: RBig) -> Result<Self, Self::Error> {
172 if value.0.numerator.is_zero() {
173 Ok(0.)
174 } else if value.0.denominator.is_power_of_two() {
175 let num_bits = value.0.numerator.bit_len();
177 let den_bits = value.0.denominator.trailing_zeros().unwrap();
178 let top_bit = num_bits as isize - den_bits as isize;
179 if top_bit > $ub {
180 Err(ConversionError::OutOfBounds)
182 } else if top_bit < $lb {
183 Err(ConversionError::LossOfPrecision)
184 } else {
185 match <$t>::encode(
186 value.0.numerator.try_into().unwrap(),
187 -(den_bits as i16),
188 ) {
189 Exact(v) => Ok(v),
190 Inexact(v, _) => {
191 if v.is_infinite() {
192 Err(ConversionError::OutOfBounds)
193 } else {
194 Err(ConversionError::LossOfPrecision)
195 }
196 }
197 }
198 }
199 } else {
200 Err(ConversionError::LossOfPrecision)
201 }
202 }
203 }
204
205 impl TryFrom<Relaxed> for $t {
206 type Error = ConversionError;
207
208 #[inline]
209 fn try_from(value: Relaxed) -> Result<Self, Self::Error> {
210 <$t>::try_from(value.canonicalize())
212 }
213 }
214 };
215}
216impl_conversion_to_float!(f32 [-149, 128]); impl_conversion_to_float!(f64 [-1074, 1024]); impl Repr {
220 fn to_f32_fast(&self) -> f32 {
222 if self.numerator.is_zero() {
224 return 0.;
225 }
226
227 let sign = self.numerator.sign();
229 let num_bits = self.numerator.bit_len();
230 let den_bits = self.denominator.bit_len();
231
232 let num_shift = num_bits as isize - 48;
233 let num48: i64 = if num_shift >= 0 {
234 (&self.numerator) >> num_shift as usize
235 } else {
236 (&self.numerator) << (-num_shift) as usize
237 }
238 .try_into()
239 .unwrap();
240
241 let den_shift = den_bits as isize - 24;
242 let den24: u32 = if den_shift >= 0 {
243 (&self.denominator) >> den_shift as usize
244 } else {
245 (&self.denominator) << (-den_shift) as usize
246 }
247 .try_into()
248 .unwrap();
249
250 let exponent = num_shift - den_shift;
252 if exponent >= 128 {
253 sign * f32::INFINITY
255 } else if exponent < -149 - 25 {
256 sign * 0f32
258 } else {
259 let (mut man, r) = num48.unsigned_abs().div_rem(den24 as u64);
260
261 let half = (r as u32 * 2).cmp(&den24);
263 if half == Ordering::Greater || (half == Ordering::Equal && man & 1 > 0) {
264 man += 1;
265 }
266 f32::encode(sign * man as i32, exponent as i16).value()
267 }
268 }
269
270 fn to_f64_fast(&self) -> f64 {
271 if self.numerator.is_zero() {
273 return 0.;
274 }
275
276 let sign = self.numerator.sign();
278 let num_bits = self.numerator.bit_len();
279 let den_bits = self.denominator.bit_len();
280
281 let num_shift = num_bits as isize - 106;
282 let num106: i128 = if num_shift >= 0 {
283 (&self.numerator) >> num_shift as usize
284 } else {
285 (&self.numerator) << (-num_shift) as usize
286 }
287 .try_into()
288 .unwrap();
289
290 let den_shift = den_bits as isize - 53;
291 let den53: u64 = if den_shift >= 0 {
292 (&self.denominator) >> den_shift as usize
293 } else {
294 (&self.denominator) << (-den_shift) as usize
295 }
296 .try_into()
297 .unwrap();
298
299 let exponent = num_shift - den_shift;
301 if exponent >= 1024 {
302 sign * f64::INFINITY
304 } else if exponent < -1074 - 54 {
305 sign * 0f64
307 } else {
308 let (mut man, r) = num106.unsigned_abs().div_rem(den53 as u128);
309
310 let half = (r as u64 * 2).cmp(&den53);
312 if half == Ordering::Greater || (half == Ordering::Equal && man & 1 > 0) {
313 man += 1;
314 }
315 f64::encode(sign * man as i64, exponent as i16).value()
316 }
317 }
318
319 fn to_f32(&self) -> Approximation<f32, Sign> {
321 if self.numerator.is_zero() {
323 return Exact(0.);
324 }
325
326 let sign = self.numerator.sign();
329 let num_bits = self.numerator.bit_len();
330 let den_bits = self.denominator.bit_len();
331
332 let shift = num_bits as isize - den_bits as isize - 24; let (num, den) = if shift >= 0 {
334 (self.numerator.clone(), (&self.denominator) << shift as usize)
335 } else {
336 ((&self.numerator) << (-shift) as usize, self.denominator.clone())
337 };
338
339 if shift >= 128 {
341 Inexact(sign * f32::INFINITY, sign)
343 } else if shift < -149 - 25 {
344 Inexact(sign * 0f32, -sign)
346 } else {
347 let (man, r) = num.unsigned_abs().div_rem(&den);
348 let man: u32 = man.try_into().unwrap();
349
350 if r.is_zero() {
352 Exact(man)
353 } else {
354 let half = (r << 1).cmp(&den);
355 if half == Ordering::Greater || (half == Ordering::Equal && man & 1 > 0) {
356 Inexact(man + 1, sign)
357 } else {
358 Inexact(man, -sign)
359 }
360 }
361 .and_then(|man| f32::encode(sign * man as i32, shift as i16))
362 }
363 }
364
365 fn to_f64(&self) -> Approximation<f64, Sign> {
366 if self.numerator.is_zero() {
368 return Exact(0.);
369 }
370
371 let sign = self.numerator.sign();
374 let num_bits = self.numerator.bit_len();
375 let den_bits = self.denominator.bit_len();
376
377 let shift = num_bits as isize - den_bits as isize - 53; let (num, den) = if shift >= 0 {
379 (self.numerator.clone(), (&self.denominator) << shift as usize)
380 } else {
381 ((&self.numerator) << (-shift) as usize, self.denominator.clone())
382 };
383
384 if shift >= 1024 {
386 Inexact(sign * f64::INFINITY, sign)
388 } else if shift < -1074 - 53 {
389 Inexact(sign * 0f64, -sign)
391 } else {
392 let (man, r) = num.unsigned_abs().div_rem(&den);
393 let man: u64 = man.try_into().unwrap();
394
395 if r.is_zero() {
397 Exact(man)
398 } else {
399 let half = (r << 1).cmp(&den);
400 if half == Ordering::Greater || (half == Ordering::Equal && man & 1 > 0) {
401 Inexact(man + 1, sign)
402 } else {
403 Inexact(man, -sign)
404 }
405 }
406 .and_then(|man| f64::encode(sign * man as i64, shift as i16))
407 }
408 }
409}
410
411impl RBig {
412 #[inline]
431 pub fn to_f32_fast(&self) -> f32 {
432 self.0.to_f32_fast()
433 }
434
435 #[inline]
454 pub fn to_f64_fast(&self) -> f64 {
455 self.0.to_f64_fast()
456 }
457
458 #[inline]
479 pub fn to_f32(&self) -> Approximation<f32, Sign> {
480 self.0.to_f32()
481 }
482
483 #[inline]
504 pub fn to_f64(&self) -> Approximation<f64, Sign> {
505 self.0.to_f64()
506 }
507
508 #[inline]
528 pub fn to_int(&self) -> Approximation<IBig, Self> {
529 let (trunc, fract) = self.clone().split_at_point();
530 if fract.is_zero() {
531 Approximation::Exact(trunc)
532 } else {
533 Approximation::Inexact(trunc, fract)
534 }
535 }
536}
537
538impl Relaxed {
539 #[inline]
543 pub fn to_f32_fast(&self) -> f32 {
544 self.0.to_f32_fast()
545 }
546 #[inline]
550 pub fn to_f64_fast(&self) -> f64 {
551 self.0.to_f64_fast()
552 }
553
554 #[inline]
558 pub fn to_f32(&self) -> Approximation<f32, Sign> {
559 self.0.to_f32()
560 }
561 #[inline]
565 pub fn to_f64(&self) -> Approximation<f64, Sign> {
566 self.0.to_f64()
567 }
568 #[inline]
572 pub fn to_int(&self) -> Approximation<IBig, Self> {
573 let (trunc, fract) = self.clone().split_at_point();
574 if fract.is_zero() {
575 Approximation::Exact(trunc)
576 } else {
577 Approximation::Inexact(trunc, fract)
578 }
579 }
580}