Skip to content

Commit b7b8a26

Browse files
committed
Add frexpf16, frexpf128, ilogbf16, and ilogbf128
1 parent 897e60a commit b7b8a26

File tree

15 files changed

+251
-139
lines changed

15 files changed

+251
-139
lines changed

crates/libm-macros/src/shared.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,16 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option<Signature>, &[&str])]
258258
None,
259259
&["fmaf128"],
260260
),
261+
(
262+
// `(f16) -> i32`
263+
FloatTy::F16,
264+
Signature {
265+
args: &[Ty::F16],
266+
returns: &[Ty::I32],
267+
},
268+
None,
269+
&["ilogbf16"],
270+
),
261271
(
262272
// `(f32) -> i32`
263273
FloatTy::F32,
@@ -278,6 +288,16 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option<Signature>, &[&str])]
278288
None,
279289
&["ilogb"],
280290
),
291+
(
292+
// `(f128) -> i32`
293+
FloatTy::F128,
294+
Signature {
295+
args: &[Ty::F128],
296+
returns: &[Ty::I32],
297+
},
298+
None,
299+
&["ilogbf128"],
300+
),
281301
(
282302
// `(i32, f32) -> f32`
283303
FloatTy::F32,
@@ -364,6 +384,19 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option<Signature>, &[&str])]
364384
}),
365385
&["modf"],
366386
),
387+
(
388+
// `(f16, &mut c_int) -> f16` as `(f16) -> (f16, i32)`
389+
FloatTy::F16,
390+
Signature {
391+
args: &[Ty::F16],
392+
returns: &[Ty::F16, Ty::I32],
393+
},
394+
Some(Signature {
395+
args: &[Ty::F16, Ty::MutCInt],
396+
returns: &[Ty::F16],
397+
}),
398+
&["frexpf16"],
399+
),
367400
(
368401
// `(f32, &mut c_int) -> f32` as `(f32) -> (f32, i32)`
369402
FloatTy::F32,
@@ -390,6 +423,19 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option<Signature>, &[&str])]
390423
}),
391424
&["frexp", "lgamma_r"],
392425
),
426+
(
427+
// `(f128, &mut c_int) -> f128` as `(f128) -> (f128, i32)`
428+
FloatTy::F128,
429+
Signature {
430+
args: &[Ty::F128],
431+
returns: &[Ty::F128, Ty::I32],
432+
},
433+
Some(Signature {
434+
args: &[Ty::F128, Ty::MutCInt],
435+
returns: &[Ty::F128],
436+
}),
437+
&["frexpf128"],
438+
),
393439
(
394440
// `(f32, f32, &mut c_int) -> f32` as `(f32, f32) -> (f32, i32)`
395441
FloatTy::F32,

crates/util/src/main.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,10 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) {
119119
| fminimumf16
120120
| fmodf128
121121
| fmodf16
122+
| frexpf128
123+
| frexpf16
124+
| ilogbf128
125+
| ilogbf16
122126
| ldexpf128
123127
| ldexpf16
124128
| rintf128

libm-test/benches/random.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,10 @@ libm_macros::for_each_function! {
159159
| fminimumf16
160160
| fmodf128
161161
| fmodf16
162+
| frexpf128
163+
| frexpf16
164+
| ilogbf128
165+
| ilogbf16
162166
| ldexpf128
163167
| ldexpf16
164168
| rintf128

libm-test/src/generate/case_list.rs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -449,14 +449,24 @@ fn fmodf16_cases() -> Vec<TestCase<op::fmodf16::Routine>> {
449449
vec![]
450450
}
451451

452-
fn frexp_cases() -> Vec<TestCase<op::frexp::Routine>> {
452+
#[cfg(f16_enabled)]
453+
fn frexpf16_cases() -> Vec<TestCase<op::frexpf16::Routine>> {
453454
vec![]
454455
}
455456

456457
fn frexpf_cases() -> Vec<TestCase<op::frexpf::Routine>> {
457458
vec![]
458459
}
459460

461+
fn frexp_cases() -> Vec<TestCase<op::frexp::Routine>> {
462+
vec![]
463+
}
464+
465+
#[cfg(f128_enabled)]
466+
fn frexpf128_cases() -> Vec<TestCase<op::frexpf128::Routine>> {
467+
vec![]
468+
}
469+
460470
fn hypot_cases() -> Vec<TestCase<op::hypot::Routine>> {
461471
vec![]
462472
}
@@ -465,14 +475,24 @@ fn hypotf_cases() -> Vec<TestCase<op::hypotf::Routine>> {
465475
vec![]
466476
}
467477

468-
fn ilogb_cases() -> Vec<TestCase<op::ilogb::Routine>> {
478+
#[cfg(f16_enabled)]
479+
fn ilogbf16_cases() -> Vec<TestCase<op::ilogbf16::Routine>> {
469480
vec![]
470481
}
471482

472483
fn ilogbf_cases() -> Vec<TestCase<op::ilogbf::Routine>> {
473484
vec![]
474485
}
475486

487+
fn ilogb_cases() -> Vec<TestCase<op::ilogb::Routine>> {
488+
vec![]
489+
}
490+
491+
#[cfg(f128_enabled)]
492+
fn ilogbf128_cases() -> Vec<TestCase<op::ilogbf128::Routine>> {
493+
vec![]
494+
}
495+
476496
fn j0_cases() -> Vec<TestCase<op::j0::Routine>> {
477497
vec![]
478498
}

libm-test/src/mpfloat.rs

Lines changed: 41 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,12 @@ libm_macros::for_each_function! {
162162
fmodf16,
163163
frexp,
164164
frexpf,
165+
frexpf128,
166+
frexpf16,
165167
ilogb,
166168
ilogbf,
169+
ilogbf128,
170+
ilogbf16,
167171
jn,
168172
jnf,
169173
ldexp,
@@ -323,43 +327,6 @@ macro_rules! impl_op_for_ty {
323327
}
324328
}
325329

326-
impl MpOp for crate::op::[<frexp $suffix>]::Routine {
327-
type MpTy = MpFloat;
328-
329-
fn new_mp() -> Self::MpTy {
330-
new_mpfloat::<Self::FTy>()
331-
}
332-
333-
fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet {
334-
this.assign(input.0);
335-
let exp = this.frexp_mut();
336-
(prep_retval::<Self::FTy>(this, Ordering::Equal), exp)
337-
}
338-
}
339-
340-
impl MpOp for crate::op::[<ilogb $suffix>]::Routine {
341-
type MpTy = MpFloat;
342-
343-
fn new_mp() -> Self::MpTy {
344-
new_mpfloat::<Self::FTy>()
345-
}
346-
347-
fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet {
348-
this.assign(input.0);
349-
350-
// `get_exp` follows `frexp` for `0.5 <= |m| < 1.0`. Adjust the exponent by
351-
// one to scale the significand to `1.0 <= |m| < 2.0`.
352-
this.get_exp().map(|v| v - 1).unwrap_or_else(|| {
353-
if this.is_infinite() {
354-
i32::MAX
355-
} else {
356-
// Zero or NaN
357-
i32::MIN
358-
}
359-
})
360-
}
361-
}
362-
363330
impl MpOp for crate::op::[<jn $suffix>]::Routine {
364331
type MpTy = MpFloat;
365332

@@ -504,6 +471,43 @@ macro_rules! impl_op_for_ty_all {
504471
}
505472
}
506473

474+
impl MpOp for crate::op::[<frexp $suffix>]::Routine {
475+
type MpTy = MpFloat;
476+
477+
fn new_mp() -> Self::MpTy {
478+
new_mpfloat::<Self::FTy>()
479+
}
480+
481+
fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet {
482+
this.assign(input.0);
483+
let exp = this.frexp_mut();
484+
(prep_retval::<Self::FTy>(this, Ordering::Equal), exp)
485+
}
486+
}
487+
488+
impl MpOp for crate::op::[<ilogb $suffix>]::Routine {
489+
type MpTy = MpFloat;
490+
491+
fn new_mp() -> Self::MpTy {
492+
new_mpfloat::<Self::FTy>()
493+
}
494+
495+
fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet {
496+
this.assign(input.0);
497+
498+
// `get_exp` follows `frexp` for `0.5 <= |m| < 1.0`. Adjust the exponent by
499+
// one to scale the significand to `1.0 <= |m| < 2.0`.
500+
this.get_exp().map(|v| v - 1).unwrap_or_else(|| {
501+
if this.is_infinite() {
502+
i32::MAX
503+
} else {
504+
// Zero or NaN
505+
i32::MIN
506+
}
507+
})
508+
}
509+
}
510+
507511
// `ldexp` and `scalbn` are the same for binary floating point, so just forward all
508512
// methods.
509513
impl MpOp for crate::op::[<ldexp $suffix>]::Routine {

libm-test/src/test_traits.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,3 +451,15 @@ impl_tuples!(
451451
(f32, f32);
452452
(f64, f64);
453453
);
454+
455+
#[cfg(f16_enabled)]
456+
impl_tuples!(
457+
(f16, i32);
458+
(f16, f16);
459+
);
460+
461+
#[cfg(f128_enabled)]
462+
impl_tuples!(
463+
(f128, i32);
464+
(f128, f128);
465+
);

libm-test/tests/compare_built_musl.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,10 @@ libm_macros::for_each_function! {
122122
fminimumf16,
123123
fmodf128,
124124
fmodf16,
125+
frexpf128,
126+
frexpf16,
127+
ilogbf128,
128+
ilogbf16,
125129
ldexpf128,
126130
ldexpf16,
127131
rintf128,

libm/src/math/frexp.rs

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,33 @@
1+
/// Decompose a float into a normalized value within the range `[0.5, 1)`, and a power of 2.
2+
///
3+
/// That is, `x * 2^p` will represent the input value.
4+
#[cfg(f16_enabled)]
15
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
2-
pub fn frexp(x: f64) -> (f64, i32) {
3-
let mut y = x.to_bits();
4-
let ee = ((y >> 52) & 0x7ff) as i32;
6+
pub fn frexpf16(x: f16) -> (f16, i32) {
7+
super::generic::frexp(x)
8+
}
59

6-
if ee == 0 {
7-
if x != 0.0 {
8-
let x1p64 = f64::from_bits(0x43f0000000000000);
9-
let (x, e) = frexp(x * x1p64);
10-
return (x, e - 64);
11-
}
12-
return (x, 0);
13-
} else if ee == 0x7ff {
14-
return (x, 0);
15-
}
10+
/// Decompose a float into a normalized value within the range `[0.5, 1)`, and a power of 2.
11+
///
12+
/// That is, `x * 2^p` will represent the input value.
13+
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
14+
pub fn frexpf(x: f32) -> (f32, i32) {
15+
super::generic::frexp(x)
16+
}
1617

17-
let e = ee - 0x3fe;
18-
y &= 0x800fffffffffffff;
19-
y |= 0x3fe0000000000000;
20-
return (f64::from_bits(y), e);
18+
/// Decompose a float into a normalized value within the range `[0.5, 1)`, and a power of 2.
19+
///
20+
/// That is, `x * 2^p` will represent the input value.
21+
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
22+
pub fn frexp(x: f64) -> (f64, i32) {
23+
super::generic::frexp(x)
24+
}
25+
26+
/// Decompose a float into a normalized value within the range `[0.5, 1)`, and a power of 2.
27+
///
28+
/// That is, `x * 2^p` will represent the input value.
29+
#[cfg(f128_enabled)]
30+
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
31+
pub fn frexpf128(x: f128) -> (f128, i32) {
32+
super::generic::frexp(x)
2133
}

libm/src/math/frexpf.rs

Lines changed: 0 additions & 22 deletions
This file was deleted.

libm/src/math/generic/frexp.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
use super::super::{CastFrom, Float, MinInt};
2+
3+
pub fn frexp<F: Float>(x: F) -> (F, i32) {
4+
let mut ix = x.to_bits();
5+
let ee = x.ex();
6+
7+
if ee == 0 {
8+
if x != F::ZERO {
9+
// normalize via multiplication; 1p64 for `f64`
10+
let magic = F::from_parts(false, F::EXP_BIAS + F::BITS, F::Int::ZERO);
11+
magic.to_bits();
12+
13+
let (x, e) = frexp(x * magic);
14+
return (x, e - F::BITS as i32);
15+
}
16+
return (x, 0);
17+
} else if ee == F::EXP_SAT {
18+
return (x, 0);
19+
}
20+
21+
let e = ee as i32 - (F::EXP_BIAS as i32 - 1);
22+
ix &= F::SIGN_MASK | F::SIG_MASK;
23+
ix |= F::Int::cast_from(F::EXP_BIAS - 1) << F::SIG_BITS;
24+
(F::from_bits(ix), e)
25+
}

0 commit comments

Comments
 (0)