1use crate::{
4 add,
5 arch::word::{DoubleWord, Word},
6 buffer::Buffer,
7 helper_macros::debug_assert_zero,
8 ibig::IBig,
9 math,
10 primitive::{
11 self, PrimitiveSigned, PrimitiveUnsigned, DWORD_BITS_USIZE, DWORD_BYTES, WORD_BITS,
12 WORD_BITS_USIZE, WORD_BYTES,
13 },
14 repr::{
15 Repr,
16 TypedReprRef::{self, *},
17 },
18 shift,
19 ubig::UBig,
20 Sign::*,
21};
22use alloc::{boxed::Box, vec, vec::Vec};
23use core::convert::{TryFrom, TryInto};
24use dashu_base::{
25 Approximation::{self, *},
26 BitTest, ConversionError, FloatEncoding, PowerOfTwo, Sign,
27};
28use static_assertions::const_assert;
29
30impl Default for UBig {
31 #[inline]
33 fn default() -> UBig {
34 UBig::ZERO
35 }
36}
37
38impl Default for IBig {
39 #[inline]
41 fn default() -> IBig {
42 IBig::ZERO
43 }
44}
45
46pub(crate) fn words_to_le_bytes<const FLIP: bool>(words: &[Word]) -> Vec<u8> {
47 debug_assert!(!words.is_empty());
48
49 let n = words.len();
50 let last = words[n - 1];
51 let skip_last_bytes = last.leading_zeros() as usize / 8;
52 let mut bytes = Vec::with_capacity(n * WORD_BYTES - skip_last_bytes);
53 for word in &words[..n - 1] {
54 let word = if FLIP { !*word } else { *word };
55 bytes.extend_from_slice(&word.to_le_bytes());
56 }
57 let last = if FLIP { !last } else { last };
58 let last_bytes = last.to_le_bytes();
59 bytes.extend_from_slice(&last_bytes[..WORD_BYTES - skip_last_bytes]);
60 bytes
61}
62
63fn words_to_be_bytes<const FLIP: bool>(words: &[Word]) -> Vec<u8> {
64 debug_assert!(!words.is_empty());
65
66 let n = words.len();
67 let last = words[n - 1];
68 let skip_last_bytes = last.leading_zeros() as usize / 8;
69 let mut bytes = Vec::with_capacity(n * WORD_BYTES - skip_last_bytes);
70 let last = if FLIP { !last } else { last };
71 let last_bytes = last.to_be_bytes();
72 bytes.extend_from_slice(&last_bytes[skip_last_bytes..]);
73 for word in words[..n - 1].iter().rev() {
74 let word = if FLIP { !*word } else { *word };
75 bytes.extend_from_slice(&word.to_be_bytes());
76 }
77 bytes
78}
79
80fn words_to_chunks(words: &[Word], chunks_out: &mut [&mut [Word]], chunk_bits: usize) {
86 assert!(!words.is_empty());
87
88 if chunk_bits % WORD_BITS_USIZE == 0 {
89 let words_per_chunk = chunk_bits / WORD_BITS_USIZE;
91 for (i, chunk_out) in chunks_out.iter_mut().enumerate() {
92 let start_pos = i * words_per_chunk;
93 let end_pos = (start_pos + words_per_chunk).min(words.len());
99 let copy_len = end_pos - start_pos;
100 chunk_out[..copy_len].copy_from_slice(&words[start_pos..end_pos]);
101 }
102 } else {
103 let bit_len =
104 words.len() * WORD_BITS_USIZE - words.last().unwrap().leading_zeros() as usize;
105 for (i, chunk_out) in chunks_out.iter_mut().enumerate() {
106 let start = i * chunk_bits;
107 let end = bit_len.min(start + chunk_bits);
108 debug_assert!(start < end); let (start_pos, end_pos) = (start / WORD_BITS_USIZE, end / WORD_BITS_USIZE);
111 let end_bits = (end % WORD_BITS_USIZE) as u32;
112 let len;
113 if end_bits != 0 {
114 len = end_pos - start_pos;
115 chunk_out[..=len].copy_from_slice(&words[start_pos..=end_pos]);
116 chunk_out[len] &= math::ones_word(end_bits);
117 } else {
118 len = end_pos - start_pos - 1;
119 chunk_out[..=len].copy_from_slice(&words[start_pos..end_pos]);
120 }
121 shift::shr_in_place(&mut chunk_out[..=len], (start % WORD_BITS_USIZE) as u32);
122 }
123 }
124}
125
126fn chunks_to_words(
132 words_out: &mut [Word],
133 chunks: &[&[Word]],
134 chunk_bits: usize,
135 buffer: &mut [Word],
136) {
137 assert!(!chunks.is_empty());
138 for (i, chunk) in chunks.iter().enumerate() {
139 let shift = i * chunk_bits;
140 buffer[..chunk.len()].copy_from_slice(chunk);
141 buffer[chunk.len()] = 0;
142 shift::shl_in_place(&mut buffer[..=chunk.len()], (shift % WORD_BITS_USIZE) as u32);
143 debug_assert_zero!(add::add_in_place(
144 &mut words_out[shift / WORD_BITS_USIZE..],
145 &buffer[..=chunk.len()]
146 ));
147 }
148}
149
150impl TypedReprRef<'_> {
151 fn to_le_bytes(self) -> Vec<u8> {
152 match self {
153 RefSmall(x) => {
154 let bytes = x.to_le_bytes();
155 let skip_bytes = x.leading_zeros() as usize / 8;
156 bytes[..DWORD_BYTES - skip_bytes].into()
157 }
158 RefLarge(words) => words_to_le_bytes::<false>(words),
159 }
160 }
161
162 fn to_signed_le_bytes(self, negate: bool) -> Vec<u8> {
163 if let RefSmall(v) = self {
165 if v == 0 {
166 return Vec::new();
167 }
168 }
169
170 let mut bytes = if negate {
171 match self {
172 RefSmall(x) => {
173 let bytes = (!x + 1).to_le_bytes();
174 let skip_bytes = x.leading_zeros() as usize / 8;
175 bytes[..DWORD_BYTES - skip_bytes].into()
176 }
177 RefLarge(words) => {
178 let mut buffer = Buffer::from(words);
179 debug_assert_zero!(add::sub_one_in_place(&mut buffer));
180 words_to_le_bytes::<true>(&buffer)
181 }
182 }
183 } else {
184 self.to_le_bytes()
185 };
186
187 let needs_sign_pad = match bytes.last() {
188 None => false, Some(&b) => (b & 0x80 != 0) != negate,
190 };
191 if needs_sign_pad {
192 bytes.push(if negate { 0xff } else { 0 });
193 }
194
195 bytes
196 }
197
198 fn to_be_bytes(self) -> Vec<u8> {
199 match self {
200 RefSmall(x) => {
201 let bytes = x.to_be_bytes();
202 let skip_bytes = x.leading_zeros() as usize / 8;
203 bytes[skip_bytes..].into()
204 }
205 RefLarge(words) => words_to_be_bytes::<false>(words),
206 }
207 }
208
209 fn to_signed_be_bytes(self, negate: bool) -> Vec<u8> {
210 if let RefSmall(v) = self {
212 if v == 0 {
213 return Vec::new();
214 }
215 }
216
217 let mut bytes = if negate {
218 match self {
219 RefSmall(x) => {
220 let bytes = (!x + 1).to_be_bytes();
221 let skip_bytes = x.leading_zeros() as usize / 8;
222 bytes[skip_bytes..].into()
223 }
224 RefLarge(words) => {
225 let mut buffer = Buffer::from(words);
226 debug_assert_zero!(add::sub_one_in_place(&mut buffer));
227 words_to_be_bytes::<true>(&buffer)
228 }
229 }
230 } else {
231 self.to_be_bytes()
232 };
233
234 let needs_sign_pad = match bytes.first() {
235 None => false, Some(&b) => (b & 0x80 != 0) != negate,
237 };
238 if needs_sign_pad {
239 bytes.insert(0, if negate { 0xff } else { 0 });
240 }
241
242 bytes
243 }
244
245 fn to_chunks(self, chunk_bits: usize) -> Vec<Repr> {
246 assert!(chunk_bits > 0);
247 let chunk_count = math::ceil_div(self.bit_len(), chunk_bits);
248
249 match self {
250 RefSmall(x) => match chunk_count {
251 0 => Vec::new(),
252 1 => vec![Repr::from_dword(x)],
253 n => {
254 const_assert!(u8::MAX as usize > DWORD_BITS_USIZE);
255 let mut buffers = Vec::with_capacity(n);
256 let chunk_bits = chunk_bits as u8; for i in 0..n as u8 {
258 let chunk = (x >> (i * chunk_bits)) & math::ones_dword(chunk_bits as _);
259 buffers.push(Repr::from_dword(chunk));
260 }
261 buffers
262 }
263 },
264 RefLarge(words) => {
265 let mut buffers = Vec::<Buffer>::new();
266 let word_per_chunk = math::ceil_div(chunk_bits, WORD_BITS_USIZE);
267 buffers.resize_with(chunk_count, || {
268 let mut buf: Buffer = Buffer::allocate(word_per_chunk + 1);
270 buf.push_zeros(word_per_chunk + 1);
271 buf
272 });
273 let mut buffer_refs: Box<[&mut [Word]]> =
274 buffers.iter_mut().map(|buf| buf.as_mut()).collect();
275 words_to_chunks(words, &mut buffer_refs, chunk_bits);
276 buffers.into_iter().map(Repr::from_buffer).collect()
277 }
278 }
279 }
280}
281
282impl Repr {
283 fn from_le_bytes(bytes: &[u8]) -> Self {
284 if bytes.len() <= DWORD_BYTES {
285 Self::from_dword(primitive::dword_from_le_bytes_partial::<false>(bytes))
287 } else {
288 Self::from_le_bytes_large::<false>(bytes)
290 }
291 }
292
293 fn from_signed_le_bytes(bytes: &[u8]) -> Self {
294 if let Some(v) = bytes.last() {
295 if *v < 0x80 {
296 return Self::from_le_bytes(bytes);
297 }
298 } else {
299 return Self::zero();
300 }
301
302 let repr = if bytes.len() <= DWORD_BYTES {
304 let dword = primitive::dword_from_le_bytes_partial::<true>(bytes);
306 Self::from_dword(!dword + 1)
307 } else {
308 Self::from_le_bytes_large::<true>(bytes)
310 };
311 repr.with_sign(Sign::Negative)
312 }
313
314 fn from_le_bytes_large<const NEG: bool>(bytes: &[u8]) -> Self {
315 debug_assert!(bytes.len() >= DWORD_BYTES);
316 let mut buffer = Buffer::allocate((bytes.len() - 1) / WORD_BYTES + 1);
317 let mut chunks = bytes.chunks_exact(WORD_BYTES);
318 for chunk in &mut chunks {
319 let word = Word::from_le_bytes(chunk.try_into().unwrap());
320 buffer.push(if NEG { !word } else { word });
321 }
322 if !chunks.remainder().is_empty() {
323 let word = primitive::word_from_le_bytes_partial::<NEG>(chunks.remainder());
324 buffer.push(if NEG { !word } else { word });
325 }
326 if NEG {
327 debug_assert_zero!(add::add_one_in_place(&mut buffer));
328 }
329 Self::from_buffer(buffer)
330 }
331
332 fn from_be_bytes(bytes: &[u8]) -> Self {
333 if bytes.len() <= DWORD_BYTES {
334 Self::from_dword(primitive::dword_from_be_bytes_partial::<false>(bytes))
335 } else {
336 Self::from_be_bytes_large::<false>(bytes)
338 }
339 }
340
341 fn from_signed_be_bytes(bytes: &[u8]) -> Self {
342 if let Some(v) = bytes.first() {
343 if *v < 0x80 {
344 return Self::from_be_bytes(bytes);
345 }
346 } else {
347 return Self::zero();
348 }
349
350 let repr = if bytes.len() <= DWORD_BYTES {
352 let dword = primitive::dword_from_be_bytes_partial::<true>(bytes);
354 Self::from_dword(!dword + 1)
355 } else {
356 Self::from_be_bytes_large::<true>(bytes)
358 };
359 repr.with_sign(Sign::Negative)
360 }
361
362 fn from_be_bytes_large<const NEG: bool>(bytes: &[u8]) -> Self {
363 debug_assert!(bytes.len() >= DWORD_BYTES);
364 let mut buffer = Buffer::allocate((bytes.len() - 1) / WORD_BYTES + 1);
365 let mut chunks = bytes.rchunks_exact(WORD_BYTES);
366 for chunk in &mut chunks {
367 let word = Word::from_be_bytes(chunk.try_into().unwrap());
368 buffer.push(if NEG { !word } else { word });
369 }
370 if !chunks.remainder().is_empty() {
371 let word = primitive::word_from_be_bytes_partial::<NEG>(chunks.remainder());
372 buffer.push(if NEG { !word } else { word });
373 }
374 if NEG {
375 debug_assert_zero!(add::add_one_in_place(&mut buffer));
376 }
377 Self::from_buffer(buffer)
378 }
379
380 fn from_chunks(chunks: &[&[Word]], chunk_bits: usize) -> Self {
381 if let Some(max_len) = chunks.iter().map(|words| words.len()).max() {
382 let result_len = max_len + (chunks.len() - 1) * chunk_bits + 1;
384 let mut result = Buffer::allocate(result_len);
385 result.push_zeros(result_len);
386 let mut buffer = Buffer::allocate_exact(max_len + 1);
387 buffer.push_zeros(max_len + 1);
388
389 chunks_to_words(&mut result, chunks, chunk_bits, &mut buffer);
390 Self::from_buffer(result)
391 } else {
392 Self::zero()
393 }
394 }
395}
396
397impl UBig {
398 #[inline]
407 pub fn from_le_bytes(bytes: &[u8]) -> UBig {
408 UBig(Repr::from_le_bytes(bytes))
409 }
410
411 #[inline]
420 pub fn from_be_bytes(bytes: &[u8]) -> UBig {
421 UBig(Repr::from_be_bytes(bytes))
422 }
423
424 pub fn to_le_bytes(&self) -> Box<[u8]> {
434 self.repr().to_le_bytes().into_boxed_slice()
435 }
436
437 pub fn to_be_bytes(&self) -> Box<[u8]> {
447 self.repr().to_be_bytes().into_boxed_slice()
448 }
449
450 #[inline]
472 pub fn from_chunks<'a, I: Iterator<Item = &'a UBig>>(chunks: I, chunk_bits: usize) -> Self {
473 let chunks: Box<_> = chunks.into_iter().map(|u| u.as_words()).collect();
474 Self(Repr::from_chunks(&chunks, chunk_bits))
475 }
476
477 #[inline]
494 pub fn to_chunks(&self, chunk_bits: usize) -> Box<[UBig]> {
495 self.repr()
496 .to_chunks(chunk_bits)
497 .into_iter()
498 .map(UBig)
499 .collect()
500 }
501
502 #[inline]
515 pub fn to_f32(&self) -> Approximation<f32, Sign> {
516 self.repr().to_f32()
517 }
518
519 #[inline]
532 pub fn to_f64(&self) -> Approximation<f64, Sign> {
533 self.repr().to_f64()
534 }
535
536 #[inline]
545 pub const fn as_ibig(&self) -> &IBig {
546 unsafe { core::mem::transmute(self) }
550 }
551}
552
553impl IBig {
554 #[inline]
567 pub fn from_le_bytes(bytes: &[u8]) -> IBig {
568 IBig(Repr::from_signed_le_bytes(bytes))
569 }
570
571 #[inline]
584 pub fn from_be_bytes(bytes: &[u8]) -> IBig {
585 IBig(Repr::from_signed_be_bytes(bytes))
586 }
587
588 #[inline]
600 pub fn to_le_bytes(&self) -> Box<[u8]> {
601 let (sign, repr) = self.as_sign_repr();
602 repr.to_signed_le_bytes(sign.into()).into_boxed_slice()
603 }
604
605 pub fn to_be_bytes(&self) -> Box<[u8]> {
617 let (sign, repr) = self.as_sign_repr();
618 repr.to_signed_be_bytes(sign.into()).into_boxed_slice()
619 }
620
621 #[inline]
634 pub fn to_f32(&self) -> Approximation<f32, Sign> {
635 let (sign, mag) = self.as_sign_repr();
636 match mag.to_f32() {
637 Exact(val) => Exact(sign * val),
638 Inexact(val, diff) => Inexact(sign * val, sign * diff),
639 }
640 }
641
642 #[inline]
655 pub fn to_f64(&self) -> Approximation<f64, Sign> {
656 let (sign, mag) = self.as_sign_repr();
657 match mag.to_f64() {
658 Exact(val) => Exact(sign * val),
659 Inexact(val, diff) => Inexact(sign * val, sign * diff),
660 }
661 }
662
663 #[inline]
675 pub const fn as_ubig(&self) -> Option<&UBig> {
676 match self.sign() {
677 Sign::Positive => {
678 unsafe { Some(core::mem::transmute::<&IBig, &UBig>(self)) }
682 }
683 Sign::Negative => None,
684 }
685 }
686}
687
688macro_rules! ubig_unsigned_conversions {
689 ($($t:ty)*) => {$(
690 impl From<$t> for UBig {
691 #[inline]
692 fn from(value: $t) -> UBig {
693 UBig::from_unsigned(value)
694 }
695 }
696
697 impl TryFrom<UBig> for $t {
698 type Error = ConversionError;
699
700 #[inline]
701 fn try_from(value: UBig) -> Result<$t, ConversionError> {
702 value.try_to_unsigned()
703 }
704 }
705
706 impl TryFrom<&UBig> for $t {
707 type Error = ConversionError;
708
709 #[inline]
710 fn try_from(value: &UBig) -> Result<$t, ConversionError> {
711 value.try_to_unsigned()
712 }
713 }
714 )*};
715}
716ubig_unsigned_conversions!(u8 u16 u32 u64 u128 usize);
717
718impl From<bool> for UBig {
719 #[inline]
720 fn from(b: bool) -> UBig {
721 u8::from(b).into()
722 }
723}
724
725macro_rules! ubig_signed_conversions {
726 ($($t:ty)*) => {$(
727 impl TryFrom<$t> for UBig {
728 type Error = ConversionError;
729
730 #[inline]
731 fn try_from(value: $t) -> Result<UBig, ConversionError> {
732 UBig::try_from_signed(value)
733 }
734 }
735
736 impl TryFrom<UBig> for $t {
737 type Error = ConversionError;
738
739 #[inline]
740 fn try_from(value: UBig) -> Result<$t, ConversionError> {
741 value.try_to_signed()
742 }
743 }
744
745 impl TryFrom<&UBig> for $t {
746 type Error = ConversionError;
747
748 #[inline]
749 fn try_from(value: &UBig) -> Result<$t, ConversionError> {
750 value.try_to_signed()
751 }
752 }
753 )*};
754}
755ubig_signed_conversions!(i8 i16 i32 i64 i128 isize);
756
757macro_rules! ibig_unsigned_conversions {
758 ($($t:ty)*) => {$(
759 impl From<$t> for IBig {
760 #[inline]
761 fn from(value: $t) -> IBig {
762 IBig::from_unsigned(value)
763 }
764 }
765
766 impl TryFrom<IBig> for $t {
767 type Error = ConversionError;
768
769 #[inline]
770 fn try_from(value: IBig) -> Result<$t, ConversionError> {
771 value.try_to_unsigned()
772 }
773 }
774
775 impl TryFrom<&IBig> for $t {
776 type Error = ConversionError;
777
778 #[inline]
779 fn try_from(value: &IBig) -> Result<$t, ConversionError> {
780 value.try_to_unsigned()
781 }
782 }
783 )*};
784}
785
786ibig_unsigned_conversions!(u8 u16 u32 u64 u128 usize);
787
788impl From<bool> for IBig {
789 #[inline]
790 fn from(b: bool) -> IBig {
791 u8::from(b).into()
792 }
793}
794
795macro_rules! ibig_signed_conversions {
796 ($($t:ty)*) => {$(
797 impl From<$t> for IBig {
798 #[inline]
799 fn from(value: $t) -> IBig {
800 IBig::from_signed(value)
801 }
802 }
803
804 impl TryFrom<IBig> for $t {
805 type Error = ConversionError;
806
807 #[inline]
808 fn try_from(value: IBig) -> Result<$t, ConversionError> {
809 value.try_to_signed()
810 }
811 }
812
813 impl TryFrom<&IBig> for $t {
814 type Error = ConversionError;
815
816 #[inline]
817 fn try_from(value: &IBig) -> Result<$t, ConversionError> {
818 value.try_to_signed()
819 }
820 }
821 )*};
822}
823ibig_signed_conversions!(i8 i16 i32 i64 i128 isize);
824
825macro_rules! ubig_float_conversions {
826 ($($t:ty => $i:ty;)*) => {$(
827 impl TryFrom<$t> for UBig {
828 type Error = ConversionError;
829
830 fn try_from(value: $t) -> Result<Self, Self::Error> {
831 let (man, exp) = value.decode().map_err(|_| ConversionError::OutOfBounds)?;
832 let mut result: UBig = man.try_into()?;
833 if exp >= 0 {
834 result <<= exp as usize;
835 } else {
836 result >>= (-exp) as usize;
837 }
838 Ok(result)
839 }
840 }
841
842 impl TryFrom<UBig> for $t {
843 type Error = ConversionError;
844
845 fn try_from(value: UBig) -> Result<Self, Self::Error> {
846 const MAX_BIT_LEN: usize = (<$t>::MANTISSA_DIGITS + 1) as usize;
847 if value.bit_len() > MAX_BIT_LEN
848 || (value.bit_len() == MAX_BIT_LEN && !value.is_power_of_two())
849 {
850 Err(ConversionError::LossOfPrecision)
852 } else {
853 Ok(<$i>::try_from(value).unwrap() as $t)
854 }
855 }
856 }
857 )*};
858}
859ubig_float_conversions!(f32 => u32; f64 => u64;);
860
861macro_rules! ibig_float_conversions {
862 ($($t:ty => $i:ty;)*) => {$(
863 impl TryFrom<$t> for IBig {
864 type Error = ConversionError;
865
866 fn try_from(value: $t) -> Result<Self, Self::Error> {
867 let (man, exp) = value.decode().map_err(|_| ConversionError::OutOfBounds)?;
868 let mut result: IBig = man.into();
869 if exp >= 0 {
870 result <<= exp as usize;
871 } else {
872 result >>= (-exp) as usize;
873 }
874 Ok(result)
875 }
876 }
877
878 impl TryFrom<IBig> for $t {
879 type Error = ConversionError;
880
881 fn try_from(value: IBig) -> Result<Self, Self::Error> {
882 const MAX_BIT_LEN: usize = (<$t>::MANTISSA_DIGITS + 1) as usize;
883 let (sign, value) = value.into_parts();
884 if value.bit_len() > MAX_BIT_LEN
885 || (value.bit_len() == MAX_BIT_LEN && !value.is_power_of_two())
886 {
887 Err(ConversionError::LossOfPrecision)
889 } else {
890 let float = <$i>::try_from(value).unwrap() as $t;
891 Ok(sign * float)
892 }
893 }
894 }
895 )*};
896}
897ibig_float_conversions!(f32 => u32; f64 => u64;);
898
899impl From<UBig> for IBig {
900 #[inline]
901 fn from(x: UBig) -> IBig {
902 IBig(x.0.with_sign(Positive))
903 }
904}
905
906impl TryFrom<IBig> for UBig {
907 type Error = ConversionError;
908
909 #[inline]
910 fn try_from(x: IBig) -> Result<UBig, ConversionError> {
911 match x.sign() {
912 Positive => Ok(UBig(x.0)),
913 Negative => Err(ConversionError::OutOfBounds),
914 }
915 }
916}
917
918impl UBig {
919 #[inline]
921 pub(crate) fn from_unsigned<T>(x: T) -> UBig
922 where
923 T: PrimitiveUnsigned,
924 {
925 UBig(Repr::from_unsigned(x))
926 }
927
928 #[inline]
930 fn try_from_signed<T>(x: T) -> Result<UBig, ConversionError>
931 where
932 T: PrimitiveSigned,
933 {
934 let (sign, mag) = x.to_sign_magnitude();
935 match sign {
936 Sign::Positive => Ok(UBig(Repr::from_unsigned(mag))),
937 Sign::Negative => Err(ConversionError::OutOfBounds),
938 }
939 }
940
941 #[inline]
943 pub(crate) fn try_to_unsigned<T>(&self) -> Result<T, ConversionError>
944 where
945 T: PrimitiveUnsigned,
946 {
947 self.repr().try_to_unsigned()
948 }
949
950 #[inline]
952 fn try_to_signed<T>(&self) -> Result<T, ConversionError>
953 where
954 T: PrimitiveSigned,
955 {
956 T::try_from_sign_magnitude(Sign::Positive, self.repr().try_to_unsigned()?)
957 }
958}
959
960impl IBig {
961 #[inline]
963 pub(crate) fn from_unsigned<T: PrimitiveUnsigned>(x: T) -> IBig {
964 IBig(Repr::from_unsigned(x))
965 }
966
967 #[inline]
969 pub(crate) fn from_signed<T: PrimitiveSigned>(x: T) -> IBig {
970 let (sign, mag) = x.to_sign_magnitude();
971 IBig(Repr::from_unsigned(mag).with_sign(sign))
972 }
973
974 #[inline]
976 pub(crate) fn try_to_unsigned<T: PrimitiveUnsigned>(&self) -> Result<T, ConversionError> {
977 let (sign, mag) = self.as_sign_repr();
978 match sign {
979 Positive => mag.try_to_unsigned(),
980 Negative => Err(ConversionError::OutOfBounds),
981 }
982 }
983
984 #[inline]
986 pub(crate) fn try_to_signed<T: PrimitiveSigned>(&self) -> Result<T, ConversionError> {
987 let (sign, mag) = self.as_sign_repr();
988 T::try_from_sign_magnitude(sign, mag.try_to_unsigned()?)
989 }
990}
991
992mod repr {
993 use core::cmp::Ordering;
994
995 use static_assertions::const_assert;
996
997 use super::*;
998 use crate::repr::TypedReprRef;
999
1000 fn unsigned_from_words<T>(words: &[Word]) -> Result<T, ConversionError>
1002 where
1003 T: PrimitiveUnsigned,
1004 {
1005 debug_assert!(words.len() >= 2);
1006 let t_words = T::BYTE_SIZE / WORD_BYTES;
1007 if t_words <= 1 || words.len() > t_words {
1008 Err(ConversionError::OutOfBounds)
1009 } else {
1010 assert!(
1011 T::BIT_SIZE % WORD_BITS == 0,
1012 "A large primitive type not a multiple of word size."
1013 );
1014 let mut repr = T::default().to_le_bytes();
1015 let bytes: &mut [u8] = repr.as_mut();
1016 for (idx, w) in words.iter().enumerate() {
1017 let pos = idx * WORD_BYTES;
1018 bytes[pos..pos + WORD_BYTES].copy_from_slice(&w.to_le_bytes());
1019 }
1020 Ok(T::from_le_bytes(repr))
1021 }
1022 }
1023
1024 impl Repr {
1025 #[inline]
1026 pub fn from_unsigned<T>(x: T) -> Self
1027 where
1028 T: PrimitiveUnsigned,
1029 {
1030 if let Ok(dw) = x.try_into() {
1031 Self::from_dword(dw)
1032 } else {
1033 let repr = x.to_le_bytes();
1034 Self::from_le_bytes_large::<false>(repr.as_ref())
1035 }
1036 }
1037 }
1038
1039 impl<'a> TypedReprRef<'a> {
1040 #[inline]
1041 pub fn try_to_unsigned<T>(self) -> Result<T, ConversionError>
1042 where
1043 T: PrimitiveUnsigned,
1044 {
1045 match self {
1046 RefSmall(dw) => T::try_from(dw).map_err(|_| ConversionError::OutOfBounds),
1047 RefLarge(words) => unsigned_from_words(words),
1048 }
1049 }
1050
1051 #[inline]
1052 pub fn to_f32(self) -> Approximation<f32, Sign> {
1053 match self {
1054 RefSmall(dword) => to_f32_small(dword),
1055 RefLarge(_) => self.to_f32_nontrivial(),
1056 }
1057 }
1058
1059 #[inline]
1060 fn to_f32_nontrivial(self) -> Approximation<f32, Sign> {
1061 let n = self.bit_len();
1062 debug_assert!(n > 32);
1063
1064 if n > 128 {
1065 Inexact(f32::INFINITY, Positive)
1066 } else {
1067 let top_u31: u32 = (self >> (n - 31)).as_typed().try_to_unsigned().unwrap();
1068 let extra_bit = self.are_low_bits_nonzero(n - 31) as u32;
1069 f32::encode((top_u31 | extra_bit) as i32, (n - 31) as i16)
1070 }
1071 }
1072
1073 #[inline]
1074 pub fn to_f64(self) -> Approximation<f64, Sign> {
1075 match self {
1076 RefSmall(dword) => to_f64_small(dword as DoubleWord),
1077 RefLarge(_) => {
1078 if self.bit_len() <= 64 {
1085 let v: u64 = self.try_to_unsigned().unwrap();
1086 let f = v as f64;
1087 let back = f as u64;
1088 match back.cmp(&v) {
1089 Ordering::Greater => Inexact(f, Sign::Positive),
1090 Ordering::Equal => Exact(f),
1091 Ordering::Less => Inexact(f, Sign::Negative),
1092 }
1093 } else {
1094 self.to_f64_nontrivial()
1095 }
1096 }
1097 }
1098 }
1099
1100 #[inline]
1101 fn to_f64_nontrivial(self) -> Approximation<f64, Sign> {
1102 let n = self.bit_len();
1103 debug_assert!(n > 64);
1104
1105 if n > 1024 {
1106 Inexact(f64::INFINITY, Positive)
1107 } else {
1108 let top_u63: u64 = (self >> (n - 63)).as_typed().try_to_unsigned().unwrap();
1109 let extra_bit = self.are_low_bits_nonzero(n - 63) as u64;
1110 f64::encode((top_u63 | extra_bit) as i64, (n - 63) as i16)
1111 }
1112 }
1113 }
1114
1115 fn to_f32_small(dword: DoubleWord) -> Approximation<f32, Sign> {
1116 let f = dword as f32;
1117 if f.is_infinite() {
1118 return Inexact(f, Sign::Positive);
1119 }
1120
1121 let back = f as DoubleWord;
1122 match back.partial_cmp(&dword).unwrap() {
1123 Ordering::Greater => Inexact(f, Sign::Positive),
1124 Ordering::Equal => Exact(f),
1125 Ordering::Less => Inexact(f, Sign::Negative),
1126 }
1127 }
1128
1129 fn to_f64_small(dword: DoubleWord) -> Approximation<f64, Sign> {
1130 const_assert!((DoubleWord::MAX as f64) < f64::MAX);
1131 let f = dword as f64;
1132 let back = f as DoubleWord;
1133
1134 match back.partial_cmp(&dword).unwrap() {
1135 Ordering::Greater => Inexact(f, Sign::Positive),
1136 Ordering::Equal => Exact(f),
1137 Ordering::Less => Inexact(f, Sign::Negative),
1138 }
1139 }
1140}
1141
1142