Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
1cac5fa
Look for `python3` first on MacOS, not `py`
jyn514 Feb 13, 2025
477a2ee
std::fs: slightly reformat `remove_dir_all` error docs
jieyouxu Feb 18, 2025
2c752bc
Undeprecate env::home_dir
arlosi Feb 20, 2025
9323ba5
Remove MaybeForgetReturn suggestion
compiler-errors Feb 20, 2025
b340545
[illumos] attempt to use posix_spawn to spawn processes
sunshowers Feb 11, 2025
a8bff87
Stabilize [T]::split_off... methods
cramertj Feb 28, 2025
ea13ff7
add exclude to config.toml
Shourya742 Feb 16, 2025
d9ceab9
add test for exclude feature
Shourya742 Feb 16, 2025
9206960
Add change info to change tracker
Shourya742 Feb 16, 2025
3998690
compiletest: remove legacy `Makefile`-based `run-make` support
jieyouxu Feb 5, 2025
413b824
run-make: remove `tools.mk`
jieyouxu Feb 5, 2025
9b17c98
run-make: update test suite README
jieyouxu Feb 5, 2025
ed168e7
run-make-support: remove outdated comments
jieyouxu Mar 1, 2025
efec638
tidy: remove legacy `Makefile` checks
jieyouxu Feb 5, 2025
b0d6a84
rustc-dev-guide: remove mentions of legacy `Makefile` run-make infra
jieyouxu Feb 5, 2025
95b030f
triagebot: stop backlinking to the test porting tracking issue
jieyouxu Feb 5, 2025
a0ed304
float: Update some constants to `pub(crate)`
tgross35 Dec 9, 2024
5a2da96
dec2flt: Update documentation of existing methods
tgross35 Dec 9, 2024
49a2d4c
dec2flt: Rename `Decimal` to `DecimalSeq`
tgross35 Dec 9, 2024
626d2c5
dec2flt: Rename `Number` to `Decimal`
tgross35 Dec 9, 2024
6c34daf
dec2flt: Rename fields to be consistent with documented notation
tgross35 Dec 9, 2024
19a909a
dec2flt: Refactor float traits
tgross35 Dec 9, 2024
37e223c
dec2flt: Refactor the fast path
tgross35 Dec 9, 2024
133705c
[rustdoc] hide item that is not marked as doc(inline) and whose src i…
xizheyin Feb 27, 2025
1f930e7
Rollup merge of #134063 - tgross35:dec2flt-refactoring, r=Noratrieb
tgross35 Mar 4, 2025
a0e1ffa
Rollup merge of #136581 - jieyouxu:makefile-be-gone, r=Kobzol
tgross35 Mar 4, 2025
9d3bbb5
Rollup merge of #136975 - jyn514:macos-x, r=Mark-Simulacrum
tgross35 Mar 4, 2025
b74c6d3
Rollup merge of #137147 - Shourya742:2025-02-16-support-exclude-in-co…
tgross35 Mar 4, 2025
1396b94
Rollup merge of #137240 - jieyouxu:remove_dir_all, r=Mark-Simulacrum
tgross35 Mar 4, 2025
1a13de3
Rollup merge of #137303 - compiler-errors:maybe-forgor, r=cjgillot
tgross35 Mar 4, 2025
99d631c
Rollup merge of #137327 - arlosi:home-dir, r=Mark-Simulacrum
tgross35 Mar 4, 2025
5d8da22
Rollup merge of #137463 - sunshowers:illumos-posix-spawn, r=Mark-Simu…
tgross35 Mar 4, 2025
b4ae140
Rollup merge of #137534 - xizheyin:issue-137342, r=GuillaumeGomez
tgross35 Mar 4, 2025
acdf367
Rollup merge of #137829 - cramertj:stabilize-split-off, r=jhpratt
tgross35 Mar 4, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
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.

Additionally, add some tests to validate internal behavior.
  • Loading branch information
tgross35 committed Mar 2, 2025
commit 49a2d4c757e27f915d15664ba92bbe0d3f590a8e
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@

use crate::num::dec2flt::common::{ByteSlice, is_8digits};

