Skip to content

Commit 59e49a0

Browse files
committed
dec2flt: Rename Decimal to DecimalSeq
This module currently contains two decimal types, `Decimal` and `Number`. These names don't provide a whole lot of insight into what exactly they are, and `Number` is actually the one that is more like an expected `Decimal` type. In accordance with this, rename the existing `Decimal` to `DecimalSeq`. This highlights that it contains a sequence of decimal digits, rather than representing a base-10 floating point (decimal) number.
1 parent 8ddb085 commit 59e49a0

File tree

5 files changed

+71
-22
lines changed

5 files changed

+71
-22
lines changed

library/core/src/num/dec2flt/decimal.rs renamed to library/core/src/num/dec2flt/decimal_seq.rs

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@
1111
1212
use crate::num::dec2flt::common::{ByteSlice, is_8digits};
1313

14-
/// A decimal floating-point number.
15-
#[derive(Clone)]
16-
pub struct Decimal {
14+
/// A decimal floating-point number, represented as a sequence of decimal digits.
15+
#[derive(Clone, Debug, PartialEq)]
16+
pub struct DecimalSeq {
1717
/// The number of significant digits in the decimal.
1818
pub num_digits: usize,
1919
/// The offset of the decimal point in the significant digits.
@@ -24,13 +24,13 @@ pub struct Decimal {
2424
pub digits: [u8; Self::MAX_DIGITS],
2525
}
2626

27-
impl Default for Decimal {
27+
impl Default for DecimalSeq {
2828
fn default() -> Self {
2929
Self { num_digits: 0, decimal_point: 0, truncated: false, digits: [0; Self::MAX_DIGITS] }
3030
}
3131
}
3232

33-
impl Decimal {
33+
impl DecimalSeq {
3434
/// The maximum number of digits required to unambiguously round up to a 64-bit float.
3535
///
3636
/// For an IEEE 754 binary64 float, this required 767 digits. So we store the max digits + 1.
@@ -61,7 +61,8 @@ impl Decimal {
6161
pub const DECIMAL_POINT_RANGE: i32 = 2047;
6262

6363
/// Append a digit to the buffer if it fits.
64-
// TODO: looks like this
64+
// todo: should this return `Option`? And should it be incrementing the digit count after
65+
// it overflows?
6566
pub fn try_add_digit(&mut self, digit: u8) {
6667
if self.num_digits < Self::MAX_DIGITS {
6768
self.digits[self.num_digits] = digit;
@@ -70,13 +71,13 @@ impl Decimal {
7071
}
7172

7273
/// Trim trailing zeros from the buffer.
73-
// TODO: switch to `.rev().position()`
74+
// todo: switch to `.rev().position()` After tests pass
7475
pub fn trim(&mut self) {
75-
// All of the following calls to `Decimal::trim` can't panic because:
76+
// All of the following calls to `DecimalSeq::trim` can't panic because:
7677
//
77-
// 1. `parse_decimal` sets `num_digits` to a max of `Decimal::MAX_DIGITS`.
78+
// 1. `parse_decimal` sets `num_digits` to a max of `DecimalSeq::MAX_DIGITS`.
7879
// 2. `right_shift` sets `num_digits` to `write_index`, which is bounded by `num_digits`.
79-
// 3. `left_shift` `num_digits` to a max of `Decimal::MAX_DIGITS`.
80+
// 3. `left_shift` `num_digits` to a max of `DecimalSeq::MAX_DIGITS`.
8081
//
8182
// Trim is only called in `right_shift` and `left_shift`.
8283
debug_assert!(self.num_digits <= Self::MAX_DIGITS);
@@ -91,21 +92,26 @@ impl Decimal {
9192
} else if self.decimal_point >= Self::MAX_DIGITS_WITHOUT_OVERFLOW as i32 {
9293
return 0xFFFF_FFFF_FFFF_FFFF_u64;
9394
}
95+
9496
let dp = self.decimal_point as usize;
9597
let mut n = 0_u64;
98+
9699
for i in 0..dp {
97100
n *= 10;
98101
if i < self.num_digits {
99102
n += self.digits[i] as u64;
100103
}
101104
}
105+
102106
let mut round_up = false;
107+
103108
if dp < self.num_digits {
104109
round_up = self.digits[dp] >= 5;
105110
if self.digits[dp] == 5 && dp + 1 == self.num_digits {
106111
round_up = self.truncated || ((dp != 0) && (1 & self.digits[dp - 1] != 0))
107112
}
108113
}
114+
109115
if round_up {
110116
n += 1;
111117
}
@@ -121,6 +127,7 @@ impl Decimal {
121127
let mut read_index = self.num_digits;
122128
let mut write_index = self.num_digits + num_new_digits;
123129
let mut n = 0_u64;
130+
124131
while read_index != 0 {
125132
read_index -= 1;
126133
write_index -= 1;
@@ -134,6 +141,7 @@ impl Decimal {
134141
}
135142
n = quotient;
136143
}
144+
137145
while n > 0 {
138146
write_index -= 1;
139147
let quotient = n / 10;
@@ -145,10 +153,13 @@ impl Decimal {
145153
}
146154
n = quotient;
147155
}
156+
148157
self.num_digits += num_new_digits;
158+
149159
if self.num_digits > Self::MAX_DIGITS {
150160
self.num_digits = Self::MAX_DIGITS;
151161
}
162+
152163
self.decimal_point += num_new_digits as i32;
153164
self.trim();
154165
}
@@ -204,8 +215,8 @@ impl Decimal {
204215
}
205216

206217
/// Parse a big integer representation of the float as a decimal.
207-
pub fn parse_decimal(mut s: &[u8]) -> Decimal {
208-
let mut d = Decimal::default();
218+
pub fn parse_decimal_seq(mut s: &[u8]) -> DecimalSeq {
219+
let mut d = DecimalSeq::default();
209220
let start = s;
210221

211222
while let Some((&b'0', s_next)) = s.split_first() {
@@ -223,7 +234,7 @@ pub fn parse_decimal(mut s: &[u8]) -> Decimal {
223234
s = s_next;
224235
}
225236
}
226-
while s.len() >= 8 && d.num_digits + 8 < Decimal::MAX_DIGITS {
237+
while s.len() >= 8 && d.num_digits + 8 < DecimalSeq::MAX_DIGITS {
227238
let v = s.read_u64();
228239
if !is_8digits(v) {
229240
break;
@@ -235,6 +246,7 @@ pub fn parse_decimal(mut s: &[u8]) -> Decimal {
235246
s = s.parse_digits(|digit| d.try_add_digit(digit));
236247
d.decimal_point = s.len() as i32 - first.len() as i32;
237248
}
249+
238250
if d.num_digits != 0 {
239251
// Ignore the trailing zeros if there are any
240252
let mut n_trailing_zeros = 0;
@@ -248,11 +260,12 @@ pub fn parse_decimal(mut s: &[u8]) -> Decimal {
248260
d.decimal_point += n_trailing_zeros as i32;
249261
d.num_digits -= n_trailing_zeros;
250262
d.decimal_point += d.num_digits as i32;
251-
if d.num_digits > Decimal::MAX_DIGITS {
263+
if d.num_digits > DecimalSeq::MAX_DIGITS {
252264
d.truncated = true;
253-
d.num_digits = Decimal::MAX_DIGITS;
265+
d.num_digits = DecimalSeq::MAX_DIGITS;
254266
}
255267
}
268+
256269
if let Some((&ch, s_next)) = s.split_first() {
257270
if ch == b'e' || ch == b'E' {
258271
s = s_next;
@@ -274,13 +287,15 @@ pub fn parse_decimal(mut s: &[u8]) -> Decimal {
274287
d.decimal_point += if neg_exp { -exp_num } else { exp_num };
275288
}
276289
}
277-
for i in d.num_digits..Decimal::MAX_DIGITS_WITHOUT_OVERFLOW {
290+
291+
for i in d.num_digits..DecimalSeq::MAX_DIGITS_WITHOUT_OVERFLOW {
278292
d.digits[i] = 0;
279293
}
294+
280295
d
281296
}
282297

283-
fn number_of_digits_decimal_left_shift(d: &Decimal, mut shift: usize) -> usize {
298+
fn number_of_digits_decimal_left_shift(d: &DecimalSeq, mut shift: usize) -> usize {
284299
#[rustfmt::skip]
285300
const TABLE: [u16; 65] = [
286301
0x0000, 0x0800, 0x0801, 0x0803, 0x1006, 0x1009, 0x100D, 0x1812, 0x1817, 0x181D, 0x2024,
@@ -345,6 +360,7 @@ fn number_of_digits_decimal_left_shift(d: &Decimal, mut shift: usize) -> usize {
345360
let pow5_a = (0x7FF & x_a) as usize;
346361
let pow5_b = (0x7FF & x_b) as usize;
347362
let pow5 = &TABLE_POW5[pow5_a..];
363+
348364
for (i, &p5) in pow5.iter().enumerate().take(pow5_b - pow5_a) {
349365
if i >= d.num_digits {
350366
return num_new_digits - 1;
@@ -356,5 +372,6 @@ fn number_of_digits_decimal_left_shift(d: &Decimal, mut shift: usize) -> usize {
356372
return num_new_digits;
357373
}
358374
}
375+
359376
num_new_digits
360377
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,11 +97,11 @@ use crate::fmt;
9797
use crate::str::FromStr;
9898

9999
mod common;
100-
mod decimal;
101100
mod fpu;
102101
mod slow;
103102
mod table;
104103
// float is used in flt2dec, and all are used in unit tests.
104+
pub mod decimal_seq;
105105
pub mod float;
106106
pub mod lemire;
107107
pub mod number;

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Slow, fallback algorithm for cases the Eisel-Lemire algorithm cannot round.
22
33
use crate::num::dec2flt::common::BiasedFp;
4-
use crate::num::dec2flt::decimal::{Decimal, parse_decimal};
4+
use crate::num::dec2flt::decimal_seq::{DecimalSeq, parse_decimal_seq};
55
use crate::num::dec2flt::float::RawFloat;
66

77
/// Parse the significant digits and biased, binary exponent of a float.
@@ -36,7 +36,7 @@ pub(crate) fn parse_long_mantissa<F: RawFloat>(s: &[u8]) -> BiasedFp {
3636
let fp_zero = BiasedFp::zero_pow2(0);
3737
let fp_inf = BiasedFp::zero_pow2(F::INFINITE_POWER);
3838

39-
let mut d = parse_decimal(s);
39+
let mut d = parse_decimal_seq(s);
4040

4141
// Short-circuit if the value can only be a literal 0 or infinity.
4242
if d.num_digits == 0 || d.decimal_point < -324 {
@@ -50,7 +50,7 @@ pub(crate) fn parse_long_mantissa<F: RawFloat>(s: &[u8]) -> BiasedFp {
5050
let n = d.decimal_point as usize;
5151
let shift = get_shift(n);
5252
d.right_shift(shift);
53-
if d.decimal_point < -Decimal::DECIMAL_POINT_RANGE {
53+
if d.decimal_point < -DecimalSeq::DECIMAL_POINT_RANGE {
5454
return fp_zero;
5555
}
5656
exp2 += shift as i32;
@@ -67,7 +67,7 @@ pub(crate) fn parse_long_mantissa<F: RawFloat>(s: &[u8]) -> BiasedFp {
6767
get_shift((-d.decimal_point) as _)
6868
};
6969
d.left_shift(shift);
70-
if d.decimal_point > Decimal::DECIMAL_POINT_RANGE {
70+
if d.decimal_point > DecimalSeq::DECIMAL_POINT_RANGE {
7171
return fp_inf;
7272
}
7373
exp2 -= shift as i32;
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
use core::num::dec2flt::decimal_seq::{DecimalSeq, parse_decimal_seq};
2+
3+
#[test]
4+
fn test_trim() {
5+
let mut dec = DecimalSeq::default();
6+
let digits = [1, 2, 3, 4];
7+
8+
dec.digits[0..4].copy_from_slice(&digits);
9+
dec.num_digits = 8;
10+
dec.trim();
11+
12+
assert_eq!(dec.digits[0..4], digits);
13+
assert_eq!(dec.num_digits, 4);
14+
}
15+
16+
#[test]
17+
fn test_parse() {
18+
// todo: more tests
19+
let tests = [("1.234", [1, 2, 3, 4], 1)];
20+
21+
for (s, exp_digits, decimal_point) in tests {
22+
let actual = parse_decimal_seq(s.as_bytes());
23+
let mut digits = [0; DecimalSeq::MAX_DIGITS];
24+
digits[..exp_digits.len()].copy_from_slice(&exp_digits);
25+
26+
let expected =
27+
DecimalSeq { num_digits: exp_digits.len(), decimal_point, truncated: false, digits };
28+
29+
assert_eq!(actual, expected);
30+
}
31+
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#![allow(overflowing_literals)]
22

3+
mod decimal_seq;
34
mod float;
45
mod lemire;
56
mod parse;

0 commit comments

Comments
 (0)