1use crate::{
4 add,
5 arch::word::{DoubleWord, Word},
6 buffer::Buffer,
7 div,
8 helper_macros::debug_assert_zero,
9 ibig::IBig,
10 math, mul,
11 primitive::{
12 self, PrimitiveSigned, PrimitiveUnsigned, DWORD_BITS_USIZE, DWORD_BYTES, WORD_BITS,
13 WORD_BITS_USIZE, WORD_BYTES,
14 },
15 repr::{
16 Repr,
17 TypedReprRef::{self, *},
18 },
19 shift,
20 ubig::UBig,
21 Sign::*,
22};
23use alloc::{boxed::Box, vec, vec::Vec};
24use core::convert::{TryFrom, TryInto};
25use dashu_base::{
26 Approximation::{self, *},
27 BitTest, ConversionError, FloatEncoding, ParseError, PowerOfTwo, Sign,
28};
29use static_assertions::const_assert;
30
31impl Default for UBig {
32 #[inline]
34 fn default() -> UBig {
35 UBig::ZERO
36 }
37}
38
39impl Default for IBig {
40 #[inline]
42 fn default() -> IBig {
43 IBig::ZERO
44 }
45}
46
47pub(crate) fn words_to_le_bytes<const FLIP: bool>(words: &[Word]) -> Vec<u8> {
48 debug_assert!(!words.is_empty());
49
50 let n = words.len();
51 let last = words[n - 1];
52 let skip_last_bytes = last.leading_zeros() as usize / 8;
53 let mut bytes = Vec::with_capacity(n * WORD_BYTES - skip_last_bytes);
54 for word in &words[..n - 1] {
55 let word = if FLIP { !*word } else { *word };
56 bytes.extend_from_slice(&word.to_le_bytes());
57 }
58 let last = if FLIP { !last } else { last };
59 let last_bytes = last.to_le_bytes();
60 bytes.extend_from_slice(&last_bytes[..WORD_BYTES - skip_last_bytes]);
61 bytes
62}
63
64fn words_to_be_bytes<const FLIP: bool>(words: &[Word]) -> Vec<u8> {
65 debug_assert!(!words.is_empty());
66
67 let n = words.len();
68 let last = words[n - 1];
69 let skip_last_bytes = last.leading_zeros() as usize / 8;
70 let mut bytes = Vec::with_capacity(n * WORD_BYTES - skip_last_bytes);
71 let last = if FLIP { !last } else { last };
72 let last_bytes = last.to_be_bytes();
73 bytes.extend_from_slice(&last_bytes[skip_last_bytes..]);
74 for word in words[..n - 1].iter().rev() {
75 let word = if FLIP { !*word } else { *word };
76 bytes.extend_from_slice(&word.to_be_bytes());
77 }
78 bytes
79}
80
81fn words_to_chunks(words: &[Word], chunks_out: &mut [&mut [Word]], chunk_bits: usize) {
87 assert!(!words.is_empty());
88
89 if chunk_bits % WORD_BITS_USIZE == 0 {
90 let words_per_chunk = chunk_bits / WORD_BITS_USIZE;
92 for (i, chunk_out) in chunks_out.iter_mut().enumerate() {
93 let start_pos = i * words_per_chunk;
94 let end_pos = (start_pos + words_per_chunk).min(words.len());
100 let copy_len = end_pos - start_pos;
101 chunk_out[..copy_len].copy_from_slice(&words[start_pos..end_pos]);
102 }
103 } else {
104 let bit_len =
105 words.len() * WORD_BITS_USIZE - words.last().unwrap().leading_zeros() as usize;
106 for (i, chunk_out) in chunks_out.iter_mut().enumerate() {
107 let start = i * chunk_bits;
108 let end = bit_len.min(start + chunk_bits);
109 debug_assert!(start < end); let (start_pos, end_pos) = (start / WORD_BITS_USIZE, end / WORD_BITS_USIZE);
112 let end_bits = (end % WORD_BITS_USIZE) as u32;
113 let len;
114 if end_bits != 0 {
115 len = end_pos - start_pos;
116 chunk_out[..=len].copy_from_slice(&words[start_pos..=end_pos]);
117 chunk_out[len] &= math::ones_word(end_bits);
118 } else {
119 len = end_pos - start_pos - 1;
120 chunk_out[..=len].copy_from_slice(&words[start_pos..end_pos]);
121 }
122 shift::shr_in_place(&mut chunk_out[..=len], (start % WORD_BITS_USIZE) as u32);
123 }
124 }
125}
126
127fn chunks_to_words(
133 words_out: &mut [Word],
134 chunks: &[&[Word]],
135 chunk_bits: usize,
136 buffer: &mut [Word],
137) {
138 assert!(!chunks.is_empty());
139 for (i, chunk) in chunks.iter().enumerate() {
140 let shift = i * chunk_bits;
141 buffer[..chunk.len()].copy_from_slice(chunk);
142 buffer[chunk.len()] = 0;
143 shift::shl_in_place(&mut buffer[..=chunk.len()], (shift % WORD_BITS_USIZE) as u32);
144 debug_assert_zero!(add::add_in_place(
145 &mut words_out[shift / WORD_BITS_USIZE..],
146 &buffer[..=chunk.len()]
147 ));
148 }
149}
150
151impl TypedReprRef<'_> {
152 fn to_le_bytes(self) -> Vec<u8> {
153 match self {
154 RefSmall(x) => {
155 let bytes = x.to_le_bytes();
156 let skip_bytes = x.leading_zeros() as usize / 8;
157 bytes[..DWORD_BYTES - skip_bytes].into()
158 }
159 RefLarge(words) => words_to_le_bytes::<false>(words),
160 }
161 }
162
163 fn to_signed_le_bytes(self, negate: bool) -> Vec<u8> {
164 if let RefSmall(v) = self {
166 if v == 0 {
167 return Vec::new();
168 }
169 }
170
171 let mut bytes = if negate {
172 match self {
173 RefSmall(x) => {
174 let bytes = (!x + 1).to_le_bytes();
175 let skip_bytes = x.leading_zeros() as usize / 8;
176 bytes[..DWORD_BYTES - skip_bytes].into()
177 }
178 RefLarge(words) => {
179 let mut buffer = Buffer::from(words);
180 debug_assert_zero!(add::sub_one_in_place(&mut buffer));
181 words_to_le_bytes::<true>(&buffer)
182 }
183 }
184 } else {
185 self.to_le_bytes()
186 };
187
188 let needs_sign_pad = match bytes.last() {
189 None => false, Some(&b) => (b & 0x80 != 0) != negate,
191 };
192 if needs_sign_pad {
193 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 needs_sign_pad = match bytes.first() {
236 None => false, Some(&b) => (b & 0x80 != 0) != negate,
238 };
239 if needs_sign_pad {
240 bytes.insert(0, if negate { 0xff } else { 0 });
241 }
242
243 bytes
244 }
245
246 fn to_chunks(self, chunk_bits: usize) -> Vec<Repr> {
247 assert!(chunk_bits > 0);
248 let chunk_count = math::ceil_div(self.bit_len(), chunk_bits);
249
250 match self {
251 RefSmall(x) => match chunk_count {
252 0 => Vec::new(),
253 1 => vec![Repr::from_dword(x)],
254 n => {
255 const_assert!(u8::MAX as usize > DWORD_BITS_USIZE);
256 let mut buffers = Vec::with_capacity(n);
257 let chunk_bits = chunk_bits as u8; for i in 0..n as u8 {
259 let chunk = (x >> (i * chunk_bits)) & math::ones_dword(chunk_bits as _);
260 buffers.push(Repr::from_dword(chunk));
261 }
262 buffers
263 }
264 },
265 RefLarge(words) => {
266 let mut buffers = Vec::<Buffer>::new();
267 let word_per_chunk = math::ceil_div(chunk_bits, WORD_BITS_USIZE);
268 buffers.resize_with(chunk_count, || {
269 let mut buf: Buffer = Buffer::allocate(word_per_chunk + 1);
271 buf.push_zeros(word_per_chunk + 1);
272 buf
273 });
274 let mut buffer_refs: Box<[&mut [Word]]> =
275 buffers.iter_mut().map(|buf| buf.as_mut()).collect();
276 words_to_chunks(words, &mut buffer_refs, chunk_bits);
277 buffers.into_iter().map(Repr::from_buffer).collect()
278 }
279 }
280 }
281}
282
283impl Repr {
284 fn from_le_bytes(bytes: &[u8]) -> Self {
285 if bytes.len() <= DWORD_BYTES {
286 Self::from_dword(primitive::dword_from_le_bytes_partial::<false>(bytes))
288 } else {
289 Self::from_le_bytes_large::<false>(bytes)
291 }
292 }
293
294 fn from_signed_le_bytes(bytes: &[u8]) -> Self {
295 if let Some(v) = bytes.last() {
296 if *v < 0x80 {
297 return Self::from_le_bytes(bytes);
298 }
299 } else {
300 return Self::zero();
301 }
302
303 let repr = if bytes.len() <= DWORD_BYTES {
305 let dword = primitive::dword_from_le_bytes_partial::<true>(bytes);
307 Self::from_dword(!dword + 1)
308 } else {
309 Self::from_le_bytes_large::<true>(bytes)
311 };
312 repr.with_sign(Sign::Negative)
313 }
314
315 fn from_le_bytes_large<const NEG: bool>(bytes: &[u8]) -> Self {
316 debug_assert!(bytes.len() >= DWORD_BYTES);
317 let mut buffer = Buffer::allocate((bytes.len() - 1) / WORD_BYTES + 1);
318 let mut chunks = bytes.chunks_exact(WORD_BYTES);
319 for chunk in &mut chunks {
320 let word = Word::from_le_bytes(chunk.try_into().unwrap());
321 buffer.push(if NEG { !word } else { word });
322 }
323 if !chunks.remainder().is_empty() {
324 let word = primitive::word_from_le_bytes_partial::<NEG>(chunks.remainder());
325 buffer.push(if NEG { !word } else { word });
326 }
327 if NEG {
328 debug_assert_zero!(add::add_one_in_place(&mut buffer));
329 }
330 Self::from_buffer(buffer)
331 }
332
333 fn from_be_bytes(bytes: &[u8]) -> Self {
334 if bytes.len() <= DWORD_BYTES {
335 Self::from_dword(primitive::dword_from_be_bytes_partial::<false>(bytes))
336 } else {
337 Self::from_be_bytes_large::<false>(bytes)
339 }
340 }
341
342 fn from_signed_be_bytes(bytes: &[u8]) -> Self {
343 if let Some(v) = bytes.first() {
344 if *v < 0x80 {
345 return Self::from_be_bytes(bytes);
346 }
347 } else {
348 return Self::zero();
349 }
350
351 let repr = if bytes.len() <= DWORD_BYTES {
353 let dword = primitive::dword_from_be_bytes_partial::<true>(bytes);
355 Self::from_dword(!dword + 1)
356 } else {
357 Self::from_be_bytes_large::<true>(bytes)
359 };
360 repr.with_sign(Sign::Negative)
361 }
362
363 fn from_be_bytes_large<const NEG: bool>(bytes: &[u8]) -> Self {
364 debug_assert!(bytes.len() >= DWORD_BYTES);
365 let mut buffer = Buffer::allocate((bytes.len() - 1) / WORD_BYTES + 1);
366 let mut chunks = bytes.rchunks_exact(WORD_BYTES);
367 for chunk in &mut chunks {
368 let word = Word::from_be_bytes(chunk.try_into().unwrap());
369 buffer.push(if NEG { !word } else { word });
370 }
371 if !chunks.remainder().is_empty() {
372 let word = primitive::word_from_be_bytes_partial::<NEG>(chunks.remainder());
373 buffer.push(if NEG { !word } else { word });
374 }
375 if NEG {
376 debug_assert_zero!(add::add_one_in_place(&mut buffer));
377 }
378 Self::from_buffer(buffer)
379 }
380
381 fn from_chunks(chunks: &[&[Word]], chunk_bits: usize) -> Self {
382 if let Some(max_len) = chunks.iter().map(|words| words.len()).max() {
383 let result_len = max_len + (chunks.len() - 1) * chunk_bits + 1;
385 let mut result = Buffer::allocate(result_len);
386 result.push_zeros(result_len);
387 let mut buffer = Buffer::allocate_exact(max_len + 1);
388 buffer.push_zeros(max_len + 1);
389
390 chunks_to_words(&mut result, chunks, chunk_bits, &mut buffer);
391 Self::from_buffer(result)
392 } else {
393 Self::zero()
394 }
395 }
396}
397
398impl UBig {
399 #[inline]
408 pub fn from_le_bytes(bytes: &[u8]) -> UBig {
409 UBig(Repr::from_le_bytes(bytes))
410 }
411
412 #[inline]
421 pub fn from_be_bytes(bytes: &[u8]) -> UBig {
422 UBig(Repr::from_be_bytes(bytes))
423 }
424
425 pub fn to_le_bytes(&self) -> Box<[u8]> {
435 self.repr().to_le_bytes().into_boxed_slice()
436 }
437
438 pub fn to_be_bytes(&self) -> Box<[u8]> {
448 self.repr().to_be_bytes().into_boxed_slice()
449 }
450
451 #[inline]
473 pub fn from_chunks<'a, I: Iterator<Item = &'a UBig>>(chunks: I, chunk_bits: usize) -> Self {
474 let chunks: Box<_> = chunks.into_iter().map(|u| u.as_words()).collect();
475 Self(Repr::from_chunks(&chunks, chunk_bits))
476 }
477
478 #[inline]
495 pub fn to_chunks(&self, chunk_bits: usize) -> Box<[UBig]> {
496 self.repr()
497 .to_chunks(chunk_bits)
498 .into_iter()
499 .map(UBig)
500 .collect()
501 }
502
503 #[inline]
516 pub fn to_f32(&self) -> Approximation<f32, Sign> {
517 self.repr().to_f32()
518 }
519
520 #[inline]
533 pub fn to_f64(&self) -> Approximation<f64, Sign> {
534 self.repr().to_f64()
535 }
536
537 #[inline]
546 pub const fn as_ibig(&self) -> &IBig {
547 unsafe { core::mem::transmute(self) }
551 }
552}
553
554impl IBig {
555 #[inline]
568 pub fn from_le_bytes(bytes: &[u8]) -> IBig {
569 IBig(Repr::from_signed_le_bytes(bytes))
570 }
571
572 #[inline]
585 pub fn from_be_bytes(bytes: &[u8]) -> IBig {
586 IBig(Repr::from_signed_be_bytes(bytes))
587 }
588
589 #[inline]
601 pub fn to_le_bytes(&self) -> Box<[u8]> {
602 let (sign, repr) = self.as_sign_repr();
603 repr.to_signed_le_bytes(sign.into()).into_boxed_slice()
604 }
605
606 pub fn to_be_bytes(&self) -> Box<[u8]> {
618 let (sign, repr) = self.as_sign_repr();
619 repr.to_signed_be_bytes(sign.into()).into_boxed_slice()
620 }
621
622 #[inline]
635 pub fn to_f32(&self) -> Approximation<f32, Sign> {
636 let (sign, mag) = self.as_sign_repr();
637 match mag.to_f32() {
638 Exact(val) => Exact(sign * val),
639 Inexact(val, diff) => Inexact(sign * val, sign * diff),
640 }
641 }
642
643 #[inline]
656 pub fn to_f64(&self) -> Approximation<f64, Sign> {
657 let (sign, mag) = self.as_sign_repr();
658 match mag.to_f64() {
659 Exact(val) => Exact(sign * val),
660 Inexact(val, diff) => Inexact(sign * val, sign * diff),
661 }
662 }
663
664 #[inline]
676 pub const fn as_ubig(&self) -> Option<&UBig> {
677 match self.sign() {
678 Sign::Positive => {
679 unsafe { Some(core::mem::transmute::<&IBig, &UBig>(self)) }
683 }
684 Sign::Negative => None,
685 }
686 }
687}
688
689macro_rules! ubig_unsigned_conversions {
690 ($($t:ty)*) => {$(
691 impl From<$t> for UBig {
692 #[inline]
693 fn from(value: $t) -> UBig {
694 UBig::from_unsigned(value)
695 }
696 }
697
698 impl TryFrom<UBig> for $t {
699 type Error = ConversionError;
700
701 #[inline]
702 fn try_from(value: UBig) -> Result<$t, ConversionError> {
703 value.try_to_unsigned()
704 }
705 }
706
707 impl TryFrom<&UBig> for $t {
708 type Error = ConversionError;
709
710 #[inline]
711 fn try_from(value: &UBig) -> Result<$t, ConversionError> {
712 value.try_to_unsigned()
713 }
714 }
715 )*};
716}
717ubig_unsigned_conversions!(u8 u16 u32 u64 u128 usize);
718
719impl From<bool> for UBig {
720 #[inline]
721 fn from(b: bool) -> UBig {
722 u8::from(b).into()
723 }
724}
725
726macro_rules! ubig_signed_conversions {
727 ($($t:ty)*) => {$(
728 impl TryFrom<$t> for UBig {
729 type Error = ConversionError;
730
731 #[inline]
732 fn try_from(value: $t) -> Result<UBig, ConversionError> {
733 UBig::try_from_signed(value)
734 }
735 }
736
737 impl TryFrom<UBig> for $t {
738 type Error = ConversionError;
739
740 #[inline]
741 fn try_from(value: UBig) -> Result<$t, ConversionError> {
742 value.try_to_signed()
743 }
744 }
745
746 impl TryFrom<&UBig> for $t {
747 type Error = ConversionError;
748
749 #[inline]
750 fn try_from(value: &UBig) -> Result<$t, ConversionError> {
751 value.try_to_signed()
752 }
753 }
754 )*};
755}
756ubig_signed_conversions!(i8 i16 i32 i64 i128 isize);
757
758macro_rules! ibig_unsigned_conversions {
759 ($($t:ty)*) => {$(
760 impl From<$t> for IBig {
761 #[inline]
762 fn from(value: $t) -> IBig {
763 IBig::from_unsigned(value)
764 }
765 }
766
767 impl TryFrom<IBig> for $t {
768 type Error = ConversionError;
769
770 #[inline]
771 fn try_from(value: IBig) -> Result<$t, ConversionError> {
772 value.try_to_unsigned()
773 }
774 }
775
776 impl TryFrom<&IBig> for $t {
777 type Error = ConversionError;
778
779 #[inline]
780 fn try_from(value: &IBig) -> Result<$t, ConversionError> {
781 value.try_to_unsigned()
782 }
783 }
784 )*};
785}
786
787ibig_unsigned_conversions!(u8 u16 u32 u64 u128 usize);
788
789impl From<bool> for IBig {
790 #[inline]
791 fn from(b: bool) -> IBig {
792 u8::from(b).into()
793 }
794}
795
796macro_rules! ibig_signed_conversions {
797 ($($t:ty)*) => {$(
798 impl From<$t> for IBig {
799 #[inline]
800 fn from(value: $t) -> IBig {
801 IBig::from_signed(value)
802 }
803 }
804
805 impl TryFrom<IBig> for $t {
806 type Error = ConversionError;
807
808 #[inline]
809 fn try_from(value: IBig) -> Result<$t, ConversionError> {
810 value.try_to_signed()
811 }
812 }
813
814 impl TryFrom<&IBig> for $t {
815 type Error = ConversionError;
816
817 #[inline]
818 fn try_from(value: &IBig) -> Result<$t, ConversionError> {
819 value.try_to_signed()
820 }
821 }
822 )*};
823}
824ibig_signed_conversions!(i8 i16 i32 i64 i128 isize);
825
826macro_rules! ubig_float_conversions {
827 ($($t:ty => $i:ty;)*) => {$(
828 impl TryFrom<$t> for UBig {
829 type Error = ConversionError;
830
831 fn try_from(value: $t) -> Result<Self, Self::Error> {
832 let (man, exp) = value.decode().map_err(|_| ConversionError::OutOfBounds)?;
833 let mut result: UBig = man.try_into()?;
834 if exp >= 0 {
835 result <<= exp as usize;
836 } else {
837 result >>= (-exp) as usize;
838 }
839 Ok(result)
840 }
841 }
842
843 impl TryFrom<UBig> for $t {
844 type Error = ConversionError;
845
846 fn try_from(value: UBig) -> Result<Self, Self::Error> {
847 const MAX_BIT_LEN: usize = (<$t>::MANTISSA_DIGITS + 1) as usize;
848 if value.bit_len() > MAX_BIT_LEN
849 || (value.bit_len() == MAX_BIT_LEN && !value.is_power_of_two())
850 {
851 Err(ConversionError::LossOfPrecision)
853 } else {
854 Ok(<$i>::try_from(value).unwrap() as $t)
855 }
856 }
857 }
858 )*};
859}
860ubig_float_conversions!(f32 => u32; f64 => u64;);
861
862macro_rules! ibig_float_conversions {
863 ($($t:ty => $i:ty;)*) => {$(
864 impl TryFrom<$t> for IBig {
865 type Error = ConversionError;
866
867 fn try_from(value: $t) -> Result<Self, Self::Error> {
868 let (man, exp) = value.decode().map_err(|_| ConversionError::OutOfBounds)?;
869 let mut result: IBig = man.into();
870 if exp >= 0 {
871 result <<= exp as usize;
872 } else {
873 result >>= (-exp) as usize;
874 }
875 Ok(result)
876 }
877 }
878
879 impl TryFrom<IBig> for $t {
880 type Error = ConversionError;
881
882 fn try_from(value: IBig) -> Result<Self, Self::Error> {
883 const MAX_BIT_LEN: usize = (<$t>::MANTISSA_DIGITS + 1) as usize;
884 let (sign, value) = value.into_parts();
885 if value.bit_len() > MAX_BIT_LEN
886 || (value.bit_len() == MAX_BIT_LEN && !value.is_power_of_two())
887 {
888 Err(ConversionError::LossOfPrecision)
890 } else {
891 let float = <$i>::try_from(value).unwrap() as $t;
892 Ok(sign * float)
893 }
894 }
895 }
896 )*};
897}
898ibig_float_conversions!(f32 => u32; f64 => u64;);
899
900impl From<UBig> for IBig {
901 #[inline]
902 fn from(x: UBig) -> IBig {
903 IBig(x.0.with_sign(Positive))
904 }
905}
906
907impl TryFrom<IBig> for UBig {
908 type Error = ConversionError;
909
910 #[inline]
911 fn try_from(x: IBig) -> Result<UBig, ConversionError> {
912 match x.sign() {
913 Positive => Ok(UBig(x.0)),
914 Negative => Err(ConversionError::OutOfBounds),
915 }
916 }
917}
918
919impl UBig {
920 #[inline]
922 pub(crate) fn from_unsigned<T>(x: T) -> UBig
923 where
924 T: PrimitiveUnsigned,
925 {
926 UBig(Repr::from_unsigned(x))
927 }
928
929 #[inline]
931 fn try_from_signed<T>(x: T) -> Result<UBig, ConversionError>
932 where
933 T: PrimitiveSigned,
934 {
935 let (sign, mag) = x.to_sign_magnitude();
936 match sign {
937 Sign::Positive => Ok(UBig(Repr::from_unsigned(mag))),
938 Sign::Negative => Err(ConversionError::OutOfBounds),
939 }
940 }
941
942 #[inline]
944 pub(crate) fn try_to_unsigned<T>(&self) -> Result<T, ConversionError>
945 where
946 T: PrimitiveUnsigned,
947 {
948 self.repr().try_to_unsigned()
949 }
950
951 #[inline]
953 fn try_to_signed<T>(&self) -> Result<T, ConversionError>
954 where
955 T: PrimitiveSigned,
956 {
957 T::try_from_sign_magnitude(Sign::Positive, self.repr().try_to_unsigned()?)
958 }
959}
960
961impl IBig {
962 #[inline]
964 pub(crate) fn from_unsigned<T: PrimitiveUnsigned>(x: T) -> IBig {
965 IBig(Repr::from_unsigned(x))
966 }
967
968 #[inline]
970 pub(crate) fn from_signed<T: PrimitiveSigned>(x: T) -> IBig {
971 let (sign, mag) = x.to_sign_magnitude();
972 IBig(Repr::from_unsigned(mag).with_sign(sign))
973 }
974
975 #[inline]
977 pub(crate) fn try_to_unsigned<T: PrimitiveUnsigned>(&self) -> Result<T, ConversionError> {
978 let (sign, mag) = self.as_sign_repr();
979 match sign {
980 Positive => mag.try_to_unsigned(),
981 Negative => Err(ConversionError::OutOfBounds),
982 }
983 }
984
985 #[inline]
987 pub(crate) fn try_to_signed<T: PrimitiveSigned>(&self) -> Result<T, ConversionError> {
988 let (sign, mag) = self.as_sign_repr();
989 T::try_from_sign_magnitude(sign, mag.try_to_unsigned()?)
990 }
991}
992
993mod repr {
994 use core::cmp::Ordering;
995
996 use static_assertions::const_assert;
997
998 use super::*;
999 use crate::repr::TypedReprRef;
1000
1001 fn unsigned_from_words<T>(words: &[Word]) -> Result<T, ConversionError>
1003 where
1004 T: PrimitiveUnsigned,
1005 {
1006 debug_assert!(words.len() >= 2);
1007 let t_words = T::BYTE_SIZE / WORD_BYTES;
1008 if t_words <= 1 || words.len() > t_words {
1009 Err(ConversionError::OutOfBounds)
1010 } else {
1011 assert!(
1012 T::BIT_SIZE % WORD_BITS == 0,
1013 "A large primitive type not a multiple of word size."
1014 );
1015 let mut repr = T::default().to_le_bytes();
1016 let bytes: &mut [u8] = repr.as_mut();
1017 for (idx, w) in words.iter().enumerate() {
1018 let pos = idx * WORD_BYTES;
1019 bytes[pos..pos + WORD_BYTES].copy_from_slice(&w.to_le_bytes());
1020 }
1021 Ok(T::from_le_bytes(repr))
1022 }
1023 }
1024
1025 impl Repr {
1026 #[inline]
1027 pub fn from_unsigned<T>(x: T) -> Self
1028 where
1029 T: PrimitiveUnsigned,
1030 {
1031 if let Ok(dw) = x.try_into() {
1032 Self::from_dword(dw)
1033 } else {
1034 let repr = x.to_le_bytes();
1035 Self::from_le_bytes_large::<false>(repr.as_ref())
1036 }
1037 }
1038 }
1039
1040 impl<'a> TypedReprRef<'a> {
1041 #[inline]
1042 pub fn try_to_unsigned<T>(self) -> Result<T, ConversionError>
1043 where
1044 T: PrimitiveUnsigned,
1045 {
1046 match self {
1047 RefSmall(dw) => T::try_from(dw).map_err(|_| ConversionError::OutOfBounds),
1048 RefLarge(words) => unsigned_from_words(words),
1049 }
1050 }
1051
1052 #[inline]
1053 pub fn to_f32(self) -> Approximation<f32, Sign> {
1054 match self {
1055 RefSmall(dword) => to_f32_small(dword),
1056 RefLarge(_) => self.to_f32_nontrivial(),
1057 }
1058 }
1059
1060 #[inline]
1061 fn to_f32_nontrivial(self) -> Approximation<f32, Sign> {
1062 let n = self.bit_len();
1063 debug_assert!(n > 32);
1064
1065 if n > 128 {
1066 Inexact(f32::INFINITY, Positive)
1067 } else {
1068 let top_u31: u32 = (self >> (n - 31)).as_typed().try_to_unsigned().unwrap();
1069 let extra_bit = self.are_low_bits_nonzero(n - 31) as u32;
1070 f32::encode((top_u31 | extra_bit) as i32, (n - 31) as i16)
1071 }
1072 }
1073
1074 #[inline]
1075 pub fn to_f64(self) -> Approximation<f64, Sign> {
1076 match self {
1077 RefSmall(dword) => to_f64_small(dword as DoubleWord),
1078 RefLarge(_) => {
1079 if self.bit_len() <= 64 {
1086 let v: u64 = self.try_to_unsigned().unwrap();
1087 let f = v as f64;
1088 let back = f as u64;
1089 match back.cmp(&v) {
1090 Ordering::Greater => Inexact(f, Sign::Positive),
1091 Ordering::Equal => Exact(f),
1092 Ordering::Less => Inexact(f, Sign::Negative),
1093 }
1094 } else {
1095 self.to_f64_nontrivial()
1096 }
1097 }
1098 }
1099 }
1100
1101 #[inline]
1102 fn to_f64_nontrivial(self) -> Approximation<f64, Sign> {
1103 let n = self.bit_len();
1104 debug_assert!(n > 64);
1105
1106 if n > 1024 {
1107 Inexact(f64::INFINITY, Positive)
1108 } else {
1109 let top_u63: u64 = (self >> (n - 63)).as_typed().try_to_unsigned().unwrap();
1110 let extra_bit = self.are_low_bits_nonzero(n - 63) as u64;
1111 f64::encode((top_u63 | extra_bit) as i64, (n - 63) as i16)
1112 }
1113 }
1114 }
1115
1116 fn to_f32_small(dword: DoubleWord) -> Approximation<f32, Sign> {
1117 let f = dword as f32;
1118 if f.is_infinite() {
1119 return Inexact(f, Sign::Positive);
1120 }
1121
1122 let back = f as DoubleWord;
1123 match back.partial_cmp(&dword).unwrap() {
1124 Ordering::Greater => Inexact(f, Sign::Positive),
1125 Ordering::Equal => Exact(f),
1126 Ordering::Less => Inexact(f, Sign::Negative),
1127 }
1128 }
1129
1130 fn to_f64_small(dword: DoubleWord) -> Approximation<f64, Sign> {
1131 const_assert!((DoubleWord::MAX as f64) < f64::MAX);
1132 let f = dword as f64;
1133 let back = f as DoubleWord;
1134
1135 match back.partial_cmp(&dword).unwrap() {
1136 Ordering::Greater => Inexact(f, Sign::Positive),
1137 Ordering::Equal => Exact(f),
1138 Ordering::Less => Inexact(f, Sign::Negative),
1139 }
1140 }
1141}
1142
1143impl UBig {
1144 #[must_use]
1169 pub fn to_digits(&self, base: Word) -> Vec<Word> {
1170 assert!(base >= 2, "base must be at least 2");
1171
1172 if self.is_zero() {
1173 return vec![0];
1174 }
1175
1176 let mut words = Buffer::from(self.as_words());
1179 let mut digits = Vec::new();
1180 while !words.is_empty() {
1181 let rem = div::div_by_word_in_place(&mut words, base);
1182 digits.push(rem);
1183 words.pop_zeros();
1184 }
1185 digits.reverse();
1186 digits
1187 }
1188
1189 pub fn from_digits(base: Word, digits: &[Word]) -> Result<UBig, ParseError> {
1213 if base < 2 {
1214 return Err(ParseError::InvalidDigit);
1215 }
1216 if digits.is_empty() {
1217 return Err(ParseError::NoDigits);
1218 }
1219 if digits.iter().any(|&d| d >= base) {
1220 return Err(ParseError::InvalidDigit);
1221 }
1222
1223 let mut acc = Buffer::from(&digits[0..1]); for &digit in &digits[1..] {
1226 let carry = mul::mul_word_in_place(&mut acc, base);
1227 if carry != 0 {
1228 acc.push_resizing(carry);
1229 }
1230 let overflow = add::add_word_in_place(&mut acc, digit);
1231 if overflow {
1232 acc.push_resizing(1);
1233 }
1234 }
1235
1236 Ok(UBig(Repr::from_buffer(acc)))
1237 }
1238}
1239
1240#[cfg(test)]
1241mod tests {
1242 use super::*;
1243
1244 #[test]
1245 fn test_to_digits_zero() {
1246 assert_eq!(UBig::ZERO.to_digits(2), vec![0]);
1247 assert_eq!(UBig::ZERO.to_digits(10), vec![0]);
1248 assert_eq!(UBig::ZERO.to_digits(256), vec![0]);
1249 }
1250
1251 #[test]
1252 fn test_to_digits_small() {
1253 assert_eq!(UBig::from(83u8).to_digits(3), vec![1, 0, 0, 0, 2]);
1255 assert_eq!(UBig::from(255u8).to_digits(16), vec![15, 15]);
1257 assert_eq!(UBig::from(256u16).to_digits(256), vec![1, 0]);
1259 assert_eq!(UBig::from(5u8).to_digits(10), vec![5]);
1261 }
1262
1263 #[test]
1264 fn test_to_digits_large_base() {
1265 let n = UBig::from(u128::MAX);
1267 let digits = n.to_digits(10_000);
1268 assert!(digits.iter().all(|&d| d < 10_000));
1269 assert_eq!(UBig::from_digits(10_000, &digits).unwrap(), n);
1270
1271 let digits = n.to_digits(Word::MAX);
1273 assert!(digits.iter().all(|&d| d < Word::MAX));
1274 assert_eq!(UBig::from_digits(Word::MAX, &digits).unwrap(), n);
1275 }
1276
1277 #[test]
1278 fn test_from_digits_errors() {
1279 assert!(UBig::from_digits(10, &[]).is_err());
1281 assert!(UBig::from_digits(0, &[0]).is_err());
1283 assert!(UBig::from_digits(1, &[0]).is_err());
1284 assert!(UBig::from_digits(10, &[9, 10]).is_err());
1286 assert!(UBig::from_digits(2, &[2]).is_err());
1287 }
1288
1289 #[test]
1290 fn test_to_from_digits_round_trip() {
1291 let values = [
1292 UBig::ZERO,
1293 UBig::ONE,
1294 UBig::from(123u32),
1295 UBig::from(u64::MAX),
1296 UBig::from(u128::MAX),
1297 UBig::from_str_radix("1234567890abcdef1234567890abcdef", 16).unwrap(),
1298 ];
1299 let bases: &[Word] = &[2, 3, 7, 10, 16, 36, 255, 256, 10_000, Word::MAX];
1301
1302 for v in &values {
1303 for &base in bases {
1304 let digits = v.to_digits(base);
1305 assert!(digits.iter().all(|&d| d < base), "digit >= base");
1306 let reconstructed = UBig::from_digits(base, &digits).unwrap();
1307 assert_eq!(&reconstructed, v, "round trip failed for base {base:?}");
1308 }
1309 }
1310 }
1311}