/// A decimal floating-point number.
#[derive(Clone)]
pub(super) struct Decimal {
/// A decimal floating-point number, represented as a sequence of decimal digits.
#[derive(Clone, Debug, PartialEq)]
pub struct DecimalSeq {
/// The number of significant digits in the decimal.
pub num_digits: usize,
/// The offset of the decimal point in the significant digits.
Expand All @@ -24,13 +24,13 @@ pub(super) struct Decimal {
pub digits: [u8; Self::MAX_DIGITS],
}

impl Default for Decimal {
impl Default for DecimalSeq {
fn default() -> Self {
Self { num_digits: 0, decimal_point: 0, truncated: false, digits: [0; Self::MAX_DIGITS] }
}
}

impl Decimal {
impl DecimalSeq {
/// The maximum number of digits required to unambiguously round up to a 64-bit float.
///
/// For an IEEE 754 binary64 float, this required 767 digits. So we store the max digits + 1.
Expand All @@ -55,7 +55,8 @@ impl Decimal {
///
/// In Python:
/// `-emin + p2 + math.floor((emin+ 1)*math.log(2, b)-math.log(1-2**(-p2), b))`
pub(super) const MAX_DIGITS: usize = 768;
pub const MAX_DIGITS: usize = 768;

/// The max decimal digits that can be exactly represented in a 64-bit integer.
pub(super) const MAX_DIGITS_WITHOUT_OVERFLOW: usize = 19;
pub(super) const DECIMAL_POINT_RANGE: i32 = 2047;
Expand All @@ -73,12 +74,12 @@ impl Decimal {

/// Trim trailing zeros from the buffer.
// FIXME(tgross35): this could be `.rev().position()` if perf is okay
pub(super) fn trim(&mut self) {
// All of the following calls to `Decimal::trim` can't panic because:
pub fn trim(&mut self) {
// All of the following calls to `DecimalSeq::trim` can't panic because:
//
// 1. `parse_decimal` sets `num_digits` to a max of `Decimal::MAX_DIGITS`.
// 1. `parse_decimal` sets `num_digits` to a max of `DecimalSeq::MAX_DIGITS`.
// 2. `right_shift` sets `num_digits` to `write_index`, which is bounded by `num_digits`.
// 3. `left_shift` `num_digits` to a max of `Decimal::MAX_DIGITS`.
// 3. `left_shift` `num_digits` to a max of `DecimalSeq::MAX_DIGITS`.
//
// Trim is only called in `right_shift` and `left_shift`.
debug_assert!(self.num_digits <= Self::MAX_DIGITS);
Expand All @@ -93,21 +94,26 @@ impl Decimal {
} else if self.decimal_point >= Self::MAX_DIGITS_WITHOUT_OVERFLOW as i32 {
return 0xFFFF_FFFF_FFFF_FFFF_u64;
}

let dp = self.decimal_point as usize;
let mut n = 0_u64;

for i in 0..dp {
n *= 10;
if i < self.num_digits {
n += self.digits[i] as u64;
}
}

let mut round_up = false;

if dp < self.num_digits {
round_up = self.digits[dp] >= 5;
if self.digits[dp] == 5 && dp + 1 == self.num_digits {
round_up = self.truncated || ((dp != 0) && (1 & self.digits[dp - 1] != 0))
}
}

if round_up {
n += 1;
}
Expand All @@ -123,6 +129,7 @@ impl Decimal {
let mut read_index = self.num_digits;
let mut write_index = self.num_digits + num_new_digits;
let mut n = 0_u64;

while read_index != 0 {
read_index -= 1;
write_index -= 1;
Expand All @@ -136,6 +143,7 @@ impl Decimal {
}
n = quotient;
}

while n > 0 {
write_index -= 1;
let quotient = n / 10;
Expand All @@ -147,10 +155,13 @@ impl Decimal {
}
n = quotient;
}

self.num_digits += num_new_digits;

if self.num_digits > Self::MAX_DIGITS {
self.num_digits = Self::MAX_DIGITS;
}

self.decimal_point += num_new_digits as i32;
self.trim();
}
Expand Down Expand Up @@ -206,8 +217,8 @@ impl Decimal {
}

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

while let Some((&b'0', s_next)) = s.split_first() {
Expand All @@ -225,7 +236,7 @@ pub(super) fn parse_decimal(mut s: &[u8]) -> Decimal {
s = s_next;
}
}
while s.len() >= 8 && d.num_digits + 8 < Decimal::MAX_DIGITS {
while s.len() >= 8 && d.num_digits + 8 < DecimalSeq::MAX_DIGITS {
let v = s.read_u64();
if !is_8digits(v) {
break;
Expand All @@ -237,6 +248,7 @@ pub(super) fn parse_decimal(mut s: &[u8]) -> Decimal {
s = s.parse_digits(|digit| d.try_add_digit(digit));
d.decimal_point = s.len() as i32 - first.len() as i32;
}

if d.num_digits != 0 {
// Ignore the trailing zeros if there are any
let mut n_trailing_zeros = 0;
Expand All @@ -250,11 +262,12 @@ pub(super) fn parse_decimal(mut s: &[u8]) -> Decimal {
d.decimal_point += n_trailing_zeros as i32;
d.num_digits -= n_trailing_zeros;
d.decimal_point += d.num_digits as i32;
if d.num_digits > Decimal::MAX_DIGITS {
if d.num_digits > DecimalSeq::MAX_DIGITS {
d.truncated = true;
d.num_digits = Decimal::MAX_DIGITS;
d.num_digits = DecimalSeq::MAX_DIGITS;
}
}

if let Some((&ch, s_next)) = s.split_first() {
if ch == b'e' || ch == b'E' {
s = s_next;
Expand All @@ -276,13 +289,15 @@ pub(super) fn parse_decimal(mut s: &[u8]) -> Decimal {
d.decimal_point += if neg_exp { -exp_num } else { exp_num };
}
}
for i in d.num_digits..Decimal::MAX_DIGITS_WITHOUT_OVERFLOW {

for i in d.num_digits..DecimalSeq::MAX_DIGITS_WITHOUT_OVERFLOW {
d.digits[i] = 0;
}

d
}

fn number_of_digits_decimal_left_shift(d: &Decimal, mut shift: usize) -> usize {
fn number_of_digits_decimal_left_shift(d: &DecimalSeq, mut shift: usize) -> usize {
#[rustfmt::skip]
const TABLE: [u16; 65] = [
0x0000, 0x0800, 0x0801, 0x0803, 0x1006, 0x1009, 0x100D, 0x1812, 0x1817, 0x181D, 0x2024,
Expand Down Expand Up @@ -347,6 +362,7 @@ fn number_of_digits_decimal_left_shift(d: &Decimal, mut shift: usize) -> usize {
let pow5_a = (0x7FF & x_a) as usize;
let pow5_b = (0x7FF & x_b) as usize;
let pow5 = &TABLE_POW5[pow5_a..];

for (i, &p5) in pow5.iter().enumerate().take(pow5_b - pow5_a) {
if i >= d.num_digits {
return num_new_digits - 1;
Expand All @@ -358,5 +374,6 @@ fn number_of_digits_decimal_left_shift(d: &Decimal, mut shift: usize) -> usize {
return num_new_digits;
}
}

num_new_digits
}
2 changes: 1 addition & 1 deletion library/core/src/num/dec2flt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ use crate::fmt;
use crate::str::FromStr;

mod common;
mod decimal;
pub mod decimal_seq;
mod fpu;
mod slow;
mod table;
Expand Down
8 changes: 4 additions & 4 deletions library/core/src/num/dec2flt/slow.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Slow, fallback algorithm for cases the Eisel-Lemire algorithm cannot round.

use crate::num::dec2flt::common::BiasedFp;
use crate::num::dec2flt::decimal::{Decimal, parse_decimal};
use crate::num::dec2flt::decimal_seq::{DecimalSeq, parse_decimal_seq};
use crate::num::dec2flt::float::RawFloat;

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

let mut d = parse_decimal(s);
let mut d = parse_decimal_seq(s);

// Short-circuit if the value can only be a literal 0 or infinity.
if d.num_digits == 0 || d.decimal_point < -324 {
Expand All @@ -50,7 +50,7 @@ pub(crate) fn parse_long_mantissa<F: RawFloat>(s: &[u8]) -> BiasedFp {
let n = d.decimal_point as usize;
let shift = get_shift(n);
d.right_shift(shift);
if d.decimal_point < -Decimal::DECIMAL_POINT_RANGE {
if d.decimal_point < -DecimalSeq::DECIMAL_POINT_RANGE {
return fp_zero;
}
exp2 += shift as i32;
Expand All @@ -67,7 +67,7 @@ pub(crate) fn parse_long_mantissa<F: RawFloat>(s: &[u8]) -> BiasedFp {
get_shift((-d.decimal_point) as _)
};
d.left_shift(shift);
if d.decimal_point > Decimal::DECIMAL_POINT_RANGE {
if d.decimal_point > DecimalSeq::DECIMAL_POINT_RANGE {
return fp_inf;
}
exp2 -= shift as i32;
Expand Down
30 changes: 30 additions & 0 deletions library/coretests/tests/num/dec2flt/decimal_seq.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use core::num::dec2flt::decimal_seq::{DecimalSeq, parse_decimal_seq};

#[test]
fn test_trim() {
let mut dec = DecimalSeq::default();
let digits = [1, 2, 3, 4];

dec.digits[0..4].copy_from_slice(&digits);
dec.num_digits = 8;
dec.trim();

assert_eq!(dec.digits[0..4], digits);
assert_eq!(dec.num_digits, 4);
}

#[test]
fn test_parse() {
let tests = [("1.234", [1, 2, 3, 4], 1)];

for (s, exp_digits, decimal_point) in tests {
let actual = parse_decimal_seq(s.as_bytes());
let mut digits = [0; DecimalSeq::MAX_DIGITS];
digits[..exp_digits.len()].copy_from_slice(&exp_digits);

let expected =
DecimalSeq { num_digits: exp_digits.len(), decimal_point, truncated: false, digits };

assert_eq!(actual, expected);
}
}
1 change: 1 addition & 0 deletions library/coretests/tests/num/dec2flt/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#![allow(overflowing_literals)]

mod decimal_seq;
mod float;
mod lemire;
mod parse;
Expand Down