Skip to content

Commit 88c3242

Browse files
committed
Auto merge of #42431 - nagisa:core-float-2, r=alexcrichton
Fix NaN handling in is_sign_negative/positive This would be my proposed fix for the #42425 provided we decide it is indeed a problem. Note this would technically be a breaking change to a stable API. We might want to consider deprecating these methods and adding new ones.
2 parents 4079e61 + 3b9fe77 commit 88c3242

File tree

4 files changed

+40
-46
lines changed

4 files changed

+40
-46
lines changed

src/libcore/num/f32.rs

+13-6
Original file line numberDiff line numberDiff line change
@@ -205,18 +205,25 @@ impl Float for f32 {
205205
}
206206
}
207207

208-
/// Returns `true` if `self` is positive, including `+0.0` and
209-
/// `Float::infinity()`.
208+
/// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with
209+
/// positive sign bit and positive infinity.
210210
#[inline]
211211
fn is_sign_positive(self) -> bool {
212-
self > 0.0 || (1.0 / self) == INFINITY
212+
!self.is_sign_negative()
213213
}
214214

215-
/// Returns `true` if `self` is negative, including `-0.0` and
216-
/// `Float::neg_infinity()`.
215+
/// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with
216+
/// negative sign bit and negative infinity.
217217
#[inline]
218218
fn is_sign_negative(self) -> bool {
219-
self < 0.0 || (1.0 / self) == NEG_INFINITY
219+
// IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus
220+
// applies to zeros and NaNs as well.
221+
#[repr(C)]
222+
union F32Bytes {
223+
f: f32,
224+
b: u32
225+
}
226+
unsafe { F32Bytes { f: self }.b & 0x8000_0000 != 0 }
220227
}
221228

222229
/// Returns the reciprocal (multiplicative inverse) of the number.

src/libcore/num/f64.rs

+11-6
Original file line numberDiff line numberDiff line change
@@ -205,18 +205,23 @@ impl Float for f64 {
205205
}
206206
}
207207

208-
/// Returns `true` if `self` is positive, including `+0.0` and
209-
/// `Float::infinity()`.
208+
/// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with
209+
/// positive sign bit and positive infinity.
210210
#[inline]
211211
fn is_sign_positive(self) -> bool {
212-
self > 0.0 || (1.0 / self) == INFINITY
212+
!self.is_sign_negative()
213213
}
214214

215-
/// Returns `true` if `self` is negative, including `-0.0` and
216-
/// `Float::neg_infinity()`.
215+
/// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with
216+
/// negative sign bit and negative infinity.
217217
#[inline]
218218
fn is_sign_negative(self) -> bool {
219-
self < 0.0 || (1.0 / self) == NEG_INFINITY
219+
#[repr(C)]
220+
union F64Bytes {
221+
f: f64,
222+
b: u64
223+
}
224+
unsafe { F64Bytes { f: self }.b & 0x8000_0000_0000_0000 != 0 }
220225
}
221226

222227
/// Returns the reciprocal (multiplicative inverse) of the number.

src/libstd/f32.rs

