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

bid128_scalb #18

Merged
merged 2 commits into from
Feb 3, 2024
Merged
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
28 changes: 28 additions & 0 deletions src/bid128_scalbln.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/* ----------------------------------------------------------------------------- */
/* decimal128 type from Intel decimal math library port to Rust. */
/* decmathlib-rs - Copyright (C) 2023-2024 Carlos Guzmán Álvarez */
/* ----------------------------------------------------------------------------- */
/* Intel® Decimal Floating-Point Math Library - Copyright (c) 2018, Intel Corp. */
/* ----------------------------------------------------------------------------- */

#![allow(non_camel_case_types)]
#![allow(non_upper_case_globals)]
#![allow(non_snake_case)]
#![allow(dead_code)]
#![allow(overflowing_literals)]

use crate::bid128_scalbn::bid128_scalbn;
use crate::d128::{_IDEC_flags, BID_UINT128};

pub (crate) fn bid128_scalbln(x: &BID_UINT128, n: i64, rnd_mode: u32, pfpsf: &mut _IDEC_flags) -> BID_UINT128 {
let mut n1: i32 = n as i32;
n1 = if (n1 as i64) < n {
0x7fffffffi32
} else if (n1 as i64) > n {
0x80000000i32
} else {
n1
};

bid128_scalbn(x, n1, rnd_mode, pfpsf)
}
90 changes: 90 additions & 0 deletions src/bid128_scalbn.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/* ----------------------------------------------------------------------------- */
/* decimal128 type from Intel decimal math library port to Rust. */
/* decmathlib-rs - Copyright (C) 2023-2024 Carlos Guzmán Álvarez */
/* ----------------------------------------------------------------------------- */
/* Intel® Decimal Floating-Point Math Library - Copyright (c) 2018, Intel Corp. */
/* ----------------------------------------------------------------------------- */

#![allow(non_camel_case_types)]
#![allow(non_upper_case_globals)]
#![allow(non_snake_case)]
#![allow(dead_code)]
#![allow(overflowing_literals)]

use crate::bid_internal::{__add_128_128, __set_status_flags, bid_get_BID128, bid_get_BID128_very_fast, unpack_BID128_value};
use crate::constants::{QUIET_MASK64, SNAN_MASK64};
use crate::core::StatusFlags;
use crate::d128::{_IDEC_flags, BID_SINT64, BID_UINT128, BID_UINT32, BID_UINT64};

const DECIMAL_EXPONENT_BIAS_128: i64 = 6176;
const MAX_DECIMAL_EXPONENT_128: i64 = 12287;

