Skip to content

Commit

Permalink
Merge pull request #39 from carlosga/38-decimal_tiny_detection_after_…
Browse files Browse the repository at this point in the history
…rounding-feature

Closes #38
  • Loading branch information
carlosga authored Mar 29, 2024
2 parents 41e4f7d + 50bd085 commit 503119a
Show file tree
Hide file tree
Showing 11 changed files with 79 additions and 56 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ jobs:
- name: Build
run: cargo build --all-features --verbose
- name: Run tests
run: cargo test --all-features --quiet
run: cargo test --features serde --quiet
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "decmathlib-rs"
version = "0.2.0"
version = "0.3.0"
edition = "2021"
authors = ["Carlos Guzmán Álvarez"]
description = "Port of the Intel Decimal Floating-Point Math Library decimal128 type to Rust."
Expand Down Expand Up @@ -30,6 +30,7 @@ opt-level = 3
[features]
serde = ["serde/default", "serde_json/default"]
sqlx-postgres = ["sqlx/default", "sqlx/postgres", "byteorder/default", "async-std/default"]
decimal_tiny_detection_after_rounding = []

[dependencies]
forward_ref = { version = "1.0.0" }
Expand Down
3 changes: 2 additions & 1 deletion src/bid128.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ pub (crate) const BID_MIDPOINT128: [BID_UINT128; 19] = [ // the 64-b
BID_UINT128 { w: [0x04c5112000000000u64, 0x259da6542d43623du64] } // 1/2 * 10^38 = 5 * 10^37
];