+8-16
Original file line numberDiff line numberDiff line change
@@ -363,39 +363,29 @@ impl f32 {
363363
#[inline]
364364
pub fn signum(self) -> f32 { num::Float::signum(self) }
365365

366-
/// Returns `true` if `self`'s sign bit is positive, including
367-
/// `+0.0` and `INFINITY`.
366+
/// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with
367+
/// positive sign bit and positive infinity.
368368
///
369369
/// ```
370-
/// use std::f32;
371-
///
372-
/// let nan = f32::NAN;
373370
/// let f = 7.0_f32;
374371
/// let g = -7.0_f32;
375372
///
376373
/// assert!(f.is_sign_positive());
377374
/// assert!(!g.is_sign_positive());
378-
/// // Requires both tests to determine if is `NaN`
379-
/// assert!(!nan.is_sign_positive() && !nan.is_sign_negative());
380375
/// ```
381376
#[stable(feature = "rust1", since = "1.0.0")]
382377
#[inline]
383378
pub fn is_sign_positive(self) -> bool { num::Float::is_sign_positive(self) }
384379

385-
/// Returns `true` if `self`'s sign is negative, including `-0.0`
386-
/// and `NEG_INFINITY`.
380+
/// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with
381+
/// negative sign bit and negative infinity.
387382
///
388383
/// ```
389-
/// use std::f32;
390-
///
391-
/// let nan = f32::NAN;
392384
/// let f = 7.0f32;
393385
/// let g = -7.0f32;
394386
///
395387
/// assert!(!f.is_sign_negative());
396388
/// assert!(g.is_sign_negative());
397-
/// // Requires both tests to determine if is `NaN`.
398-
/// assert!(!nan.is_sign_positive() && !nan.is_sign_negative());
399389
/// ```
400390
#[stable(feature = "rust1", since = "1.0.0")]
401391
#[inline]
@@ -1184,7 +1174,7 @@ mod tests {
11841174
assert!(!nan.is_infinite());
11851175
assert!(!nan.is_finite());
11861176
assert!(!nan.is_normal());
1187-
assert!(!nan.is_sign_positive());
1177+
assert!(nan.is_sign_positive());
11881178
assert!(!nan.is_sign_negative());
11891179
assert_eq!(Fp::Nan, nan.classify());
11901180
}
@@ -1428,7 +1418,8 @@ mod tests {
14281418
assert!(!(-1f32).is_sign_positive());
14291419
assert!(!NEG_INFINITY.is_sign_positive());
14301420
assert!(!(1f32/NEG_INFINITY).is_sign_positive());
1431-
assert!(!NAN.is_sign_positive());
1421+
assert!(NAN.is_sign_positive());
1422+
assert!(!(-NAN).is_sign_positive());
14321423
}
14331424

14341425
#[test]
@@ -1441,6 +1432,7 @@ mod tests {
14411432
assert!(NEG_INFINITY.is_sign_negative());
14421433
assert!((1f32/NEG_INFINITY).is_sign_negative());
14431434
assert!(!NAN.is_sign_negative());
1435+
assert!((-NAN).is_sign_negative());
14441436
}
14451437

14461438
#[test]

src/libstd/f64.rs

+8-18
Original file line numberDiff line numberDiff line change
@@ -301,21 +301,15 @@ impl f64 {
301301
#[inline]
302302
pub fn signum(self) -> f64 { num::Float::signum(self) }
303303

304-
/// Returns `true` if `self`'s sign bit is positive, including
305-
/// `+0.0` and `INFINITY`.
304+
/// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with
305+
/// positive sign bit and positive infinity.
306306
///
307307
/// ```
308-
/// use std::f64;
309-
///
310-
/// let nan: f64 = f64::NAN;
311-
///
312308
/// let f = 7.0_f64;
313309
/// let g = -7.0_f64;
314310
///
315311
/// assert!(f.is_sign_positive());
316312
/// assert!(!g.is_sign_positive());
317-
/// // Requires both tests to determine if is `NaN`
318-
/// assert!(!nan.is_sign_positive() && !nan.is_sign_negative());
319313
/// ```
320314
#[stable(feature = "rust1", since = "1.0.0")]
321315
#[inline]
@@ -326,21 +320,15 @@ impl f64 {
326320
#[inline]
327321
pub fn is_positive(self) -> bool { num::Float::is_sign_positive(self) }
328322

329-
/// Returns `true` if `self`'s sign is negative, including `-0.0`
330-
/// and `NEG_INFINITY`.
323+
/// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with
324+
/// negative sign bit and negative infinity.
331325
///
332326
/// ```
333-
/// use std::f64;
334-
///
335-
/// let nan = f64::NAN;
336-
///
337327
/// let f = 7.0_f64;
338328
/// let g = -7.0_f64;
339329
///
340330
/// assert!(!f.is_sign_negative());
341331
/// assert!(g.is_sign_negative());
342-
/// // Requires both tests to determine if is `NaN`.
343-
/// assert!(!nan.is_sign_positive() && !nan.is_sign_negative());
344332
/// ```
345333
#[stable(feature = "rust1", since = "1.0.0")]
346334
#[inline]
@@ -1101,7 +1089,7 @@ mod tests {
11011089
assert!(!nan.is_infinite());
11021090
assert!(!nan.is_finite());
11031091
assert!(!nan.is_normal());
1104-
assert!(!nan.is_sign_positive());
1092+
assert!(nan.is_sign_positive());
11051093
assert!(!nan.is_sign_negative());
11061094
assert_eq!(Fp::Nan, nan.classify());
11071095
}
@@ -1347,7 +1335,8 @@ mod tests {
13471335
assert!(!(-1f64).is_sign_positive());
13481336
assert!(!NEG_INFINITY.is_sign_positive());
13491337
assert!(!(1f64/NEG_INFINITY).is_sign_positive());
1350-
assert!(!NAN.is_sign_positive());
1338+
assert!(NAN.is_sign_positive());
1339+
assert!(!(-NAN).is_sign_positive());
13511340
}
13521341

13531342
#[test]
@@ -1360,6 +1349,7 @@ mod tests {
13601349
assert!(NEG_INFINITY.is_sign_negative());
13611350
assert!((1f64/NEG_INFINITY).is_sign_negative());
13621351
assert!(!NAN.is_sign_negative());
1352+
assert!((-NAN).is_sign_negative());
13631353
}
13641354

13651355
#[test]

0 commit comments

Comments
 (0)