Skip to content
This repository was archived by the owner on Apr 28, 2025. It is now read-only.

Commit e9d7e6c

Browse files
committed
Add scalbnf16 and scalbnf128
The `scalbn` functions are similar enough that they can easily be made generic. Do so and `f16` and `f128` versions.
1 parent 459dd80 commit e9d7e6c

17 files changed

+230
-87
lines changed

crates/libm-macros/src/shared.rs

+14
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,13 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option<Signature>, &[&str])]
134134
None,
135135
&["jn", "yn"],
136136
),
137+
(
138+
// `(f16, i32) -> f16`
139+
FloatTy::F16,
140+
Signature { args: &[Ty::F16, Ty::I32], returns: &[Ty::F16] },
141+
None,
142+
&["scalbnf16", "ldexpf16"],
143+
),
137144
(
138145
// `(f32, i32) -> f32`
139146
FloatTy::F32,
@@ -148,6 +155,13 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option<Signature>, &[&str])]
148155
None,
149156
&["scalbn", "ldexp"],
150157
),
158+
(
159+
// `(f128, i32) -> f128`
160+
FloatTy::F128,
161+
Signature { args: &[Ty::F128, Ty::I32], returns: &[Ty::F128] },
162+
None,
163+
&["scalbnf128", "ldexpf128"],
164+
),
151165
(
152166
// `(f32, &mut f32) -> f32` as `(f32) -> (f32, f32)`
153167
FloatTy::F32,

crates/libm-test/benches/random.rs

+4
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,12 @@ libm_macros::for_each_function! {
127127
| fdimf16
128128
| floorf128
129129
| floorf16
130+
| ldexpf128
131+
| ldexpf16
130132
| rintf128
131133
| rintf16
134+
| scalbnf128
135+
| scalbnf16
132136
| sqrtf128
133137
| sqrtf16
134138
| truncf128

crates/libm-test/src/mpfloat.rs

+34-29
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,10 @@ libm_macros::for_each_function! {
158158
ilogbf,
159159
jn,
160160
jnf,
161-
ldexp,ldexpf,
161+
ldexp,
162+
ldexpf,
163+
ldexpf128,
164+
ldexpf16,
162165
lgamma_r,
163166
lgammaf_r,
164167
modf,
@@ -176,6 +179,8 @@ libm_macros::for_each_function! {
176179
roundf,
177180
scalbn,
178181
scalbnf,
182+
scalbnf128,
183+
scalbnf16,
179184
sincos,sincosf,
180185
trunc,
181186
truncf,
@@ -367,34 +372,6 @@ macro_rules! impl_op_for_ty {
367372
}
368373
}
369374

370-
// `ldexp` and `scalbn` are the same for binary floating point, so just forward all
371-
// methods.
372-
impl MpOp for crate::op::[<ldexp $suffix>]::Routine {
373-
type MpTy = <crate::op::[<scalbn $suffix>]::Routine as MpOp>::MpTy;
374-
375-
fn new_mp() -> Self::MpTy {
376-
<crate::op::[<scalbn $suffix>]::Routine as MpOp>::new_mp()
377-
}
378-
379-
fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet {
380-
<crate::op::[<scalbn $suffix>]::Routine as MpOp>::run(this, input)
381-
}
382-
}
383-
384-
impl MpOp for crate::op::[<scalbn $suffix>]::Routine {
385-
type MpTy = MpFloat;
386-
387-
fn new_mp() -> Self::MpTy {
388-
new_mpfloat::<Self::FTy>()
389-
}
390-
391-
fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet {
392-
this.assign(input.0);
393-
*this <<= input.1;
394-
prep_retval::<Self::FTy>(this, Ordering::Equal)
395-
}
396-
}
397-
398375
impl MpOp for crate::op::[<sincos $suffix>]::Routine {
399376
type MpTy = (MpFloat, MpFloat);
400377

@@ -475,6 +452,34 @@ macro_rules! impl_op_for_ty_all {
475452
prep_retval::<Self::RustRet>(&mut this.0, Ordering::Equal)
476453
}
477454
}
455+
456+
// `ldexp` and `scalbn` are the same for binary floating point, so just forward all
457+
// methods.
458+
impl MpOp for crate::op::[<ldexp $suffix>]::Routine {
459+
type MpTy = <crate::op::[<scalbn $suffix>]::Routine as MpOp>::MpTy;
460+
461+
fn new_mp() -> Self::MpTy {
462+
<crate::op::[<scalbn $suffix>]::Routine as MpOp>::new_mp()
463+
}
464+
465+
fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet {
466+
<crate::op::[<scalbn $suffix>]::Routine as MpOp>::run(this, input)
467+
}
468+
}
469+
470+
impl MpOp for crate::op::[<scalbn $suffix>]::Routine {
471+
type MpTy = MpFloat;
472+
473+
fn new_mp() -> Self::MpTy {
474+
new_mpfloat::<Self::FTy>()
475+
}
476+
477+
fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet {
478+
this.assign(input.0);
479+
*this <<= input.1;
480+
prep_retval::<Self::FTy>(this, Ordering::Equal)
481+
}
482+
}
478483
}
479484
};
480485
}