pub (crate) fn bid128_scalbn(x: &BID_UINT128, n: i32, rnd_mode: u32, pfpsf: &mut _IDEC_flags) -> BID_UINT128 {
let mut CX: BID_UINT128 = BID_UINT128::default();
let mut CX2: BID_UINT128 = BID_UINT128::default();
let mut CBID_X8: BID_UINT128 = BID_UINT128::default();
let mut res: BID_UINT128 = BID_UINT128::default();
let mut exp64: BID_SINT64;
let mut sign_x: BID_UINT64 = 0;
let mut exponent_x: i32 = 0;

// unpack arguments, check for NaN or Infinity
if unpack_BID128_value(&mut sign_x, &mut exponent_x, &mut CX, x) == 0 {
// x is Inf. or NaN or 0
if (x.w[1] & SNAN_MASK64) == SNAN_MASK64 { // y is sNaN
__set_status_flags(pfpsf, StatusFlags::BID_INVALID_EXCEPTION);
}
res.w[1] = CX.w[1] & QUIET_MASK64;
res.w[0] = CX.w[0];
if CX.w[1] == 0 {
exp64 = (exponent_x as BID_SINT64) + n as BID_SINT64;
if exp64 < 0 {
exp64 = 0;
}
if exp64 > MAX_DECIMAL_EXPONENT_128 {
exp64 = MAX_DECIMAL_EXPONENT_128;
}
exponent_x = exp64 as i32;
bid_get_BID128_very_fast(&mut res, sign_x, exponent_x, &CX);
}
return res;
}

exp64 = (exponent_x as BID_SINT64) + (n as BID_SINT64);
exponent_x = exp64 as i32;

if (exponent_x as BID_UINT32) <= (MAX_DECIMAL_EXPONENT_128 as BID_UINT32) {
bid_get_BID128_very_fast(&mut res, sign_x, exponent_x, &CX);
return res;
}
// check for overflow
if exp64 > MAX_DECIMAL_EXPONENT_128 {
if CX.w[1] < 0x314dc6448d93u64 {
// try to normalize coefficient
loop {
CBID_X8.w[1] = (CX.w[1] << 3) | (CX.w[0] >> 61);
CBID_X8.w[0] = CX.w[0] << 3;
CX2.w[1] = (CX.w[1] << 1) | (CX.w[0] >> 63);
CX2.w[0] = CX.w[0] << 1;
CX = __add_128_128(&CX2, &CBID_X8);

exponent_x -= 1;
exp64 -= 1;

if !(CX.w[1] < 0x314dc6448d93u64 && exp64 > MAX_DECIMAL_EXPONENT_128) {
break;
}
}
}
if exp64 <= MAX_DECIMAL_EXPONENT_128 {
bid_get_BID128_very_fast (&mut res, sign_x, exponent_x, &CX);
return res;
} else {
exponent_x = 0x7fffffff; // overflow
}
}
// exponent < 0
// the BID pack routine will round the coefficient
res = bid_get_BID128(sign_x, exponent_x, &CX, rnd_mode, pfpsf);
res
}
9 changes: 4 additions & 5 deletions src/bid128_string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,17 +252,16 @@ pub (crate) fn bid128_from_string(str: &str, rnd_mode: u32, pfpsf: &mut _IDEC_fl
// c gets first character
c = str.chars().nth(ps);

// if c is nu64 or not equal to a (radix point, negative sign,
// positive sign, or number) it might be SNaN, sNaN, Infinity
// if c is nu64 or not equal to a (radix point, negative sign, positive sign, or number) it might be SNaN, sNaN, Infinity
if c.is_none() || (c != Some('.') && c != Some('-') && c != Some('+') && ((c.unwrap() as i32 - '0' as i32) > 9)) {
let range = &str[ps..];

res.w[0] = 0;
res.w[1] = if range.eq_ignore_ascii_case("inf") || range.eq_ignore_ascii_case("infinity") {
// Infinity
0x7800000000000000u64
} else if range.eq_ignore_ascii_case("snan") { // return sNaN
// case insensitive check for snan
} else if range.len() >= 4 && range[0..4].eq_ignore_ascii_case("snan") { // return sNaN
// case-insensitive check for snan
0x7e00000000000000u64
} else { // return qNaN
0x7c00000000000000u64
Expand All @@ -272,7 +271,7 @@ pub (crate) fn bid128_from_string(str: &str, rnd_mode: u32, pfpsf: &mut _IDEC_fl

let range = &str[ps + 1..];

// if +Inf, -Inf, +Infinity, or -Infinity (case insensitive check for inf)
// if +Inf, -Inf, +Infinity, or -Infinity (case-insensitive check for inf)
if range.eq_ignore_ascii_case("inf") || range.eq_ignore_ascii_case("infinity") {
res.w[0] = 0;
res.w[1] = if c == Some('+') {
Expand Down
9 changes: 7 additions & 2 deletions src/bid_internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ pub (crate) fn bid_handle_UF_128_rem(sgn: BID_UINT64, mut expon: i32, CQ: &BID_U
}

/// Macro for handling BID128 underflow
pub (crate) fn handle_UF_128(sgn: BID_UINT64, mut expon: i32, CQ: &BID_UINT128, rnd_mode: u32, pfpsc: &mut _IDEC_flags) -> BID_UINT128{
pub (crate) fn handle_UF_128(sgn: BID_UINT64, expon: i32, CQ: &BID_UINT128, rnd_mode: u32, pfpsc: &mut _IDEC_flags) -> BID_UINT128 {
let T128: BID_UINT128;
let TP128: BID_UINT128;
let mut Qh: BID_UINT128;
Expand All @@ -449,12 +449,17 @@ pub (crate) fn handle_UF_128(sgn: BID_UINT64, mut expon: i32, CQ: &BID_UINT128,
let mut status: _IDEC_flags = StatusFlags::BID_EXACT_STATUS;
let mut pres: BID_UINT128 = BID_UINT128::default();
let mut CQ: BID_UINT128 = *CQ;
let mut expon = expon;

// UF occurs
if expon + (MAX_FORMAT_DIGITS_128 as i32) < 0 {
if (expon + (MAX_FORMAT_DIGITS_128 as i32)) < 0 {
__set_status_flags(pfpsc, StatusFlags::BID_UNDERFLOW_EXCEPTION | StatusFlags::BID_INEXACT_EXCEPTION);
pres.w[1] = sgn;
pres.w[0] = 0;
if (sgn != 0 && rnd_mode == RoundingMode::BID_ROUNDING_DOWN)
|| (sgn == 0 && rnd_mode == RoundingMode::BID_ROUNDING_UP) {
pres.w[0] = 1u64;
}
return pres;
}

Expand Down
16 changes: 14 additions & 2 deletions src/d128.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ use crate::bid128_mul::bid128_mul;

use crate::bid128_noncomp::*;
use crate::bid128_rem::bid128_rem;
use crate::bid128_scalbln::bid128_scalbln;
use crate::bid128_scalbn::bid128_scalbn;
use crate::bid128_string::{bid128_from_string, bid128_to_string};
use crate::bid128_to_int32::*;
use crate::bid128_to_int64::*;
Expand Down Expand Up @@ -227,8 +229,8 @@ impl decimal128 {

/// Convert a decimal floating-point value represented in string format
/// (decimal character sequence) to 128-bit decimal floating-point format (binary encoding)
pub fn from_string(value: &str, rnd_mode: u32, pfpsf: &mut _IDEC_flags) -> Self {
bid128_from_string(value, rnd_mode, pfpsf)
pub fn from_string(value: &str, rnd_mode: Option<u32>, pfpsf: &mut _IDEC_flags) -> Self {
bid128_from_string(value, rnd_mode.unwrap_or(DEFAULT_ROUNDING_MODE), pfpsf)
}

pub fn from_u64(value: u64) -> Self {
Expand All @@ -245,6 +247,16 @@ impl decimal128 {
bid64_to_bid128(bid, status)
}

/// Returns x * 10^N
pub fn scalbn(&self, n: i32, rnd_mode: Option<u32>, pfpsf: &mut _IDEC_flags) -> Self {
bid128_scalbn(self, n, rnd_mode.unwrap_or(DEFAULT_ROUNDING_MODE), pfpsf)
}

/// Returns x * 10^N
pub fn scalbln(&self, n: i64, rnd_mode: Option<u32>, pfpsf: &mut _IDEC_flags) -> Self {
bid128_scalbln(self, n, rnd_mode.unwrap_or(DEFAULT_ROUNDING_MODE), pfpsf)
}

/// Convert 128-bit decimal floating-point value to 64-bit decimal floating-point format (binary encoding)
pub fn to_decimal64(&self, rnd_mode: Option<u32>, status: &mut _IDEC_flags) -> decimal64 {
bid128_to_bid64(self, rnd_mode.unwrap_or(DEFAULT_ROUNDING_MODE), status)
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,4 @@ mod bid_round;
mod constants;
mod convert;
pub mod core;
pub mod d128;
pub mod d128;mod bid128_scalbn;mod bid128_scalbln;
Loading
Loading