@@ -45,6 +45,34 @@ fn set_range_errno() {
4545 unsafe { set_abi_errno ( libc:: ERANGE ) } ;
4646}
4747
48+ /// nextafter/nexttoward range-error rule, matching glibc: ERANGE on overflow
49+ /// (finite x -> infinite result) and on underflow (result subnormal-or-zero AND
50+ /// magnitude decreased). nextafter(0, y) -> smallest subnormal is NOT an
51+ /// underflow (magnitude increased from 0), so it sets no errno.
52+ #[ inline]
53+ fn nextafter_range_error_f64 ( x : f64 , r : f64 ) -> bool {
54+ if x. is_nan ( ) || r. is_nan ( ) {
55+ return false ;
56+ }
57+ if x. is_finite ( ) && r. is_infinite ( ) {
58+ return true ; // overflow
59+ }
60+ let sub_or_zero = r == 0.0 || r. abs ( ) < f64:: MIN_POSITIVE ;
61+ sub_or_zero && r. abs ( ) < x. abs ( ) // underflow (magnitude decreased)
62+ }
63+
64+ #[ inline]
65+ fn nextafter_range_error_f32 ( x : f32 , r : f32 ) -> bool {
66+ if x. is_nan ( ) || r. is_nan ( ) {
67+ return false ;
68+ }
69+ if x. is_finite ( ) && r. is_infinite ( ) {
70+ return true ;
71+ }
72+ let sub_or_zero = r == 0.0 || r. abs ( ) < f32:: MIN_POSITIVE ;
73+ sub_or_zero && r. abs ( ) < x. abs ( )
74+ }
75+
4876#[ inline]
4977fn scaling_range_error_f64 ( x : f64 , out : f64 ) -> bool {
5078 x. is_finite ( ) && x != 0.0 && ( out. is_infinite ( ) || out == 0.0 )
@@ -613,7 +641,11 @@ pub unsafe extern "C" fn scalbln(x: f64, n: i64) -> f64 {
613641
614642#[ cfg_attr( not( debug_assertions) , unsafe ( no_mangle) ) ]
615643pub unsafe extern "C" fn nextafter ( x : f64 , y : f64 ) -> f64 {
616- frankenlibc_core:: math:: nextafter ( x, y)
644+ let out = frankenlibc_core:: math:: nextafter ( x, y) ;
645+ if nextafter_range_error_f64 ( x, out) {
646+ set_range_errno ( ) ;
647+ }
648+ out
617649}
618650
619651/// C99 `nexttoward`: next representable f64 toward a long-double direction.
@@ -623,7 +655,11 @@ pub unsafe extern "C" fn nextafter(x: f64, y: f64) -> f64 {
623655 unsafe ( no_mangle)
624656) ]
625657pub unsafe extern "C" fn nexttoward ( x : f64 , y : f64 ) -> f64 {
626- frankenlibc_core:: math:: nexttoward ( x, y)
658+ let out = frankenlibc_core:: math:: nexttoward ( x, y) ;
659+ if nextafter_range_error_f64 ( x, out) {
660+ set_range_errno ( ) ;
661+ }
662+ out
627663}
628664
629665#[ cfg_attr( not( debug_assertions) , unsafe ( no_mangle) ) ]
@@ -633,9 +669,8 @@ pub unsafe extern "C" fn ilogb(x: f64) -> c_int {
633669
634670#[ cfg_attr( not( debug_assertions) , unsafe ( no_mangle) ) ]
635671pub unsafe extern "C" fn logb ( x : f64 ) -> f64 {
636- if x == 0.0 {
637- set_range_errno ( ) ; // pole error: logb(0) = -Infinity
638- }
672+ // glibc raises the FE_DIVBYZERO flag for logb(0) (handled in core) but does
673+ // NOT set errno — leave errno untouched to match.
639674 frankenlibc_core:: math:: logb ( x)
640675}
641676
@@ -811,6 +846,10 @@ pub unsafe extern "C" fn gamma(x: f64) -> f64 {
811846/// Extract significand scaled to [1, 2).
812847#[ cfg_attr( not( debug_assertions) , unsafe ( no_mangle) ) ]
813848pub unsafe extern "C" fn significand ( x : f64 ) -> f64 {
849+ // significand(0) has no normalized mantissa: glibc reports EDOM.
850+ if x == 0.0 {
851+ set_domain_errno ( ) ;
852+ }
814853 frankenlibc_core:: math:: significand ( x)
815854}
816855
@@ -1159,11 +1198,8 @@ pub unsafe extern "C" fn log1pf(x: f32) -> f32 {
11591198
11601199#[ cfg_attr( not( debug_assertions) , unsafe ( no_mangle) ) ]
11611200pub unsafe extern "C" fn logbf ( x : f32 ) -> f32 {
1162- let out = unary_entry_f32 ( x, 4 , frankenlibc_core:: math:: logbf) ;
1163- if x == 0.0 {
1164- set_range_errno ( ) ;
1165- }
1166- out
1201+ // glibc does not set errno for logbf(0) (only the FE_DIVBYZERO flag).
1202+ unary_entry_f32 ( x, 4 , frankenlibc_core:: math:: logbf)
11671203}
11681204
11691205// --- Special functions f32 ---
@@ -1405,7 +1441,11 @@ pub unsafe extern "C" fn scalblnf(x: f32, n: c_long) -> f32 {
14051441
14061442#[ cfg_attr( not( debug_assertions) , unsafe ( no_mangle) ) ]
14071443pub unsafe extern "C" fn nextafterf ( x : f32 , y : f32 ) -> f32 {
1408- binary_entry_f32 ( x, y, 3 , frankenlibc_core:: math:: nextafterf)
1444+ let out = binary_entry_f32 ( x, y, 3 , frankenlibc_core:: math:: nextafterf) ;
1445+ if nextafter_range_error_f32 ( x, out) {
1446+ set_range_errno ( ) ;
1447+ }
1448+ out
14091449}
14101450
14111451/// C99 `nexttowardf`: next representable f32 toward a long-double direction.
@@ -1414,7 +1454,11 @@ pub unsafe extern "C" fn nextafterf(x: f32, y: f32) -> f32 {
14141454 unsafe ( no_mangle)
14151455) ]
14161456pub unsafe extern "C" fn nexttowardf ( x : f32 , y : f64 ) -> f32 {
1417- frankenlibc_core:: math:: nexttowardf ( x, y)
1457+ let out = frankenlibc_core:: math:: nexttowardf ( x, y) ;
1458+ if nextafter_range_error_f32 ( x, out) {
1459+ set_range_errno ( ) ;
1460+ }
1461+ out
14181462}
14191463
14201464#[ cfg( all( target_arch = "x86_64" , any( not( debug_assertions) , test) ) ) ]
@@ -1650,6 +1694,10 @@ pub unsafe extern "C" fn gammaf(x: f32) -> f32 {
16501694
16511695#[ cfg_attr( not( debug_assertions) , unsafe ( no_mangle) ) ]
16521696pub unsafe extern "C" fn significandf ( x : f32 ) -> f32 {
1697+ // significand(0) has no normalized mantissa: glibc reports EDOM.
1698+ if x == 0.0 {
1699+ set_domain_errno ( ) ;
1700+ }
16531701 unary_entry_f32 ( x, 3 , frankenlibc_core:: math:: significandf)
16541702}
16551703
0 commit comments