crates/libm-test/src/precision.rs

+4
Original file line numberDiff line numberDiff line change
@@ -585,8 +585,12 @@ fn int_float_common<F1: Float, F2: Float>(
585585
DEFAULT
586586
}
587587

588+
#[cfg(f16_enabled)]
589+
impl MaybeOverride<(f16, i32)> for SpecialCase {}
588590
impl MaybeOverride<(f32, i32)> for SpecialCase {}
589591
impl MaybeOverride<(f64, i32)> for SpecialCase {}
592+
#[cfg(f128_enabled)]
593+
impl MaybeOverride<(f128, i32)> for SpecialCase {}
590594

591595
impl MaybeOverride<(f32, f32, f32)> for SpecialCase {
592596
fn check_float<F: Float>(

crates/libm-test/tests/compare_built_musl.rs

+4
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,12 @@ libm_macros::for_each_function! {
8989
fdimf16,
9090
floorf128,
9191
floorf16,
92+
ldexpf128,
93+
ldexpf16,
9294
rintf128,
9395
rintf16,
96+
scalbnf128,
97+
scalbnf16,
9498
sqrtf128,
9599
sqrtf16,
96100
truncf128,

crates/util/src/main.rs

+4
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,12 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) {
9696
| fdimf16
9797
| floorf128
9898
| floorf16
99+
| ldexpf128
100+
| ldexpf16
99101
| rintf128
100102
| rintf16
103+
| scalbnf128
104+
| scalbnf16
101105
| sqrtf128
102106
| sqrtf16
103107
| truncf128

etc/function-definitions.json

+28
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,18 @@
506506
],
507507
"type": "f32"
508508
},
509+
"ldexpf128": {
510+
"sources": [
511+
"src/math/ldexpf128.rs"
512+
],
513+
"type": "f128"
514+
},
515+
"ldexpf16": {
516+
"sources": [
517+
"src/math/ldexpf16.rs"
518+
],
519+
"type": "f16"
520+
},
509521
"lgamma": {
510522
"sources": [
511523
"src/libm_helper.rs",
@@ -698,16 +710,32 @@
698710
"scalbn": {
699711
"sources": [
700712
"src/libm_helper.rs",
713+
"src/math/generic/scalbn.rs",
701714
"src/math/scalbn.rs"
702715
],
703716
"type": "f64"
704717
},
705718
"scalbnf": {
706719
"sources": [
720+
"src/math/generic/scalbn.rs",
707721
"src/math/scalbnf.rs"
708722
],
709723
"type": "f32"
710724
},
725+
"scalbnf128": {
726+
"sources": [
727+
"src/math/generic/scalbn.rs",
728+
"src/math/scalbnf128.rs"
729+
],
730+
"type": "f128"
731+
},
732+
"scalbnf16": {
733+
"sources": [
734+
"src/math/generic/scalbn.rs",
735+
"src/math/scalbnf16.rs"
736+
],
737+
"type": "f16"
738+
},
711739
"sin": {
712740
"sources": [
713741
"src/libm_helper.rs",

etc/function-list.txt

+4
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ jn
7373
jnf
7474
ldexp
7575
ldexpf
76+
ldexpf128
77+
ldexpf16
7678
lgamma
7779
lgamma_r
7880
lgammaf
@@ -103,6 +105,8 @@ round
103105
roundf
104106
scalbn
105107
scalbnf
108+
scalbnf128
109+
scalbnf16
106110
sin
107111
sincos
108112
sincosf

src/math/generic/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ mod fabs;
44
mod fdim;
55
mod floor;
66
mod rint;
7+
mod scalbn;
78
mod sqrt;
89
mod trunc;
910

@@ -13,5 +14,6 @@ pub use fabs::fabs;
1314
pub use fdim::fdim;
1415
pub use floor::floor;
1516
pub use rint::rint;
17+
pub use scalbn::scalbn;
1618
pub use sqrt::sqrt;
1719
pub use trunc::trunc;

src/math/generic/scalbn.rs

+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
use super::super::{CastFrom, CastInto, Float, IntTy, MinInt};
2+
3+
/// Scale the exponent.
4+
///
5+
/// From N3220:
6+
///
7+
/// > The scalbn and scalbln functions compute `x * b^n`, where `b = FLT_RADIX` if the return type
8+
/// > of the function is a standard floating type, or `b = 10` if the return type of the function
9+
/// > is a decimal floating type. A range error occurs for some finite x, depending on n.
10+
/// >
11+
/// > [...]
12+
/// >
13+
/// > * `scalbn(±0, n)` returns `±0`.
14+
/// > * `scalbn(x, 0)` returns `x`.
15+
/// > * `scalbn(±∞, n)` returns `±∞`.
16+
/// >
17+
/// > If the calculation does not overflow or underflow, the returned value is exact and
18+
/// > independent of the current rounding direction mode.
19+
pub fn scalbn<F: Float>(mut x: F, mut n: i32) -> F
20+
where
21+
u32: CastInto<F::Int>,
22+
F::Int: CastFrom<i32>,
23+
F::Int: CastFrom<u32>,
24+
{
25+
if n == 0 || x == F::ZERO || x.is_nan() || x.is_infinite() {
26+
return x;
27+
}
28+
29+
// Bits including the implicit bit
30+
let sig_total_bits = F::SIG_BITS + 1;
31+
32+
// Maximum and minimum values when biased
33+
let exp_max: i32 = F::EXP_BIAS as i32;
34+
let exp_min = -(exp_max - 1);
35+
let exp_min_with_subnorm = -((F::EXP_BIAS + F::SIG_BITS + 1) as i32);
36+
37+
// let x_exp = x.exp();
38+
// let x_sig = x.frac();
39+
40+
if n > exp_max {
41+
return F::INFINITY * x.signum();
42+
}
43+
44+
if n < exp_min_with_subnorm {
45+
return F::ZERO * x.signum();
46+
}
47+
48+
// 2 ^ Emax, where Emax is the maximum biased exponent value (1023 for f64)
49+
let f_exp_max = F::from_bits(F::Int::cast_from(F::EXP_BIAS << 1) << F::SIG_BITS);
50+
// 2 ^ Emin, where Emin is the minimum biased exponent value (-1022 for f64)
51+
let f_exp_min = F::from_bits(IntTy::<F>::ONE << F::SIG_BITS);
52+
// 2 ^ sig_total_bits, representation of what can be accounted for with subnormals
53+
let f_exp_subnorm = F::from_bits((F::EXP_BIAS + sig_total_bits).cast() << F::SIG_BITS);
54+
55+
// std::println!("{exp_max} {exp_min} {n}");
56+
// std::dbg!(x, exp_max, exp_min, n);
57+
58+
if n > exp_max {
59+
x *= f_exp_max;
60+
n -= exp_max;
61+
// std::dbg!(11, x, n);
62+
if n > exp_max {
63+
x *= f_exp_max;
64+
n -= exp_max;
65+
// std::dbg!(12, x, n);
66+
if n > exp_max {
67+
n = exp_max;
68+
// std::dbg!(13, x, n);
69+
}
70+
}
71+
} else if n < exp_min {
72+
let mul = f_exp_min * f_exp_subnorm;
73+
let add = (exp_max - 1) - sig_total_bits as i32;
74+
75+
x *= mul;
76+
n += add;
77+
// std::dbg!(21, x, n);
78+
if n < exp_min {
79+
x *= mul;
80+
n += add;
81+
// std::dbg!(22, x, n);
82+
if n < exp_min {
83+
n = exp_min;
84+
// std::dbg!(23, x, n);
85+
}
86+
}
87+
}
88+
89+
x * F::from_bits(F::Int::cast_from(F::EXP_BIAS as i32 + n) << F::SIG_BITS)
90+
}
91+
92+
// DELETE
93+
94+
extern crate std;
95+
96+
#[test]
97+
fn testme() {
98+
assert_eq!(scalbn::<f16>(f16::from_bits(0x6ecb), -1336428830), f16::ZERO);
99+
}
100+
101+
#[test]
102+
fn testme2() {
103+
// assert_eq!(scalbn(-f64::INFINITY, -2147033648), f64::ZERO);
104+
}

src/math/ldexpf128.rs

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
2+
pub fn ldexpf128(x: f128, n: i32) -> f128 {
3+
super::scalbnf128(x, n)
4+
}

src/math/ldexpf16.rs

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
2+
pub fn ldexpf16(x: f16, n: i32) -> f16 {
3+
super::scalbnf16(x, n)
4+
}

0 commit comments

Comments
 (0)