Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More effisient formatting of numbers with small decimal mantissas #11

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
55 changes: 22 additions & 33 deletions src/d2s.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ pub fn d2d(ieee_mantissa: u64, ieee_exponent: u32) -> FloatingDecimal64 {
let mut vr: u64;
let mut vp: u64 = unsafe { mem::uninitialized() };
let mut vm: u64 = unsafe { mem::uninitialized() };
let e10: i32;
let mut e10: i32;
let mut vm_is_trailing_zeros = false;
let mut vr_is_trailing_zeros = false;
if e2 >= 0 {
Expand Down Expand Up @@ -300,10 +300,9 @@ pub fn d2d(ieee_mantissa: u64, ieee_exponent: u32) -> FloatingDecimal64 {
}

// Step 4: Find the shortest decimal representation in the interval of valid representations.
let mut removed = 0i32;
let mut last_removed_digit = 0u8;
// On average, we remove ~2 digits.
let output = if vm_is_trailing_zeros || vr_is_trailing_zeros {
if vm_is_trailing_zeros || vr_is_trailing_zeros {
let mut last_removed_digit = 0u8;
// General case, which happens rarely (~0.7%).
loop {
let vp_div10 = div10(vp);
Expand All @@ -320,7 +319,7 @@ pub fn d2d(ieee_mantissa: u64, ieee_exponent: u32) -> FloatingDecimal64 {
vr = vr_div10;
vp = vp_div10;
vm = vm_div10;
removed += 1;
e10 += 1;
}
if vm_is_trailing_zeros {
loop {
Expand All @@ -337,57 +336,47 @@ pub fn d2d(ieee_mantissa: u64, ieee_exponent: u32) -> FloatingDecimal64 {
vr = vr_div10;
vp = vp_div10;
vm = vm_div10;
removed += 1;
e10 += 1;
}
}
if vr_is_trailing_zeros && last_removed_digit == 5 && vr % 2 == 0 {
// Round even if the exact number is .....50..0.
last_removed_digit = 4;
}
// We need to take vr + 1 if vr is outside bounds or we need to round up.
vr + ((vr == vm && (!accept_bounds || !vm_is_trailing_zeros)) || last_removed_digit >= 5)
as u64
vr += ((vr == vm && (!accept_bounds || !vm_is_trailing_zeros)) || last_removed_digit >= 5) as u64
} else {
// Specialized for the common case (~99.3%). Percentages below are relative to this.
let mut round_up = false;
let vp_div100 = div100(vp);
let vm_div100 = div100(vm);
// Optimization: remove two digits at a time (~86.2%).
if vp_div100 > vm_div100 {
// Optimization: remove two digits at a time.
loop {
let vp_div100 = div100(vp);
let vm_div100 = div100(vm);
if vp_div100 <= vm_div100 {
break;
}
let vr_div100 = div100(vr);
let vr_mod100 = (vr - 100 * vr_div100) as u32;
round_up = vr_mod100 >= 50;
round_up = (vr - 100 * vr_div100) >= 50;
vr = vr_div100;
vp = vp_div100;
vm = vm_div100;
removed += 2;
e10 += 2;
}
// Loop iterations below (approximately), without optimization above:
// 0: 0.03%, 1: 13.8%, 2: 70.6%, 3: 14.0%, 4: 1.40%, 5: 0.14%, 6+: 0.02%
// Loop iterations below (approximately), with optimization above:
// 0: 70.6%, 1: 27.8%, 2: 1.40%, 3: 0.14%, 4+: 0.02%
loop {
let vp_div10 = div10(vp);
let vm_div10 = div10(vm);
if vp_div10 <= vm_div10 {
break;
}
let vm_div10 = div10(vm);
if div10(vp) > vm_div10 {
let vr_div10 = div10(vr);
let vr_mod10 = (vr - 10 * vr_div10) as u32;
round_up = vr_mod10 >= 5;
round_up = (vr - 10 * vr_div10) >= 5;
vr = vr_div10;
vp = vp_div10;
vm = vm_div10;
removed += 1;
e10 += 1;
}
// We need to take vr + 1 if vr is outside bounds or we need to round up.
vr + (vr == vm || round_up) as u64
vr += (round_up || vr == vm) as u64
};
let exp = e10 + removed;

FloatingDecimal64 {
exponent: exp,
mantissa: output,
exponent: e10,
mantissa: vr,
}
}

Expand Down
49 changes: 30 additions & 19 deletions src/f2s.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ pub fn f2d(ieee_mantissa: u32, ieee_exponent: u32) -> FloatingDecimal32 {
let mut vr: u32;
let mut vp: u32;
let mut vm: u32;
let e10: i32;
let mut e10: i32;
let mut vm_is_trailing_zeros = false;
let mut vr_is_trailing_zeros = false;
let mut last_removed_digit = 0u8;
Expand Down Expand Up @@ -302,8 +302,7 @@ pub fn f2d(ieee_mantissa: u32, ieee_exponent: u32) -> FloatingDecimal32 {
}

// Step 4: Find the shortest decimal representation in the interval of valid representations.
let mut removed = 0i32;
let output = if vm_is_trailing_zeros || vr_is_trailing_zeros {
if vm_is_trailing_zeros || vr_is_trailing_zeros {
// General case, which happens rarely (~4.0%).
while vp / 10 > vm / 10 {
vm_is_trailing_zeros &= vm - (vm / 10) * 10 == 0;
Expand All @@ -312,7 +311,7 @@ pub fn f2d(ieee_mantissa: u32, ieee_exponent: u32) -> FloatingDecimal32 {
vr /= 10;
vp /= 10;
vm /= 10;
removed += 1;
e10 += 1;
}
if vm_is_trailing_zeros {
while vm % 10 == 0 {
Expand All @@ -321,35 +320,47 @@ pub fn f2d(ieee_mantissa: u32, ieee_exponent: u32) -> FloatingDecimal32 {
vr /= 10;
vp /= 10;
vm /= 10;
removed += 1;
e10 += 1;
}
}
if vr_is_trailing_zeros && last_removed_digit == 5 && vr % 2 == 0 {
// Round even if the exact number is .....50..0.
last_removed_digit = 4;
}
// We need to take vr + 1 if vr is outside bounds or we need to round up.
vr + ((vr == vm && (!accept_bounds || !vm_is_trailing_zeros)) || last_removed_digit >= 5)
as u32
vr += ((vr == vm && (!accept_bounds || !vm_is_trailing_zeros)) || last_removed_digit >= 5) as u32
} else {
// Specialized for the common case (~96.0%). Percentages below are relative to this.
// Loop iterations below (approximately):
// 0: 13.6%, 1: 70.7%, 2: 14.1%, 3: 1.39%, 4: 0.14%, 5+: 0.01%
while vp / 10 > vm / 10 {
last_removed_digit = (vr % 10) as u8;
vr /= 10;
vp /= 10;
vm /= 10;
removed += 1;
let mut round_up = last_removed_digit >= 5;
// Optimization: remove two digits at a time.
loop {
let vp_div100 = vp / 100;
let vm_div100 = vm / 100;
if vp_div100 <= vm_div100 {
break;
}
let vr_div100 = vr / 100;
round_up = (vr - 100 * vr_div100) >= 50;
vr = vr_div100;
vp = vp_div100;
vm = vm_div100;
e10 += 2;
}
let vm_div10 = vm / 10;
if vp / 10 > vm_div10 {
let vr_div10 = vr / 10;
round_up = (vr - 10 * vr_div10) >= 5;
vr = vr_div10;
vm = vm_div10;
e10 += 1;
}
// We need to take vr + 1 if vr is outside bounds or we need to round up.
vr + (vr == vm || last_removed_digit >= 5) as u32
vr += (round_up || vr == vm) as u32
};
let exp = e10 + removed;

FloatingDecimal32 {
exponent: exp,
mantissa: output,
exponent: e10,
mantissa: vr,
}
}

Expand Down