Skip to content

Commit e7020f6

Browse files
committed
dec2flt: Update documentation of existing methods
Fix or elaborate existing float parsing documentation. This includes introducing a notation.
1 parent f167efa commit e7020f6

File tree

3 files changed

+31
-15
lines changed

3 files changed

+31
-15
lines changed

library/core/src/num/dec2flt/common.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ pub(crate) trait ByteSlice {
88
/// Writes a 64-bit integer as 8 bytes in little-endian order.
99
fn write_u64(&mut self, value: u64);
1010

11-
/// Calculate the offset of a slice from another.
11+
/// Calculate the difference in length between two slices.
1212
fn offset_from(&self, other: &Self) -> isize;
1313

1414
/// Iteratively parse and consume digits from bytes.
15-
/// Returns the same bytes with consumed digits being
16-
/// elided.
15+
///
16+
/// Returns the same bytes with consumed digits being elided. Breaks on invalid digits.
1717
fn parse_digits(&self, func: impl FnMut(u8)) -> &Self;
1818
}
1919

@@ -39,11 +39,11 @@ impl ByteSlice for [u8] {
3939
fn parse_digits(&self, mut func: impl FnMut(u8)) -> &Self {
4040
let mut s = self;
4141

42-
while let Some((c, s_next)) = s.split_first() {
42+
while let Some((c, rest)) = s.split_first() {
4343
let c = c.wrapping_sub(b'0');
4444
if c < 10 {
4545
func(c);
46-
s = s_next;
46+
s = rest;
4747
} else {
4848
break;
4949
}
@@ -53,7 +53,9 @@ impl ByteSlice for [u8] {
5353
}
5454
}
5555

56-
/// Determine if 8 bytes are all decimal digits.
56+
/// Determine if all characters in an 8-byte byte string (represented as a `u64`) are all decimal
57+
/// digits.
58+
///
5759
/// This does not care about the order in which the bytes were loaded.
5860
pub(crate) fn is_8digits(v: u64) -> bool {
5961
let a = v.wrapping_add(0x4646_4646_4646_4646);

library/core/src/num/dec2flt/decimal.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//! Arbitrary-precision decimal class for fallback algorithms.
1+
//! Arbitrary-precision decimal type used by fallback algorithms.
22
//!
33
//! This is only used if the fast-path (native floats) and
44
//! the Eisel-Lemire algorithm are unable to unambiguously
@@ -11,6 +11,7 @@
1111
1212
use crate::num::dec2flt::common::{is_8digits, ByteSlice};
1313

14+
/// A decimal floating-point number.
1415
#[derive(Clone)]
1516
pub struct Decimal {
1617
/// The number of significant digits in the decimal.
@@ -30,18 +31,17 @@ impl Default for Decimal {
3031
}
3132

3233
impl Decimal {
33-
/// The maximum number of digits required to unambiguously round a float.
34+
/// The maximum number of digits required to unambiguously round up to a 64-bit float.
3435
///
35-
/// For a double-precision IEEE 754 float, this required 767 digits,
36-
/// so we store the max digits + 1.
36+
/// For an IEEE 754 binary64 float, this required 767 digits. So we store the max digits + 1.
3737
///
3838
/// We can exactly represent a float in radix `b` from radix 2 if
3939
/// `b` is divisible by 2. This function calculates the exact number of
4040
/// digits required to exactly represent that float.
4141
///
4242
/// According to the "Handbook of Floating Point Arithmetic",
43-
/// for IEEE754, with emin being the min exponent, p2 being the
44-
/// precision, and b being the radix, the number of digits follows as:
43+
/// for IEEE754, with `emin` being the min exponent, `p2` being the
44+
/// precision, and `b` being the radix, the number of digits follows as:
4545
///
4646
/// `−emin + p2 + ⌊(emin + 1) log(2, b) − log(1 − 2^(−p2), b)⌋`
4747
///
@@ -56,11 +56,12 @@ impl Decimal {
5656
/// In Python:
5757
/// `-emin + p2 + math.floor((emin+ 1)*math.log(2, b)-math.log(1-2**(-p2), b))`
5858
pub const MAX_DIGITS: usize = 768;
59-
/// The max digits that can be exactly represented in a 64-bit integer.
59+
/// The max decimal digits that can be exactly represented in a 64-bit integer.
6060
pub const MAX_DIGITS_WITHOUT_OVERFLOW: usize = 19;
6161
pub const DECIMAL_POINT_RANGE: i32 = 2047;
6262

63-
/// Append a digit to the buffer.
63+
/// Append a digit to the buffer if it fits.
64+
// TODO: looks like this
6465
pub fn try_add_digit(&mut self, digit: u8) {
6566
if self.num_digits < Self::MAX_DIGITS {
6667
self.digits[self.num_digits] = digit;
@@ -69,6 +70,7 @@ impl Decimal {
6970
}
7071

7172
/// Trim trailing zeros from the buffer.
73+
// TODO: switch to `.rev().position()`
7274
pub fn trim(&mut self) {
7375
// All of the following calls to `Decimal::trim` can't panic because:
7476
//
@@ -86,7 +88,7 @@ impl Decimal {
8688
pub fn round(&self) -> u64 {
8789
if self.num_digits == 0 || self.decimal_point < 0 {
8890
return 0;
89-
} else if self.decimal_point > 18 {
91+
} else if self.decimal_point >= Self::MAX_DIGITS_WITHOUT_OVERFLOW as i32 {
9092
return 0xFFFF_FFFF_FFFF_FFFF_u64;
9193
}
9294
let dp = self.decimal_point as usize;

library/core/src/num/dec2flt/mod.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,18 @@
6767
//! "such that the exponent +/- the number of decimal digits fits into a 64 bit integer".
6868
//! Larger exponents are accepted, but we don't do arithmetic with them, they are immediately
6969
//! turned into {positive,negative} {zero,infinity}.
70+
//!
71+
//! # Notation
72+
//!
73+
//! This module uses the same notation as the Lemire paper:
74+
//!
75+
//! - `m`: binary mantissa; always nonnegative
76+
//! - `p`: binary exponent; a signed integer
77+
//! - `w`: decimal significand; always nonnegative
78+
//! - `q`: decimal exponent; a signed integer
79+
//!
80+
//! This gives `m * 2^p` for the binary floating-point number, with `w * 10^q` as the decimal
81+
//! equivalent.
7082
7183
#![doc(hidden)]
7284
#![unstable(

0 commit comments

Comments
 (0)