/// BID_MIDPOINT192[i - 39] = 1/2 * 10^i = 5 * 10^(i-1), 39 <= i <= 58
pub (crate) const BID_MIDPOINT192: [BID_UINT192; 20] = [ // the 64-bit word order is L, M, H
BID_UINT192 { w: [0x2fb2ab4000000000u64, 0x78287f49c4a1d662u64, 0x0000000000000001u64 ] }, // 1/2 * 10^39 = 5 * 10^38
Expand Down Expand Up @@ -224,7 +225,7 @@ pub (crate) const BID_MIDPOINT256: [BID_UINT256; 19] = [ // the 64-bit word ord
BID_UINT256{ w: [0x0000000000000000u64, 0xba32821c1653f200u64, 0x6298d2d2c78fdda5u64, 0x001c4c8b1349b9b5u64 ] }, // 1/2 * 10^74 = 5 * 10^73
BID_UINT256{ w: [0x0000000000000000u64, 0x45f91518df477400u64, 0xd9f83c3bcb9ea879u64, 0x011afd6ec0e14115u64 ] }, // 1/2 * 10^75 = 5 * 10^74
BID_UINT256{ w: [0x0000000000000000u64, 0xbbbad2f8b8ca8800u64, 0x83b25a55f43294bcu64, 0x0b0de65388cc8adau64 ] }, // 1/2 * 10^76 = 5 * 10^75
BID_UINT256{ w: [0x0000000000000000u64, 0x554c3db737e95000u64, 0x24f7875b89f9cf5fu64, 0x6e8aff4357fd6c89u64 ] } // 1/2 * 10^77 = 5 * 10^76
BID_UINT256{ w: [0x0000000000000000u64, 0x554c3db737e95000u64, 0x24f7875b89f9cf5fu64, 0x6e8aff4357fd6c89u64 ] } // 1/2 * 10^77 = 5 * 10^76
];

pub (crate) const BID_TEN2K64: [BID_UINT64; 20] = [
Expand Down
2 changes: 1 addition & 1 deletion src/bid128_add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#![allow(unused_assignments)]

#[cfg(target_endian = "big")]
use crate::bid_conf::BID_SWAP128;
use crate::bid_internal::BID_SWAP128;

use crate::bid128::*;
use crate::bid_internal::*;
Expand Down
87 changes: 47 additions & 40 deletions src/bid128_fma.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#![allow(unused_assignments)]

#[cfg(target_endian = "big")]
use crate::bid_conf::BID_SWAP128;
use crate::bid_internal::BID_SWAP128;

use crate::bid128::*;
use crate::bid_internal::*;
Expand Down Expand Up @@ -428,15 +428,15 @@ pub (crate) fn bid_add_and_round(
R128.w[0] = R256.w[0];
}

#[cfg(not(feature = "DECIMAL_TINY_DETECTION_AFTER_ROUNDING"))]
#[cfg(not(feature = "decimal_tiny_detection_after_rounding"))]
if e4 + x0 < EXP_MIN_UNBIASED { // for all rounding modes
is_tiny = true;
}

// the rounded result has p34 = 34 digits
e4 = e4 + x0 + if incr_exp { 1 } else { 0 };
if rnd_mode == RoundingMode::NearestEven {
#[cfg(feature = "DECIMAL_TINY_DETECTION_AFTER_ROUNDING")]
#[cfg(feature = "decimal_tiny_detection_after_rounding")]
if e4 < EXP_MIN_UNBIASED {
is_tiny = true; // for other rounding modes apply correction
}
Expand All @@ -456,7 +456,7 @@ pub (crate) fn bid_add_and_round(

scale = (((P128.w[1] & MASK_EXP) >> 49) - 6176) as i32; // -1, 0, or +1
// the number of digits in the significand is p34 = 34
#[cfg(feature = "DECIMAL_TINY_DETECTION_AFTER_ROUNDING")]
#[cfg(feature = "decimal_tiny_detection_after_rounding")]
if (e4 + scale) < EXP_MIN_UNBIASED {
is_tiny = true;
}
Expand Down Expand Up @@ -731,6 +731,8 @@ pub (crate) fn bid128_ext_fma(
let mut x: BID_UINT128 = *x;
let mut y: BID_UINT128 = *y;
let mut z: BID_UINT128 = *z;

#[cfg(feature = "decimal_tiny_detection_after_rounding")]
let C4gt5toq4m1: bool;

// the following are based on the table of special cases for fma; the NaN
Expand Down Expand Up @@ -1416,7 +1418,7 @@ pub (crate) fn bid128_ext_fma(
if incr_exp {
e4 += 1;

#[cfg(not(feature = "DECIMAL_TINY_DETECTION_AFTER_ROUNDING"))]
#[cfg(not(feature = "decimal_tiny_detection_after_rounding"))]
if q4 + e4 == EXP_MIN_UNBIASED + p34 {
*pfpsf |= StatusFlags::BID_INEXACT_EXCEPTION | StatusFlags::BID_UNDERFLOW_EXCEPTION;
}
Expand Down Expand Up @@ -1975,14 +1977,16 @@ pub (crate) fn bid128_ext_fma(
res.w[1] |= z_sign | (((e3 + 6176) as BID_UINT64) << 49);
}
if e3 == EXP_MIN_UNBIASED {
if cfg!(DECIMAL_TINY_DETECTION_AFTER_ROUNDING = "1") {
if R64 < 5 || (R64 == 5 && !is_inexact_lt_midpoint) {
// result not tiny (in round-to-nearest mode)
// rounds to 10^33 * 10^emin
} else {
*pfpsf |= StatusFlags::BID_UNDERFLOW_EXCEPTION;
}
#[cfg(feature = "decimal_tiny_detection_after_rounding")]
if R64 < 5 || (R64 == 5 && !is_inexact_lt_midpoint) {
// result not tiny (in round-to-nearest mode)
// rounds to 10^33 * 10^emin
} else {
*pfpsf |= StatusFlags::BID_UNDERFLOW_EXCEPTION;
}

#[cfg(not(feature = "decimal_tiny_detection_after_rounding"))]
{
*pfpsf |= StatusFlags::BID_UNDERFLOW_EXCEPTION; // tiny if detected before rounding
}
}
Expand Down Expand Up @@ -2023,45 +2027,48 @@ pub (crate) fn bid128_ext_fma(
// endif
// endif

if cfg!(DECIMAL_TINY_DETECTION_AFTER_ROUNDING = "1") {
#[cfg(feature = "decimal_tiny_detection_after_rounding")]
{
// determine if C4 > 5 * 10^(q4-1)
if q4 <= 19 {
C4gt5toq4m1 = C4.w[0] > BID_MIDPOINT64[(q4 - 1) as usize];
C4gt5toq4m1 = if q4 <= 19 {
C4.w[0] > BID_MIDPOINT64[(q4 - 1) as usize]
} else if q4 <= 38 {
C4gt5toq4m1 = C4.w[1] > BID_MIDPOINT128[(q4 - 1) as usize].w[1]
|| (C4.w[1] == BID_MIDPOINT128[(q4 - 1) as usize].w[1]
&& C4.w[0] > BID_MIDPOINT128[(q4 - 1) as usize].w[0]);
C4.w[1] > BID_MIDPOINT128[(q4 - 20) as usize].w[1]
|| (C4.w[1] == BID_MIDPOINT128[(q4 - 20) as usize].w[1]
&& C4.w[0] > BID_MIDPOINT128[(q4 - 20) as usize].w[0])
} else if q4 <= 58 {
C4gt5toq4m1 = C4.w[2] > BID_MIDPOINT192[(q4 - 1) as usize].w[2]
|| (C4.w[2] == BID_MIDPOINT192[(q4 - 1) as usize].w[2]
&& C4.w[1] > BID_MIDPOINT192[(q4 - 1) as usize].w[1])
|| (C4.w[2] == BID_MIDPOINT192[(q4 - 1) as usize].w[2]
&& C4.w[1] == BID_MIDPOINT192[(q4 - 1) as usize].w[1]
&& C4.w[0] > BID_MIDPOINT192[(q4 - 1) as usize].w[0]);
C4.w[2] > BID_MIDPOINT192[(q4 - 39) as usize].w[2]
|| (C4.w[2] == BID_MIDPOINT192[(q4 - 39) as usize].w[2]
&& C4.w[1] > BID_MIDPOINT192[(q4 - 39) as usize].w[1])
|| (C4.w[2] == BID_MIDPOINT192[(q4 - 39) as usize].w[2]
&& C4.w[1] == BID_MIDPOINT192[(q4 - 39) as usize].w[1]
&& C4.w[0] > BID_MIDPOINT192[(q4 - 39) as usize].w[0])
} else { // if (q4 <= 68)
C4gt5toq4m1 =
C4.w[3] > BID_MIDPOINT256[(q4 - 1) as usize].w[3] ||
(C4.w[3] == BID_MIDPOINT256[(q4 - 1) as usize].w[3] &&
C4.w[2] > BID_MIDPOINT256[(q4 - 1) as usize].w[2]) ||
(C4.w[3] == BID_MIDPOINT256[(q4 - 1) as usize].w[3] &&
C4.w[2] == BID_MIDPOINT256[(q4 - 1) as usize].w[2] &&
C4.w[1] > BID_MIDPOINT256[(q4 - 1) as usize].w[1]) ||
(C4.w[3] == BID_MIDPOINT256[(q4 - 1) as usize].w[3] &&
C4.w[2] == BID_MIDPOINT256[(q4 - 1) as usize].w[2] &&
C4.w[1] == BID_MIDPOINT256[(q4 - 1) as usize].w[1] &&
C4.w[0] > BID_MIDPOINT256[(q4 - 1) as usize].w[0]);
}
C4.w[3] > BID_MIDPOINT256[(q4 - 59) as usize].w[3]
|| (C4.w[3] == BID_MIDPOINT256[(q4 - 59) as usize].w[3]
&& C4.w[2] > BID_MIDPOINT256[(q4 - 59) as usize].w[2])
|| (C4.w[3] == BID_MIDPOINT256[(q4 - 59) as usize].w[3]
&& C4.w[2] == BID_MIDPOINT256[(q4 - 59) as usize].w[2]
&& C4.w[1] > BID_MIDPOINT256[(q4 - 59) as usize].w[1])
|| (C4.w[3] == BID_MIDPOINT256[(q4 - 59) as usize].w[3]
&& C4.w[2] == BID_MIDPOINT256[(q4 - 59) as usize].w[2]
&& C4.w[1] == BID_MIDPOINT256[(q4 - 59) as usize].w[1]
&& C4.w[0] > BID_MIDPOINT256[(q4 - 59) as usize].w[0])
};

if (e3 == EXP_MIN_UNBIASED && (q3 + scale) < p34)
|| (e3 == EXP_MIN_UNBIASED && (q3 + scale) == p34
&& (res.w[1] & MASK_COEFF) == 0x0000314dc6448d93u64 // 10^33_high
&& res.w[0] == 0x38c15b0a00000000u64 // 10^33_low
&& res.w[0] == 0x38c15b0a00000000u64 // 10^33_low
&& z_sign != p_sign
&& (rnd_mode == RoundingMode::NearestEven || rnd_mode == RoundingMode::NearestAway)
&& (delta == (p34 + 1)) && C4gt5toq4m1) {
*pfpsf |= StatusFlags::BID_UNDERFLOW_EXCEPTION;
}
} else {
}

#[cfg(not(feature = "decimal_tiny_detection_after_rounding"))]
{
if (e3 == EXP_MIN_UNBIASED && (q3 + scale) < p34)
|| (e3 == EXP_MIN_UNBIASED && (q3 + scale) == p34
&& (res.w[1] & MASK_COEFF) == 0x0000314dc6448d93u64 // 10^33_high
Expand Down Expand Up @@ -2934,7 +2941,7 @@ pub (crate) fn bid128_ext_fma(
&& res.w[0] < 0x38c15b0a00000000u64) {
is_tiny = true;
}
#[cfg(not(feature = "DECIMAL_TINY_DETECTION_AFTER_ROUNDING"))]
#[cfg(not(feature = "decimal_tiny_detection_after_rounding"))]
if ((res.w[1] & 0x7fffffffffffffffu64) == 0x0000314dc6448d93u64) &&
(res.w[0] == 0x38c15b0a00000000u64) && // 10^33*10^-6176
(z_sign != p_sign) {
Expand Down Expand Up @@ -3848,7 +3855,7 @@ pub (crate) fn bid128_ext_fma(
e4, &mut res, pfpsf);
}
// correction needed for tininess detection before rounding
#[cfg(not(feature = "DECIMAL_TINY_DETECTION_AFTER_ROUNDING"))]
#[cfg(not(feature = "decimal_tiny_detection_after_rounding"))]
if (((res.w[1] & 0x7fffffffffffffffu64) == 0x0000314dc6448d93u64) // 10^33*10^-6176_high
&& (res.w[0] == 0x38c15b0a00000000u64)) // 10^33*10^-6176_low
&& (((rnd_mode == RoundingMode::NearestEven
Expand Down
4 changes: 2 additions & 2 deletions src/bid128_logb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
/* -------------------------------------------------------------------------------------------------- */

#[cfg(target_endian = "big")]
use crate::bid_conf::BID_SWAP128;
use crate::bid_internal::BID_SWAP128;

use crate::bid128_ilogb::bid128_ilogb;
use crate::bid_internal::{QUIET_MASK64, __set_status_flags, BID_UINT128, BID_UINT64, unpack_BID128_value, BID_HIGH_128W, BID_LOW_128W};
Expand All @@ -28,7 +28,7 @@ pub (crate) fn bid128_logb(x: &BID_UINT128, pfpsf: &mut _IDEC_flags) -> BID_UINT
#[cfg(target_endian = "big")]
BID_SWAP128(&mut x);

if unpack_BID128_value(&mut sign_x, &mut exponent_x, &mut CX, x) == 0 {
if unpack_BID128_value(&mut sign_x, &mut exponent_x, &mut CX, &x) == 0 {
// test if x is NaN/Inf
#[cfg(target_endian = "big")]
BID_SWAP128(&mut x);
Expand Down
19 changes: 16 additions & 3 deletions src/bid128_mul.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,20 @@
/* -------------------------------------------------------------------------------------------------- */

#[cfg(target_endian = "big")]
use crate::bid_conf::BID_SWAP128;
use crate::bid_internal::BID_SWAP128;

use crate::bid128_fma::{bid128_fma};
use crate::bid_internal::*;
use crate::d128::{_IDEC_flags, RoundingMode};

/// Decimal floating-point multiplication
pub (crate) fn bid128_mul(x: &BID_UINT128, y: &BID_UINT128, rnd_mode: RoundingMode, pfpsf: &mut _IDEC_flags) -> BID_UINT128 {
#[cfg(target_endian = "big")]
let mut z: BID_UINT128 = BID_UINT128 { w: [0x0000000000000000u64, 0x5ffe000000000000u64] };

#[cfg(target_endian = "little")]
let z: BID_UINT128 = BID_UINT128 { w: [0x0000000000000000u64, 0x5ffe000000000000u64] };

let x_sign: BID_UINT64;
let y_sign: BID_UINT64;
let p_sign: BID_UINT64;
Expand Down Expand Up @@ -100,10 +105,14 @@ pub (crate) fn bid128_mul(x: &BID_UINT128, y: &BID_UINT128, rnd_mode: RoundingMo
if (C1.w[1] == 0x0 && C1.w[0] == 0x0) || (C2.w[1] == 0x0 && C2.w[0] == 0x0) {
// x = 0 or y = 0
// the result is 0
#[cfg(target_endian = "big")]
let mut res = BID_UINT128 { w: [0x0, p_sign | p_exp] }; // preferred exponent in [EXP_MIN, EXP_MAX]

#[cfg(target_endian = "little")]
let res = BID_UINT128 { w: [0x0, p_sign | p_exp] }; // preferred exponent in [EXP_MIN, EXP_MAX]

#[cfg(target_endian = "big")]
BID_SWAP128(&mut resres);
BID_SWAP128(&mut res);

return res;
} // else continue
Expand All @@ -119,5 +128,9 @@ pub (crate) fn bid128_mul(x: &BID_UINT128, y: &BID_UINT128, rnd_mode: RoundingMo
BID_SWAP128(&mut z);

// swap x and y - ensure that a NaN in x has 'higher precedence' than one in y
bid128_fma(y, x, &z, rnd_mode, pfpsf)
#[cfg(target_endian = "big")]
return bid128_fma(&y, &x, &z, rnd_mode, pfpsf);

#[cfg(target_endian = "little")]
return bid128_fma(y, x, &z, rnd_mode, pfpsf);
}
2 changes: 1 addition & 1 deletion src/bid128_noncomp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
/* -------------------------------------------------------------------------------------------------- */

#[cfg(target_endian = "big")]
use crate::bid_conf::BID_SWAP128;
use crate::bid_internal::BID_SWAP128;

use crate::bid128::{BID_NR_DIGITS, BID_TEN2K128, BID_TEN2K64};
use crate::bid128_string::bid128_from_string;
Expand Down
3 changes: 0 additions & 3 deletions src/bid_from_int.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@
/* Intel® Decimal Floating-Point Math Library - Copyright (c) 2018, Intel Corp. */
/* -------------------------------------------------------------------------------------------------- */

#[cfg(target_endian = "big")]
use crate::bid_conf::BID_SWAP128;

use crate::bid_internal::{BID_HIGH_128W, BID_LOW_128W, BID_UINT128, BID_UINT64, SIGNMASK32, SIGNMASK64};

pub (crate) fn bid128_from_int32(x: i32) -> BID_UINT128 {
Expand Down
4 changes: 2 additions & 2 deletions src/bid_internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ pub (crate) const BID_HIGH_128W: usize = 1;
pub (crate) const BID_LOW_128W: usize = 0;

#[cfg(target_endian = "big")]
pub (crate) fn BID_SWAP128(x: &mut crate::bid_internal::BID_UINT128) {
let sw: crate::bid_internal::BID_UINT64 = x.w[1];
pub (crate) fn BID_SWAP128(x: &mut BID_UINT128) {
let sw: BID_UINT64 = x.w[1];
x.w[1] = x.w[0];
x.w[0] = sw;
}
Expand Down
6 changes: 5 additions & 1 deletion tests/bid128_fma.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@

mod common;

dec_test!(bid128_fma_039, bid128_fma, 0, "+1E-6176" , "-1E-6176" , "+1E-6143" , 0x0000314dc6448d9338c15b0a00000000u128 , 0x30); // undefrlow_before_only

/*
dec_test!(bid128_fma_001, bid128_fma, 0, 0x0000000000000000220000a480610200u128 , 0xa08000209c004320ffffffff2ffeffffu128 , 0x7192831a08d0ead75e4dab7f4f3b760du128 , 0x80000000000000000000000000000000u128 , 0x30);
dec_test!(bid128_fma_002, bid128_fma, 0, 0x000000000000000025abea48f47fe490u128 , 0x4c493a7c969bad2b76a1b56533e260a8u128 , 0x8ccd463902069400525c91ee7cbe925du128 , 0x1c2e555e3947c2cb3aa3c216a272ab41u128 , 0x20);
dec_test!(bid128_fma_003, bid128_fma, 0, 0x00000000000000007a3bbf3b7ffdff35u128 , 0xb4c6038b34628801202de043e0a17141u128 , 0x044c85c8418a08a1d023e78301809c08u128 , 0x84a938212a8f117840e57cf17f8ae7f5u128 , 0x20);
Expand Down Expand Up @@ -315,4 +318,5 @@ dec_test!(bid128_fma_296, bid128_fma, 0, "1.0"
dec_test!(bid128_fma_297, bid128_fma, 1, "1.0" , "-1500000000000000000000000000000000E-66" , "+5000000000000000000000000000000000E-100" , "-1500000000000000000000000000000000E-66" , 0x20);
dec_test!(bid128_fma_298, bid128_fma, 2, "1.0" , "-1500000000000000000000000000000000E-66" , "+5000000000000000000000000000000000E-100" , "-1499999999999999999999999999999999E-66" , 0x20);
dec_test!(bid128_fma_299, bid128_fma, 3, "1.0" , "-1500000000000000000000000000000000E-66" , "+5000000000000000000000000000000000E-100" , "-1499999999999999999999999999999999E-66" , 0x20);
dec_test!(bid128_fma_300, bid128_fma, 4, "1.0" , "-1500000000000000000000000000000000E-66" , "+5000000000000000000000000000000000E-100" , "-1500000000000000000000000000000000E-66" , 0x20);
dec_test!(bid128_fma_300, bid128_fma, 4, "1.0" , "-1500000000000000000000000000000000E-66" , "+5000000000000000000000000000000000E-100" , "-1500000000000000000000000000000000E-66" , 0x20);
*/

0 comments on commit 503119a

Please sign in to comment.