1use crate::bytes::{DigitsExp, DigitsUnds};
17use crate::types::extra::{LeEqU8, LeEqU16, LeEqU32, LeEqU64, LeEqU128};
18use crate::{
19 FixedI8, FixedI16, FixedI32, FixedI64, FixedI128, FixedU8, FixedU16, FixedU32, FixedU64,
20 FixedU128,
21};
22use core::error::Error;
23use core::fmt::{Display, Formatter, Result as FmtResult};
24use core::num::NonZeroU32;
25use core::str::FromStr;
26
27macro_rules! all {
93 ($Single:ident) => {
94 use crate::from_str::{ParseErrorKind, ParseFixedError, Sep};
95
96 #[inline]
97 pub const fn from_str_radix(
98 s: &[u8],
99 radix: u32,
100 frac_nbits: u32,
101 ) -> Result<$Single, ParseFixedError> {
102 match overflowing_from_str_radix(s, radix, frac_nbits) {
103 Ok((val, false)) => Ok(val),
104 Ok((_, true)) => Err(ParseFixedError {
105 kind: ParseErrorKind::Overflow,
106 }),
107 Err(e) => Err(e),
108 }
109 }
110
111 #[inline]
112 pub const fn saturating_from_str_radix(
113 s: &[u8],
114 radix: u32,
115 frac_nbits: u32,
116 ) -> Result<$Single, ParseFixedError> {
117 match overflowing_from_str_radix(s, radix, frac_nbits) {
118 Ok((val, false)) => Ok(val),
119 Ok((_, true)) => {
120 let starts_with_minus = match s.first() {
121 Some(byte) => *byte == b'-',
122 None => false,
123 };
124 if starts_with_minus {
125 Ok($Single::MIN)
126 } else {
127 Ok($Single::MAX)
128 }
129 }
130 Err(e) => Err(e),
131 }
132 }
133
134 #[inline]
135 pub const fn wrapping_from_str_radix(
136 s: &[u8],
137 radix: u32,
138 frac_nbits: u32,
139 ) -> Result<$Single, ParseFixedError> {
140 match overflowing_from_str_radix(s, radix, frac_nbits) {
141 Ok((val, _)) => Ok(val),
142 Err(e) => Err(e),
143 }
144 }
145
146 #[inline]
147 pub const fn overflowing_from_str_radix(
148 s: &[u8],
149 radix: u32,
150 frac_nbits: u32,
151 ) -> Result<($Single, bool), ParseFixedError> {
152 match from_str(s, radix, Sep::Error, frac_nbits) {
153 Ok(val) => Ok(val),
154 Err(kind) => Err(ParseFixedError { kind }),
155 }
156 }
157 };
158}
159
160macro_rules! signed {
168 ($Single:ident, $Uns:ident) => {
169 pub mod $Single {
170 all! { $Single }
171
172 pub(super) const fn from_str(
173 bytes: &[u8],
174 radix: u32,
175 sep: Sep,
176 frac_nbits: u32,
177 ) -> Result<($Single, bool), ParseErrorKind> {
178 let (neg, abs, mut overflow) = match crate::from_str::$Uns::get_int_frac(
179 bytes,
180 radix,
181 sep,
182 $Single::BITS - frac_nbits,
183 frac_nbits,
184 ) {
185 Ok((neg, abs, overflow)) => (neg, abs, overflow),
186 Err(e) => return Err(e),
187 };
188 let bound = if !neg { $Single::MAX } else { $Single::MIN };
189 if abs > bound.unsigned_abs() {
190 overflow = true;
191 }
192 let abs = if neg { abs.wrapping_neg() } else { abs } as $Single;
193 Ok((abs, overflow))
194 }
195
196 pub const fn lit(mut s: &[u8], frac_nbits: u32) -> Result<$Single, ParseFixedError> {
197 if s.is_empty() {
198 return Err(ParseFixedError {
199 kind: ParseErrorKind::NoDigits,
200 });
201 }
202 let neg = if s[0] == b'-' {
203 s = s.split_at(1).1;
204 true
205 } else {
206 false
207 };
208 let abs = match crate::from_str::$Uns::lit_no_sign(s, frac_nbits) {
209 Ok(val) => val,
210 Err(kind) => return Err(ParseFixedError { kind }),
211 };
212 let bound = if !neg { $Single::MAX } else { $Single::MIN };
213 if abs > bound.unsigned_abs() {
214 return Err(ParseFixedError {
215 kind: ParseErrorKind::Overflow,
216 });
217 }
218 let val = if neg { abs.wrapping_neg() } else { abs } as $Single;
219 Ok(val)
220 }
221 }
222 };
223}
224
225signed! { i8, u8 }
226signed! { i16, u16 }
227signed! { i32, u32 }
228signed! { i64, u64 }
229signed! { i128, u128 }
230
231macro_rules! unsigned {
252 ($Uns:ident $(, $Half:ident)?) => {
253 use crate::from_str::{
254 frac_is_half, parse_bounds, unchecked_hex_digit, BitExp, DigitsExp, Parse, Round,
255 };
256
257 all! { $Uns }
258
259 pub(super) const fn from_str(
260 bytes: &[u8],
261 radix: u32,
262 sep: Sep,
263 frac_nbits: u32,
264 ) -> Result<($Uns, bool), ParseErrorKind> {
265 let (neg, abs, mut overflow) =
266 match get_int_frac(bytes, radix, sep, $Uns::BITS - frac_nbits, frac_nbits) {
267 Ok((neg, abs, overflow)) => (neg, abs, overflow),
268 Err(e) => return Err(e),
269 };
270 if neg && abs > 0 {
271 overflow = true;
272 }
273 let abs = if neg { abs.wrapping_neg() } else { abs };
274 Ok((abs, overflow))
275 }
276
277 #[inline]
278 pub const fn lit(s: &[u8], frac_nbits: u32) -> Result<$Uns, ParseFixedError> {
279 match lit_no_sign(s, frac_nbits) {
280 Ok(val) => Ok(val),
281 Err(kind) => Err(ParseFixedError { kind }),
282 }
283 }
284
285 pub(super) const fn lit_no_sign(
286 mut bytes: &[u8],
287 frac_nbits: u32,
288 ) -> Result<$Uns, ParseErrorKind> {
289 if bytes.is_empty() {
290 return Err(ParseErrorKind::NoDigits);
291 }
292 let radix = if bytes.len() >= 2 && bytes[0] == b'0' {
293 match bytes[1] {
294 b'b' => 2,
295 b'o' => 8,
296 b'x' => 16,
297 _ => 10,
298 }
299 } else {
300 10
301 };
302 if radix != 10 {
303 bytes = bytes.split_at(2).1;
304 while let Some((b'_', rest)) = bytes.split_first() {
305 bytes = rest;
306 }
307 }
308 if let Some((b'-' | b'+', _)) = bytes.split_first() {
309 return Err(ParseErrorKind::MisplacedSign);
310 }
311 match from_str(bytes, radix, Sep::Skip, frac_nbits) {
312 Ok((val, false)) => Ok(val),
313 Ok((_, true)) => Err(ParseErrorKind::Overflow),
314 Err(e) => Err(e),
315 }
316 }
317
318 pub(super) const fn get_int_frac(
319 bytes: &[u8],
320 radix: u32,
321 sep: Sep,
322 int_nbits: u32,
323 frac_nbits: u32,
324 ) -> Result<(bool, $Uns, bool), ParseErrorKind> {
325 let Parse {
326 neg,
327 int,
328 frac,
329 bit_exp,
330 } = match parse_bounds(bytes, radix, sep) {
331 Ok(o) => o,
332 Err(e) => return Err(e),
333 };
334 let (int_val, mut overflow) = get_int(int, radix, int_nbits, bit_exp);
335 let (frac_val, frac_overflow) = match get_frac(frac, radix, frac_nbits, bit_exp) {
336 Some(val) => (val, false),
337 None => (0, true),
338 };
339 let mut val = int_val | frac_val;
340 if frac_overflow || (is_odd(int_val) && frac_nbits == 0 && frac_is_half(frac, radix)) {
347 let (new_val, new_overflow) = if int_nbits == 0 {
348 (val, true)
349 } else {
350 val.overflowing_add(1 << frac_nbits)
351 };
352 if new_overflow {
353 overflow = true;
354 }
355 val = new_val;
356 }
357 Ok((neg, val, overflow))
358 }
359
360 pub(super) const fn get_int(
361 int: DigitsExp,
362 radix: u32,
363 nbits: u32,
364 bit_exp: Option<BitExp>,
365 ) -> ($Uns, bool) {
366 $(
367 if nbits <= $Half::BITS {
368 let (half, overflow) =
369 crate::from_str::$Half::get_int(int, radix, nbits, bit_exp);
370 return ((half as $Uns) << $Half::BITS, overflow);
371 }
372 )?
373
374 if int.is_empty() && bit_exp.is_none() {
375 return (0, false);
376 }
377 let (mut parsed_int, mut overflow): ($Uns, bool) = match radix {
378 2 => bin_str_int_to_bin(int),
379 8 => oct_str_int_to_bin(int, bit_exp),
380 16 => hex_str_int_to_bin(int, bit_exp),
381 _ => {
382 debug_assert!(radix == 10);
383 dec_str_int_to_bin(int)
384 }
385 };
386 let remove_bits = $Uns::BITS - nbits;
387 if nbits == 0 {
388 overflow = true;
389 parsed_int = 0;
390 } else if remove_bits > 0 {
391 if (parsed_int >> nbits) != 0 {
392 overflow = true;
393 }
394 parsed_int <<= remove_bits;
395 }
396 (parsed_int, overflow)
397 }
398
399 pub(super) const fn get_frac(
400 frac: DigitsExp,
401 radix: u32,
402 nbits: u32,
403 bit_exp: Option<BitExp>,
404 ) -> Option<$Uns> {
405 $(
406 if nbits <= $Half::BITS {
407 return match crate::from_str::$Half::get_frac(frac, radix, nbits, bit_exp) {
408 Some(half) => Some(half as $Uns),
409 None => None,
410 };
411 }
412 )?
413
414 if frac.is_empty() {
415 return Some(0);
416 }
417 match radix {
418 2 => bin_str_frac_to_bin(frac, nbits),
419 8 => oct_str_frac_to_bin(frac, nbits, bit_exp),
420 16 => hex_str_frac_to_bin(frac, nbits, bit_exp),
421 _ => {
422 debug_assert!(radix == 10);
423 dec_str_frac_to_bin(frac, nbits)
424 }
425 }
426 }
427
428 const fn bin_str_int_to_bin(digits: DigitsExp) -> ($Uns, bool) {
429 let max_len = $Uns::BITS as usize;
430 let (digits, overflow) = if digits.len() > max_len {
431 let (_, last_max_len) = digits.split_at(digits.len() - max_len);
432 (last_max_len, true)
433 } else {
434 (digits, false)
435 };
436 let mut acc = 0;
437 let mut rem_digits = digits;
438 while let Some((digit, rem)) = rem_digits.split_first() {
439 rem_digits = rem;
440
441 acc = (acc << 1) + from_byte(digit - b'0');
442 }
443 (acc, overflow)
444 }
445
446 const fn bin_str_frac_to_bin(digits: DigitsExp, nbits: u32) -> Option<$Uns> {
447 let mut rem_bits = nbits;
448 let mut acc = 0;
449 let mut rem_digits = digits;
450 while let Some((digit, rem)) = rem_digits.split_first() {
451 rem_digits = rem;
452
453 let val = digit - b'0';
454 if rem_bits < 1 {
455 if val != 0 {
456 if !rem_digits.is_empty() || is_odd(acc) {
459 acc = match acc.checked_add(1) {
460 Some(acc) => acc,
461 None => return None,
462 };
463 }
464 }
465 if nbits != $Uns::BITS && acc >> nbits != 0 {
466 return None;
467 }
468 return Some(acc);
469 }
470 acc = (acc << 1) + from_byte(val);
471 rem_bits -= 1;
472 }
473 Some(acc << rem_bits)
474 }
475
476 const fn oct_str_int_to_bin(digits: DigitsExp, bit_exp: Option<BitExp>) -> ($Uns, bool) {
477 let (exp, exp_extra_digit) = match bit_exp {
478 Some(s) => (s.exp.get(), s.first_frac_digit),
479 None => (0, 0),
480 };
481 if digits.is_empty() {
483 let val = (from_byte(exp_extra_digit - b'0')) >> (3 - exp);
484 return (val, false)
485 }
486 let max_digits = ($Uns::BITS - exp).div_ceil(3) as usize;
488 let (digits, mut overflow) = if digits.len() > max_digits {
489 let (_, last_max_digits) = digits.split_at(digits.len() - max_digits);
490 (last_max_digits, true)
491 } else {
492 (digits, false)
493 };
494 let Some((first_digit, mut rem_digits)) = digits.split_first() else {
495 unreachable!();
496 };
497 let mut acc = from_byte(first_digit - b'0');
498 if digits.len() == max_digits {
499 let first_max_bits = $Uns::BITS - exp - (max_digits as u32 - 1) * 3;
500 let first_max = (from_byte(1) << first_max_bits) - 1;
501 if acc > first_max {
502 overflow = true;
503 }
504 }
505 while let Some((digit, rem)) = rem_digits.split_first() {
506 rem_digits = rem;
507
508 acc = (acc << 3) + from_byte(digit - b'0');
509 }
510 if bit_exp.is_some() {
511 let val = (exp_extra_digit - b'0') >> (3 - exp);
512 acc = (acc << exp) + from_byte(val);
513 }
514 (acc, overflow)
515 }
516
517 const fn oct_str_frac_to_bin(
518 digits: DigitsExp,
519 nbits: u32,
520 bit_exp: Option<BitExp>,
521 ) -> Option<$Uns> {
522 let mut rem_bits = nbits;
523 let mut acc = 0;
524 let mut rem_digits = digits;
525 let mut val_bits = match bit_exp {
526 Some(s) => 3 - s.exp.get(),
527 None => 3,
528 };
529 while let Some((digit, rem)) = rem_digits.split_first() {
530 rem_digits = rem;
531
532 let val = if val_bits != 3 {
534 let first_digit_mask = (1 << val_bits) - 1;
535 (digit - b'0') & first_digit_mask
536 } else {
537 digit - b'0'
538 };
539 if rem_bits < val_bits {
540 acc = (acc << rem_bits) + from_byte(val >> (3 - rem_bits));
541 let half = 1 << (2 - rem_bits);
542 if val & half != 0 {
543 if val & (half - 1) != 0 || !rem_digits.is_empty() || is_odd(acc) {
546 acc = match acc.checked_add(1) {
547 Some(acc) => acc,
548 None => return None,
549 };
550 }
551 }
552 if nbits != $Uns::BITS && acc >> nbits != 0 {
553 return None;
554 }
555 return Some(acc);
556 }
557 acc = (acc << 3) + from_byte(val);
558 rem_bits -= val_bits;
559 val_bits = 3;
560 }
561 Some(acc << rem_bits)
562 }
563
564 const fn hex_str_int_to_bin(digits: DigitsExp, bit_exp: Option<BitExp>) -> ($Uns, bool) {
565 let (exp, exp_extra_digit) = match bit_exp {
566 Some(s) => (s.exp.get(), s.first_frac_digit),
567 None => (0, 0),
568 };
569 if digits.is_empty() {
571 let val = (from_byte(exp_extra_digit - b'0')) >> (3 - exp);
572 return (val, false)
573 }
574 let max_digits = ($Uns::BITS - exp).div_ceil(4) as usize;
576 let (digits, mut overflow) = if digits.len() > max_digits {
577 let (_, last_max_digits) = digits.split_at(digits.len() - max_digits);
578 (last_max_digits, true)
579 } else {
580 (digits, false)
581 };
582 let Some((first_digit, mut rem_digits)) = digits.split_first() else {
583 unreachable!();
584 };
585 let mut acc = from_byte(unchecked_hex_digit(first_digit));
586 if digits.len() == max_digits {
587 let first_max_bits = $Uns::BITS - exp - (max_digits as u32 - 1) * 4;
588 let first_max = (from_byte(1) << first_max_bits) - 1;
589 if acc > first_max {
590 overflow = true;
591 }
592 }
593 while let Some((digit, rem)) = rem_digits.split_first() {
594 rem_digits = rem;
595
596 acc = (acc << 4) + from_byte(unchecked_hex_digit(digit));
597 }
598 if bit_exp.is_some() {
599 let val = unchecked_hex_digit(exp_extra_digit) >> (4 - exp);
600 acc = (acc << exp) + from_byte(val);
601 }
602 (acc, overflow)
603 }
604
605 const fn hex_str_frac_to_bin(
606 digits: DigitsExp,
607 nbits: u32,
608 bit_exp: Option<BitExp>,
609 ) -> Option<$Uns> {
610 let mut rem_bits = nbits;
611 let mut acc = 0;
612 let mut rem_digits = digits;
613 let mut val_bits = match bit_exp {
614 Some(s) => 4 - s.exp.get(),
615 None => 4,
616 };
617 while let Some((digit, rem)) = rem_digits.split_first() {
618 rem_digits = rem;
619
620 let val = if val_bits != 4 {
622 let first_digit_mask = (1 << val_bits) - 1;
623 unchecked_hex_digit(digit) & first_digit_mask
624 } else {
625 unchecked_hex_digit(digit)
626 };
627 if rem_bits < val_bits {
628 acc = (acc << rem_bits) + from_byte(val >> (4 - rem_bits));
629 let half = 1 << (3 - rem_bits);
630 if val & half != 0 {
631 if val & (half - 1) != 0 || !rem_digits.is_empty() || is_odd(acc) {
634 acc = match acc.checked_add(1) {
635 Some(acc) => acc,
636 None => return None,
637 };
638 }
639 }
640 if nbits != $Uns::BITS && acc >> nbits != 0 {
641 return None;
642 }
643 return Some(acc);
644 }
645 acc = (acc << 4) + from_byte(val);
646 rem_bits -= val_bits;
647 val_bits = 4;
648 }
649 Some(acc << rem_bits)
650 }
651
652 pub(super) const fn dec_str_int_to_bin(digits: DigitsExp) -> ($Uns, bool) {
653 let max_effective_len = $Uns::BITS as usize;
654 let (digits, mut overflow) = if digits.len() > max_effective_len {
655 let (_, last_max_effective_len) = digits.split_at(digits.len() - max_effective_len);
656 (last_max_effective_len, true)
657 } else {
658 (digits, false)
659 };
660 let mut acc = 0;
661 let mut rem_digits = digits;
662 while let Some((digit, rem)) = rem_digits.split_first() {
663 rem_digits = rem;
664
665 let (prod, mul_overflow) = mul10_overflow(acc);
666 let (add, add_overflow) = prod.overflowing_add(from_byte(digit - b'0'));
667 acc = add;
668 overflow = overflow || mul_overflow != 0 || add_overflow;
669 }
670 (acc, overflow)
671 }
672
673 const fn dec_str_frac_to_bin(digits: DigitsExp, nbits: u32) -> Option<$Uns> {
674 let (val, is_short) = parse_is_short(digits);
675 let one: $Uns = 1;
676 let dump_bits = $Uns::BITS - nbits;
677 let round = if is_short {
679 Round::Nearest
680 } else {
681 Round::Floor
682 };
683 let Some(floor) = dec_to_bin(val, nbits, round) else {
684 return None;
685 };
686 if is_short {
687 return Some(floor);
688 }
689 let (mut boundary, mut add_5) = if nbits == 0 {
694 (one << ($Uns::BITS - 1), false)
695 } else if dump_bits == 0 {
696 (floor, true)
697 } else {
698 ((floor << dump_bits) + (one << (dump_bits - 1)), false)
699 };
700 let mut tie = true;
701 let mut rem_digits = digits;
702 while let Some((digit, rem)) = rem_digits.split_first() {
703 rem_digits = rem;
704
705 if !add_5 && boundary == 0 {
706 tie = false;
708 break;
709 }
710 let (prod, mut boundary_digit) = mul10_overflow(boundary);
711 boundary = prod;
712 if add_5 {
713 let (wrapped, overflow) = boundary.overflowing_add(5);
714 boundary = wrapped;
715 if overflow {
716 boundary_digit += 1;
717 }
718 add_5 = false;
719 }
720 if digit - b'0' < boundary_digit {
721 return Some(floor);
722 }
723 if digit - b'0' > boundary_digit {
724 tie = false;
725 break;
726 }
727 }
728 if tie && !is_odd(floor) {
729 return Some(floor);
730 }
731 let Some(next_up) = floor.checked_add(1) else {
732 return None;
733 };
734 if dump_bits != 0 && next_up >> nbits != 0 {
735 None
736 } else {
737 Some(next_up)
738 }
739 }
740
741 const fn from_byte(b: u8) -> $Uns {
742 b as $Uns
743 }
744
745 pub(super) const fn is_odd(val: $Uns) -> bool {
746 val & 1 != 0
747 }
748 };
749}
750
751macro_rules! unsigned_not_u128 {
760 ($Single:ident $(, $Half:ident)?; $Double:ident, $dec:expr, $bin:expr) => {
761 pub mod $Single {
762 unsigned! { $Single $(, $Half)? }
763
764 #[inline]
765 const fn mul10_overflow(x: $Single) -> ($Single, u8) {
766 let prod = (x as $Double) * 10;
767 (prod as $Single, (prod >> <$Single>::BITS) as u8)
768 }
769
770 pub(super) const fn dec_to_bin(
771 val: $Double,
772 nbits: u32,
773 round: Round,
774 ) -> Option<$Single> {
775 debug_assert!(val < $Double::pow(10, $dec));
776 debug_assert!(nbits <= $bin);
777 let fives = $Double::pow(5, $dec);
778 let denom = fives * 2;
779 let mut numer = val << ($bin - $dec + 1) >> ($bin - nbits);
780 match round {
781 Round::Nearest => {
782 numer += fives;
784 if numer >> nbits >= denom {
788 return if nbits == 0 && val == fives << ($dec - 1) {
790 Some(0)
791 } else {
792 None
793 };
794 }
795 }
796 Round::Floor => {}
797 }
798 let (mut div, tie) = (numer / denom, numer % denom == 0);
799 if tie && crate::from_str::$Double::is_odd(div) {
800 div -= 1;
801 }
802 Some(div as $Single)
803 }
804
805 const fn parse_is_short(digits: DigitsExp) -> ($Double, bool) {
806 let (is_short, slice, pad) =
807 if let Some(rem) = usize::checked_sub($dec, digits.len()) {
808 (true, digits, $Double::pow(10, rem as u32))
809 } else {
810 let (short, _) = digits.split_at($dec);
811 (false, short, 1)
812 };
813 let val = crate::from_str::$Double::dec_str_int_to_bin(slice).0 * pad;
814 (val, is_short)
815 }
816 }
817 };
818}
819
820unsigned_not_u128! { u8; u16, 3, 8 }
821unsigned_not_u128! { u16, u8; u32, 6, 16 }
822unsigned_not_u128! { u32, u16; u64, 13, 32 }
823unsigned_not_u128! { u64, u32; u128, 27, 64 }
824
825pub mod u128 {
826 unsigned! { u128, u64 }
827
828 use crate::int256;
829 use crate::int256::U256;
830 use core::num::NonZeroU128;
831
832 #[inline]
833 const fn mul10_overflow(x: u128) -> (u128, u8) {
834 const LO_MASK: u128 = !(!0 << 64);
835 let hi = (x >> 64) * 10;
836 let lo = (x & LO_MASK) * 10;
837 let (hi_lo, hi_hi) = (hi as u64, (hi >> 64) as u64);
841 let (lo_lo, lo_hi) = (lo as u64, (lo >> 64) as u64);
842 let (wrapped, overflow) = hi_lo.overflowing_add(lo_hi);
843 (
844 ((wrapped as u128) << 64) | (lo_lo as u128),
845 (hi_hi as u8) + (overflow as u8),
846 )
847 }
848
849 pub(super) const fn dec_to_bin(
850 (hi, lo): (u128, u128),
851 nbits: u32,
852 round: Round,
853 ) -> Option<u128> {
854 debug_assert!(hi < 10u128.pow(27));
855 debug_assert!(lo < 10u128.pow(27));
856 debug_assert!(nbits <= 128);
857 let fives = 5u128.pow(54);
858 let denom = fives * 2;
859 let Some(denom) = NonZeroU128::new(denom) else {
860 unreachable!();
861 };
862 let hi_e27 = int256::wide_mul_u128(hi, 10u128.pow(27));
864 let (val_lo, overflow) = hi_e27.lo.overflowing_add(lo);
865 let val_hi = hi_e27.hi + (overflow as u128);
866 let (mut numer_lo, mut numer_hi) = (val_lo, val_hi);
867 if nbits < (54 - 1) {
868 let shr = (54 - 1) - nbits;
869 numer_lo = (numer_lo >> shr) | (numer_hi << (128 - shr));
870 numer_hi >>= shr;
871 } else if nbits > (54 - 1) {
872 let shl = nbits - (54 - 1);
873 numer_hi = (numer_hi << shl) | (numer_lo >> (128 - shl));
874 numer_lo <<= shl;
875 }
876 match round {
877 Round::Nearest => {
878 let (wrapped, overflow) = numer_lo.overflowing_add(fives);
880 numer_lo = wrapped;
881 if overflow {
882 numer_hi += 1;
883 }
884 let check_overflow = if nbits == 128 {
885 numer_hi
886 } else if nbits == 0 {
887 numer_lo
888 } else {
889 (numer_lo >> nbits) | (numer_hi << (128 - nbits))
890 };
891 if check_overflow >= denom.get() {
895 let half_hi = fives >> (128 - (54 - 1));
897 let half_lo = fives << (54 - 1);
898 return if nbits == 0 && val_hi == half_hi && val_lo == half_lo {
899 Some(0)
900 } else {
901 None
902 };
903 }
904 }
905 Round::Floor => {}
906 }
907 let (mut div, tie) = div_tie(numer_hi, numer_lo, denom);
908 if tie && is_odd(div) {
909 div -= 1;
910 }
911 Some(div)
912 }
913
914 const fn parse_is_short(digits: DigitsExp) -> ((u128, u128), bool) {
915 if let Some(rem) = 27usize.checked_sub(digits.len()) {
916 let hi = dec_str_int_to_bin(digits).0 * 10u128.pow(rem as u32);
917 ((hi, 0), true)
918 } else {
919 let (begin, end) = digits.split_at(27);
920 let hi = dec_str_int_to_bin(begin).0;
921
922 let (is_short, slice, pad) = if let Some(rem) = 54usize.checked_sub(digits.len()) {
923 (true, end, 10u128.pow(rem as u32))
924 } else {
925 let (mid, _) = end.split_at(27);
926 (false, mid, 1)
927 };
928 let lo = dec_str_int_to_bin(slice).0 * pad;
929 ((hi, lo), is_short)
930 }
931 }
932
933 const fn div_tie(dividend_hi: u128, dividend_lo: u128, divisor: NonZeroU128) -> (u128, bool) {
934 let dividend = U256 {
935 lo: dividend_lo,
936 hi: dividend_hi,
937 };
938 let (quot, rem) = int256::div_rem_u256_u128(dividend, divisor);
939 (quot.lo, rem == 0)
940 }
941}
942
943const fn unchecked_hex_digit(byte: u8) -> u8 {
944 (byte & 0x0f) + if byte >= 0x40 { 9 } else { 0 }
949}
950
951#[derive(Clone, Copy, Debug)]
952pub enum Round {
953 Nearest,
954 Floor,
955}
956
957#[derive(Clone, Copy, Debug)]
958struct BitExp {
959 exp: NonZeroU32,
960 first_frac_digit: u8,
961}
962
963impl BitExp {
964 const fn new(bit_exp: u32, frac: DigitsExp) -> Option<BitExp> {
965 let Some(exp) = NonZeroU32::new(bit_exp) else {
966 return None;
967 };
968 let first_frac_digit = match frac.split_first() {
969 Some((digit, _)) => digit,
970 None => b'0',
971 };
972 Some(BitExp {
973 exp,
974 first_frac_digit,
975 })
976 }
977}
978
979#[derive(Clone, Copy, Debug)]
982struct Parse<'a> {
983 neg: bool,
984 int: DigitsExp<'a>,
985 frac: DigitsExp<'a>,
986 bit_exp: Option<BitExp>,
987}
988
989#[derive(Clone, Copy, Debug)]
990pub enum Sep {
991 Skip,
992 Error,
993}
994
995#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1013pub struct ParseFixedError {
1014 kind: ParseErrorKind,
1015}
1016
1017#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1018enum ParseErrorKind {
1019 InvalidDigit,
1020 MisplacedSign,
1021 MisplacedUnderscore,
1022 NoDigits,
1023 TooManyPoints,
1024 Overflow,
1025 ExpInvalidDigit,
1026 ExpNoDigits,
1027 TooManyExp,
1028 ExpOverflow,
1029}
1030
1031impl ParseFixedError {
1032 #[inline]
1033 #[track_caller]
1034 pub(crate) const fn lit_message(self) -> &'static str {
1035 use self::ParseErrorKind::*;
1036 match self.kind {
1037 InvalidDigit => "invalid literal: invalid digit found in string",
1038 MisplacedSign => "invalid literal: misplaced sign found in string",
1039 MisplacedUnderscore => "invalid literal: misplaced underscore found in string",
1040 NoDigits => "invalid literal: string has no digits",
1041 TooManyPoints => "invalid literal: more than one point found in string",
1042 Overflow => "invalid literal: overflow",
1043 ExpInvalidDigit => "invalid literal: invalid digit found in exponent",
1044 ExpNoDigits => "invalid literal: exponent has no digits",
1045 TooManyExp => "invalid literal: more than one exponent found",
1046 ExpOverflow => "invalid literal: exponent overflow",
1047 }
1048 }
1049
1050 #[inline]
1051 pub(crate) const fn message(self) -> &'static str {
1052 use self::ParseErrorKind::*;
1053 match self.kind {
1054 InvalidDigit => "invalid digit found in string",
1055 MisplacedSign => "misplaced sign found in string",
1056 MisplacedUnderscore => "misplaced underscore found in string",
1057 NoDigits => "string has no digits",
1058 TooManyPoints => "more than one point found in string",
1059 Overflow => "overflow",
1060 ExpInvalidDigit => "invalid digit found in exponent",
1061 ExpNoDigits => "exponent has no digits",
1062 TooManyExp => "more than one exponent found",
1063 ExpOverflow => "exponent overflow",
1064 }
1065 }
1066}
1067
1068impl Display for ParseFixedError {
1069 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
1070 Display::fmt(self.message(), f)
1071 }
1072}
1073
1074impl Error for ParseFixedError {
1075 fn description(&self) -> &str {
1076 self.message()
1077 }
1078}
1079
1080const fn parse_bounds(bytes: &[u8], radix: u32, sep: Sep) -> Result<Parse<'_>, ParseErrorKind> {
1083 let mut sign: Option<bool> = None;
1084 let mut int_start: Option<usize> = None;
1085 let mut point: Option<usize> = None;
1086 let mut frac_end: Option<usize> = None;
1087 let mut has_int_digit = false;
1088 let mut has_frac_digit = false;
1089 let mut exp_sep: Option<usize> = None;
1090 let mut exp_sign: Option<bool> = None;
1091 let mut exp: i32 = 0;
1092 let mut has_exp_digit = false;
1093 let mut exp_is_bit = false;
1094
1095 let mut next_index = 0;
1096 let mut rem_bytes = bytes;
1097 while let Some((&byte, rem)) = rem_bytes.split_first() {
1098 let index = next_index;
1099 next_index += 1;
1100 rem_bytes = rem;
1101
1102 match (byte, radix) {
1103 (b'+', _) => {
1104 if exp_sep.is_none() {
1105 if sign.is_some() || has_int_digit || point.is_some() {
1106 return Err(ParseErrorKind::MisplacedSign);
1107 }
1108 sign = Some(false);
1109 } else {
1110 if exp_sign.is_some() || has_exp_digit {
1111 return Err(ParseErrorKind::MisplacedSign);
1112 }
1113 exp_sign = Some(false);
1114 }
1115 }
1116 (b'-', _) => {
1117 if exp_sep.is_none() {
1118 if sign.is_some() || has_int_digit || point.is_some() {
1119 return Err(ParseErrorKind::MisplacedSign);
1120 }
1121 sign = Some(true);
1122 } else {
1123 if exp_sign.is_some() || has_exp_digit {
1124 return Err(ParseErrorKind::MisplacedSign);
1125 }
1126 exp_sign = Some(true);
1127 }
1128 }
1129 (b'.', _) => {
1130 if exp_sep.is_some() {
1131 return Err(ParseErrorKind::ExpInvalidDigit);
1132 }
1133 if point.is_some() {
1134 return Err(ParseErrorKind::TooManyPoints);
1135 }
1136 point = Some(index);
1137 frac_end = Some(index + 1);
1138 }
1139 (b'_', _) => {
1140 if matches!(sep, Sep::Error) {
1141 if exp_sep.is_some() {
1142 return Err(ParseErrorKind::ExpInvalidDigit);
1143 }
1144 return Err(ParseErrorKind::InvalidDigit);
1145 };
1146 if (point.is_none() && exp_sep.is_none() && !has_int_digit)
1147 || (point.is_some() && exp_sep.is_none() && !has_frac_digit)
1148 || (exp_sep.is_some() && !has_exp_digit)
1149 {
1150 return Err(ParseErrorKind::MisplacedUnderscore);
1151 }
1152 }
1153 (b'e' | b'E', 2 | 8 | 10) | (b'@', _) => {
1154 if exp_sep.is_some() {
1155 return Err(ParseErrorKind::TooManyExp);
1156 }
1157 exp_sep = Some(index);
1158 }
1159 (b'p' | b'P', 2 | 8 | 16) => {
1160 if exp_sep.is_some() {
1161 return Err(ParseErrorKind::TooManyExp);
1162 }
1163 exp_sep = Some(index);
1164 exp_is_bit = true;
1165 }
1166 (b'0'..=b'1', 2)
1167 | (b'0'..=b'7', 8)
1168 | (b'0'..=b'9', 10)
1169 | (b'0'..=b'9' | b'a'..=b'f' | b'A'..=b'F', 16)
1170 if exp_sep.is_none() =>
1171 {
1172 if point.is_none() {
1173 has_int_digit = true;
1174 if int_start.is_none() && byte != b'0' {
1175 int_start = Some(index);
1176 }
1177 } else {
1178 has_frac_digit = true;
1179 if byte != b'0' {
1180 frac_end = Some(index + 1);
1181 }
1182 }
1183 }
1184 (b'0'..=b'9', _) if exp_sep.is_some() => {
1185 exp = match exp.checked_mul(10) {
1186 Some(s) => s,
1187 None => {
1188 return Err(ParseErrorKind::ExpOverflow);
1189 }
1190 };
1191 let add = match exp_sign {
1192 Some(true) => -((byte - b'0') as i32),
1193 Some(false) | None => (byte - b'0') as i32,
1194 };
1195 exp = match exp.checked_add(add) {
1196 Some(s) => s,
1197 None => {
1198 return Err(ParseErrorKind::ExpOverflow);
1199 }
1200 };
1201 has_exp_digit = true;
1202 }
1203 _ => {
1204 if exp_sep.is_some() {
1205 return Err(ParseErrorKind::ExpInvalidDigit);
1206 }
1207 return Err(ParseErrorKind::InvalidDigit);
1208 }
1209 }
1210 }
1211 if !has_int_digit && !has_frac_digit {
1212 return Err(ParseErrorKind::NoDigits);
1213 }
1214 if exp_sep.is_some() && !has_exp_digit {
1215 return Err(ParseErrorKind::ExpNoDigits);
1216 }
1217 #[allow(unknown_lints, clippy::manual_unwrap_or_default)]
1219 let neg = match sign {
1220 Some(s) => s,
1221 None => false,
1222 };
1223 let int = match (int_start, point, exp_sep) {
1224 (Some(begin), Some(end), _) | (Some(begin), None, Some(end)) => {
1225 let (up_to_end, _) = bytes.split_at(end);
1226 let (_, from_begin) = up_to_end.split_at(begin);
1227 DigitsUnds::new(from_begin)
1228 }
1229 (Some(begin), None, None) => {
1230 let (_, from_begin) = bytes.split_at(begin);
1231 DigitsUnds::new(from_begin)
1232 }
1233 (None, _, _) => DigitsUnds::EMPTY,
1234 };
1235 let frac = match (point, frac_end) {
1236 (Some(point), Some(end)) => {
1237 let (up_to_end, _) = bytes.split_at(end);
1238 let (_, from_after_point) = up_to_end.split_at(point + 1);
1239 DigitsUnds::new(from_after_point)
1240 }
1241 _ => DigitsUnds::EMPTY,
1242 };
1243 let bit_exp = if exp_is_bit {
1244 match radix {
1245 2 => 0,
1246 8 => {
1247 let (q, r) = (exp.div_euclid(3), exp.rem_euclid(3));
1248 exp = q;
1249 r.unsigned_abs()
1250 }
1251 16 => {
1252 let (q, r) = (exp.div_euclid(4), exp.rem_euclid(4));
1253 exp = q;
1254 r.unsigned_abs()
1255 }
1256 _ => unreachable!(),
1257 }
1258 } else {
1259 0
1260 };
1261 let Some((int, frac)) = DigitsExp::new_int_frac(int, frac, exp) else {
1262 return Err(ParseErrorKind::ExpOverflow);
1263 };
1264 let bit_exp = BitExp::new(bit_exp, frac);
1265 Ok(Parse {
1266 neg,
1267 int,
1268 frac,
1269 bit_exp,
1270 })
1271}
1272
1273const fn frac_is_half(digits: DigitsExp, radix: u32) -> bool {
1274 match digits.split_first() {
1277 Some((digit, rest)) => digit - b'0' == (radix as u8) / 2 && rest.is_empty(),
1278 None => false,
1279 }
1280}
1281
1282macro_rules! impl_from_str {
1283 ($Fixed:ident, $LeEqU:ident) => {
1284 impl<Frac: $LeEqU> FromStr for $Fixed<Frac> {
1285 type Err = ParseFixedError;
1286 #[inline]
1290 fn from_str(s: &str) -> Result<Self, Self::Err> {
1291 Self::from_str(s)
1292 }
1293 }
1294 };
1295}
1296impl_from_str! { FixedI8, LeEqU8 }
1297impl_from_str! { FixedI16, LeEqU16 }
1298impl_from_str! { FixedI32, LeEqU32 }
1299impl_from_str! { FixedI64, LeEqU64 }
1300impl_from_str! { FixedI128, LeEqU128 }
1301impl_from_str! { FixedU8, LeEqU8 }
1302impl_from_str! { FixedU16, LeEqU16 }
1303impl_from_str! { FixedU32, LeEqU32 }
1304impl_from_str! { FixedU64, LeEqU64 }
1305impl_from_str! { FixedU128, LeEqU128 }
1306
1307#[cfg(test)]
1308mod tests {
1309 use crate::bytes::DigitsExp;
1310 use crate::from_str;
1311 use crate::from_str::{Parse, ParseErrorKind, ParseFixedError, Round, Sep, parse_bounds};
1312 use crate::types::*;
1313 use std::format;
1314 #[cfg(not(feature = "std"))]
1315 use std::string::{String, ToString};
1316
1317 #[test]
1318 fn overflowing() {
1319 let overflow = ParseFixedError {
1320 kind: ParseErrorKind::Overflow,
1321 };
1322 assert_eq!(
1323 U4F4::overflowing_from_str("15.5"),
1324 Ok((U4F4::from_bits(0xF8), false))
1325 );
1326 assert_eq!(U4F4::from_str("15.5"), Ok(U4F4::from_bits(0xF8)));
1327 assert_eq!(
1328 U4F4::overflowing_from_str("31.5"),
1329 Ok((U4F4::from_bits(0xF8), true))
1330 );
1331 assert_eq!(U4F4::from_str("31.5"), Err(overflow));
1332 assert_eq!(
1333 U4F4::overflowing_from_str("271.5"),
1334 Ok((U4F4::from_bits(0xF8), true))
1335 );
1336 assert_eq!(
1337 U8F0::overflowing_from_str("271"),
1338 Ok((U8F0::from_bits(0x0F), true))
1339 );
1340 let longer_than_8 = format!("{}", (1 << 30) + 15);
1341 assert_eq!(
1342 U8F0::overflowing_from_str(&longer_than_8),
1343 Ok((U8F0::from_bits(0x0F), true))
1344 );
1345
1346 assert_eq!(
1347 U4F4::overflowing_from_str_binary("1111.1000"),
1348 Ok((U4F4::from_bits(0xF8), false))
1349 );
1350 assert_eq!(
1351 U4F4::from_str_binary("1111.1000"),
1352 Ok(U4F4::from_bits(0xF8))
1353 );
1354 assert_eq!(
1355 U4F4::overflowing_from_str_binary("11111.1000"),
1356 Ok((U4F4::from_bits(0xF8), true))
1357 );
1358 assert_eq!(U4F4::from_str_binary("11111.1000"), Err(overflow));
1359 assert_eq!(
1360 U8F0::overflowing_from_str_binary("100001111"),
1361 Ok((U8F0::from_bits(0x0F), true))
1362 );
1363
1364 assert_eq!(
1365 U4F4::overflowing_from_str_octal("17.7"),
1366 Ok((U4F4::from_bits(0xFE), false))
1367 );
1368 assert_eq!(U4F4::from_str_octal("17.7"), Ok(U4F4::from_bits(0xFE)));
1369 assert_eq!(
1370 U4F4::overflowing_from_str_octal("77.7"),
1371 Ok((U4F4::from_bits(0xFE), true))
1372 );
1373 assert_eq!(U4F4::from_str_octal("77.7"), Err(overflow));
1374 assert_eq!(
1375 U4F4::overflowing_from_str_octal("707.7"),
1376 Ok((U4F4::from_bits(0x7E), true))
1377 );
1378 assert_eq!(
1379 U8F0::overflowing_from_str_octal("1307"),
1380 Ok((U8F0::from_bits(0o307), true))
1381 );
1382
1383 assert_eq!(
1384 U6F10::overflowing_from_str_hex("3F.8"),
1385 Ok((U6F10::from_bits(0xFE00), false))
1386 );
1387 assert_eq!(U6F10::from_str_hex("3F.8"), Ok(U6F10::from_bits(0xFE00)));
1388 assert_eq!(
1389 U6F10::overflowing_from_str_hex("FF.8"),
1390 Ok((U6F10::from_bits(0xFE00), true))
1391 );
1392 assert_eq!(U6F10::from_str_hex("FF.8"), Err(overflow));
1393 assert_eq!(
1394 U6F10::overflowing_from_str_hex("F0F.8"),
1395 Ok((U6F10::from_bits(0x3E00), true))
1396 );
1397 assert_eq!(
1398 U16F0::overflowing_from_str_hex("100FF"),
1399 Ok((U16F0::from_bits(0x00FF), true))
1400 );
1401 }
1402
1403 #[test]
1404 fn check_dec_8() {
1405 let two_pow = 8f64.exp2();
1406 let limit = 1000;
1407 for i in 0..limit {
1408 let ans = from_str::u8::dec_to_bin(i, 8, Round::Nearest);
1409 let approx = two_pow * f64::from(i) / f64::from(limit);
1410 let error = (ans.map_or(two_pow, f64::from) - approx).abs();
1411 assert!(
1412 error <= 0.5,
1413 "i {i} ans {ans:?} approx {approx} error {error}"
1414 );
1415 }
1416 }
1417
1418 #[test]
1419 fn check_dec_16() {
1420 let two_pow = 16f64.exp2();
1421 let limit = 1_000_000;
1422 for i in 0..limit {
1423 let ans = from_str::u16::dec_to_bin(i, 16, Round::Nearest);
1424 let approx = two_pow * f64::from(i) / f64::from(limit);
1425 let error = (ans.map_or(two_pow, f64::from) - approx).abs();
1426 assert!(
1427 error <= 0.5,
1428 "i {i} ans {ans:?} approx {approx} error {error}"
1429 );
1430 }
1431 }
1432
1433 #[test]
1434 fn check_dec_32() {
1435 let two_pow = 32f64.exp2();
1436 let limit = 10_000_000_000_000;
1437 for iter in 0..1_000_000 {
1438 for &i in &[
1439 iter,
1440 limit / 4 - 1 - iter,
1441 limit / 4 + iter,
1442 limit / 3 - 1 - iter,
1443 limit / 3 + iter,
1444 limit / 2 - 1 - iter,
1445 limit / 2 + iter,
1446 limit - iter - 1,
1447 ] {
1448 let ans = from_str::u32::dec_to_bin(i, 32, Round::Nearest);
1449 let approx = two_pow * i as f64 / limit as f64;
1450 let error = (ans.map_or(two_pow, f64::from) - approx).abs();
1451 assert!(
1452 error <= 0.5,
1453 "i {i} ans {ans:?} approx {approx} error {error}"
1454 );
1455 }
1456 }
1457 }
1458
1459 #[test]
1460 fn check_dec_64() {
1461 let two_pow = 64f64.exp2();
1462 let limit = 1_000_000_000_000_000_000_000_000_000;
1463 for iter in 0..200_000 {
1464 for &i in &[
1465 iter,
1466 limit / 4 - 1 - iter,
1467 limit / 4 + iter,
1468 limit / 3 - 1 - iter,
1469 limit / 3 + iter,
1470 limit / 2 - 1 - iter,
1471 limit / 2 + iter,
1472 limit - iter - 1,
1473 ] {
1474 let ans = from_str::u64::dec_to_bin(i, 64, Round::Nearest);
1475 let approx = two_pow * i as f64 / limit as f64;
1476 let error = (ans.map_or(two_pow, |x| x as f64) - approx).abs();
1477 assert!(
1478 error <= 0.5,
1479 "i {i} ans {ans:?} approx {approx} error {error}"
1480 );
1481 }
1482 }
1483 }
1484
1485 #[test]
1486 fn check_dec_128() {
1487 let nines = 10u128.pow(27) - 1;
1488 let zeros = 0;
1489 let too_big = from_str::u128::dec_to_bin((nines, nines), 128, Round::Nearest);
1490 assert_eq!(too_big, None);
1491 let big = from_str::u128::dec_to_bin((nines, zeros), 128, Round::Nearest);
1492 assert_eq!(
1493 big,
1494 Some(340_282_366_920_938_463_463_374_607_091_485_844_535)
1495 );
1496 let small = from_str::u128::dec_to_bin((zeros, nines), 128, Round::Nearest);
1497 assert_eq!(small, Some(340_282_366_921));
1498 let zero = from_str::u128::dec_to_bin((zeros, zeros), 128, Round::Nearest);
1499 assert_eq!(zero, Some(0));
1500 let x = from_str::u128::dec_to_bin(
1501 (
1502 123_456_789_012_345_678_901_234_567,
1503 987_654_321_098_765_432_109_876_543,
1504 ),
1505 128,
1506 Round::Nearest,
1507 );
1508 assert_eq!(x, Some(42_010_168_377_579_896_403_540_037_811_203_677_112));
1509
1510 let eights = 888_888_888_888_888_888_888_888_888;
1511 let narrow = from_str::u128::dec_to_bin((eights, zeros), 40, Round::Nearest);
1512 assert_eq!(narrow, Some(977_343_669_134));
1513 }
1514
1515 fn digits_eq_bytes(mut digits: DigitsExp, bytes: &[u8]) -> bool {
1516 let mut bytes = bytes.iter().copied();
1517 while let Some((digit, rem)) = digits.split_first() {
1518 digits = rem;
1519 match bytes.next() {
1520 Some(byte) => {
1521 if byte != digit {
1522 return false;
1523 }
1524 }
1525 None => return false,
1526 }
1527 }
1528 bytes.next().is_none()
1529 }
1530
1531 #[track_caller]
1532 fn check_parse_bounds_ok(bytes: &str, radix: u32, sep: Sep, check: (bool, &str, &str, u32)) {
1533 let bytes = bytes.as_bytes();
1534 let Parse {
1535 neg,
1536 int,
1537 frac,
1538 bit_exp,
1539 } = parse_bounds(bytes, radix, sep).unwrap();
1540 assert_eq!(neg, check.0);
1541 assert!(digits_eq_bytes(int, check.1.as_bytes()));
1542 assert!(digits_eq_bytes(frac, check.2.as_bytes()));
1543 match bit_exp {
1544 Some(bit_exp) => {
1545 assert_eq!(bit_exp.exp.get(), check.3);
1546 assert_eq!(
1547 bit_exp.first_frac_digit,
1548 frac.split_first().map_or(b'0', |x| x.0)
1549 );
1550 }
1551 None => assert_eq!(0, check.3),
1552 }
1553 }
1554
1555 #[track_caller]
1556 fn check_parse_bounds_err(bytes: &str, radix: u32, sep: Sep, check: ParseErrorKind) {
1557 let bytes = bytes.as_bytes();
1558 let kind = parse_bounds(bytes, radix, sep).unwrap_err();
1559 assert_eq!(kind, check);
1560 }
1561
1562 #[test]
1563 fn check_parse_bounds() {
1564 let sep = Sep::Error;
1565
1566 check_parse_bounds_ok("-12.34", 10, sep, (true, "12", "34", 0));
1567 check_parse_bounds_ok("012.", 10, sep, (false, "12", "", 0));
1568 check_parse_bounds_ok("+.340", 10, sep, (false, "", "34", 0));
1569 check_parse_bounds_ok("0", 10, sep, (false, "", "", 0));
1570 check_parse_bounds_ok("-.C1A0", 16, sep, (true, "", "C1A", 0));
1571 check_parse_bounds_ok("-.C1A0@1", 16, sep, (true, "C", "1A", 0));
1572 check_parse_bounds_ok("-.C1A0@+1", 16, sep, (true, "C", "1A", 0));
1573 check_parse_bounds_ok("-.C1A0@-1", 16, sep, (true, "", "0C1A", 0));
1574 check_parse_bounds_ok("-C1A0@-2", 16, sep, (true, "C1", "A", 0));
1575 check_parse_bounds_ok("-.C1A0p5", 16, sep, (true, "C", "1A", 1));
1576 check_parse_bounds_ok("-C1A0P-2", 16, sep, (true, "C1A", "", 2));
1577
1578 check_parse_bounds_err("0 ", 10, sep, ParseErrorKind::InvalidDigit);
1579 check_parse_bounds_err("+-", 10, sep, ParseErrorKind::MisplacedSign);
1580 check_parse_bounds_err("1+2", 10, sep, ParseErrorKind::MisplacedSign);
1581 check_parse_bounds_err("1-2", 10, sep, ParseErrorKind::MisplacedSign);
1582 check_parse_bounds_err("+.", 10, sep, ParseErrorKind::NoDigits);
1583 check_parse_bounds_err(".1.", 10, sep, ParseErrorKind::TooManyPoints);
1584 check_parse_bounds_err("C1A0@2F", 16, sep, ParseErrorKind::ExpInvalidDigit);
1585 check_parse_bounds_err("12.34E", 10, sep, ParseErrorKind::ExpNoDigits);
1586 check_parse_bounds_err("C1A0@1P1", 16, sep, ParseErrorKind::TooManyExp);
1587 check_parse_bounds_err("1E3000000000", 10, sep, ParseErrorKind::ExpOverflow);
1588
1589 check_parse_bounds_err("-_12.34", 10, sep, ParseErrorKind::InvalidDigit);
1590 check_parse_bounds_err("-1_2.34", 10, sep, ParseErrorKind::InvalidDigit);
1591 check_parse_bounds_err("-12_.34", 10, sep, ParseErrorKind::InvalidDigit);
1592 check_parse_bounds_err("-12._34", 10, sep, ParseErrorKind::InvalidDigit);
1593 check_parse_bounds_err("-12.3_4", 10, sep, ParseErrorKind::InvalidDigit);
1594 check_parse_bounds_err("-123E4_", 10, sep, ParseErrorKind::ExpInvalidDigit);
1595 check_parse_bounds_err("-12.34_", 10, sep, ParseErrorKind::InvalidDigit);
1596 check_parse_bounds_err(
1597 "-0_1__2___.3____4_____0",
1598 10,
1599 sep,
1600 ParseErrorKind::InvalidDigit,
1601 );
1602 check_parse_bounds_err("-1_2__.3_4__e+0___5", 10, sep, ParseErrorKind::InvalidDigit);
1603 check_parse_bounds_err("-1_2__.3_4__E-0___5", 10, sep, ParseErrorKind::InvalidDigit);
1604 }
1605
1606 #[test]
1607 fn check_parse_bounds_underscore() {
1608 let sep = Sep::Skip;
1609
1610 check_parse_bounds_ok("-12.34", 10, sep, (true, "12", "34", 0));
1611 check_parse_bounds_ok("012.", 10, sep, (false, "12", "", 0));
1612 check_parse_bounds_ok("+.340", 10, sep, (false, "", "34", 0));
1613 check_parse_bounds_ok("0", 10, sep, (false, "", "", 0));
1614 check_parse_bounds_ok("-.C1A0", 16, sep, (true, "", "C1A", 0));
1615 check_parse_bounds_ok("-.C1A0@1", 16, sep, (true, "C", "1A", 0));
1616 check_parse_bounds_ok("-.C1A0@+1", 16, sep, (true, "C", "1A", 0));
1617 check_parse_bounds_ok("-.C1A0@-1", 16, sep, (true, "", "0C1A", 0));
1618 check_parse_bounds_ok("-C1A0@-2", 16, sep, (true, "C1", "A", 0));
1619 check_parse_bounds_ok("-.C1A0p5", 16, sep, (true, "C", "1A", 1));
1620 check_parse_bounds_ok("-C1A0P-2", 16, sep, (true, "C1A", "", 2));
1621
1622 check_parse_bounds_err("0 ", 10, sep, ParseErrorKind::InvalidDigit);
1623 check_parse_bounds_err("+-", 10, sep, ParseErrorKind::MisplacedSign);
1624 check_parse_bounds_err("1+2", 10, sep, ParseErrorKind::MisplacedSign);
1625 check_parse_bounds_err("1-2", 10, sep, ParseErrorKind::MisplacedSign);
1626 check_parse_bounds_err("+.", 10, sep, ParseErrorKind::NoDigits);
1627 check_parse_bounds_err(".1.", 10, sep, ParseErrorKind::TooManyPoints);
1628 check_parse_bounds_err("C1A0@2F", 16, sep, ParseErrorKind::ExpInvalidDigit);
1629 check_parse_bounds_err("12.34E", 10, sep, ParseErrorKind::ExpNoDigits);
1630 check_parse_bounds_err("C1A0@1P1", 16, sep, ParseErrorKind::TooManyExp);
1631 check_parse_bounds_err("1E3000000000", 10, sep, ParseErrorKind::ExpOverflow);
1632
1633 check_parse_bounds_err("-_12.34", 10, sep, ParseErrorKind::MisplacedUnderscore);
1634 check_parse_bounds_ok("-1_2.34", 10, sep, (true, "12", "34", 0));
1635 check_parse_bounds_ok("-12_.34", 10, sep, (true, "12", "34", 0));
1636 check_parse_bounds_err("-12._34", 10, sep, ParseErrorKind::MisplacedUnderscore);
1637 check_parse_bounds_ok("-12.3_4", 10, sep, (true, "12", "34", 0));
1638 check_parse_bounds_ok("-12.34_", 10, sep, (true, "12", "34", 0));
1639 check_parse_bounds_ok("-123E4_", 10, sep, (true, "1230000", "", 0));
1640 check_parse_bounds_ok("-0_1__2___.3____4_____0", 10, sep, (true, "12", "34", 0));
1641 check_parse_bounds_ok("-1_2__.3_4__e+0___5", 10, sep, (true, "1234000", "", 0));
1642 check_parse_bounds_ok("-1_2__.3_4__E-0___5", 10, sep, (true, "", "0001234", 0));
1643 }
1644
1645 macro_rules! assert_ok {
1646 ($T:ty, $str:expr, $radix:expr, $bits:expr, $overflow:expr) => {
1647 let m = match $radix {
1648 2 => <$T>::overflowing_from_str_binary($str),
1649 8 => <$T>::overflowing_from_str_octal($str),
1650 10 => <$T>::overflowing_from_str($str),
1651 16 => <$T>::overflowing_from_str_hex($str),
1652 _ => unreachable!(),
1653 };
1654 match m {
1655 Ok((f, o)) => {
1656 assert_eq!(f.to_bits(), $bits, "{} -> ({f}, {o})", $str);
1657 assert_eq!(o, $overflow, "{} -> ({f}, {o})", $str);
1658 }
1659 Err(e) => panic!("could not parse {}: {e}", $str),
1660 }
1661 };
1662 }
1663
1664 #[test]
1665 fn check_i8_u8_from_str() {
1666 assert_ok!(I0F8, "-1", 10, 0x00, true);
1667 assert_ok!(I0F8, "-0.502", 10, 0x7F, true);
1668 assert_ok!(I0F8, "-0.501", 10, -0x80, false);
1669 assert_ok!(I0F8, "0.498", 10, 0x7F, false);
1670 assert_ok!(I0F8, "0.499", 10, -0x80, true);
1671 assert_ok!(I0F8, "1", 10, 0x00, true);
1672
1673 assert_ok!(I4F4, "-8.04", 10, 0x7F, true);
1674 assert_ok!(I4F4, "-8.03", 10, -0x80, false);
1675 assert_ok!(I4F4, "7.96", 10, 0x7F, false);
1676 assert_ok!(I4F4, "7.97", 10, -0x80, true);
1677
1678 assert_ok!(I8F0, "-128.501", 10, 0x7F, true);
1679 assert_ok!(I8F0, "-128.5", 10, -0x80, false);
1681 assert_ok!(I8F0, "127.499", 10, 0x7F, false);
1682 assert_ok!(I8F0, "127.5", 10, -0x80, true);
1684
1685 assert_ok!(U0F8, "-0", 10, 0x00, false);
1686 assert_ok!(U0F8, "0.498", 10, 0x7F, false);
1687 assert_ok!(U0F8, "0.499", 10, 0x80, false);
1688 assert_ok!(U0F8, "0.998", 10, 0xFF, false);
1689 assert_ok!(U0F8, "0.999", 10, 0x00, true);
1690 assert_ok!(U0F8, "1", 10, 0x00, true);
1691
1692 assert_ok!(U4F4, "7.96", 10, 0x7F, false);
1693 assert_ok!(U4F4, "7.97", 10, 0x80, false);
1694 assert_ok!(U4F4, "15.96", 10, 0xFF, false);
1695 assert_ok!(U4F4, "15.97", 10, 0x00, true);
1696
1697 assert_ok!(U8F0, "127.499", 10, 0x7F, false);
1698 assert_ok!(U8F0, "127.5", 10, 0x80, false);
1700 assert_ok!(U8F0, "255.499", 10, 0xFF, false);
1701 assert_ok!(U8F0, "255.5", 10, 0x00, true);
1703 }
1704
1705 #[test]
1706 fn check_i16_u16_from_str() {
1707 assert_ok!(I0F16, "-1", 10, 0x00, true);
1708 assert_ok!(I0F16, "-0.500008", 10, 0x7FFF, true);
1709 assert_ok!(I0F16, "-0.500007", 10, -0x8000, false);
1710 assert_ok!(I0F16, "+0.499992", 10, 0x7FFF, false);
1711 assert_ok!(I0F16, "+0.499993", 10, -0x8000, true);
1712 assert_ok!(I0F16, "1", 10, 0x0000, true);
1713
1714 assert_ok!(I8F8, "-128.002", 10, 0x7FFF, true);
1715 assert_ok!(I8F8, "-128.001", 10, -0x8000, false);
1716 assert_ok!(I8F8, "+127.998", 10, 0x7FFF, false);
1717 assert_ok!(I8F8, "+127.999", 10, -0x8000, true);
1718
1719 assert_ok!(I16F0, "-32768.500001", 10, 0x7FFF, true);
1720 assert_ok!(I16F0, "-32768.5", 10, -0x8000, false);
1722 assert_ok!(I16F0, "+32767.499999", 10, 0x7FFF, false);
1723 assert_ok!(I16F0, "+32767.5", 10, -0x8000, true);
1725
1726 assert_ok!(U0F16, "-0", 10, 0x0000, false);
1727 assert_ok!(U0F16, "0.499992", 10, 0x7FFF, false);
1728 assert_ok!(U0F16, "0.499993", 10, 0x8000, false);
1729 assert_ok!(U0F16, "0.999992", 10, 0xFFFF, false);
1730 assert_ok!(U0F16, "0.999993", 10, 0x0000, true);
1731 assert_ok!(U0F16, "1", 10, 0x0000, true);
1732
1733 assert_ok!(U8F8, "127.998", 10, 0x7FFF, false);
1734 assert_ok!(U8F8, "127.999", 10, 0x8000, false);
1735 assert_ok!(U8F8, "255.998", 10, 0xFFFF, false);
1736 assert_ok!(U8F8, "255.999", 10, 0x0000, true);
1737
1738 assert_ok!(U16F0, "32767.499999", 10, 0x7FFF, false);
1739 assert_ok!(U16F0, "32767.5", 10, 0x8000, false);
1741 assert_ok!(U16F0, "65535.499999", 10, 0xFFFF, false);
1742 assert_ok!(U16F0, "65535.5", 10, 0x0000, true);
1744 }
1745
1746 #[test]
1747 fn check_i32_u32_from_str() {
1748 assert_ok!(I0F32, "-1", 10, 0x0000_0000, true);
1749 assert_ok!(I0F32, "-0.5000000002", 10, 0x7FFF_FFFF, true);
1750 assert_ok!(I0F32, "-0.5000000001", 10, -0x8000_0000, false);
1751 assert_ok!(I0F32, "0.4999999998", 10, 0x7FFF_FFFF, false);
1752 assert_ok!(I0F32, "0.4999999999", 10, -0x8000_0000, true);
1753 assert_ok!(I0F32, "1", 10, 0x0000_0000, true);
1754
1755 assert_ok!(I16F16, "-32768.000008", 10, 0x7FFF_FFFF, true);
1756 assert_ok!(I16F16, "-32768.000007", 10, -0x8000_0000, false);
1757 assert_ok!(I16F16, "32767.999992", 10, 0x7FFF_FFFF, false);
1758 assert_ok!(I16F16, "32767.999993", 10, -0x8000_0000, true);
1759
1760 assert_ok!(I32F0, "-2147483648.5000000001", 10, 0x7FFF_FFFF, true);
1761 assert_ok!(I32F0, "-2147483648.5", 10, -0x8000_0000, false);
1763 assert_ok!(I32F0, "2147483647.4999999999", 10, 0x7FFF_FFFF, false);
1764 assert_ok!(I32F0, "2147483647.5", 10, -0x8000_0000, true);
1766
1767 assert_ok!(U0F32, "-0", 10, 0x0000_0000, false);
1768 assert_ok!(U0F32, "0.4999999998", 10, 0x7FFF_FFFF, false);
1769 assert_ok!(U0F32, "0.4999999999", 10, 0x8000_0000, false);
1770 assert_ok!(U0F32, "0.9999999998", 10, 0xFFFF_FFFF, false);
1771 assert_ok!(U0F32, "0.9999999999", 10, 0x0000_0000, true);
1772 assert_ok!(U0F32, "1", 10, 0x0000_0000, true);
1773
1774 assert_ok!(U16F16, "32767.999992", 10, 0x7FFF_FFFF, false);
1775 assert_ok!(U16F16, "32767.999993", 10, 0x8000_0000, false);
1776 assert_ok!(U16F16, "65535.999992", 10, 0xFFFF_FFFF, false);
1777 assert_ok!(U16F16, "65535.999993", 10, 0x0000_0000, true);
1778
1779 assert_ok!(U32F0, "2147483647.4999999999", 10, 0x7FFF_FFFF, false);
1780 assert_ok!(U32F0, "2147483647.5", 10, 0x8000_0000, false);
1782 assert_ok!(U32F0, "4294967295.4999999999", 10, 0xFFFF_FFFF, false);
1783 assert_ok!(U32F0, "4294967295.5", 10, 0x0000_0000, true);
1785 }
1786
1787 #[test]
1788 fn check_i64_u64_from_str() {
1789 assert_ok!(I0F64, "-1", 10, 0x0000_0000_0000_0000, true);
1790 assert_ok!(
1791 I0F64,
1792 "-0.50000000000000000003",
1793 10,
1794 0x7FFF_FFFF_FFFF_FFFF,
1795 true
1796 );
1797 assert_ok!(
1798 I0F64,
1799 "-0.50000000000000000002",
1800 10,
1801 -0x8000_0000_0000_0000,
1802 false
1803 );
1804 assert_ok!(
1805 I0F64,
1806 "+0.49999999999999999997",
1807 10,
1808 0x7FFF_FFFF_FFFF_FFFF,
1809 false
1810 );
1811 assert_ok!(
1812 I0F64,
1813 "+0.49999999999999999998",
1814 10,
1815 -0x8000_0000_0000_0000,
1816 true
1817 );
1818 assert_ok!(I0F64, "1", 10, 0x0000_0000_0000_0000, true);
1819
1820 assert_ok!(
1821 I32F32,
1822 "-2147483648.0000000002",
1823 10,
1824 0x7FFF_FFFF_FFFF_FFFF,
1825 true
1826 );
1827 assert_ok!(
1828 I32F32,
1829 "-2147483648.0000000001",
1830 10,
1831 -0x8000_0000_0000_0000,
1832 false
1833 );
1834 assert_ok!(
1835 I32F32,
1836 "2147483647.9999999998",
1837 10,
1838 0x7FFF_FFFF_FFFF_FFFF,
1839 false
1840 );
1841 assert_ok!(
1842 I32F32,
1843 "2147483647.9999999999",
1844 10,
1845 -0x8000_0000_0000_0000,
1846 true
1847 );
1848
1849 assert_ok!(
1850 I64F0,
1851 "-9223372036854775808.50000000000000000001",
1852 10,
1853 0x7FFF_FFFF_FFFF_FFFF,
1854 true
1855 );
1856 assert_ok!(
1858 I64F0,
1859 "-9223372036854775808.5",
1860 10,
1861 -0x8000_0000_0000_0000,
1862 false
1863 );
1864 assert_ok!(
1865 I64F0,
1866 "9223372036854775807.49999999999999999999",
1867 10,
1868 0x7FFF_FFFF_FFFF_FFFF,
1869 false
1870 );
1871 assert_ok!(
1873 I64F0,
1874 "9223372036854775807.5",
1875 10,
1876 -0x8000_0000_0000_0000,
1877 true
1878 );
1879
1880 assert_ok!(U0F64, "-0", 10, 0x0000_0000_0000_0000, false);
1881 assert_ok!(
1882 U0F64,
1883 "0.49999999999999999997",
1884 10,
1885 0x7FFF_FFFF_FFFF_FFFF,
1886 false
1887 );
1888 assert_ok!(
1889 U0F64,
1890 "0.49999999999999999998",
1891 10,
1892 0x8000_0000_0000_0000,
1893 false
1894 );
1895 assert_ok!(
1896 U0F64,
1897 "0.99999999999999999997",
1898 10,
1899 0xFFFF_FFFF_FFFF_FFFF,
1900 false
1901 );
1902 assert_ok!(
1903 U0F64,
1904 "0.99999999999999999998",
1905 10,
1906 0x0000_0000_0000_0000,
1907 true
1908 );
1909 assert_ok!(U0F64, "1", 10, 0x0000_0000_0000_0000, true);
1910
1911 assert_ok!(
1912 U32F32,
1913 "2147483647.9999999998",
1914 10,
1915 0x7FFF_FFFF_FFFF_FFFF,
1916 false
1917 );
1918 assert_ok!(
1919 U32F32,
1920 "2147483647.9999999999",
1921 10,
1922 0x8000_0000_0000_0000,
1923 false
1924 );
1925 assert_ok!(
1926 U32F32,
1927 "4294967295.9999999998",
1928 10,
1929 0xFFFF_FFFF_FFFF_FFFF,
1930 false
1931 );
1932 assert_ok!(
1933 U32F32,
1934 "4294967295.9999999999",
1935 10,
1936 0x0000_0000_0000_0000,
1937 true
1938 );
1939
1940 assert_ok!(
1941 U64F0,
1942 "9223372036854775807.49999999999999999999",
1943 10,
1944 0x7FFF_FFFF_FFFF_FFFF,
1945 false
1946 );
1947 assert_ok!(
1949 U64F0,
1950 "9223372036854775807.5",
1951 10,
1952 0x8000_0000_0000_0000,
1953 false
1954 );
1955 assert_ok!(
1956 U64F0,
1957 "18446744073709551615.49999999999999999999",
1958 10,
1959 0xFFFF_FFFF_FFFF_FFFF,
1960 false
1961 );
1962 assert_ok!(
1964 U64F0,
1965 "18446744073709551615.5",
1966 10,
1967 0x0000_0000_0000_0000,
1968 true
1969 );
1970 }
1971
1972 #[test]
1973 fn check_i128_u128_from_str() {
1974 assert_ok!(
1975 I0F128,
1976 "-1",
1977 10,
1978 0x0000_0000_0000_0000_0000_0000_0000_0000,
1979 true
1980 );
1981 assert_ok!(
1982 I0F128,
1983 "-0.500000000000000000000000000000000000002",
1984 10,
1985 0x7FFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF,
1986 true
1987 );
1988 assert_ok!(
1989 I0F128,
1990 "-0.500000000000000000000000000000000000001",
1991 10,
1992 -0x8000_0000_0000_0000_0000_0000_0000_0000,
1993 false
1994 );
1995 assert_ok!(
1996 I0F128,
1997 "0.499999999999999999999999999999999999998",
1998 10,
1999 0x7FFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF,
2000 false
2001 );
2002 assert_ok!(
2003 I0F128,
2004 "0.499999999999999999999999999999999999999",
2005 10,
2006 -0x8000_0000_0000_0000_0000_0000_0000_0000,
2007 true
2008 );
2009 assert_ok!(
2010 I0F128,
2011 "1",
2012 10,
2013 0x0000_0000_0000_0000_0000_0000_0000_0000,
2014 true
2015 );
2016
2017 assert_ok!(
2018 I64F64,
2019 "-9223372036854775808.00000000000000000003",
2020 10,
2021 0x7FFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF,
2022 true
2023 );
2024 assert_ok!(
2025 I64F64,
2026 "-9223372036854775808.00000000000000000002",
2027 10,
2028 -0x8000_0000_0000_0000_0000_0000_0000_0000,
2029 false
2030 );
2031 assert_ok!(
2032 I64F64,
2033 "9223372036854775807.99999999999999999997",
2034 10,
2035 0x7FFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF,
2036 false
2037 );
2038 assert_ok!(
2039 I64F64,
2040 "9223372036854775807.99999999999999999998",
2041 10,
2042 -0x8000_0000_0000_0000_0000_0000_0000_0000,
2043 true
2044 );
2045
2046 assert_ok!(
2047 I128F0,
2048 "-170141183460469231731687303715884105728.5000000000000000000000000000000000000001",
2049 10,
2050 0x7FFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF,
2051 true
2052 );
2053 assert_ok!(
2055 I128F0,
2056 "-170141183460469231731687303715884105728.5",
2057 10,
2058 -0x8000_0000_0000_0000_0000_0000_0000_0000,
2059 false
2060 );
2061 assert_ok!(
2062 I128F0,
2063 "170141183460469231731687303715884105727.4999999999999999999999999999999999999999",
2064 10,
2065 0x7FFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF,
2066 false
2067 );
2068 assert_ok!(
2070 I128F0,
2071 "170141183460469231731687303715884105727.5",
2072 10,
2073 -0x8000_0000_0000_0000_0000_0000_0000_0000,
2074 true
2075 );
2076
2077 assert_ok!(
2078 U0F128,
2079 "-0",
2080 10,
2081 0x0000_0000_0000_0000_0000_0000_0000_0000,
2082 false
2083 );
2084 assert_ok!(
2085 U0F128,
2086 "0.499999999999999999999999999999999999998",
2087 10,
2088 0x7FFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF,
2089 false
2090 );
2091 assert_ok!(
2092 U0F128,
2093 "0.499999999999999999999999999999999999999",
2094 10,
2095 0x8000_0000_0000_0000_0000_0000_0000_0000,
2096 false
2097 );
2098 assert_ok!(
2099 U0F128,
2100 "0.999999999999999999999999999999999999998",
2101 10,
2102 0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF,
2103 false
2104 );
2105 assert_ok!(
2106 U0F128,
2107 "0.999999999999999999999999999999999999999",
2108 10,
2109 0x0000_0000_0000_0000_0000_0000_0000_0000,
2110 true
2111 );
2112 assert_ok!(
2113 U0F128,
2114 "1",
2115 10,
2116 0x0000_0000_0000_0000_0000_0000_0000_0000,
2117 true
2118 );
2119
2120 assert_ok!(
2121 U64F64,
2122 "9223372036854775807.99999999999999999997",
2123 10,
2124 0x7FFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF,
2125 false
2126 );
2127 assert_ok!(
2128 U64F64,
2129 "9223372036854775807.99999999999999999998",
2130 10,
2131 0x8000_0000_0000_0000_0000_0000_0000_0000,
2132 false
2133 );
2134 assert_ok!(
2135 U64F64,
2136 "18446744073709551615.99999999999999999997",
2137 10,
2138 0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF,
2139 false
2140 );
2141 assert_ok!(
2142 U64F64,
2143 "18446744073709551615.99999999999999999998",
2144 10,
2145 0x0000_0000_0000_0000_0000_0000_0000_0000,
2146 true
2147 );
2148
2149 assert_ok!(
2150 U128F0,
2151 "170141183460469231731687303715884105727.4999999999999999999999999999999999999999",
2152 10,
2153 0x7FFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF,
2154 false
2155 );
2156 assert_ok!(
2158 U128F0,
2159 "170141183460469231731687303715884105727.5",
2160 10,
2161 0x8000_0000_0000_0000_0000_0000_0000_0000,
2162 false
2163 );
2164 assert_ok!(
2165 U128F0,
2166 "340282366920938463463374607431768211455.4999999999999999999999999999999999999999",
2167 10,
2168 0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF,
2169 false
2170 );
2171 assert_ok!(
2173 U128F0,
2174 "340282366920938463463374607431768211455.5",
2175 10,
2176 0x0000_0000_0000_0000_0000_0000_0000_0000,
2177 true
2178 );
2179 }
2180
2181 #[test]
2182 fn check_i16_u16_from_str_binary() {
2183 assert_ok!(I0F16, "-1", 2, 0x0000, true);
2184 assert_ok!(I0F16, "-0.100000000000000011", 2, 0x7FFF, true);
2185 assert_ok!(I0F16, "-0.100000000000000010", 2, -0x8000, false);
2186 assert_ok!(I0F16, "-0.011111111111111110", 2, -0x8000, false);
2187 assert_ok!(I0F16, "+0.011111111111111101", 2, 0x7FFF, false);
2188 assert_ok!(I0F16, "+0.011111111111111110", 2, -0x8000, true);
2189 assert_ok!(I0F16, "1", 2, 0x0000, true);
2190
2191 assert_ok!(I8F8, "-10000000.0000000011", 2, 0x7FFF, true);
2192 assert_ok!(I8F8, "-10000000.0000000010", 2, -0x8000, false);
2193 assert_ok!(I8F8, "-01111111.1111111110", 2, -0x8000, false);
2194 assert_ok!(I8F8, "+01111111.1111111101", 2, 0x7FFF, false);
2195 assert_ok!(I8F8, "+01111111.1111111110", 2, -0x8000, true);
2196
2197 assert_ok!(I16F0, "-1000000000000000.11", 2, 0x7FFF, true);
2198 assert_ok!(I16F0, "-1000000000000000.10", 2, -0x8000, false);
2199 assert_ok!(I16F0, "-0111111111111111.10", 2, -0x8000, false);
2200 assert_ok!(I16F0, "+0111111111111111.01", 2, 0x7FFF, false);
2201 assert_ok!(I16F0, "+0111111111111111.10", 2, -0x8000, true);
2202
2203 assert_ok!(U0F16, "-0", 2, 0x0000, false);
2204 assert_ok!(U0F16, "0.011111111111111101", 2, 0x7FFF, false);
2205 assert_ok!(U0F16, "0.011111111111111110", 2, 0x8000, false);
2206 assert_ok!(U0F16, "0.111111111111111101", 2, 0xFFFF, false);
2207 assert_ok!(U0F16, "0.111111111111111110", 2, 0x0000, true);
2208 assert_ok!(U0F16, "1", 2, 0x0000, true);
2209
2210 assert_ok!(U8F8, "01111111.1111111101", 2, 0x7FFF, false);
2211 assert_ok!(U8F8, "01111111.1111111110", 2, 0x8000, false);
2212 assert_ok!(U8F8, "11111111.1111111101", 2, 0xFFFF, false);
2213 assert_ok!(U8F8, "11111111.1111111110", 2, 0x0000, true);
2214
2215 assert_ok!(U16F0, "0111111111111111.01", 2, 0x7FFF, false);
2216 assert_ok!(U16F0, "0111111111111111.10", 2, 0x8000, false);
2217 assert_ok!(U16F0, "1111111111111111.01", 2, 0xFFFF, false);
2218 assert_ok!(U16F0, "1111111111111111.10", 2, 0x0000, true);
2219
2220 assert_ok!(U0F16, "00111.11111111111101e-4", 2, 0x7FFF, false);
2221 assert_ok!(U16F0, "011111111111.111101e4", 2, 0x7FFF, false);
2222 assert_ok!(U8F8, "011.110P3", 2, 0x1E00, false);
2223 assert_ok!(U8F8, "011.110P-3", 2, 0x0078, false);
2224 }
2225
2226 #[test]
2227 fn check_i16_u16_from_str_octal() {
2228 assert_ok!(I0F16, "-1", 8, 0x0000, true);
2229 assert_ok!(I0F16, "-0.400003", 8, 0x7FFF, true);
2230 assert_ok!(I0F16, "-0.400002", 8, -0x8000, false);
2231 assert_ok!(I0F16, "-0.377776", 8, -0x8000, false);
2232 assert_ok!(I0F16, "+0.377775", 8, 0x7FFF, false);
2233 assert_ok!(I0F16, "+0.377776", 8, -0x8000, true);
2234 assert_ok!(I0F16, "1", 8, 0x0000, true);
2235
2236 assert_ok!(I8F8, "-200.0011", 8, 0x7FFF, true);
2237 assert_ok!(I8F8, "-200.0010", 8, -0x8000, false);
2238 assert_ok!(I8F8, "-177.7770", 8, -0x8000, false);
2239 assert_ok!(I8F8, "+177.7767", 8, 0x7FFF, false);
2240 assert_ok!(I8F8, "+177.7770", 8, -0x8000, true);
2241
2242 assert_ok!(I16F0, "-100000.5", 8, 0x7FFF, true);
2243 assert_ok!(I16F0, "-100000.4", 8, -0x8000, false);
2244 assert_ok!(I16F0, "-077777.4", 8, -0x8000, false);
2245 assert_ok!(I16F0, "+077777.3", 8, 0x7FFF, false);
2246 assert_ok!(I16F0, "+077777.4", 8, -0x8000, true);
2247
2248 assert_ok!(U0F16, "-0", 8, 0x0000, false);
2249 assert_ok!(U0F16, "0.377775", 8, 0x7FFF, false);
2250 assert_ok!(U0F16, "0.377776", 8, 0x8000, false);
2251 assert_ok!(U0F16, "0.777775", 8, 0xFFFF, false);
2252 assert_ok!(U0F16, "0.777776", 8, 0x0000, true);
2253 assert_ok!(U0F16, "1", 8, 0x0000, true);
2254
2255 assert_ok!(U8F8, "177.7767", 8, 0x7FFF, false);
2256 assert_ok!(U8F8, "177.7770", 8, 0x8000, false);
2257 assert_ok!(U8F8, "377.7767", 8, 0xFFFF, false);
2258 assert_ok!(U8F8, "377.7770", 8, 0x0000, true);
2259
2260 assert_ok!(U16F0, "077777.3", 8, 0x7FFF, false);
2261 assert_ok!(U16F0, "077777.4", 8, 0x8000, false);
2262 assert_ok!(U16F0, "177777.3", 8, 0xFFFF, false);
2263 assert_ok!(U16F0, "177777.4", 8, 0x0000, true);
2264
2265 assert_ok!(U0F16, "037.7775e-2", 8, 0x7FFF, false);
2266 assert_ok!(U16F0, "0777.773e2", 8, 0x7FFF, false);
2267 assert_ok!(U8F8, "037.450P4", 8, 0xF940, true);
2268 assert_ok!(U8F8, "037.450P3", 8, 0xFCA0, false);
2269 assert_ok!(U8F8, "037.450P2", 8, 0x7E50, false);
2270 assert_ok!(U8F8, "037.450P1", 8, 0x3F28, false);
2271 assert_ok!(U8F8, "037.450P0", 8, 0x1F94, false);
2272 assert_ok!(U8F8, "037.450P-1", 8, 0x0FCA, false);
2273 assert_ok!(U8F8, "037.450P-2", 8, 0x07E5, false);
2274 assert_ok!(U8F8, "037.450P-3", 8, 0x03F2, false);
2275 assert_ok!(U8F8, "037.450P-4", 8, 0x01F9, false);
2276 }
2277
2278 #[test]
2279 fn check_i16_u16_from_str_hex() {
2280 assert_ok!(I0F16, "-1", 16, 0x0000, true);
2281 assert_ok!(I0F16, "-0.80009", 16, 0x7FFF, true);
2282 assert_ok!(I0F16, "-0.80008", 16, -0x8000, false);
2283 assert_ok!(I0F16, "-0.7FFF8", 16, -0x8000, false);
2284 assert_ok!(I0F16, "+0.7FFF7", 16, 0x7FFF, false);
2285 assert_ok!(I0F16, "+0.7FFF8", 16, -0x8000, true);
2286 assert_ok!(I0F16, "1", 16, 0x0000, true);
2287
2288 assert_ok!(I8F8, "-80.009", 16, 0x7FFF, true);
2289 assert_ok!(I8F8, "-80.008", 16, -0x8000, false);
2290 assert_ok!(I8F8, "-7F.FF8", 16, -0x8000, false);
2291 assert_ok!(I8F8, "+7F.FF7", 16, 0x7FFF, false);
2292 assert_ok!(I8F8, "+7F.FF8", 16, -0x8000, true);
2293
2294 assert_ok!(I16F0, "-8000.9", 16, 0x7FFF, true);
2295 assert_ok!(I16F0, "-8000.8", 16, -0x8000, false);
2296 assert_ok!(I16F0, "-7FFF.8", 16, -0x8000, false);
2297 assert_ok!(I16F0, "+7FFF.7", 16, 0x7FFF, false);
2298 assert_ok!(I16F0, "+7FFF.8", 16, -0x8000, true);
2299
2300 assert_ok!(U0F16, "-0", 16, 0x0000, false);
2301 assert_ok!(U0F16, "0.7FFF7", 16, 0x7FFF, false);
2302 assert_ok!(U0F16, "0.7FFF8", 16, 0x8000, false);
2303 assert_ok!(U0F16, "0.FFFF7", 16, 0xFFFF, false);
2304 assert_ok!(U0F16, "0.FFFF8", 16, 0x0000, true);
2305 assert_ok!(U0F16, "1", 16, 0x0000, true);
2306
2307 assert_ok!(U8F8, "7F.FF7", 16, 0x7FFF, false);
2308 assert_ok!(U8F8, "7F.FF8", 16, 0x8000, false);
2309 assert_ok!(U8F8, "FF.FF7", 16, 0xFFFF, false);
2310 assert_ok!(U8F8, "FF.FF8", 16, 0x0000, true);
2311
2312 assert_ok!(U16F0, "7FFF.7", 16, 0x7FFF, false);
2313 assert_ok!(U16F0, "7FFF.8", 16, 0x8000, false);
2314 assert_ok!(U16F0, "FFFF.7", 16, 0xFFFF, false);
2315 assert_ok!(U16F0, "FFFF.8", 16, 0x0000, true);
2316
2317 assert_ok!(U0F16, "07F.FF7@-2", 16, 0x7FFF, false);
2318 assert_ok!(U16F0, "7F.FF7@2", 16, 0x7FFF, false);
2319 assert_ok!(U8F8, "13.B8P4", 16, 0x3B80, true);
2320 assert_ok!(U8F8, "13.B8P3", 16, 0x9DC0, false);
2321 assert_ok!(U8F8, "13.B8P2", 16, 0x4EE0, false);
2322 assert_ok!(U8F8, "13.B8P1", 16, 0x2770, false);
2323 assert_ok!(U8F8, "13.B8P0", 16, 0x13B8, false);
2324 assert_ok!(U8F8, "13.B8P-1", 16, 0x09DC, false);
2325 assert_ok!(U8F8, "13.B8P-2", 16, 0x04EE, false);
2326 assert_ok!(U8F8, "13.B8P-3", 16, 0x0277, false);
2327 assert_ok!(U8F8, "13.B8P-4", 16, 0x013C, false);
2328 }
2329
2330 #[test]
2331 fn check_i128_u128_from_str_hex() {
2332 assert_ok!(
2333 I0F128,
2334 "-1",
2335 16,
2336 0x0000_0000_0000_0000_0000_0000_0000_0000,
2337 true
2338 );
2339 assert_ok!(
2340 I0F128,
2341 "-0.800000000000000000000000000000009",
2342 16,
2343 0x7FFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF,
2344 true
2345 );
2346 assert_ok!(
2347 I0F128,
2348 "-0.800000000000000000000000000000008",
2349 16,
2350 -0x8000_0000_0000_0000_0000_0000_0000_0000,
2351 false
2352 );
2353 assert_ok!(
2354 I0F128,
2355 "-0.7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8",
2356 16,
2357 -0x8000_0000_0000_0000_0000_0000_0000_0000,
2358 false
2359 );
2360 assert_ok!(
2361 I0F128,
2362 "+0.7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7",
2363 16,
2364 0x7FFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF,
2365 false
2366 );
2367 assert_ok!(
2368 I0F128,
2369 "+0.7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8",
2370 16,
2371 -0x8000_0000_0000_0000_0000_0000_0000_0000,
2372 true
2373 );
2374 assert_ok!(
2375 I0F128,
2376 "1",
2377 16,
2378 0x0000_0000_0000_0000_0000_0000_0000_0000,
2379 true
2380 );
2381
2382 assert_ok!(
2383 I64F64,
2384 "-8000000000000000.00000000000000009",
2385 16,
2386 0x7FFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF,
2387 true
2388 );
2389 assert_ok!(
2390 I64F64,
2391 "-8000000000000000.00000000000000008",
2392 16,
2393 -0x8000_0000_0000_0000_0000_0000_0000_0000,
2394 false
2395 );
2396 assert_ok!(
2397 I64F64,
2398 "-7FFFFFFFFFFFFFFF.FFFFFFFFFFFFFFFF8",
2399 16,
2400 -0x8000_0000_0000_0000_0000_0000_0000_0000,
2401 false
2402 );
2403 assert_ok!(
2404 I64F64,
2405 "+7FFFFFFFFFFFFFFF.FFFFFFFFFFFFFFFF7",
2406 16,
2407 0x7FFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF,
2408 false
2409 );
2410 assert_ok!(
2411 I64F64,
2412 "+7FFFFFFFFFFFFFFF.FFFFFFFFFFFFFFFF8",
2413 16,
2414 -0x8000_0000_0000_0000_0000_0000_0000_0000,
2415 true
2416 );
2417
2418 assert_ok!(
2419 I128F0,
2420 "-80000000000000000000000000000000.9",
2421 16,
2422 0x7FFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF,
2423 true
2424 );
2425 assert_ok!(
2426 I128F0,
2427 "-80000000000000000000000000000000.8",
2428 16,
2429 -0x8000_0000_0000_0000_0000_0000_0000_0000,
2430 false
2431 );
2432 assert_ok!(
2433 I128F0,
2434 "-7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF.8",
2435 16,
2436 -0x8000_0000_0000_0000_0000_0000_0000_0000,
2437 false
2438 );
2439 assert_ok!(
2440 I128F0,
2441 "+7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF.7",
2442 16,
2443 0x7FFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF,
2444 false
2445 );
2446 assert_ok!(
2447 I128F0,
2448 "+7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF.8",
2449 16,
2450 -0x8000_0000_0000_0000_0000_0000_0000_0000,
2451 true
2452 );
2453
2454 assert_ok!(
2455 U0F128,
2456 "-0",
2457 16,
2458 0x0000_0000_0000_0000_0000_0000_0000_0000,
2459 false
2460 );
2461 assert_ok!(
2462 U0F128,
2463 "0.7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7",
2464 16,
2465 0x7FFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF,
2466 false
2467 );
2468 assert_ok!(
2469 U0F128,
2470 "0.7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8",
2471 16,
2472 0x8000_0000_0000_0000_0000_0000_0000_0000,
2473 false
2474 );
2475 assert_ok!(
2476 U0F128,
2477 "0.FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7",
2478 16,
2479 0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF,
2480 false
2481 );
2482 assert_ok!(
2483 U0F128,
2484 "0.FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8",
2485 16,
2486 0x0000_0000_0000_0000_0000_0000_0000_0000,
2487 true
2488 );
2489 assert_ok!(
2490 U0F128,
2491 "1",
2492 16,
2493 0x0000_0000_0000_0000_0000_0000_0000_0000,
2494 true
2495 );
2496
2497 assert_ok!(
2498 U64F64,
2499 "7FFFFFFFFFFFFFFF.FFFFFFFFFFFFFFFF7",
2500 16,
2501 0x7FFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF,
2502 false
2503 );
2504 assert_ok!(
2505 U64F64,
2506 "7FFFFFFFFFFFFFFF.FFFFFFFFFFFFFFFF8",
2507 16,
2508 0x8000_0000_0000_0000_0000_0000_0000_0000,
2509 false
2510 );
2511 assert_ok!(
2512 U64F64,
2513 "FFFFFFFFFFFFFFFF.FFFFFFFFFFFFFFFF7",
2514 16,
2515 0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF,
2516 false
2517 );
2518 assert_ok!(
2519 U64F64,
2520 "FFFFFFFFFFFFFFFF.FFFFFFFFFFFFFFFF8",
2521 16,
2522 0x0000_0000_0000_0000_0000_0000_0000_0000,
2523 true
2524 );
2525
2526 assert_ok!(
2527 U128F0,
2528 "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF.7",
2529 16,
2530 0x7FFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF,
2531 false
2532 );
2533 assert_ok!(
2534 U128F0,
2535 "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF.8",
2536 16,
2537 0x8000_0000_0000_0000_0000_0000_0000_0000,
2538 false
2539 );
2540 assert_ok!(
2541 U128F0,
2542 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF.7",
2543 16,
2544 0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF,
2545 false
2546 );
2547 assert_ok!(
2548 U128F0,
2549 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF.8",
2550 16,
2551 0x0000_0000_0000_0000_0000_0000_0000_0000,
2552 true
2553 );
2554 }
2555
2556 struct Fractions {
2562 zero: String,
2563 gt_0: String,
2564 max: String,
2565 over: String,
2566 }
2567 fn without_last(a: &str) -> &str {
2568 &a[..a.len() - 1]
2569 }
2570 fn make_fraction_strings(max_int: &str, eps_frac: &str) -> Fractions {
2571 let eps_frac_compl: String = eps_frac
2572 .chars()
2573 .map(|digit| (b'0' + b'9' - digit as u8) as char)
2574 .collect();
2575
2576 let zero = String::from("0.") + eps_frac;
2577 let gt_0 = String::from(&*zero) + "000001";
2578 let max = String::from(max_int) + &eps_frac_compl + "999999";
2579 let over = String::from(max_int) + without_last(&eps_frac_compl) + "5";
2580 Fractions {
2581 zero,
2582 gt_0,
2583 max,
2584 over,
2585 }
2586 }
2587
2588 #[test]
2594 fn check_exact_decimal() {
2595 let max_int_0 = String::from("0.");
2596 let max_int_4 = String::from("15.");
2597 let max_int_8 = format!("{}.", !0u8);
2598 let max_int_16 = format!("{}.", !0u16);
2599 let max_int_28 = format!("{}.", !0u32 >> 4);
2600 let max_int_32 = format!("{}.", !0u32);
2601 let max_int_64 = format!("{}.", !0u64);
2602 let max_int_124 = format!("{}.", !0u128 >> 4);
2603 let max_int_128 = format!("{}.", !0u128);
2604
2605 let eps_0 = "5";
2618 let eps_4 = "03125";
2619 let eps_8 = "001953125";
2620 let eps_16 = "00000762939453125";
2621 let eps_28 = "00000000186264514923095703125";
2622 let eps_32 = "000000000116415321826934814453125";
2623 let eps_64 = "00000000000000000002710505431213761085018632002174854278564453125";
2624 let eps_124 = "0000000000000000000000000000000000000235098870164457501593747307\
2625 4444491355637331113544175043017503412556834518909454345703125";
2626 let eps_128 = "0000000000000000000000000000000000000014693679385278593849609206\
2627 71527807097273331945965109401885939632848021574318408966064453125";
2628
2629 let frac_0_8 = make_fraction_strings(&max_int_0, eps_8);
2630 assert_ok!(U0F8, &frac_0_8.zero, 10, 0, false);
2631 assert_ok!(U0F8, &frac_0_8.gt_0, 10, 1, false);
2632 assert_ok!(U0F8, &frac_0_8.max, 10, !0, false);
2633 assert_ok!(U0F8, &frac_0_8.over, 10, 0, true);
2634
2635 let frac_4_4 = make_fraction_strings(&max_int_4, eps_4);
2636 assert_ok!(U4F4, &frac_4_4.zero, 10, 0, false);
2637 assert_ok!(U4F4, &frac_4_4.gt_0, 10, 1, false);
2638 assert_ok!(U4F4, &frac_4_4.max, 10, !0, false);
2639 assert_ok!(U4F4, &frac_4_4.over, 10, 0, true);
2640
2641 let frac_8_0 = make_fraction_strings(&max_int_8, eps_0);
2642 assert_ok!(U8F0, &frac_8_0.zero, 10, 0, false);
2643 assert_ok!(U8F0, &frac_8_0.gt_0, 10, 1, false);
2644 assert_ok!(U8F0, &frac_8_0.max, 10, !0, false);
2645 assert_ok!(U8F0, &frac_8_0.over, 10, 0, true);
2646
2647 let frac_0_32 = make_fraction_strings(&max_int_0, eps_32);
2648 assert_ok!(U0F32, &frac_0_32.zero, 10, 0, false);
2649 assert_ok!(U0F32, &frac_0_32.gt_0, 10, 1, false);
2650 assert_ok!(U0F32, &frac_0_32.max, 10, !0, false);
2651 assert_ok!(U0F32, &frac_0_32.over, 10, 0, true);
2652
2653 let frac_4_28 = make_fraction_strings(&max_int_4, eps_28);
2654 assert_ok!(U4F28, &frac_4_28.zero, 10, 0, false);
2655 assert_ok!(U4F28, &frac_4_28.gt_0, 10, 1, false);
2656 assert_ok!(U4F28, &frac_4_28.max, 10, !0, false);
2657 assert_ok!(U4F28, &frac_4_28.over, 10, 0, true);
2658
2659 let frac_16_16 = make_fraction_strings(&max_int_16, eps_16);
2660 assert_ok!(U16F16, &frac_16_16.zero, 10, 0, false);
2661 assert_ok!(U16F16, &frac_16_16.gt_0, 10, 1, false);
2662 assert_ok!(U16F16, &frac_16_16.max, 10, !0, false);
2663 assert_ok!(U16F16, &frac_16_16.over, 10, 0, true);
2664
2665 let frac_28_4 = make_fraction_strings(&max_int_28, eps_4);
2666 assert_ok!(U28F4, &frac_28_4.zero, 10, 0, false);
2667 assert_ok!(U28F4, &frac_28_4.gt_0, 10, 1, false);
2668 assert_ok!(U28F4, &frac_28_4.max, 10, !0, false);
2669 assert_ok!(U28F4, &frac_28_4.over, 10, 0, true);
2670
2671 let frac_32_0 = make_fraction_strings(&max_int_32, eps_0);
2672 assert_ok!(U32F0, &frac_32_0.zero, 10, 0, false);
2673 assert_ok!(U32F0, &frac_32_0.gt_0, 10, 1, false);
2674 assert_ok!(U32F0, &frac_32_0.max, 10, !0, false);
2675 assert_ok!(U32F0, &frac_32_0.over, 10, 0, true);
2676
2677 let frac_0_128 = make_fraction_strings(&max_int_0, eps_128);
2678 assert_ok!(U0F128, &frac_0_128.zero, 10, 0, false);
2679 assert_ok!(U0F128, &frac_0_128.gt_0, 10, 1, false);
2680 assert_ok!(U0F128, &frac_0_128.max, 10, !0, false);
2681 assert_ok!(U0F128, &frac_0_128.over, 10, 0, true);
2682
2683 let frac_4_124 = make_fraction_strings(&max_int_4, eps_124);
2684 assert_ok!(U4F124, &frac_4_124.zero, 10, 0, false);
2685 assert_ok!(U4F124, &frac_4_124.gt_0, 10, 1, false);
2686 assert_ok!(U4F124, &frac_4_124.max, 10, !0, false);
2687 assert_ok!(U4F124, &frac_4_124.over, 10, 0, true);
2688
2689 let frac_64_64 = make_fraction_strings(&max_int_64, eps_64);
2690 assert_ok!(U64F64, &frac_64_64.zero, 10, 0, false);
2691 assert_ok!(U64F64, &frac_64_64.gt_0, 10, 1, false);
2692 assert_ok!(U64F64, &frac_64_64.max, 10, !0, false);
2693 assert_ok!(U64F64, &frac_64_64.over, 10, 0, true);
2694
2695 let frac_124_4 = make_fraction_strings(&max_int_124, eps_4);
2696 assert_ok!(U124F4, &frac_124_4.zero, 10, 0, false);
2697 assert_ok!(U124F4, &frac_124_4.gt_0, 10, 1, false);
2698 assert_ok!(U124F4, &frac_124_4.max, 10, !0, false);
2699 assert_ok!(U124F4, &frac_124_4.over, 10, 0, true);
2700
2701 let frac_128_0 = make_fraction_strings(&max_int_128, eps_0);
2702 assert_ok!(U128F0, &frac_128_0.zero, 10, 0, false);
2703 assert_ok!(U128F0, &frac_128_0.gt_0, 10, 1, false);
2704 assert_ok!(U128F0, &frac_128_0.max, 10, !0, false);
2705 assert_ok!(U128F0, &frac_128_0.over, 10, 0, true);
2706
2707 assert_ok!(
2710 U4F4,
2711 "0.40624999999999999999999999999999999999999999999999",
2712 10,
2713 0x06,
2714 false
2715 );
2716 assert_ok!(U4F4, "0.40625", 10, 0x06, false);
2717 assert_ok!(
2718 U4F4,
2719 "0.40625000000000000000000000000000000000000000000001",
2720 10,
2721 0x07,
2722 false
2723 );
2724 assert_ok!(U4F4, "0.4375", 10, 0x07, false);
2726 assert_ok!(
2728 U4F4,
2729 "0.46874999999999999999999999999999999999999999999999",
2730 10,
2731 0x07,
2732 false
2733 );
2734 assert_ok!(U4F4, "0.46875", 10, 0x08, false);
2735 assert_ok!(
2736 U4F4,
2737 "0.46875000000000000000000000000000000000000000000001",
2738 10,
2739 0x08,
2740 false
2741 );
2742 assert_ok!(U4F4, "0.5", 10, 0x08, false);
2744 assert_ok!(
2746 U4F4,
2747 "0.53124999999999999999999999999999999999999999999999",
2748 10,
2749 0x08,
2750 false
2751 );
2752 assert_ok!(U4F4, "0.53125", 10, 0x08, false);
2753 assert_ok!(
2754 U4F4,
2755 "0.53125000000000000000000000000000000000000000000001",
2756 10,
2757 0x09,
2758 false
2759 );
2760 assert_ok!(U4F4, "0.5625", 10, 0x09, false);
2762 }
2763
2764 #[test]
2765 fn frac4() {
2766 for u in 0..=255u8 {
2767 let (ifix, ufix) = (I4F4::from_bits(u as i8), U4F4::from_bits(u));
2768 let (ifix_str, ufix_str) = (ifix.to_string(), ufix.to_string());
2769 assert_eq!(I4F4::from_str(&ifix_str).unwrap(), ifix);
2770 assert_eq!(U4F4::from_str(&ufix_str).unwrap(), ufix);
2771 }
2772 }
2773
2774 #[test]
2775 fn frac17() {
2776 for u in 0..(1 << 17) {
2777 let fix = U15F17::from_bits(u) + U15F17::from_num(99);
2778 let fix_pos = I15F17::from_num(fix);
2779 let fix_neg = -fix_pos;
2780 let fix_str = fix.to_string();
2781 let fix_pos_str = fix_pos.to_string();
2782 let fix_neg_str = fix_neg.to_string();
2783 assert_eq!(fix_str, fix_pos_str);
2784 if u != 0 {
2785 assert_eq!(&fix_neg_str[..1], "-");
2786 assert_eq!(&fix_neg_str[1..], fix_pos_str);
2787 }
2788 assert_eq!(U15F17::from_str(&fix_str).unwrap(), fix);
2789 assert_eq!(I15F17::from_str(&fix_pos_str).unwrap(), fix_pos);
2790 assert_eq!(I15F17::from_str(&fix_neg_str).unwrap(), fix_neg);
2791
2792 let fix_str3 = format!("{fix:.3}");
2793 let fix_pos_str3 = format!("{fix_pos:.3}");
2794 let fix_neg_str3 = format!("{fix_neg:.3}");
2795 assert_eq!(fix_str3, fix_pos_str3);
2796 if u != 0 {
2797 assert_eq!(&fix_neg_str3[..1], "-");
2798 assert_eq!(&fix_neg_str3[1..], fix_pos_str3);
2799 }
2800 let max_diff = U15F17::from_bits((5 << 17) / 10000 + 1);
2801 let from_fix_str3 = U15F17::from_str(&fix_str3).unwrap();
2802 assert!(from_fix_str3.dist(fix) <= max_diff);
2803 let from_fix_pos_str3 = I15F17::from_str(&fix_pos_str3).unwrap();
2804 assert!(from_fix_pos_str3.dist(fix_pos) <= max_diff);
2805 let from_fix_neg_str3 = I15F17::from_str(&fix_neg_str3).unwrap();
2806 assert!(from_fix_neg_str3.dist(fix_neg) <= max_diff);
2807
2808 let fix_str9 = format!("{fix:.9}");
2809 let fix_pos_str9 = format!("{fix_pos:.9}");
2810 let fix_neg_str9 = format!("{fix_neg:.9}");
2811 assert_eq!(fix_str9, fix_pos_str9);
2812 if u != 0 {
2813 assert_eq!(&fix_neg_str9[..1], "-");
2814 assert_eq!(&fix_neg_str9[1..], fix_pos_str9);
2815 }
2816 assert_eq!(U15F17::from_str(&fix_str9).unwrap(), fix);
2817 assert_eq!(I15F17::from_str(&fix_pos_str9).unwrap(), fix_pos);
2818 assert_eq!(I15F17::from_str(&fix_neg_str9).unwrap(), fix_neg);
2819 }
2820 }
2821}