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 leading_zeros = match self {
188 RefSmall(x) => x.leading_zeros(),
189 RefLarge(words) => words.last().unwrap().leading_zeros(),
190 };
191 if leading_zeros % 8 == 0 {
192 bytes.push(if negate { 0xff } else { 0 });
194 }
195
196 bytes
197 }
198
199 fn to_be_bytes(self) -> Vec<u8> {
200 match self {
201 RefSmall(x) => {
202 let bytes = x.to_be_bytes();
203 let skip_bytes = x.leading_zeros() as usize / 8;
204 bytes[skip_bytes..].into()
205 }
206 RefLarge(words) => words_to_be_bytes::<false>(words),
207 }
208 }
209
210 fn to_signed_be_bytes(self, negate: bool) -> Vec<u8> {
211 if let RefSmall(v) = self {
213 if v == 0 {
214 return Vec::new();
215 }
216 }
217
218 let mut bytes = if negate {
219 match self {
220 RefSmall(x) => {
221 let bytes = (!x + 1).to_be_bytes();
222 let skip_bytes = x.leading_zeros() as usize / 8;
223 bytes[skip_bytes..].into()
224 }
225 RefLarge(words) => {
226 let mut buffer = Buffer::from(words);
227 debug_assert_zero!(add::sub_one_in_place(&mut buffer));
228 words_to_be_bytes::<true>(&buffer)
229 }
230 }
231 } else {
232 self.to_be_bytes()
233 };
234
235 let leading_zeros = match self {
236 RefSmall(x) => x.leading_zeros(),
237 RefLarge(words) => words.last().unwrap().leading_zeros(),
238 };
239 if leading_zeros % 8 == 0 {
240 bytes.insert(0, if negate { 0xff } else { 0 });
242 }
243
244 bytes
245 }
246
247 fn to_chunks(self, chunk_bits: usize) -> Vec<Repr> {
248 assert!(chunk_bits > 0);
249 let chunk_count = math::ceil_div(self.bit_len(), chunk_bits);
250
251 match self {
252 RefSmall(x) => match chunk_count {
253 0 => Vec::new(),
254 1 => vec![Repr::from_dword(x)],
255 n => {
256 const_assert!(u8::MAX as usize > DWORD_BITS_USIZE);
257 let mut buffers = Vec::with_capacity(n);
258 let chunk_bits = chunk_bits as u8; for i in 0..n as u8 {
260 let chunk = (x >> (i * chunk_bits)) & math::ones_dword(chunk_bits as _);
261 buffers.push(Repr::from_dword(chunk));
262 }
263 buffers
264 }
265 },
266 RefLarge(words) => {
267 let mut buffers = Vec::<Buffer>::new();
268 let word_per_chunk = math::ceil_div(chunk_bits, WORD_BITS_USIZE);
269 buffers.resize_with(chunk_count, || {
270 let mut buf: Buffer = Buffer::allocate(word_per_chunk + 1);
272 buf.push_zeros(word_per_chunk + 1);
273 buf
274 });
275 let mut buffer_refs: Box<[&mut [Word]]> =
276 buffers.iter_mut().map(|buf| buf.as_mut()).collect();
277 words_to_chunks(words, &mut buffer_refs, chunk_bits);
278 buffers.into_iter().map(Repr::from_buffer).collect()
279 }
280 }
281 }
282}
283
284impl Repr {
285 fn from_le_bytes(bytes: &[u8]) -> Self {
286 if bytes.len() <= DWORD_BYTES {
287 Self::from_dword(primitive::dword_from_le_bytes_partial::<false>(bytes))
289 } else {
290 Self::from_le_bytes_large::<false>(bytes)
292 }
293 }
294
295 fn from_signed_le_bytes(bytes: &[u8]) -> Self {
296 if let Some(v) = bytes.last() {
297 if *v < 0x80 {
298 return Self::from_le_bytes(bytes);
299 }
300 } else {
301 return Self::zero();
302 }
303
304 let repr = if bytes.len() <= DWORD_BYTES {
306 let dword = primitive::dword_from_le_bytes_partial::<true>(bytes);
308 Self::from_dword(!dword + 1)
309 } else {
310 Self::from_le_bytes_large::<true>(bytes)
312 };
313 repr.with_sign(Sign::Negative)
314 }
315
316 fn from_le_bytes_large<const NEG: bool>(bytes: &[u8]) -> Self {
317 debug_assert!(bytes.len() >= DWORD_BYTES);
318 let mut buffer = Buffer::allocate((bytes.len() - 1) / WORD_BYTES + 1);
319 let mut chunks = bytes.chunks_exact(WORD_BYTES);
320 for chunk in &mut chunks {
321 let word = Word::from_le_bytes(chunk.try_into().unwrap());
322 buffer.push(if NEG { !word } else { word });
323 }
324 if !chunks.remainder().is_empty() {
325 let word = primitive::word_from_le_bytes_partial::<NEG>(chunks.remainder());
326 buffer.push(if NEG { !word } else { word });
327 }
328 if NEG {
329 debug_assert_zero!(add::add_one_in_place(&mut buffer));
330 }
331 Self::from_buffer(buffer)
332 }
333
334 fn from_be_bytes(bytes: &[u8]) -> Self {
335 if bytes.len() <= DWORD_BYTES {
336 Self::from_dword(primitive::dword_from_be_bytes_partial::<false>(bytes))
337 } else {
338 Self::from_be_bytes_large::<false>(bytes)
340 }
341 }
342
343 fn from_signed_be_bytes(bytes: &[u8]) -> Self {
344 if let Some(v) = bytes.first() {
345 if *v < 0x80 {
346 return Self::from_be_bytes(bytes);
347 }
348 } else {
349 return Self::zero();
350 }
351
352 let repr = if bytes.len() <= DWORD_BYTES {
354 let dword = primitive::dword_from_be_bytes_partial::<true>(bytes);
356 Self::from_dword(!dword + 1)
357 } else {
358 Self::from_be_bytes_large::<true>(bytes)
360 };
361 repr.with_sign(Sign::Negative)
362 }
363
364 fn from_be_bytes_large<const NEG: bool>(bytes: &[u8]) -> Self {
365 debug_assert!(bytes.len() >= DWORD_BYTES);
366 let mut buffer = Buffer::allocate((bytes.len() - 1) / WORD_BYTES + 1);
367 let mut chunks = bytes.rchunks_exact(WORD_BYTES);
368 for chunk in &mut chunks {
369 let word = Word::from_be_bytes(chunk.try_into().unwrap());
370 buffer.push(if NEG { !word } else { word });
371 }
372 if !chunks.remainder().is_empty() {
373 let word = primitive::word_from_be_bytes_partial::<NEG>(chunks.remainder());
374 buffer.push(if NEG { !word } else { word });
375 }
376 if NEG {
377 debug_assert_zero!(add::add_one_in_place(&mut buffer));
378 }
379 Self::from_buffer(buffer)
380 }
381
382 fn from_chunks(chunks: &[&[Word]], chunk_bits: usize) -> Self {
383 if let Some(max_len) = chunks.iter().map(|words| words.len()).max() {
384 let result_len = max_len + (chunks.len() - 1) * chunk_bits + 1;
386 let mut result = Buffer::allocate(result_len);
387 result.push_zeros(result_len);
388 let mut buffer = Buffer::allocate_exact(max_len + 1);
389 buffer.push_zeros(max_len + 1);
390
391 chunks_to_words(&mut result, chunks, chunk_bits, &mut buffer);
392 Self::from_buffer(result)
393 } else {
394 Self::zero()
395 }
396 }
397}
398
399impl UBig {
400 #[inline]
409 pub fn from_le_bytes(bytes: &[u8]) -> UBig {
410 UBig(Repr::from_le_bytes(bytes))
411 }
412
413 #[inline]
422 pub fn from_be_bytes(bytes: &[u8]) -> UBig {
423 UBig(Repr::from_be_bytes(bytes))
424 }
425
426 pub fn to_le_bytes(&self) -> Box<[u8]> {
436 self.repr().to_le_bytes().into_boxed_slice()
437 }
438
439 pub fn to_be_bytes(&self) -> Box<[u8]> {
449 self.repr().to_be_bytes().into_boxed_slice()
450 }
451
452 #[inline]
474 pub fn from_chunks<'a, I: Iterator<Item = &'a UBig>>(chunks: I, chunk_bits: usize) -> Self {
475 let chunks: Box<_> = chunks.into_iter().map(|u| u.as_words()).collect();
476 Self(Repr::from_chunks(&chunks, chunk_bits))
477 }
478
479 #[inline]
496 pub fn to_chunks(&self, chunk_bits: usize) -> Box<[UBig]> {
497 self.repr()
498 .to_chunks(chunk_bits)
499 .into_iter()
500 .map(UBig)
501 .collect()
502 }
503
504 #[inline]
517 pub fn to_f32(&self) -> Approximation<f32, Sign> {
518 self.repr().to_f32()
519 }
520
521 #[inline]
534 pub fn to_f64(&self) -> Approximation<f64, Sign> {
535 self.repr().to_f64()
536 }
537
538 #[inline]
547 pub const fn as_ibig(&self) -> &IBig {
548 unsafe { core::mem::transmute(self) }
552 }
553}
554
555impl IBig {
556 #[inline]
569 pub fn from_le_bytes(bytes: &[u8]) -> IBig {
570 IBig(Repr::from_signed_le_bytes(bytes))
571 }
572
573 #[inline]
586 pub fn from_be_bytes(bytes: &[u8]) -> IBig {
587 IBig(Repr::from_signed_be_bytes(bytes))
588 }
589
590 #[inline]
602 pub fn to_le_bytes(&self) -> Box<[u8]> {
603 let (sign, repr) = self.as_sign_repr();
604 repr.to_signed_le_bytes(sign.into()).into_boxed_slice()
605 }
606
607 pub fn to_be_bytes(&self) -> Box<[u8]> {
619 let (sign, repr) = self.as_sign_repr();
620 repr.to_signed_be_bytes(sign.into()).into_boxed_slice()
621 }
622
623 #[inline]
636 pub fn to_f32(&self) -> Approximation<f32, Sign> {
637 let (sign, mag) = self.as_sign_repr();
638 match mag.to_f32() {
639 Exact(val) => Exact(sign * val),
640 Inexact(val, diff) => Inexact(sign * val, sign * diff),
641 }
642 }
643
644 #[inline]
657 pub fn to_f64(&self) -> Approximation<f64, Sign> {
658 let (sign, mag) = self.as_sign_repr();
659 match mag.to_f64() {
660 Exact(val) => Exact(sign * val),
661 Inexact(val, diff) => Inexact(sign * val, sign * diff),
662 }
663 }
664
665 #[inline]
677 pub const fn as_ubig(&self) -> Option<&UBig> {
678 match self.sign() {
679 Sign::Positive => {
680 unsafe { Some(core::mem::transmute::<&IBig, &UBig>(self)) }
684 }
685 Sign::Negative => None,
686 }
687 }
688}
689
690macro_rules! ubig_unsigned_conversions {
691 ($($t:ty)*) => {$(
692 impl From<$t> for UBig {
693 #[inline]
694 fn from(value: $t) -> UBig {
695 UBig::from_unsigned(value)
696 }
697 }
698
699 impl TryFrom<UBig> for $t {
700 type Error = ConversionError;
701
702 #[inline]
703 fn try_from(value: UBig) -> Result<$t, ConversionError> {
704 value.try_to_unsigned()
705 }
706 }
707
708 impl TryFrom<&UBig> for $t {
709 type Error = ConversionError;
710
711 #[inline]
712 fn try_from(value: &UBig) -> Result<$t, ConversionError> {
713 value.try_to_unsigned()
714 }
715 }
716 )*};
717}
718ubig_unsigned_conversions!(u8 u16 u32 u64 u128 usize);
719
720impl From<bool> for UBig {
721 #[inline]
722 fn from(b: bool) -> UBig {
723 u8::from(b).into()
724 }
725}
726
727macro_rules! ubig_signed_conversions {
728 ($($t:ty)*) => {$(
729 impl TryFrom<$t> for UBig {
730 type Error = ConversionError;
731
732 #[inline]
733 fn try_from(value: $t) -> Result<UBig, ConversionError> {
734 UBig::try_from_signed(value)
735 }
736 }
737
738 impl TryFrom<UBig> for $t {
739 type Error = ConversionError;
740
741 #[inline]
742 fn try_from(value: UBig) -> Result<$t, ConversionError> {
743 value.try_to_signed()
744 }
745 }
746
747 impl TryFrom<&UBig> for $t {
748 type Error = ConversionError;
749
750 #[inline]
751 fn try_from(value: &UBig) -> Result<$t, ConversionError> {
752 value.try_to_signed()
753 }
754 }
755 )*};
756}
757ubig_signed_conversions!(i8 i16 i32 i64 i128 isize);
758
759macro_rules! ibig_unsigned_conversions {
760 ($($t:ty)*) => {$(
761 impl From<$t> for IBig {
762 #[inline]
763 fn from(value: $t) -> IBig {
764 IBig::from_unsigned(value)
765 }
766 }
767
768 impl TryFrom<IBig> for $t {
769 type Error = ConversionError;
770
771 #[inline]
772 fn try_from(value: IBig) -> Result<$t, ConversionError> {
773 value.try_to_unsigned()
774 }
775 }
776
777 impl TryFrom<&IBig> for $t {
778 type Error = ConversionError;
779
780 #[inline]
781 fn try_from(value: &IBig) -> Result<$t, ConversionError> {
782 value.try_to_unsigned()
783 }
784 }
785 )*};
786}
787
788ibig_unsigned_conversions!(u8 u16 u32 u64 u128 usize);
789
790impl From<bool> for IBig {
791 #[inline]
792 fn from(b: bool) -> IBig {
793 u8::from(b).into()
794 }
795}
796
797macro_rules! ibig_signed_conversions {
798 ($($t:ty)*) => {$(
799 impl From<$t> for IBig {
800 #[inline]
801 fn from(value: $t) -> IBig {
802 IBig::from_signed(value)
803 }
804 }
805
806 impl TryFrom<IBig> for $t {
807 type Error = ConversionError;
808
809 #[inline]
810 fn try_from(value: IBig) -> Result<$t, ConversionError> {
811 value.try_to_signed()
812 }
813 }
814
815 impl TryFrom<&IBig> for $t {
816 type Error = ConversionError;
817
818 #[inline]
819 fn try_from(value: &IBig) -> Result<$t, ConversionError> {
820 value.try_to_signed()
821 }
822 }
823 )*};
824}
825ibig_signed_conversions!(i8 i16 i32 i64 i128 isize);
826
827macro_rules! ubig_float_conversions {
828 ($($t:ty => $i:ty;)*) => {$(
829 impl TryFrom<$t> for UBig {
830 type Error = ConversionError;
831
832 fn try_from(value: $t) -> Result<Self, Self::Error> {
833 let (man, exp) = value.decode().map_err(|_| ConversionError::OutOfBounds)?;
834 let mut result: UBig = man.try_into()?;
835 if exp >= 0 {
836 result <<= exp as usize;
837 } else {
838 result >>= (-exp) as usize;
839 }
840 Ok(result)
841 }
842 }
843
844 impl TryFrom<UBig> for $t {
845 type Error = ConversionError;
846
847 fn try_from(value: UBig) -> Result<Self, Self::Error> {
848 const MAX_BIT_LEN: usize = (<$t>::MANTISSA_DIGITS + 1) as usize;
849 if value.bit_len() > MAX_BIT_LEN
850 || (value.bit_len() == MAX_BIT_LEN && !value.is_power_of_two())
851 {
852 Err(ConversionError::LossOfPrecision)
854 } else {
855 Ok(<$i>::try_from(value).unwrap() as $t)
856 }
857 }
858 }
859 )*};
860}
861ubig_float_conversions!(f32 => u32; f64 => u64;);
862
863macro_rules! ibig_float_conversions {
864 ($($t:ty => $i:ty;)*) => {$(
865 impl TryFrom<$t> for IBig {
866 type Error = ConversionError;
867
868 fn try_from(value: $t) -> Result<Self, Self::Error> {
869 let (man, exp) = value.decode().map_err(|_| ConversionError::OutOfBounds)?;
870 let mut result: IBig = man.into();
871 if exp >= 0 {
872 result <<= exp as usize;
873 } else {
874 result >>= (-exp) as usize;
875 }
876 Ok(result)
877 }
878 }
879
880 impl TryFrom<IBig> for $t {
881 type Error = ConversionError;
882
883 fn try_from(value: IBig) -> Result<Self, Self::Error> {
884 const MAX_BIT_LEN: usize = (<$t>::MANTISSA_DIGITS + 1) as usize;
885 let (sign, value) = value.into_parts();
886 if value.bit_len() > MAX_BIT_LEN
887 || (value.bit_len() == MAX_BIT_LEN && !value.is_power_of_two())
888 {
889 Err(ConversionError::LossOfPrecision)
891 } else {
892 let float = <$i>::try_from(value).unwrap() as $t;
893 Ok(sign * float)
894 }
895 }
896 }
897 )*};
898}
899ibig_float_conversions!(f32 => u32; f64 => u64;);
900
901impl From<UBig> for IBig {
902 #[inline]
903 fn from(x: UBig) -> IBig {
904 IBig(x.0.with_sign(Positive))
905 }
906}
907
908impl TryFrom<IBig> for UBig {
909 type Error = ConversionError;
910
911 #[inline]
912 fn try_from(x: IBig) -> Result<UBig, ConversionError> {
913 match x.sign() {
914 Positive => Ok(UBig(x.0)),
915 Negative => Err(ConversionError::OutOfBounds),
916 }
917 }
918}
919
920impl UBig {
921 #[inline]
923 pub(crate) fn from_unsigned<T>(x: T) -> UBig
924 where
925 T: PrimitiveUnsigned,
926 {
927 UBig(Repr::from_unsigned(x))
928 }
929
930 #[inline]
932 fn try_from_signed<T>(x: T) -> Result<UBig, ConversionError>
933 where
934 T: PrimitiveSigned,
935 {
936 let (sign, mag) = x.to_sign_magnitude();
937 match sign {
938 Sign::Positive => Ok(UBig(Repr::from_unsigned(mag))),
939 Sign::Negative => Err(ConversionError::OutOfBounds),
940 }
941 }
942
943 #[inline]
945 pub(crate) fn try_to_unsigned<T>(&self) -> Result<T, ConversionError>
946 where
947 T: PrimitiveUnsigned,
948 {
949 self.repr().try_to_unsigned()
950 }
951
952 #[inline]
954 fn try_to_signed<T>(&self) -> Result<T, ConversionError>
955 where
956 T: PrimitiveSigned,
957 {
958 T::try_from_sign_magnitude(Sign::Positive, self.repr().try_to_unsigned()?)
959 }
960}
961
962impl IBig {
963 #[inline]
965 pub(crate) fn from_unsigned<T: PrimitiveUnsigned>(x: T) -> IBig {
966 IBig(Repr::from_unsigned(x))
967 }
968
969 #[inline]
971 pub(crate) fn from_signed<T: PrimitiveSigned>(x: T) -> IBig {
972 let (sign, mag) = x.to_sign_magnitude();
973 IBig(Repr::from_unsigned(mag).with_sign(sign))
974 }
975
976 #[inline]
978 pub(crate) fn try_to_unsigned<T: PrimitiveUnsigned>(&self) -> Result<T, ConversionError> {
979 let (sign, mag) = self.as_sign_repr();
980 match sign {
981 Positive => mag.try_to_unsigned(),
982 Negative => Err(ConversionError::OutOfBounds),
983 }
984 }
985
986 #[inline]
988 pub(crate) fn try_to_signed<T: PrimitiveSigned>(&self) -> Result<T, ConversionError> {
989 let (sign, mag) = self.as_sign_repr();
990 T::try_from_sign_magnitude(sign, mag.try_to_unsigned()?)
991 }
992}
993
994mod repr {
995 use core::cmp::Ordering;
996
997 use static_assertions::const_assert;
998
999 use super::*;
1000 use crate::repr::TypedReprRef;
1001
1002 fn unsigned_from_words<T>(words: &[Word]) -> Result<T, ConversionError>
1004 where
1005 T: PrimitiveUnsigned,
1006 {
1007 debug_assert!(words.len() >= 2);
1008 let t_words = T::BYTE_SIZE / WORD_BYTES;
1009 if t_words <= 1 || words.len() > t_words {
1010 Err(ConversionError::OutOfBounds)
1011 } else {
1012 assert!(
1013 T::BIT_SIZE % WORD_BITS == 0,
1014 "A large primitive type not a multiple of word size."
1015 );
1016 let mut repr = T::default().to_le_bytes();
1017 let bytes: &mut [u8] = repr.as_mut();
1018 for (idx, w) in words.iter().enumerate() {
1019 let pos = idx * WORD_BYTES;
1020 bytes[pos..pos + WORD_BYTES].copy_from_slice(&w.to_le_bytes());
1021 }
1022 Ok(T::from_le_bytes(repr))
1023 }
1024 }
1025
1026 impl Repr {
1027 #[inline]
1028 pub fn from_unsigned<T>(x: T) -> Self
1029 where
1030 T: PrimitiveUnsigned,
1031 {
1032 if let Ok(dw) = x.try_into() {
1033 Self::from_dword(dw)
1034 } else {
1035 let repr = x.to_le_bytes();
1036 Self::from_le_bytes_large::<false>(repr.as_ref())
1037 }
1038 }
1039 }
1040
1041 impl<'a> TypedReprRef<'a> {
1042 #[inline]
1043 pub fn try_to_unsigned<T>(self) -> Result<T, ConversionError>
1044 where
1045 T: PrimitiveUnsigned,
1046 {
1047 match self {
1048 RefSmall(dw) => T::try_from(dw).map_err(|_| ConversionError::OutOfBounds),
1049 RefLarge(words) => unsigned_from_words(words),
1050 }
1051 }
1052
1053 #[inline]
1054 pub fn to_f32(self) -> Approximation<f32, Sign> {
1055 match self {
1056 RefSmall(dword) => to_f32_small(dword),
1057 RefLarge(_) => self.to_f32_nontrivial(),
1058 }
1059 }
1060
1061 #[inline]
1062 fn to_f32_nontrivial(self) -> Approximation<f32, Sign> {
1063 let n = self.bit_len();
1064 debug_assert!(n > 32);
1065
1066 if n > 128 {
1067 Inexact(f32::INFINITY, Positive)
1068 } else {
1069 let top_u31: u32 = (self >> (n - 31)).as_typed().try_to_unsigned().unwrap();
1070 let extra_bit = self.are_low_bits_nonzero(n - 31) as u32;
1071 f32::encode((top_u31 | extra_bit) as i32, (n - 31) as i16)
1072 }
1073 }
1074
1075 #[inline]
1076 pub fn to_f64(self) -> Approximation<f64, Sign> {
1077 match self {
1078 RefSmall(dword) => to_f64_small(dword as DoubleWord),
1079 RefLarge(_) => {
1080 if self.bit_len() <= 64 {
1087 let v: u64 = self.try_to_unsigned().unwrap();
1088 let f = v as f64;
1089 let back = f as u64;
1090 match back.cmp(&v) {
1091 Ordering::Greater => Inexact(f, Sign::Positive),
1092 Ordering::Equal => Exact(f),
1093 Ordering::Less => Inexact(f, Sign::Negative),
1094 }
1095 } else {
1096 self.to_f64_nontrivial()
1097 }
1098 }
1099 }
1100 }
1101
1102 #[inline]
1103 fn to_f64_nontrivial(self) -> Approximation<f64, Sign> {
1104 let n = self.bit_len();
1105 debug_assert!(n > 64);
1106
1107 if n > 1024 {
1108 Inexact(f64::INFINITY, Positive)
1109 } else {
1110 let top_u63: u64 = (self >> (n - 63)).as_typed().try_to_unsigned().unwrap();
1111 let extra_bit = self.are_low_bits_nonzero(n - 63) as u64;
1112 f64::encode((top_u63 | extra_bit) as i64, (n - 63) as i16)
1113 }
1114 }
1115 }
1116
1117 fn to_f32_small(dword: DoubleWord) -> Approximation<f32, Sign> {
1118 let f = dword as f32;
1119 if f.is_infinite() {
1120 return Inexact(f, Sign::Positive);
1121 }
1122
1123 let back = f as DoubleWord;
1124 match back.partial_cmp(&dword).unwrap() {
1125 Ordering::Greater => Inexact(f, Sign::Positive),
1126 Ordering::Equal => Exact(f),
1127 Ordering::Less => Inexact(f, Sign::Negative),
1128 }
1129 }
1130
1131 fn to_f64_small(dword: DoubleWord) -> Approximation<f64, Sign> {
1132 const_assert!((DoubleWord::MAX as f64) < f64::MAX);
1133 let f = dword as f64;
1134 let back = f as DoubleWord;
1135
1136 match back.partial_cmp(&dword).unwrap() {
1137 Ordering::Greater => Inexact(f, Sign::Positive),
1138 Ordering::Equal => Exact(f),
1139 Ordering::Less => Inexact(f, Sign::Negative),
1140 }
1141 }
1142}
1143
1144