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

Commit 0b159b2

Browse files
committed
f64 wip
1 parent bdd1e03 commit 0b159b2

File tree

6 files changed

+238
-20
lines changed

6 files changed

+238
-20
lines changed

crates/libm-test/src/f8_impl.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ pub struct f8(u8);
2020
impl Float for f8 {
2121
type Int = u8;
2222
type SignedInt = i8;
23-
type ExpInt = i8;
2423

2524
const ZERO: Self = Self(0b0_0000_000);
2625
const NEG_ZERO: Self = Self(0b1_0000_000);
@@ -62,8 +61,8 @@ impl Float for f8 {
6261
self.0 & Self::SIGN_MASK != 0
6362
}
6463

65-
fn exp(self) -> Self::ExpInt {
66-
unimplemented!()
64+
fn exp(self) -> i32 {
65+
((self.to_bits() & Self::EXP_MASK) >> Self::SIG_BITS) as i32
6766
}
6867

6968
fn from_bits(a: Self::Int) -> Self {

src/math/fma.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ fn mul(x: u64, y: u64) -> (u64, u64) {
4242
/// according to the rounding mode characterized by the value of FLT_ROUNDS.
4343
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
4444
pub fn fma(x: f64, y: f64, z: f64) -> f64 {
45+
if true {
46+
return super::generic::fma(x, y, z, scalbn);
47+
}
48+
4549
let x1p63: f64 = f64::from_bits(0x43e0000000000000); // 0x1p63 === 2 ^ 63
4650
let x0_ffffff8p_63 = f64::from_bits(0x3bfffffff0000000); // 0x0.ffffff8p-63
4751

src/math/fmaf128.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
#[expect(unused)]
12
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
23
pub fn fmaf128(x: f128, y: f128, z: f128) -> f128 {
3-
super::generic::fma(x, y, z)
4+
// super::generic::fma(x, y, z)
5+
todo!()
46
}

src/math/generic/fma.rs

Lines changed: 205 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,216 @@
11
#![allow(unused)]
22

3+
use core::ops::{Shl, Shr};
4+
35
use super::super::fenv::{
46
FE_INEXACT, FE_TONEAREST, FE_UNDERFLOW, feclearexcept, fegetround, feraiseexcept, fetestexcept,
57
};
8+
use super::super::support::{DInt, HInt, Int};
69
use super::super::{CastFrom, CastInto, Float, IntTy, MinInt};
710

11+
const ZEROINFNAN: i32 = 0x7ff - 0x3ff - 52 - 1;
12+
813
/// Fused multiply add.
9-
pub fn fma<F: Float>(x: F, y: F, z: F) -> F {
10-
todo!()
14+
pub fn fma<F: Float>(x: F, y: F, z: F, scbn: impl FnOnce(F, i32) -> F) -> F
15+
where
16+
F::Int: CastFrom<u32>,
17+
F::Int: HInt,
18+
F::Int: Shr<i32, Output = F::Int>,
19+
F::Int: Shl<i32, Output = F::Int>,
20+
F::SignedInt: CastInto<F>,
21+
u32: CastInto<F::Int>,
22+
bool: CastInto<F::Int>,
23+
{
24+
let one = F::Int::ONE;
25+
let zero = F::Int::ZERO;
26+
27+
let nx = Norm::from_float(x);
28+
let ny = Norm::from_float(y);
29+
let nz = Norm::from_float(z);
30+
31+
if nx.e >= ZEROINFNAN || ny.e >= ZEROINFNAN {
32+
return x * y + z;
33+
}
34+
if nz.e >= ZEROINFNAN {
35+
if nz.e > ZEROINFNAN {
36+
/* z==0 */
37+
return x * y + z;
38+
}
39+
return z;
40+
}
41+
42+
let zhi: F::Int;
43+
let zlo: F::Int;
44+
45+
let (mut rlo, mut rhi) = nx.m.widen_mul(ny.m).lo_hi();
46+
47+
let mut e: i32 = nx.e + ny.e;
48+
let mut d: i32 = nz.e - e;
49+
50+
let fbits = F::BITS as i32;
51+
52+
if d > 0 {
53+
if d < fbits {
54+
zlo = nz.m << d;
55+
zhi = nz.m >> (fbits - d);
56+
} else {
57+
zlo = zero;
58+
zhi = nz.m;
59+
e = nz.e - fbits;
60+
d -= fbits;
61+
if d == 0 {
62+
} else if d < fbits {
63+
rlo = (rhi << (fbits - d)) | (rlo >> d) | ((rlo << (fbits - d)) != zero).cast();
64+
rhi = rhi >> d;
65+
} else {
66+
rlo = one;
67+
rhi = zero;
68+
}
69+
}
70+
} else {
71+
zhi = zero;
72+
d = -d;
73+
if d == 0 {
74+
zlo = nz.m;
75+
} else if d < fbits {
76+
zlo = (nz.m >> d) | ((nz.m << (fbits - d)) != zero).cast();
77+
} else {
78+
zlo = one;
79+
}
80+
}
81+
82+
/* add */
83+
let mut neg: bool = nx.neg ^ ny.neg;
84+
let samesign: bool = neg ^ nz.neg;
85+
let mut nonzero: i32 = 1;
86+
if samesign {
87+
/* r += z */
88+
rlo = rlo.wrapping_add(zlo);
89+
rhi += zhi + (rlo < zlo).cast();
90+
} else {
91+
/* r -= z */
92+
let (res, borrow) = rlo.overflowing_sub(zlo);
93+
rlo = res;
94+
rhi = rhi.wrapping_sub(zhi.wrapping_add(borrow.cast()));
95+
if (rhi >> (F::BITS - 1)) != zero {
96+
rlo = (rlo.signed()).wrapping_neg().unsigned();
97+
rhi = (rhi.signed()).wrapping_neg().unsigned() - (rlo != zero).cast();
98+
neg = !neg;
99+
}
100+
nonzero = (rhi != zero) as i32;
101+
}
102+
103+
/* set rhi to top 63bit of the result (last bit is sticky) */
104+
if nonzero != 0 {
105+
e += fbits;
106+
d = rhi.leading_zeros() as i32 - 1;
107+
/* note: d > 0 */
108+
rhi = (rhi << d) | (rlo >> (fbits - d)) | ((rlo << d) != zero).cast();
109+
} else if rlo != zero {
110+
d = rlo.leading_zeros() as i32 - 1;
111+
if d < 0 {
112+
rhi = (rlo >> 1) | (rlo & one);
113+
} else {
114+
rhi = rlo << d;
115+
}
116+
} else {
117+
/* exact +-0 */
118+
return x * y + z;
119+
}
120+
e -= d;
121+
122+
/* convert to double */
123+
let mut i: F::SignedInt = rhi.signed(); /* i is in [1<<62,(1<<63)-1] */
124+
if neg {
125+
i = -i;
126+
}
127+
let mut r: F = i.cast(); /* |r| is in [0x1p62,0x1p63] */
128+
129+
if e < -1022 - 62 {
130+
/* result is subnormal before rounding */
131+
if e == -1022 - 63 {
132+
let mut c: F = foo::<F>();
133+
if neg {
134+
c = -c;
135+
}
136+
if r == c {
137+
/* min normal after rounding, underflow depends
138+
on arch behaviour which can be imitated by
139+
a double to float conversion */
140+
// let fltmin: f32 = (x0_ffffff8p_63 * f32::MIN_POSITIVE as f64 * r) as f32;
141+
// return f64::MIN_POSITIVE / f32::MIN_POSITIVE as f64 * fltmin as f64;
142+
todo!()
143+
}
144+
/* one bit is lost when scaled, add another top bit to
145+
only round once at conversion if it is inexact */
146+
if (rhi << (F::SIG_BITS + 1)) != zero {
147+
let tmp: F::Int = (rhi >> 1) | (rhi & one) | (one << (F::BITS - 2));
148+
i = tmp.signed();
149+
if neg {
150+
i = -i;
151+
}
152+
r = i.cast();
153+
r = (F::ONE + F::ONE) * r - c; /* remove top bit */
154+
155+
/* raise underflow portably, such that it
156+
cannot be optimized away */
157+
{
158+
// let tiny: f64 = f64::MIN_POSITIVE / f32::MIN_POSITIVE as f64 * r;
159+
// r += (tiny * tiny) * (r - r);
160+
todo!()
161+
}
162+
}
163+
} else {
164+
/* only round once when scaled */
165+
d = 10;
166+
i = (((rhi >> d) | ((rhi << (fbits - d)) != zero).cast()) << d).signed();
167+
if neg {
168+
i = -i;
169+
}
170+
r = i.cast();
171+
}
172+
}
173+
174+
// todo!()
175+
//
176+
scbn(r, e)
177+
}
178+
179+
struct Norm<F: Float> {
180+
m: F::Int,
181+
e: i32,
182+
neg: bool,
183+
}
184+
185+
impl<F: Float> Norm<F> {
186+
fn from_float(x: F) -> Self
187+
where
188+
F::Int: CastFrom<u32>,
189+
u32: CastInto<F::Int>,
190+
{
191+
let mut ix = x.to_bits();
192+
let mut e = x.exp();
193+
let neg = x.is_sign_negative();
194+
if e.is_zero() {
195+
ix = (x * foo::<F>()).to_bits();
196+
e = x.exp();
197+
e = if e != 0 { e - (F::BITS as i32) } else { 0x800 };
198+
}
199+
ix &= F::SIG_MASK;
200+
ix |= F::IMPLICIT_BIT;
201+
ix <<= 1;
202+
e -= 0x3ff + 52 + 1;
203+
204+
Self { m: ix, e, neg }
205+
}
206+
}
207+
208+
// 1p63 magic number
209+
fn foo<F: Float>() -> F
210+
where
211+
u32: CastInto<F::Int>,
212+
{
213+
F::from_parts(false, (F::BITS - 1).cast(), F::Int::ZERO)
11214
}
12215

13216
/// FMA implementation when there is a larger float type available.

src/math/support/float_traits.rs

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
use core::{fmt, mem, ops};
1+
use core::ops::{self, Neg};
2+
use core::{fmt, mem};
23

34
use super::int_traits::{Int, MinInt};
45

@@ -23,10 +24,9 @@ pub trait Float:
2324
type Int: Int<OtherSign = Self::SignedInt, Unsigned = Self::Int>;
2425

2526
/// A int of the same width as the float
26-
type SignedInt: Int + MinInt<OtherSign = Self::Int, Unsigned = Self::Int>;
27-
28-
/// An int capable of containing the exponent bits plus a sign bit. This is signed.
29-
type ExpInt: Int;
27+
type SignedInt: Int
28+
+ MinInt<OtherSign = Self::Int, Unsigned = Self::Int>
29+
+ Neg<Output = Self::SignedInt>;
3030

3131
const ZERO: Self;
3232
const NEG_ZERO: Self;
@@ -98,7 +98,7 @@ pub trait Float:
9898
}
9999

100100
/// Returns the exponent, not adjusting for bias.
101-
fn exp(self) -> Self::ExpInt;
101+
fn exp(self) -> i32;
102102

103103
/// Returns the significand with no implicit bit (or the "fractional" part)
104104
fn frac(self) -> Self::Int {
@@ -145,15 +145,13 @@ macro_rules! float_impl {
145145
$ty:ident,
146146
$ity:ident,
147147
$sity:ident,
148-
$expty:ident,
149148
$bits:expr,
150149
$significand_bits:expr,
151150
$from_bits:path
152151
) => {
153152
impl Float for $ty {
154153
type Int = $ity;
155154
type SignedInt = $sity;
156-
type ExpInt = $expty;
157155

158156
const ZERO: Self = 0.0;
159157
const NEG_ZERO: Self = -0.0;
@@ -190,8 +188,8 @@ macro_rules! float_impl {
190188
fn is_sign_negative(self) -> bool {
191189
self.is_sign_negative()
192190
}
193-
fn exp(self) -> Self::ExpInt {
194-
((self.to_bits() & Self::EXP_MASK) >> Self::SIG_BITS) as Self::ExpInt
191+
fn exp(self) -> i32 {
192+
((self.to_bits() & Self::EXP_MASK) >> Self::SIG_BITS) as i32
195193
}
196194
fn from_bits(a: Self::Int) -> Self {
197195
Self::from_bits(a)
@@ -225,11 +223,11 @@ macro_rules! float_impl {
225223
}
226224

227225
#[cfg(f16_enabled)]
228-
float_impl!(f16, u16, i16, i8, 16, 10, f16::from_bits);
229-
float_impl!(f32, u32, i32, i16, 32, 23, f32_from_bits);
230-
float_impl!(f64, u64, i64, i16, 64, 52, f64_from_bits);
226+
float_impl!(f16, u16, i16, 16, 10, f16::from_bits);
227+
float_impl!(f32, u32, i32, 32, 23, f32_from_bits);
228+
float_impl!(f64, u64, i64, 64, 52, f64_from_bits);
231229
#[cfg(f128_enabled)]
232-
float_impl!(f128, u128, i128, i16, 128, 112, f128::from_bits);
230+
float_impl!(f128, u128, i128, 128, 112, f128::from_bits);
233231

234232
/* FIXME(msrv): vendor some things that are not const stable at our MSRV */
235233

src/math/support/int_traits.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ pub trait Int:
8282
fn wrapping_shr(self, other: u32) -> Self;
8383
fn rotate_left(self, other: u32) -> Self;
8484
fn overflowing_add(self, other: Self) -> (Self, bool);
85+
fn overflowing_sub(self, other: Self) -> (Self, bool);
8586
fn leading_zeros(self) -> u32;
8687
fn ilog2(self) -> u32;
8788
}
@@ -140,6 +141,10 @@ macro_rules! int_impl_common {
140141
<Self>::overflowing_add(self, other)
141142
}
142143

144+
fn overflowing_sub(self, other: Self) -> (Self, bool) {
145+
<Self>::overflowing_sub(self, other)
146+
}
147+
143148
fn leading_zeros(self) -> u32 {
144149
<Self>::leading_zeros(self)
145150
}
@@ -383,9 +388,16 @@ cast_into!(i64);
383388
cast_into!(u128);
384389
cast_into!(i128);
385390

391+
cast_into!(i64; f32);
392+
cast_into!(i64; f64);
386393
cast_into!(f32; f64);
387394
cast_into!(f64; f32);
388395

396+
cast_into!(bool; u16);
397+
cast_into!(bool; u32);
398+
cast_into!(bool; u64);
399+
cast_into!(bool; u128);
400+
389401
cfg_if! {
390402
if #[cfg(f16_enabled)] {
391403
cast_into!(f16; f32, f64);

0 commit comments

Comments
 (0)