lexical_parse_float/
limits.rs

1//! Determine the limits of exact exponent and mantissas for floats.
2
3#![doc(hidden)]
4
5use lexical_util::assert::debug_assert_radix;
6#[cfg(feature = "f16")]
7use lexical_util::bf16::bf16;
8#[cfg(feature = "f16")]
9use lexical_util::f16::f16;
10
11// EXACT EXPONENT
12// --------------
13
14// Calculating the exponent limit requires determining the largest exponent
15// we can calculate for a radix that can be **exactly** store in the
16// float type. If the value is a power-of-two, then we simply
17// need to scale the minimum, denormal exp and maximum exp to the type
18// size. Otherwise, we need to calculate the number of digits
19// that can fit into the type's precision, after removing a power-of-two
20// (since these values can be represented exactly).
21//
22// The mantissa limit is the number of digits we can remove from
23// the exponent into the mantissa, and is therefore is the
24// `⌊ precision / log2(radix) ⌋`, where precision does not include
25// the hidden bit.
26//
27// The algorithm for calculating both `exponent_limit` and `mantissa_limit`,
28// in Python, can be done as follows:
29//
30// DO NOT MODIFY: Generated by `src/etc/limits.py`
31
32// EXACT FLOAT
33// -----------
34
35/// Get exact exponent limit for radix.
36#[doc(hidden)]
37pub trait ExactFloat {
38    /// Get min and max exponent limits (exact) from radix.
39    fn exponent_limit(radix: u32) -> (i64, i64);
40
41    /// Get the number of digits that can be shifted from exponent to mantissa.
42    fn mantissa_limit(radix: u32) -> i64;
43}
44
45impl ExactFloat for f32 {
46    #[inline(always)]
47    fn exponent_limit(radix: u32) -> (i64, i64) {
48        debug_assert_radix(radix);
49        f32_exponent_limit(radix)
50    }
51
52    #[inline(always)]
53    fn mantissa_limit(radix: u32) -> i64 {
54        debug_assert_radix(radix);
55        f32_mantissa_limit(radix)
56    }
57}
58
59impl ExactFloat for f64 {
60    #[inline(always)]
61    fn exponent_limit(radix: u32) -> (i64, i64) {
62        debug_assert_radix(radix);
63        f64_exponent_limit(radix)
64    }
65
66    #[inline(always)]
67    fn mantissa_limit(radix: u32) -> i64 {
68        debug_assert_radix(radix);
69        f64_mantissa_limit(radix)
70    }
71}
72
73#[cfg(feature = "f16")]
74impl ExactFloat for f16 {
75    #[inline(always)]
76    fn exponent_limit(_: u32) -> (i64, i64) {
77        unimplemented!()
78    }
79
80    #[inline(always)]
81    fn mantissa_limit(_: u32) -> i64 {
82        unimplemented!()
83    }
84}
85
86#[cfg(feature = "f16")]
87impl ExactFloat for bf16 {
88    #[inline(always)]
89    fn exponent_limit(_: u32) -> (i64, i64) {
90        unimplemented!()
91    }
92
93    #[inline(always)]
94    fn mantissa_limit(_: u32) -> i64 {
95        unimplemented!()
96    }
97}
98
99//#[cfg(feature = "f128")]
100//impl ExactFloat for f128 {
101//    #[inline(always)]
102//    fn exponent_limit(radix: u32) -> (i64, i64) {
103//        debug_assert_radix(radix);
104//        f128_exponent_limit(radix)
105//        }
106//    }
107//
108//    #[inline(always)]
109//    fn mantissa_limit(radix: u32) -> i64 {
110//        debug_assert_radix(radix);
111//        f128_mantissa_limit(radix)
112//    }
113//}
114
115// CONST FN
116// --------
117
118/// Get the exponent limit as a const fn.
119#[must_use]
120#[inline(always)]
121#[cfg(feature = "radix")]
122pub const fn f32_exponent_limit(radix: u32) -> (i64, i64) {
123    match radix {
124        2 => (-127, 127),
125        3 => (-15, 15),
126        4 => (-63, 63),
127        5 => (-10, 10),
128        6 => (-15, 15),
129        7 => (-8, 8),
130        8 => (-42, 42),
131        9 => (-7, 7),
132        10 => (-10, 10),
133        11 => (-6, 6),
134        12 => (-15, 15),
135        13 => (-6, 6),
136        14 => (-8, 8),
137        15 => (-6, 6),
138        16 => (-31, 31),
139        17 => (-5, 5),
140        18 => (-7, 7),
141        19 => (-5, 5),
142        20 => (-10, 10),
143        21 => (-5, 5),
144        22 => (-6, 6),
145        23 => (-5, 5),
146        24 => (-15, 15),
147        25 => (-5, 5),
148        26 => (-6, 6),
149        27 => (-5, 5),
150        28 => (-8, 8),
151        29 => (-4, 4),
152        30 => (-6, 6),
153        31 => (-4, 4),
154        32 => (-25, 25),
155        33 => (-4, 4),
156        34 => (-5, 5),
157        35 => (-4, 4),
158        36 => (-7, 7),
159        _ => (0, 0),
160    }
161}
162
163/// Get the exponent limit as a const fn.
164#[must_use]
165#[inline(always)]
166#[cfg(all(feature = "power-of-two", not(feature = "radix")))]
167pub const fn f32_exponent_limit(radix: u32) -> (i64, i64) {
168    match radix {
169        2 => (-127, 127),
170        4 => (-63, 63),
171        8 => (-42, 42),
172        10 => (-10, 10),
173        16 => (-31, 31),
174        32 => (-25, 25),
175        _ => (0, 0),
176    }
177}
178
179/// Get the exponent limit as a const fn.
180#[must_use]
181#[inline(always)]
182#[cfg(not(feature = "power-of-two"))]
183pub const fn f32_exponent_limit(radix: u32) -> (i64, i64) {
184    match radix {
185        10 => (-10, 10),
186        _ => (0, 0),
187    }
188}
189
190/// Get the mantissa limit as a const fn.
191#[must_use]
192#[inline(always)]
193#[cfg(feature = "radix")]
194pub const fn f32_mantissa_limit(radix: u32) -> i64 {
195    match radix {
196        2 => 24,
197        3 => 15,
198        4 => 12,
199        5 => 10,
200        6 => 9,
201        7 => 8,
202        8 => 8,
203        9 => 7,
204        10 => 7,
205        11 => 6,
206        12 => 6,
207        13 => 6,
208        14 => 6,
209        15 => 6,
210        16 => 6,
211        17 => 5,
212        18 => 5,
213        19 => 5,
214        20 => 5,
215        21 => 5,
216        22 => 5,
217        23 => 5,
218        24 => 5,
219        25 => 5,
220        26 => 5,
221        27 => 5,
222        28 => 4,
223        29 => 4,
224        30 => 4,
225        31 => 4,
226        32 => 4,
227        33 => 4,
228        34 => 4,
229        35 => 4,
230        36 => 4,
231        _ => 0,
232    }
233}
234
235/// Get the mantissa limit as a const fn.
236#[must_use]
237#[inline(always)]
238#[cfg(all(feature = "power-of-two", not(feature = "radix")))]
239pub const fn f32_mantissa_limit(radix: u32) -> i64 {
240    match radix {
241        2 => 24,
242        4 => 12,
243        8 => 8,
244        10 => 7,
245        16 => 6,
246        32 => 4,
247        _ => 0,
248    }
249}
250
251/// Get the mantissa limit as a const fn.
252#[must_use]
253#[inline(always)]
254#[cfg(not(feature = "power-of-two"))]
255pub const fn f32_mantissa_limit(radix: u32) -> i64 {
256    match radix {
257        10 => 7,
258        _ => 0,
259    }
260}
261
262/// Get the exponent limit as a const fn.
263#[must_use]
264#[inline(always)]
265#[cfg(feature = "radix")]
266pub const fn f64_exponent_limit(radix: u32) -> (i64, i64) {
267    match radix {
268        2 => (-1023, 1023),
269        3 => (-33, 33),
270        4 => (-511, 511),
271        5 => (-22, 22),
272        6 => (-33, 33),
273        7 => (-18, 18),
274        8 => (-341, 341),
275        9 => (-16, 16),
276        10 => (-22, 22),
277        11 => (-15, 15),
278        12 => (-33, 33),
279        13 => (-14, 14),
280        14 => (-18, 18),
281        15 => (-13, 13),
282        16 => (-255, 255),
283        17 => (-12, 12),
284        18 => (-16, 16),
285        19 => (-12, 12),
286        20 => (-22, 22),
287        21 => (-12, 12),
288        22 => (-15, 15),
289        23 => (-11, 11),
290        24 => (-33, 33),
291        25 => (-11, 11),
292        26 => (-14, 14),
293        27 => (-11, 11),
294        28 => (-18, 18),
295        29 => (-10, 10),
296        30 => (-13, 13),
297        31 => (-10, 10),
298        32 => (-204, 204),
299        33 => (-10, 10),
300        34 => (-12, 12),
301        35 => (-10, 10),
302        36 => (-16, 16),
303        _ => (0, 0),
304    }
305}
306
307// Get the exponent limit as a const fn.
308#[must_use]
309#[inline(always)]
310#[cfg(all(feature = "power-of-two", not(feature = "radix")))]
311pub const fn f64_exponent_limit(radix: u32) -> (i64, i64) {
312    match radix {
313        2 => (-1023, 1023),
314        4 => (-511, 511),
315        8 => (-341, 341),
316        10 => (-22, 22),
317        16 => (-255, 255),
318        32 => (-204, 204),
319        _ => (0, 0),
320    }
321}
322
323/// Get the exponent limit as a const fn.
324#[must_use]
325#[inline(always)]
326#[cfg(not(feature = "power-of-two"))]
327pub const fn f64_exponent_limit(radix: u32) -> (i64, i64) {
328    match radix {
329        10 => (-22, 22),
330        _ => (0, 0),
331    }
332}
333
334/// Get the mantissa limit as a const fn.
335#[must_use]
336#[inline(always)]
337#[cfg(feature = "radix")]
338pub const fn f64_mantissa_limit(radix: u32) -> i64 {
339    match radix {
340        2 => 53,
341        3 => 33,
342        4 => 26,
343        5 => 22,
344        6 => 20,
345        7 => 18,
346        8 => 17,
347        9 => 16,
348        10 => 15,
349        11 => 15,
350        12 => 14,
351        13 => 14,
352        14 => 13,
353        15 => 13,
354        16 => 13,
355        17 => 12,
356        18 => 12,
357        19 => 12,
358        20 => 12,
359        21 => 12,
360        22 => 11,
361        23 => 11,
362        24 => 11,
363        25 => 11,
364        26 => 11,
365        27 => 11,
366        28 => 11,
367        29 => 10,
368        30 => 10,
369        31 => 10,
370        32 => 10,
371        33 => 10,
372        34 => 10,
373        35 => 10,
374        36 => 10,
375        _ => 0,
376    }
377}
378
379/// Get the mantissa limit as a const fn.
380#[must_use]
381#[inline(always)]
382#[cfg(all(feature = "power-of-two", not(feature = "radix")))]
383pub const fn f64_mantissa_limit(radix: u32) -> i64 {
384    match radix {
385        2 => 53,
386        4 => 26,
387        8 => 17,
388        10 => 15,
389        16 => 13,
390        32 => 10,
391        _ => 0,
392    }
393}
394
395/// Get the mantissa limit as a const fn.
396#[must_use]
397#[inline(always)]
398#[cfg(not(feature = "power-of-two"))]
399pub const fn f64_mantissa_limit(radix: u32) -> i64 {
400    match radix {
401        10 => 15,
402        _ => 0,
403    }
404}
405
406/// Get the exponent limit as a const fn.
407#[must_use]
408#[inline(always)]
409#[cfg(feature = "f128")]
410#[cfg(feature = "radix")]
411pub const fn f128_exponent_limit(radix: u32) -> (i64, i64) {
412    match radix {
413        2 => (-16494, 16383),
414        3 => (-71, 71),
415        4 => (-8247, 8191),
416        5 => (-48, 48),
417        6 => (-71, 71),
418        7 => (-40, 40),
419        8 => (-5498, 5461),
420        9 => (-35, 35),
421        10 => (-48, 48),
422        11 => (-32, 32),
423        12 => (-71, 71),
424        13 => (-30, 30),
425        14 => (-40, 40),
426        15 => (-28, 28),
427        16 => (-4123, 4095),
428        17 => (-27, 27),
429        18 => (-35, 35),
430        19 => (-26, 26),
431        20 => (-48, 48),
432        21 => (-25, 25),
433        22 => (-32, 32),
434        23 => (-24, 24),
435        24 => (-71, 71),
436        25 => (-24, 24),
437        26 => (-30, 30),
438        27 => (-23, 23),
439        28 => (-40, 40),
440        29 => (-23, 23),
441        30 => (-28, 28),
442        31 => (-22, 22),
443        32 => (-3298, 3276),
444        33 => (-22, 22),
445        34 => (-27, 27),
446        35 => (-22, 22),
447        36 => (-35, 35),
448        // Invalid radix
449        _ => (0, 0),
450    }
451}
452
453/// Get the exponent limit as a const fn.
454#[inline(always)]
455#[cfg(feature = "f128")]
456#[cfg(all(feature = "power-of-two", not(feature = "radix")))]
457pub const fn f128_exponent_limit(radix: u32) -> (i64, i64) {
458    match radix {
459        2 => (-16494, 16383),
460        4 => (-8247, 8191),
461        8 => (-5498, 5461),
462        10 => (-48, 48),
463        16 => (-4123, 4095),
464        32 => (-3298, 3276),
465        // Invalid radix
466        _ => (0, 0),
467    }
468}
469
470/// Get the exponent limit as a const fn.
471#[must_use]
472#[inline(always)]
473#[cfg(feature = "f128")]
474#[cfg(not(feature = "power-of-two"))]
475pub const fn f128_exponent_limit(radix: u32) -> (i64, i64) {
476    match radix {
477        10 => (-48, 48),
478        // Invalid radix
479        _ => (0, 0),
480    }
481}
482
483/// Get the mantissa limit as a const fn.
484#[must_use]
485#[inline(always)]
486#[cfg(feature = "f128")]
487#[cfg(feature = "radix")]
488pub const fn f128_mantissa_limit(radix: u32) -> i64 {
489    match radix {
490        2 => 113,
491        3 => 71,
492        4 => 56,
493        5 => 48,
494        6 => 43,
495        7 => 40,
496        8 => 37,
497        9 => 35,
498        10 => 34,
499        11 => 32,
500        12 => 31,
501        13 => 30,
502        14 => 29,
503        15 => 28,
504        16 => 28,
505        17 => 27,
506        18 => 27,
507        19 => 26,
508        20 => 26,
509        21 => 25,
510        22 => 25,
511        23 => 24,
512        24 => 24,
513        25 => 24,
514        26 => 24,
515        27 => 23,
516        28 => 23,
517        29 => 23,
518        30 => 23,
519        31 => 22,
520        32 => 22,
521        33 => 22,
522        34 => 22,
523        35 => 22,
524        36 => 21,
525        // Invalid radix
526        _ => 0,
527    }
528}
529
530/// Get the mantissa limit as a const fn.
531#[must_use]
532#[inline(always)]
533#[cfg(feature = "f128")]
534#[cfg(all(feature = "power-of-two", not(feature = "radix")))]
535pub const fn f128_mantissa_limit(radix: u32) -> i64 {
536    match radix {
537        2 => 113,
538        4 => 56,
539        8 => 37,
540        10 => 34,
541        16 => 28,
542        32 => 22,
543        // Invalid radix
544        _ => 0,
545    }
546}
547
548/// Get the mantissa limit as a const fn.
549#[must_use]
550#[inline(always)]
551#[cfg(feature = "f128")]
552#[cfg(not(feature = "power-of-two"))]
553pub const fn f128_mantissa_limit(radix: u32) -> i64 {
554    match radix {
555        10 => 34,
556        // Invalid radix
557        _ => 0,
558    }
559}
560
561// POWER LIMITS
562// ------------
563
564//  The code used to generate these limits is as follows:
565//
566//  ```text
567//  import math
568//
569//  def find_power(base, max_value):
570//      '''Using log is unreliable, since it uses float math.'''
571//
572//      power = 0
573//      while base**power < max_value:
574//          power += 1
575//      return power - 1
576//
577//  def print_function(bits):
578//      print('#[inline(always)]')
579//      print(f'pub const fn u{bits}_power_limit(radix: u32) -> u32 {{')
580//      print('    match radix {')
581//      max_value = 2**bits - 1
582//      for radix in range(2, 37):
583//          power = find_power(radix, max_value)
584//          print(f'        {radix} => {power},')
585//      print('        // Any other radix should be unreachable.')
586//      print('        _ => 1,')
587//      print('    }')
588//      print('}')
589//      print('')
590//
591//  print_function(32)
592//  print_function(64)
593//  ```
594
595/// Get the maximum value for `radix^N` that can be represented in a u32.
596/// This is calculated as `⌊log(2^32 - 1, b)⌋`.
597#[must_use]
598#[inline(always)]
599#[cfg(feature = "radix")]
600pub const fn u32_power_limit(radix: u32) -> u32 {
601    match radix {
602        2 => 31,
603        3 => 20,
604        4 => 15,
605        5 => 13,
606        6 => 12,
607        7 => 11,
608        8 => 10,
609        9 => 10,
610        10 => 9,
611        11 => 9,
612        12 => 8,
613        13 => 8,
614        14 => 8,
615        15 => 8,
616        16 => 7,
617        17 => 7,
618        18 => 7,
619        19 => 7,
620        20 => 7,
621        21 => 7,
622        22 => 7,
623        23 => 7,
624        24 => 6,
625        25 => 6,
626        26 => 6,
627        27 => 6,
628        28 => 6,
629        29 => 6,
630        30 => 6,
631        31 => 6,
632        32 => 6,
633        33 => 6,
634        34 => 6,
635        35 => 6,
636        36 => 6,
637        // Any other radix should be unreachable.
638        _ => 1,
639    }
640}
641
642/// This is calculated as `⌊log(2^32 - 1, b)⌋`.
643#[must_use]
644#[inline(always)]
645#[cfg(all(feature = "power-of-two", not(feature = "radix")))]
646pub const fn u32_power_limit(radix: u32) -> u32 {
647    match radix {
648        2 => 31,
649        4 => 15,
650        5 => 13,
651        8 => 10,
652        10 => 9,
653        16 => 7,
654        32 => 6,
655        // Any other radix should be unreachable.
656        _ => 1,
657    }
658}
659
660/// This is calculated as `⌊log(2^32 - 1, b)⌋`.
661#[must_use]
662#[inline(always)]
663#[cfg(not(feature = "power-of-two"))]
664pub const fn u32_power_limit(radix: u32) -> u32 {
665    match radix {
666        5 => 13,
667        10 => 9,
668        // Any other radix should be unreachable.
669        _ => 1,
670    }
671}
672
673/// Get the maximum value for `radix^N` that can be represented in a u64.
674/// This is calculated as `⌊log(2^64 - 1, b)⌋`.
675#[must_use]
676#[inline(always)]
677#[cfg(feature = "radix")]
678pub const fn u64_power_limit(radix: u32) -> u32 {
679    match radix {
680        2 => 63,
681        3 => 40,
682        4 => 31,
683        5 => 27,
684        6 => 24,
685        7 => 22,
686        8 => 21,
687        9 => 20,
688        10 => 19,
689        11 => 18,
690        12 => 17,
691        13 => 17,
692        14 => 16,
693        15 => 16,
694        16 => 15,
695        17 => 15,
696        18 => 15,
697        19 => 15,
698        20 => 14,
699        21 => 14,
700        22 => 14,
701        23 => 14,
702        24 => 13,
703        25 => 13,
704        26 => 13,
705        27 => 13,
706        28 => 13,
707        29 => 13,
708        30 => 13,
709        31 => 12,
710        32 => 12,
711        33 => 12,
712        34 => 12,
713        35 => 12,
714        36 => 12,
715        // Any other radix should be unreachable.
716        _ => 1,
717    }
718}
719
720/// Get the maximum value for `radix^N` that can be represented in a u64.
721/// This is calculated as `⌊log(2^64 - 1, b)⌋`.
722#[must_use]
723#[inline(always)]
724#[cfg(all(feature = "power-of-two", not(feature = "radix")))]
725pub const fn u64_power_limit(radix: u32) -> u32 {
726    match radix {
727        2 => 63,
728        4 => 31,
729        5 => 27,
730        8 => 21,
731        10 => 19,
732        16 => 15,
733        32 => 12,
734        // Any other radix should be unreachable.
735        _ => 1,
736    }
737}
738
739#[must_use]
740#[inline(always)]
741#[cfg(not(feature = "power-of-two"))]
742pub const fn u64_power_limit(radix: u32) -> u32 {
743    match radix {
744        5 => 27,
745        10 => 19,
746        // Any other radix should be unreachable.
747        _ => 1,
748    }
749}
750
751// MAX DIGITS
752// ----------
753
754/// Calculate the maximum number of digits possible in the mantissa.
755///
756/// Returns the maximum number of digits plus one.
757///
758/// We can exactly represent a float in radix `b` from radix 2 if
759/// `b` is divisible by 2. This function calculates the exact number of
760/// digits required to exactly represent that float. This makes sense,
761/// and the exact reference and I quote is:
762///
763///  > A necessary and sufficient condition for all numbers representable in
764///  > radix β
765///  > with a finite number of digits to be representable in radix γ with a
766///  > finite number of digits is that β should divide an integer power of γ.
767///
768/// According to the "Handbook of Floating Point Arithmetic",
769/// for IEEE754, with `emin` being the min exponent, `p2` being the
770/// precision, and `b` being the radix, the number of digits follows as:
771///
772/// `−emin + p2 + ⌊(emin + 1) log(2, b) − log(1 − 2^(−p2), b)⌋`
773///
774/// For f16, this follows as:
775///     emin = -14
776///     p2 = 11
777///
778/// For bfloat16 , this follows as:
779///     emin = -126
780///     p2 = 8
781///
782/// For f32, this follows as:
783///     emin = -126
784///     p2 = 24
785///
786/// For f64, this follows as:
787///     emin = -1022
788///     p2 = 53
789///
790/// For f128, this follows as:
791///     emin = -16382
792///     p2 = 113
793///
794/// In Python:
795///     `-emin + p2 + math.floor((emin+ 1)*math.log(2, b)-math.log(1-2**(-p2),
796/// b))`
797///
798/// This was used to calculate the maximum number of digits for [2, 36].
799///
800/// The minimum, denormal exponent can be calculated as follows: given
801/// the number of exponent bits `exp_bits`, and the number of bits
802/// in the mantissa `mantissa_bits`, we have an exponent bias
803/// `exp_bias` equal to `2^(exp_bits-1) - 1 + mantissa_bits`. We
804/// therefore have a denormal exponent `denormal_exp` equal to
805/// `1 - exp_bias` and the minimum, denormal float `min_float` is
806/// therefore `2^denormal_exp`.
807///
808/// For f16, this follows as:
809///     exp_bits = 5
810///     mantissa_bits = 10
811///     exp_bias = 25
812///     denormal_exp = -24
813///     min_float = 5.96 * 10^−8
814///
815/// For bfloat16, this follows as:
816///     exp_bits = 8
817///     mantissa_bits = 7
818///     exp_bias = 134
819///     denormal_exp = -133
820///     min_float = 9.18 * 10^−41
821///
822/// For f32, this follows as:
823///     exp_bits = 8
824///     mantissa_bits = 23
825///     exp_bias = 150
826///     denormal_exp = -149
827///     min_float = 1.40 * 10^−45
828///
829/// For f64, this follows as:
830///     exp_bits = 11
831///     mantissa_bits = 52
832///     exp_bias = 1075
833///     denormal_exp = -1074
834///     min_float = 5.00 * 10^−324
835///
836/// For f128, this follows as:
837///     exp_bits = 15
838///     mantissa_bits = 112
839///     exp_bias = 16495
840///     denormal_exp = -16494
841///     min_float = 6.48 * 10^−4966
842///
843/// These match statements can be generated with the following Python
844/// code:
845/// ```python
846/// import math
847///
848/// def digits(emin, p2, b):
849///     return -emin + p2 + math.floor((emin+ 1)*math.log(2, b)-math.log(1-2**(-p2), b))
850///
851/// def max_digits(emin, p2):
852///     radices = [6, 10, 12, 14, 18, 20, 22, 24 26 28, 30, 34, 36]
853///     print('match radix {')
854///     for radix in radices:
855///         value = digits(emin, p2, radix)
856///         print(f'    {radix} => Some({value + 2}),')
857///     print('    // Powers of two should be unreachable.')
858///     print('    // Odd numbers will have infinite digits.')
859///     print('    _ => None,')
860///     print('}')
861/// ```
862#[allow(clippy::doc_markdown)] // reason="not meant to be function parameters"
863pub trait MaxDigits {
864    fn max_digits(radix: u32) -> Option<usize>;
865}
866
867/// emin = -126
868/// p2 = 24
869impl MaxDigits for f32 {
870    #[inline(always)]
871    fn max_digits(radix: u32) -> Option<usize> {
872        debug_assert_radix(radix);
873        f32_max_digits(radix)
874    }
875}
876
877/// emin = -1022
878/// p2 = 53
879impl MaxDigits for f64 {
880    #[inline(always)]
881    fn max_digits(radix: u32) -> Option<usize> {
882        debug_assert_radix(radix);
883        f64_max_digits(radix)
884    }
885}
886
887#[cfg(feature = "f16")]
888impl MaxDigits for f16 {
889    #[inline(always)]
890    fn max_digits(_: u32) -> Option<usize> {
891        unimplemented!()
892    }
893}
894
895#[cfg(feature = "f16")]
896impl MaxDigits for bf16 {
897    #[inline(always)]
898    fn max_digits(_: u32) -> Option<usize> {
899        unimplemented!()
900    }
901}
902
903///// `emin = -16382`
904///// `p2 = 113`
905//#[cfg(feature = "f128")]
906//impl MaxDigits for f128 {
907//    #[inline(always)]
908//    fn max_digits(radix: u32) -> Option<usize> {
909//        match radix {
910//            6 => Some(10159),
911//            10 => Some(11565),
912//            12 => Some(11927),
913//            14 => Some(12194),
914//            18 => Some(12568),
915//            20 => Some(12706),
916//            22 => Some(12823),
917//            24 => Some(12924),
918//            26 => Some(13012),
919//            28 => Some(13089),
920//            30 => Some(13158),
921//            34 => Some(13277),
922//            36 => Some(13328),
923//            // Powers of two should be unreachable.
924//            // Odd numbers will have infinite digits.
925//            _ => None,
926//        }
927//    }
928//}
929
930// CONST FN
931// --------
932
933/// Get the maximum number of significant digits as a const fn.
934#[must_use]
935#[inline(always)]
936pub const fn f32_max_digits(radix: u32) -> Option<usize> {
937    match radix {
938        6 => Some(103),
939        10 => Some(114),
940        12 => Some(117),
941        14 => Some(119),
942        18 => Some(122),
943        20 => Some(123),
944        22 => Some(123),
945        24 => Some(124),
946        26 => Some(125),
947        28 => Some(125),
948        30 => Some(126),
949        34 => Some(127),
950        36 => Some(127),
951        // Powers of two should be unreachable.
952        // Odd numbers will have infinite digits.
953        _ => None,
954    }
955}
956
957/// Get the maximum number of significant digits as a const fn.
958#[must_use]
959#[inline(always)]
960pub const fn f64_max_digits(radix: u32) -> Option<usize> {
961    match radix {
962        6 => Some(682),
963        10 => Some(769),
964        12 => Some(792),
965        14 => Some(808),
966        18 => Some(832),
967        20 => Some(840),
968        22 => Some(848),
969        24 => Some(854),
970        26 => Some(859),
971        28 => Some(864),
972        30 => Some(868),
973        34 => Some(876),
974        36 => Some(879),
975        // Powers of two should be unreachable.
976        // Odd numbers will have infinite digits.
977        _ => None,
978    }
979}