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// match radix {
105// 2 if cfg!(feature = "power-of-two") => (-16494, 16383),
106// 3 if cfg!(feature = "radix") => (-71, 71),
107// 4 if cfg!(feature = "power-of-two") => (-8247, 8191),
108// 5 if cfg!(feature = "radix") => (-48, 48),
109// 6 if cfg!(feature = "radix") => (-71, 71),
110// 7 if cfg!(feature = "radix") => (-40, 40),
111// 8 if cfg!(feature = "power-of-two") => (-5498, 5461),
112// 9 if cfg!(feature = "radix") => (-35, 35),
113// 10 => (-48, 48),
114// 11 if cfg!(feature = "radix") => (-32, 32),
115// 12 if cfg!(feature = "radix") => (-71, 71),
116// 13 if cfg!(feature = "radix") => (-30, 30),
117// 14 if cfg!(feature = "radix") => (-40, 40),
118// 15 if cfg!(feature = "radix") => (-28, 28),
119// 16 if cfg!(feature = "power-of-two") => (-4123, 4095),
120// 17 if cfg!(feature = "radix") => (-27, 27),
121// 18 if cfg!(feature = "radix") => (-35, 35),
122// 19 if cfg!(feature = "radix") => (-26, 26),
123// 20 if cfg!(feature = "radix") => (-48, 48),
124// 21 if cfg!(feature = "radix") => (-25, 25),
125// 22 if cfg!(feature = "radix") => (-32, 32),
126// 23 if cfg!(feature = "radix") => (-24, 24),
127// 24 if cfg!(feature = "radix") => (-71, 71),
128// 25 if cfg!(feature = "radix") => (-24, 24),
129// 26 if cfg!(feature = "radix") => (-30, 30),
130// 27 if cfg!(feature = "radix") => (-23, 23),
131// 28 if cfg!(feature = "radix") => (-40, 40),
132// 29 if cfg!(feature = "radix") => (-23, 23),
133// 30 if cfg!(feature = "radix") => (-28, 28),
134// 31 if cfg!(feature = "radix") => (-22, 22),
135// 32 if cfg!(feature = "power-of-two") => (-3298, 3276),
136// 33 if cfg!(feature = "radix") => (-22, 22),
137// 34 if cfg!(feature = "radix") => (-27, 27),
138// 35 if cfg!(feature = "radix") => (-22, 22),
139// 36 if cfg!(feature = "radix") => (-35, 35),
140// // Invalid radix
141// _ => unreachable!(),
142// }
143// }
144//
145// #[inline(always)]
146// fn mantissa_limit(radix: u32) -> i64 {
147// debug_assert_radix(radix);
148// match radix {
149// 2 if cfg!(feature = "power-of-two") => 113,
150// 3 if cfg!(feature = "radix") => 71,
151// 4 if cfg!(feature = "power-of-two") => 56,
152// 5 if cfg!(feature = "radix") => 48,
153// 6 if cfg!(feature = "radix") => 43,
154// 7 if cfg!(feature = "radix") => 40,
155// 8 if cfg!(feature = "power-of-two") => 37,
156// 9 if cfg!(feature = "radix") => 35,
157// 10 => 34,
158// 11 if cfg!(feature = "radix") => 32,
159// 12 if cfg!(feature = "radix") => 31,
160// 13 if cfg!(feature = "radix") => 30,
161// 14 if cfg!(feature = "radix") => 29,
162// 15 if cfg!(feature = "radix") => 28,
163// 16 if cfg!(feature = "power-of-two") => 28,
164// 17 if cfg!(feature = "radix") => 27,
165// 18 if cfg!(feature = "radix") => 27,
166// 19 if cfg!(feature = "radix") => 26,
167// 20 if cfg!(feature = "radix") => 26,
168// 21 if cfg!(feature = "radix") => 25,
169// 22 if cfg!(feature = "radix") => 25,
170// 23 if cfg!(feature = "radix") => 24,
171// 24 if cfg!(feature = "radix") => 24,
172// 25 if cfg!(feature = "radix") => 24,
173// 26 if cfg!(feature = "radix") => 24,
174// 27 if cfg!(feature = "radix") => 23,
175// 28 if cfg!(feature = "radix") => 23,
176// 29 if cfg!(feature = "radix") => 23,
177// 30 if cfg!(feature = "radix") => 23,
178// 31 if cfg!(feature = "radix") => 22,
179// 32 if cfg!(feature = "power-of-two") => 22,
180// 33 if cfg!(feature = "radix") => 22,
181// 34 if cfg!(feature = "radix") => 22,
182// 35 if cfg!(feature = "radix") => 22,
183// 36 if cfg!(feature = "radix") => 21,
184// // Invalid radix
185// _ => unreachable!(),
186// }
187// }
188//}
189
190// CONST FN
191// --------
192
193/// Get the exponent limit as a const fn.
194#[inline(always)]
195pub const fn f32_exponent_limit(radix: u32) -> (i64, i64) {
196 match radix {
197 2 if cfg!(feature = "power-of-two") => (-127, 127),
198 3 if cfg!(feature = "radix") => (-15, 15),
199 4 if cfg!(feature = "power-of-two") => (-63, 63),
200 5 if cfg!(feature = "radix") => (-10, 10),
201 6 if cfg!(feature = "radix") => (-15, 15),
202 7 if cfg!(feature = "radix") => (-8, 8),
203 8 if cfg!(feature = "power-of-two") => (-42, 42),
204 9 if cfg!(feature = "radix") => (-7, 7),
205 10 => (-10, 10),
206 11 if cfg!(feature = "radix") => (-6, 6),
207 12 if cfg!(feature = "radix") => (-15, 15),
208 13 if cfg!(feature = "radix") => (-6, 6),
209 14 if cfg!(feature = "radix") => (-8, 8),
210 15 if cfg!(feature = "radix") => (-6, 6),
211 16 if cfg!(feature = "power-of-two") => (-31, 31),
212 17 if cfg!(feature = "radix") => (-5, 5),
213 18 if cfg!(feature = "radix") => (-7, 7),
214 19 if cfg!(feature = "radix") => (-5, 5),
215 20 if cfg!(feature = "radix") => (-10, 10),
216 21 if cfg!(feature = "radix") => (-5, 5),
217 22 if cfg!(feature = "radix") => (-6, 6),
218 23 if cfg!(feature = "radix") => (-5, 5),
219 24 if cfg!(feature = "radix") => (-15, 15),
220 25 if cfg!(feature = "radix") => (-5, 5),
221 26 if cfg!(feature = "radix") => (-6, 6),
222 27 if cfg!(feature = "radix") => (-5, 5),
223 28 if cfg!(feature = "radix") => (-8, 8),
224 29 if cfg!(feature = "radix") => (-4, 4),
225 30 if cfg!(feature = "radix") => (-6, 6),
226 31 if cfg!(feature = "radix") => (-4, 4),
227 32 if cfg!(feature = "power-of-two") => (-25, 25),
228 33 if cfg!(feature = "radix") => (-4, 4),
229 34 if cfg!(feature = "radix") => (-5, 5),
230 35 if cfg!(feature = "radix") => (-4, 4),
231 36 if cfg!(feature = "radix") => (-7, 7),
232 _ => (0, 0),
233 }
234}
235
236/// Get the mantissa limit as a const fn.
237#[inline(always)]
238pub const fn f32_mantissa_limit(radix: u32) -> i64 {
239 match radix {
240 2 if cfg!(feature = "power-of-two") => 24,
241 3 if cfg!(feature = "radix") => 15,
242 4 if cfg!(feature = "power-of-two") => 12,
243 5 if cfg!(feature = "radix") => 10,
244 6 if cfg!(feature = "radix") => 9,
245 7 if cfg!(feature = "radix") => 8,
246 8 if cfg!(feature = "power-of-two") => 8,
247 9 if cfg!(feature = "radix") => 7,
248 10 => 7,
249 11 if cfg!(feature = "radix") => 6,
250 12 if cfg!(feature = "radix") => 6,
251 13 if cfg!(feature = "radix") => 6,
252 14 if cfg!(feature = "radix") => 6,
253 15 if cfg!(feature = "radix") => 6,
254 16 if cfg!(feature = "power-of-two") => 6,
255 17 if cfg!(feature = "radix") => 5,
256 18 if cfg!(feature = "radix") => 5,
257 19 if cfg!(feature = "radix") => 5,
258 20 if cfg!(feature = "radix") => 5,
259 21 if cfg!(feature = "radix") => 5,
260 22 if cfg!(feature = "radix") => 5,
261 23 if cfg!(feature = "radix") => 5,
262 24 if cfg!(feature = "radix") => 5,
263 25 if cfg!(feature = "radix") => 5,
264 26 if cfg!(feature = "radix") => 5,
265 27 if cfg!(feature = "radix") => 5,
266 28 if cfg!(feature = "radix") => 4,
267 29 if cfg!(feature = "radix") => 4,
268 30 if cfg!(feature = "radix") => 4,
269 31 if cfg!(feature = "radix") => 4,
270 32 if cfg!(feature = "power-of-two") => 4,
271 33 if cfg!(feature = "radix") => 4,
272 34 if cfg!(feature = "radix") => 4,
273 35 if cfg!(feature = "radix") => 4,
274 36 if cfg!(feature = "radix") => 4,
275 _ => 0,
276 }
277}
278
279/// Get the exponent limit as a const fn.
280#[inline(always)]
281pub const fn f64_exponent_limit(radix: u32) -> (i64, i64) {
282 match radix {
283 2 if cfg!(feature = "power-of-two") => (-1023, 1023),
284 3 if cfg!(feature = "radix") => (-33, 33),
285 4 if cfg!(feature = "power-of-two") => (-511, 511),
286 5 if cfg!(feature = "radix") => (-22, 22),
287 6 if cfg!(feature = "radix") => (-33, 33),
288 7 if cfg!(feature = "radix") => (-18, 18),
289 8 if cfg!(feature = "power-of-two") => (-341, 341),
290 9 if cfg!(feature = "radix") => (-16, 16),
291 10 => (-22, 22),
292 11 if cfg!(feature = "radix") => (-15, 15),
293 12 if cfg!(feature = "radix") => (-33, 33),
294 13 if cfg!(feature = "radix") => (-14, 14),
295 14 if cfg!(feature = "radix") => (-18, 18),
296 15 if cfg!(feature = "radix") => (-13, 13),
297 16 if cfg!(feature = "power-of-two") => (-255, 255),
298 17 if cfg!(feature = "radix") => (-12, 12),
299 18 if cfg!(feature = "radix") => (-16, 16),
300 19 if cfg!(feature = "radix") => (-12, 12),
301 20 if cfg!(feature = "radix") => (-22, 22),
302 21 if cfg!(feature = "radix") => (-12, 12),
303 22 if cfg!(feature = "radix") => (-15, 15),
304 23 if cfg!(feature = "radix") => (-11, 11),
305 24 if cfg!(feature = "radix") => (-33, 33),
306 25 if cfg!(feature = "radix") => (-11, 11),
307 26 if cfg!(feature = "radix") => (-14, 14),
308 27 if cfg!(feature = "radix") => (-11, 11),
309 28 if cfg!(feature = "radix") => (-18, 18),
310 29 if cfg!(feature = "radix") => (-10, 10),
311 30 if cfg!(feature = "radix") => (-13, 13),
312 31 if cfg!(feature = "radix") => (-10, 10),
313 32 if cfg!(feature = "power-of-two") => (-204, 204),
314 33 if cfg!(feature = "radix") => (-10, 10),
315 34 if cfg!(feature = "radix") => (-12, 12),
316 35 if cfg!(feature = "radix") => (-10, 10),
317 36 if cfg!(feature = "radix") => (-16, 16),
318 _ => (0, 0),
319 }
320}
321
322/// Get the mantissa limit as a const fn.
323#[inline(always)]
324pub const fn f64_mantissa_limit(radix: u32) -> i64 {
325 match radix {
326 2 if cfg!(feature = "power-of-two") => 53,
327 3 if cfg!(feature = "radix") => 33,
328 4 if cfg!(feature = "power-of-two") => 26,
329 5 if cfg!(feature = "radix") => 22,
330 6 if cfg!(feature = "radix") => 20,
331 7 if cfg!(feature = "radix") => 18,
332 8 if cfg!(feature = "power-of-two") => 17,
333 9 if cfg!(feature = "radix") => 16,
334 10 => 15,
335 11 if cfg!(feature = "radix") => 15,
336 12 if cfg!(feature = "radix") => 14,
337 13 if cfg!(feature = "radix") => 14,
338 14 if cfg!(feature = "radix") => 13,
339 15 if cfg!(feature = "radix") => 13,
340 16 if cfg!(feature = "power-of-two") => 13,
341 17 if cfg!(feature = "radix") => 12,
342 18 if cfg!(feature = "radix") => 12,
343 19 if cfg!(feature = "radix") => 12,
344 20 if cfg!(feature = "radix") => 12,
345 21 if cfg!(feature = "radix") => 12,
346 22 if cfg!(feature = "radix") => 11,
347 23 if cfg!(feature = "radix") => 11,
348 24 if cfg!(feature = "radix") => 11,
349 25 if cfg!(feature = "radix") => 11,
350 26 if cfg!(feature = "radix") => 11,
351 27 if cfg!(feature = "radix") => 11,
352 28 if cfg!(feature = "radix") => 11,
353 29 if cfg!(feature = "radix") => 10,
354 30 if cfg!(feature = "radix") => 10,
355 31 if cfg!(feature = "radix") => 10,
356 32 if cfg!(feature = "power-of-two") => 10,
357 33 if cfg!(feature = "radix") => 10,
358 34 if cfg!(feature = "radix") => 10,
359 35 if cfg!(feature = "radix") => 10,
360 36 if cfg!(feature = "radix") => 10,
361 _ => 0,
362 }
363}
364
365// POWER LIMITS
366// ------------
367
368// The code used to generate these limits is as follows:
369//
370// ```text
371// import math
372//
373// def find_power(base, max_value):
374// '''Using log is unreliable, since it uses float math.'''
375//
376// power = 0
377// while base**power < max_value:
378// power += 1
379// return power - 1
380//
381// def print_function(bits):
382// print('#[inline(always)]')
383// print(f'pub const fn u{bits}_power_limit(radix: u32) -> u32 {{')
384// print(' match radix {')
385// max_value = 2**bits - 1
386// for radix in range(2, 37):
387// power = find_power(radix, max_value)
388// print(f' {radix} => {power},')
389// print(' // Any other radix should be unreachable.')
390// print(' _ => 1,')
391// print(' }')
392// print('}')
393// print('')
394//
395// print_function(32)
396// print_function(64)
397// ```
398
399/// Get the maximum value for `radix^N` that can be represented in a u32.
400/// This is calculated as `⌊log(2^32 - 1, b)⌋`.
401#[inline(always)]
402pub const fn u32_power_limit(radix: u32) -> u32 {
403 match radix {
404 2 if cfg!(feature = "power-of-two") => 31,
405 3 if cfg!(feature = "radix") => 20,
406 4 if cfg!(feature = "power-of-two") => 15,
407 5 => 13,
408 6 if cfg!(feature = "radix") => 12,
409 7 if cfg!(feature = "radix") => 11,
410 8 if cfg!(feature = "power-of-two") => 10,
411 9 if cfg!(feature = "radix") => 10,
412 10 => 9,
413 11 if cfg!(feature = "radix") => 9,
414 12 if cfg!(feature = "radix") => 8,
415 13 if cfg!(feature = "radix") => 8,
416 14 if cfg!(feature = "radix") => 8,
417 15 if cfg!(feature = "radix") => 8,
418 16 if cfg!(feature = "power-of-two") => 7,
419 17 if cfg!(feature = "radix") => 7,
420 18 if cfg!(feature = "radix") => 7,
421 19 if cfg!(feature = "radix") => 7,
422 20 if cfg!(feature = "radix") => 7,
423 21 if cfg!(feature = "radix") => 7,
424 22 if cfg!(feature = "radix") => 7,
425 23 if cfg!(feature = "radix") => 7,
426 24 if cfg!(feature = "radix") => 6,
427 25 if cfg!(feature = "radix") => 6,
428 26 if cfg!(feature = "radix") => 6,
429 27 if cfg!(feature = "radix") => 6,
430 28 if cfg!(feature = "radix") => 6,
431 29 if cfg!(feature = "radix") => 6,
432 30 if cfg!(feature = "radix") => 6,
433 31 if cfg!(feature = "radix") => 6,
434 32 if cfg!(feature = "power-of-two") => 6,
435 33 if cfg!(feature = "radix") => 6,
436 34 if cfg!(feature = "radix") => 6,
437 35 if cfg!(feature = "radix") => 6,
438 36 if cfg!(feature = "radix") => 6,
439 // Any other radix should be unreachable.
440 _ => 1,
441 }
442}
443
444/// Get the maximum value for `radix^N` that can be represented in a u64.
445/// This is calculated as `⌊log(2^64 - 1, b)⌋`.
446#[inline(always)]
447pub const fn u64_power_limit(radix: u32) -> u32 {
448 match radix {
449 2 if cfg!(feature = "power-of-two") => 63,
450 3 if cfg!(feature = "radix") => 40,
451 4 if cfg!(feature = "power-of-two") => 31,
452 5 => 27,
453 6 if cfg!(feature = "radix") => 24,
454 7 if cfg!(feature = "radix") => 22,
455 8 if cfg!(feature = "power-of-two") => 21,
456 9 if cfg!(feature = "radix") => 20,
457 10 => 19,
458 11 if cfg!(feature = "radix") => 18,
459 12 if cfg!(feature = "radix") => 17,
460 13 if cfg!(feature = "radix") => 17,
461 14 if cfg!(feature = "radix") => 16,
462 15 if cfg!(feature = "radix") => 16,
463 16 if cfg!(feature = "power-of-two") => 15,
464 17 if cfg!(feature = "radix") => 15,
465 18 if cfg!(feature = "radix") => 15,
466 19 if cfg!(feature = "radix") => 15,
467 20 if cfg!(feature = "radix") => 14,
468 21 if cfg!(feature = "radix") => 14,
469 22 if cfg!(feature = "radix") => 14,
470 23 if cfg!(feature = "radix") => 14,
471 24 if cfg!(feature = "radix") => 13,
472 25 if cfg!(feature = "radix") => 13,
473 26 if cfg!(feature = "radix") => 13,
474 27 if cfg!(feature = "radix") => 13,
475 28 if cfg!(feature = "radix") => 13,
476 29 if cfg!(feature = "radix") => 13,
477 30 if cfg!(feature = "radix") => 13,
478 31 if cfg!(feature = "radix") => 12,
479 32 if cfg!(feature = "power-of-two") => 12,
480 33 if cfg!(feature = "radix") => 12,
481 34 if cfg!(feature = "radix") => 12,
482 35 if cfg!(feature = "radix") => 12,
483 36 if cfg!(feature = "radix") => 12,
484 // Any other radix should be unreachable.
485 _ => 1,
486 }
487}
488
489// MAX DIGITS
490// ----------
491
492/// Calculate the maximum number of digits possible in the mantissa.
493///
494/// Returns the maximum number of digits plus one.
495///
496/// We can exactly represent a float in radix `b` from radix 2 if
497/// `b` is divisible by 2. This function calculates the exact number of
498/// digits required to exactly represent that float. This makes sense,
499/// and the exact reference and I quote is:
500///
501/// > A necessary and sufficient condition for all numbers representable in radix β
502/// > with a finite number of digits to be representable in radix γ with a
503/// > finite number of digits is that β should divide an integer power of γ.
504///
505/// According to the "Handbook of Floating Point Arithmetic",
506/// for IEEE754, with emin being the min exponent, p2 being the
507/// precision, and b being the radix, the number of digits follows as:
508///
509/// `−emin + p2 + ⌊(emin + 1) log(2, b) − log(1 − 2^(−p2), b)⌋`
510///
511/// For f16, this follows as:
512/// emin = -14
513/// p2 = 11
514///
515/// For bfloat16 , this follows as:
516/// emin = -126
517/// p2 = 8
518///
519/// For f32, this follows as:
520/// emin = -126
521/// p2 = 24
522///
523/// For f64, this follows as:
524/// emin = -1022
525/// p2 = 53
526///
527/// For f128, this follows as:
528/// emin = -16382
529/// p2 = 113
530///
531/// In Python:
532/// `-emin + p2 + math.floor((emin+ 1)*math.log(2, b)-math.log(1-2**(-p2), b))`
533///
534/// This was used to calculate the maximum number of digits for [2, 36].
535///
536/// The minimum, denormal exponent can be calculated as follows: given
537/// the number of exponent bits `exp_bits`, and the number of bits
538/// in the mantissa `mantissa_bits`, we have an exponent bias
539/// `exp_bias` equal to `2^(exp_bits-1) - 1 + mantissa_bits`. We
540/// therefore have a denormal exponent `denormal_exp` equal to
541/// `1 - exp_bias` and the minimum, denormal float `min_float` is
542/// therefore `2^denormal_exp`.
543///
544/// For f16, this follows as:
545/// exp_bits = 5
546/// mantissa_bits = 10
547/// exp_bias = 25
548/// denormal_exp = -24
549/// min_float = 5.96 * 10^−8
550///
551/// For bfloat16, this follows as:
552/// exp_bits = 8
553/// mantissa_bits = 7
554/// exp_bias = 134
555/// denormal_exp = -133
556/// min_float = 9.18 * 10^−41
557///
558/// For f32, this follows as:
559/// exp_bits = 8
560/// mantissa_bits = 23
561/// exp_bias = 150
562/// denormal_exp = -149
563/// min_float = 1.40 * 10^−45
564///
565/// For f64, this follows as:
566/// exp_bits = 11
567/// mantissa_bits = 52
568/// exp_bias = 1075
569/// denormal_exp = -1074
570/// min_float = 5.00 * 10^−324
571///
572/// For f128, this follows as:
573/// exp_bits = 15
574/// mantissa_bits = 112
575/// exp_bias = 16495
576/// denormal_exp = -16494
577/// min_float = 6.48 * 10^−4966
578///
579/// These match statements can be generated with the following Python
580/// code:
581/// ```python
582/// import math
583///
584/// def digits(emin, p2, b):
585/// return -emin + p2 + math.floor((emin+ 1)*math.log(2, b)-math.log(1-2**(-p2), b))
586///
587/// def max_digits(emin, p2):
588/// radices = [6, 10, 12, 14, 18, 20, 22, 24 26 28, 30, 34, 36]
589/// print('match radix {')
590/// for radix in radices:
591/// value = digits(emin, p2, radix)
592/// print(f' {radix} => Some({value + 2}),')
593/// print(' // Powers of two should be unreachable.')
594/// print(' // Odd numbers will have infinite digits.')
595/// print(' _ => None,')
596/// print('}')
597/// ```
598pub trait MaxDigits {
599 fn max_digits(radix: u32) -> Option<usize>;
600}
601
602/// emin = -126
603/// p2 = 24
604impl MaxDigits for f32 {
605 #[inline(always)]
606 fn max_digits(radix: u32) -> Option<usize> {
607 debug_assert_radix(radix);
608 f32_max_digits(radix)
609 }
610}
611
612/// emin = -1022
613/// p2 = 53
614impl MaxDigits for f64 {
615 #[inline(always)]
616 fn max_digits(radix: u32) -> Option<usize> {
617 debug_assert_radix(radix);
618 f64_max_digits(radix)
619 }
620}
621
622#[cfg(feature = "f16")]
623impl MaxDigits for f16 {
624 #[inline(always)]
625 fn max_digits(_: u32) -> Option<usize> {
626 unimplemented!()
627 }
628}
629
630#[cfg(feature = "f16")]
631impl MaxDigits for bf16 {
632 #[inline(always)]
633 fn max_digits(_: u32) -> Option<usize> {
634 unimplemented!()
635 }
636}
637
638///// emin = -16382
639///// p2 = 113
640//#[cfg(feature = "f128")]
641//impl MaxDigits for f128 {
642// #[inline(always)]
643// fn max_digits(radix: u32) -> Option<usize> {
644// match radix {
645// 6 => Some(10159),
646// 10 => Some(11565),
647// 12 => Some(11927),
648// 14 => Some(12194),
649// 18 => Some(12568),
650// 20 => Some(12706),
651// 22 => Some(12823),
652// 24 => Some(12924),
653// 26 => Some(13012),
654// 28 => Some(13089),
655// 30 => Some(13158),
656// 34 => Some(13277),
657// 36 => Some(13328),
658// // Powers of two should be unreachable.
659// // Odd numbers will have infinite digits.
660// _ => None,
661// }
662// }
663//}
664
665// CONST FN
666// --------
667
668/// Get the maximum number of significant digits as a const fn.
669#[inline(always)]
670pub const fn f32_max_digits(radix: u32) -> Option<usize> {
671 match radix {
672 6 => Some(103),
673 10 => Some(114),
674 12 => Some(117),
675 14 => Some(119),
676 18 => Some(122),
677 20 => Some(123),
678 22 => Some(123),
679 24 => Some(124),
680 26 => Some(125),
681 28 => Some(125),
682 30 => Some(126),
683 34 => Some(127),
684 36 => Some(127),
685 // Powers of two should be unreachable.
686 // Odd numbers will have infinite digits.
687 _ => None,
688 }
689}
690
691/// Get the maximum number of significant digits as a const fn.
692#[inline(always)]
693pub const fn f64_max_digits(radix: u32) -> Option<usize> {
694 match radix {
695 6 => Some(682),
696 10 => Some(769),
697 12 => Some(792),
698 14 => Some(808),
699 18 => Some(832),
700 20 => Some(840),
701 22 => Some(848),
702 24 => Some(854),
703 26 => Some(859),
704 28 => Some(864),
705 30 => Some(868),
706 34 => Some(876),
707 36 => Some(879),
708 // Powers of two should be unreachable.
709 // Odd numbers will have infinite digits.
710 _ => None,
711 }
712}