@@ -4006,29 +4006,103 @@ pub unsafe extern "C" fn tanpif64x(x: f64) -> f64 {
40064006 unsafe { tanpi ( x) }
40074007}
40084008#[ cfg_attr( not( debug_assertions) , unsafe ( no_mangle) ) ]
4009- pub unsafe extern "C" fn tanpif128 ( x : f64 ) -> f64 {
4010- unsafe { tanpi ( x) }
4009+ pub unsafe extern "C" fn tanpif128 ( x : f128 ) -> f128 {
4010+ // glibc s_tanpi_template, on the byte-exact tanl.
4011+ const PI : f128 = 3.141592653589793238462643383279502884f128 ;
4012+ const EPS : f128 = f128:: from_bits ( 16271u128 << 112 ) ;
4013+ if x. abs ( ) < EPS {
4014+ return PI * x;
4015+ }
4016+ if x. is_infinite ( ) {
4017+ set_domain_errno ( ) ;
4018+ return f128:: from_bits ( ( 0xffff_u128 << 112 ) | ( 1u128 << 111 ) ) ; // x86 neg qNaN
4019+ }
4020+ let mut y = x - 2.0 * ( 0.5 * x) . round ( ) ;
4021+ let mut absy = y. abs ( ) ;
4022+ if absy == 0.0 {
4023+ return ( 0.0f128 ) . copysign ( x) ;
4024+ } else if absy == 1.0 {
4025+ return ( 0.0f128 ) . copysign ( -x) ;
4026+ } else if absy == 0.5 {
4027+ set_range_errno ( ) ;
4028+ return 1.0 / ( 0.0f128 ) . copysign ( y) ;
4029+ } else if absy > 0.5 {
4030+ y -= ( 1.0f128 ) . copysign ( y) ;
4031+ absy = y. abs ( ) ;
4032+ }
4033+ if absy <= 0.25 {
4034+ tanl_f128 ( PI * y)
4035+ } else {
4036+ ( 1.0 / tanl_f128 ( PI * ( 0.5 - absy) ) ) . copysign ( y)
4037+ }
40114038}
40124039
40134040// --- roundeven ---
40144041
4042+ // Round to nearest integer, ties to EVEN, implemented purely in the integer
4043+ // (bit) domain. Unlike a float-arithmetic formulation (x.round() + tie fixup +
4044+ // `as i64` casts), this raises NO floating-point exceptions: glibc's roundeven
4045+ // is the IEEE roundToIntegralTiesToEven operation, which never signals
4046+ // FE_INEXACT (even on non-integers) nor FE_INVALID (on infinities). The earlier
4047+ // implementation produced bit-exact results but spuriously raised FE_INEXACT on
4048+ // every non-integer and FE_INVALID on ±inf (the float->int cast), diverging from
4049+ // glibc's exception-free contract.
40154050fn roundeven_impl ( x : f64 ) -> f64 {
4016- let r = x. round ( ) ;
4017- if ( x - r ) . abs ( ) == 0.5 {
4018- let r2 = if x > 0.0 { x . floor ( ) } else { x . ceil ( ) } ;
4019- if ( r2 as i64 ) % 2 == 0 { r2 } else { r }
4020- } else {
4021- r
4051+ let bits = x. to_bits ( ) ;
4052+ let sign = bits & 0x8000_0000_0000_0000 ;
4053+ let e = ( ( bits >> 52 ) & 0x7ff ) as i32 ;
4054+ // |x| >= 2^52 (and inf/NaN): already integral, return unchanged.
4055+ if e >= 1023 + 52 {
4056+ return x ;
40224057 }
4058+ // |x| < 1: result is ±0 (|x| <= 0.5, ties-to-even rounds 0.5 to 0) or ±1.
4059+ if e < 1023 {
4060+ let mag = f64:: from_bits ( bits & 0x7fff_ffff_ffff_ffff ) ;
4061+ let r = if mag > 0.5 { 1.0_f64 } else { 0.0_f64 } ;
4062+ return f64:: from_bits ( r. to_bits ( ) | sign) ;
4063+ }
4064+ // 1 <= |x| < 2^52: split mantissa into integer/fractional bits.
4065+ let frac_bits = 1075 - e; // 1..=52 fractional mantissa bits
4066+ let half = 1u64 << ( frac_bits - 1 ) ;
4067+ let frac_mask = ( 1u64 << frac_bits) - 1 ;
4068+ let int_part = bits & !frac_mask;
4069+ let frac = bits & frac_mask;
4070+ // Round up when above the halfway point, or exactly halfway with an odd
4071+ // integer (ties to even). Integer add carries naturally into the exponent.
4072+ let round_up = frac > half || ( frac == half && ( int_part & ( 1u64 << frac_bits) ) != 0 ) ;
4073+ let out = if round_up {
4074+ int_part + ( 1u64 << frac_bits)
4075+ } else {
4076+ int_part
4077+ } ;
4078+ f64:: from_bits ( out)
40234079}
40244080fn roundevenf_impl ( x : f32 ) -> f32 {
4025- let r = x. round ( ) ;
4026- if ( x - r ) . abs ( ) == 0.5f32 {
4027- let r2 = if x > 0.0f32 { x . floor ( ) } else { x . ceil ( ) } ;
4028- if ( r2 as i32 ) % 2 == 0 { r2 } else { r }
4029- } else {
4030- r
4081+ let bits = x. to_bits ( ) ;
4082+ let sign = bits & 0x8000_0000 ;
4083+ let e = ( ( bits >> 23 ) & 0xff ) as i32 ;
4084+ // |x| >= 2^23 (and inf/NaN): already integral.
4085+ if e >= 127 + 23 {
4086+ return x ;
40314087 }
4088+ // |x| < 1: ±0 or ±1.
4089+ if e < 127 {
4090+ let mag = f32:: from_bits ( bits & 0x7fff_ffff ) ;
4091+ let r = if mag > 0.5 { 1.0_f32 } else { 0.0_f32 } ;
4092+ return f32:: from_bits ( r. to_bits ( ) | sign) ;
4093+ }
4094+ let frac_bits = 150 - e; // 1..=23 fractional mantissa bits
4095+ let half = 1u32 << ( frac_bits - 1 ) ;
4096+ let frac_mask = ( 1u32 << frac_bits) - 1 ;
4097+ let int_part = bits & !frac_mask;
4098+ let frac = bits & frac_mask;
4099+ let round_up = frac > half || ( frac == half && ( int_part & ( 1u32 << frac_bits) ) != 0 ) ;
4100+ let out = if round_up {
4101+ int_part + ( 1u32 << frac_bits)
4102+ } else {
4103+ int_part
4104+ } ;
4105+ f32:: from_bits ( out)
40324106}
40334107#[ cfg_attr( not( debug_assertions) , unsafe ( no_mangle) ) ]
40344108pub unsafe extern "C" fn roundeven ( x : f64 ) -> f64 {
@@ -5820,8 +5894,10 @@ pub unsafe extern "C" fn lgammaf64x_r(x: f64, signgamp: *mut c_int) -> f64 {
58205894 unsafe { lgamma_r ( x, signgamp) }
58215895}
58225896#[ cfg_attr( not( debug_assertions) , unsafe ( no_mangle) ) ]
5823- pub unsafe extern "C" fn lgammaf128_r ( x : f64 , signgamp : * mut c_int ) -> f64 {
5824- unsafe { lgamma_r ( x, signgamp) }
5897+ pub unsafe extern "C" fn lgammaf128_r ( x : f128 , signgamp : * mut c_int ) -> f128 {
5898+ // ABI-correct binary128 surface; the Bessel/gamma quad kernels are still a
5899+ // tracked parity gap, so preserve the existing f64 implementation quality.
5900+ unsafe { lgamma_r ( x as f64 , signgamp) as f128 }
58255901}
58265902
58275903// =========================================================================
@@ -6379,19 +6455,26 @@ pub unsafe extern "C" fn dfmal(x: f64, y: f64, z: f64) -> f64 {
63796455// Type-generic narrowing operations
63806456#[ cfg_attr( not( debug_assertions) , unsafe ( no_mangle) ) ]
63816457pub unsafe extern "C" fn f32addf32x ( x : f64 , y : f64 ) -> f32 {
6382- ( x + y) as f32
6458+ // _Float32x is `double` on x86_64, so this equals f32addf64/fadd; route
6459+ // through fadd for correct single rounding.
6460+ unsafe { fadd ( x, y) }
63836461}
63846462#[ cfg_attr( not( debug_assertions) , unsafe ( no_mangle) ) ]
63856463pub unsafe extern "C" fn f32addf64 ( x : f64 , y : f64 ) -> f32 {
6386- ( x + y) as f32
6464+ // Identical operation to `fadd` (f32 = round(x+y)). Route through it so this
6465+ // explicit-width spelling gets the correct single rounding (round-to-odd),
6466+ // not the double-rounding `(x+y) as f32`.
6467+ unsafe { fadd ( x, y) }
63876468}
63886469#[ cfg_attr( not( debug_assertions) , unsafe ( no_mangle) ) ]
63896470pub unsafe extern "C" fn f32addf64x ( x : f64 , y : f64 ) -> f32 {
6390- ( x + y) as f32
6471+ // _Float64x is f64 in fl, so this is the same op as f32addf64/fadd; route
6472+ // through fadd for correct single rounding (not double-rounding).
6473+ unsafe { fadd ( x, y) }
63916474}
63926475#[ cfg_attr( not( debug_assertions) , unsafe ( no_mangle) ) ]
6393- pub unsafe extern "C" fn f32addf128 ( x : f64 , y : f64 ) -> f32 {
6394- ( x + y) as f32
6476+ pub unsafe extern "C" fn f32addf128 ( x : f128 , y : f128 ) -> f32 {
6477+ nadd_ro_f128 ( x , y) as f32
63956478}
63966479#[ cfg_attr( not( debug_assertions) , unsafe ( no_mangle) ) ]
63976480pub unsafe extern "C" fn f32xaddf64 ( x : f64 , y : f64 ) -> f64 {
@@ -6420,19 +6503,20 @@ pub unsafe extern "C" fn f64xaddf128(x: f64, y: f64) -> f64 {
64206503}
64216504#[ cfg_attr( not( debug_assertions) , unsafe ( no_mangle) ) ]
64226505pub unsafe extern "C" fn f32divf32x ( x : f64 , y : f64 ) -> f32 {
6423- ( x / y) as f32
6506+ unsafe { fdiv ( x , y) }
64246507}
64256508#[ cfg_attr( not( debug_assertions) , unsafe ( no_mangle) ) ]
64266509pub unsafe extern "C" fn f32divf64 ( x : f64 , y : f64 ) -> f32 {
6427- ( x / y) as f32
6510+ // Route through `fdiv` for correct single rounding (round-to-odd).
6511+ unsafe { fdiv ( x, y) }
64286512}
64296513#[ cfg_attr( not( debug_assertions) , unsafe ( no_mangle) ) ]
64306514pub unsafe extern "C" fn f32divf64x ( x : f64 , y : f64 ) -> f32 {
6431- ( x / y) as f32
6515+ unsafe { fdiv ( x , y) }
64326516}
64336517#[ cfg_attr( not( debug_assertions) , unsafe ( no_mangle) ) ]
6434- pub unsafe extern "C" fn f32divf128 ( x : f64 , y : f64 ) -> f32 {
6435- ( x / y) as f32
6518+ pub unsafe extern "C" fn f32divf128 ( x : f128 , y : f128 ) -> f32 {
6519+ ndiv_ro_f128 ( x , y) as f32
64366520}
64376521#[ cfg_attr( not( debug_assertions) , unsafe ( no_mangle) ) ]
64386522pub unsafe extern "C" fn f32xdivf64 ( x : f64 , y : f64 ) -> f64 {
@@ -6460,19 +6544,20 @@ pub unsafe extern "C" fn f64xdivf128(x: f64, y: f64) -> f64 {
64606544}
64616545#[ cfg_attr( not( debug_assertions) , unsafe ( no_mangle) ) ]
64626546pub unsafe extern "C" fn f32mulf32x ( x : f64 , y : f64 ) -> f32 {
6463- ( x * y) as f32
6547+ unsafe { fmul ( x , y) }
64646548}
64656549#[ cfg_attr( not( debug_assertions) , unsafe ( no_mangle) ) ]
64666550pub unsafe extern "C" fn f32mulf64 ( x : f64 , y : f64 ) -> f32 {
6467- ( x * y) as f32
6551+ // Route through `fmul` for correct single rounding (round-to-odd).
6552+ unsafe { fmul ( x, y) }
64686553}
64696554#[ cfg_attr( not( debug_assertions) , unsafe ( no_mangle) ) ]
64706555pub unsafe extern "C" fn f32mulf64x ( x : f64 , y : f64 ) -> f32 {
6471- ( x * y) as f32
6556+ unsafe { fmul ( x , y) }
64726557}
64736558#[ cfg_attr( not( debug_assertions) , unsafe ( no_mangle) ) ]
6474- pub unsafe extern "C" fn f32mulf128 ( x : f64 , y : f64 ) -> f32 {
6475- ( x * y) as f32
6559+ pub unsafe extern "C" fn f32mulf128 ( x : f128 , y : f128 ) -> f32 {
6560+ nmul_ro_f128 ( x , y) as f32
64766561}
64776562#[ cfg_attr( not( debug_assertions) , unsafe ( no_mangle) ) ]
64786563pub unsafe extern "C" fn f32xmulf64 ( x : f64 , y : f64 ) -> f64 {
@@ -6500,23 +6585,20 @@ pub unsafe extern "C" fn f64xmulf128(x: f64, y: f64) -> f64 {
65006585}
65016586#[ cfg_attr( not( debug_assertions) , unsafe ( no_mangle) ) ]
65026587pub unsafe extern "C" fn f32sqrtf32x ( x : f64 ) -> f32 {
6503- let r = unsafe { sqrt ( x) } ;
6504- r as f32
6588+ unsafe { fsqrt ( x) }
65056589}
65066590#[ cfg_attr( not( debug_assertions) , unsafe ( no_mangle) ) ]
65076591pub unsafe extern "C" fn f32sqrtf64 ( x : f64 ) -> f32 {
6508- let r = unsafe { sqrt ( x ) } ;
6509- r as f32
6592+ // Route through `fsqrt` for correct single rounding (round-to-odd).
6593+ unsafe { fsqrt ( x ) }
65106594}
65116595#[ cfg_attr( not( debug_assertions) , unsafe ( no_mangle) ) ]
65126596pub unsafe extern "C" fn f32sqrtf64x ( x : f64 ) -> f32 {
6513- let r = unsafe { sqrt ( x) } ;
6514- r as f32
6597+ unsafe { fsqrt ( x) }
65156598}
65166599#[ cfg_attr( not( debug_assertions) , unsafe ( no_mangle) ) ]
6517- pub unsafe extern "C" fn f32sqrtf128 ( x : f64 ) -> f32 {
6518- let r = unsafe { sqrt ( x) } ;
6519- r as f32
6600+ pub unsafe extern "C" fn f32sqrtf128 ( x : f128 ) -> f32 {
6601+ nsqrt_ro_f128 ( x) as f32
65206602}
65216603#[ cfg_attr( not( debug_assertions) , unsafe ( no_mangle) ) ]
65226604pub unsafe extern "C" fn f32xsqrtf64 ( x : f64 ) -> f64 {
@@ -6544,19 +6626,20 @@ pub unsafe extern "C" fn f64xsqrtf128(x: f64) -> f64 {
65446626}
65456627#[ cfg_attr( not( debug_assertions) , unsafe ( no_mangle) ) ]
65466628pub unsafe extern "C" fn f32subf32x ( x : f64 , y : f64 ) -> f32 {
6547- ( x - y) as f32
6629+ unsafe { fsub ( x , y) }
65486630}
65496631#[ cfg_attr( not( debug_assertions) , unsafe ( no_mangle) ) ]
65506632pub unsafe extern "C" fn f32subf64 ( x : f64 , y : f64 ) -> f32 {
6551- ( x - y) as f32
6633+ // Route through `fsub` for correct single rounding (round-to-odd).
6634+ unsafe { fsub ( x, y) }
65526635}
65536636#[ cfg_attr( not( debug_assertions) , unsafe ( no_mangle) ) ]
65546637pub unsafe extern "C" fn f32subf64x ( x : f64 , y : f64 ) -> f32 {
6555- ( x - y) as f32
6638+ unsafe { fsub ( x , y) }
65566639}
65576640#[ cfg_attr( not( debug_assertions) , unsafe ( no_mangle) ) ]
6558- pub unsafe extern "C" fn f32subf128 ( x : f64 , y : f64 ) -> f32 {
6559- ( x - y) as f32
6641+ pub unsafe extern "C" fn f32subf128 ( x : f128 , y : f128 ) -> f32 {
6642+ nsub_ro_f128 ( x , y) as f32
65606643}
65616644#[ cfg_attr( not( debug_assertions) , unsafe ( no_mangle) ) ]
65626645pub unsafe extern "C" fn f32xsubf64 ( x : f64 , y : f64 ) -> f64 {
@@ -6584,23 +6667,20 @@ pub unsafe extern "C" fn f64xsubf128(x: f64, y: f64) -> f64 {
65846667}
65856668#[ cfg_attr( not( debug_assertions) , unsafe ( no_mangle) ) ]
65866669pub unsafe extern "C" fn f32fmaf32x ( x : f64 , y : f64 , z : f64 ) -> f32 {
6587- let r = unsafe { fma ( x, y, z) } ;
6588- r as f32
6670+ unsafe { ffma ( x, y, z) }
65896671}
65906672#[ cfg_attr( not( debug_assertions) , unsafe ( no_mangle) ) ]
65916673pub unsafe extern "C" fn f32fmaf64 ( x : f64 , y : f64 , z : f64 ) -> f32 {
6592- let r = unsafe { fma ( x , y , z ) } ;
6593- r as f32
6674+ // Route through `ffma` for correct single rounding (round-to-odd).
6675+ unsafe { ffma ( x , y , z ) }
65946676}
65956677#[ cfg_attr( not( debug_assertions) , unsafe ( no_mangle) ) ]
65966678pub unsafe extern "C" fn f32fmaf64x ( x : f64 , y : f64 , z : f64 ) -> f32 {
6597- let r = unsafe { fma ( x, y, z) } ;
6598- r as f32
6679+ unsafe { ffma ( x, y, z) }
65996680}
66006681#[ cfg_attr( not( debug_assertions) , unsafe ( no_mangle) ) ]
6601- pub unsafe extern "C" fn f32fmaf128 ( x : f64 , y : f64 , z : f64 ) -> f32 {
6602- let r = unsafe { fma ( x, y, z) } ;
6603- r as f32
6682+ pub unsafe extern "C" fn f32fmaf128 ( x : f128 , y : f128 , z : f128 ) -> f32 {
6683+ nfma_ro_f128 ( x, y, z) as f32
66046684}
66056685#[ cfg_attr( not( debug_assertions) , unsafe ( no_mangle) ) ]
66066686pub unsafe extern "C" fn f32xfmaf64 ( x : f64 , y : f64 , z : f64 ) -> f64 {
@@ -13190,14 +13270,14 @@ pub unsafe extern "C" fn __gammal_r_finite(x: f64, signgamp: *mut c_int) -> f64
1319013270 unsafe { crate :: math_abi:: lgamma_r ( x, signgamp) }
1319113271}
1319213272#[ cfg_attr( not( debug_assertions) , unsafe ( no_mangle) ) ]
13193- pub unsafe extern "C" fn __gammaf128_r_finite ( x : f64 , signgamp : * mut c_int ) -> f64 {
13194- unsafe { crate :: math_abi:: lgamma_r ( x, signgamp) }
13273+ pub unsafe extern "C" fn __gammaf128_r_finite ( x : f128 , signgamp : * mut c_int ) -> f128 {
13274+ unsafe { crate :: math_abi:: lgammaf128_r ( x, signgamp) }
1319513275}
1319613276
1319713277// __finite classification variants (f128)
1319813278#[ cfg_attr( not( debug_assertions) , unsafe ( no_mangle) ) ]
13199- pub unsafe extern "C" fn __finitef128 ( x : f64 ) -> c_int {
13200- frankenlibc_core :: math :: finite ( x )
13279+ pub unsafe extern "C" fn __finitef128 ( x : f128 ) -> c_int {
13280+ ( ( ( x . to_bits ( ) >> 112 ) & 0x7fff ) != 0x7fff ) as c_int
1320113281}
1320213282
1320313283#[ cfg( test) ]
0 commit comments