Skip to content

Commit 3b9fe77

Browse files
committed
Fix NaN handling in is_sign_negative/positive
See #42425
1 parent 0da9721 commit 3b9fe77

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
@@ -365,39 +365,29 @@ impl f32 {
365365
#[inline]
366366
pub fn signum(self) -> f32 { num::Float::signum(self) }
367367

368-
/// Returns `true` if `self`'s sign bit is positive, including
369-
/// `+0.0` and `INFINITY`.
368+
/// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with
369+
/// positive sign bit and positive infinity.
370370
///
371371
/// ```
372-
/// use std::f32;
373-
///
374-
/// let nan = f32::NAN;
375372
/// let f = 7.0_f32;
376373
/// let g = -7.0_f32;
377374
///
378375
/// assert!(f.is_sign_positive());
379376
/// assert!(!g.is_sign_positive());
380-
/// // Requires both tests to determine if is `NaN`
381-
/// assert!(!nan.is_sign_positive() && !nan.is_sign_negative());
382377
/// ```
383378
#[stable(feature = "rust1", since = "1.0.0")]
384379
#[inline]
385380
pub fn is_sign_positive(self) -> bool { num::Float::is_sign_positive(self) }
386381

387-
/// Returns `true` if `self`'s sign is negative, including `-0.0`
388-
/// and `NEG_INFINITY`.
382+
/// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with
383+
/// negative sign bit and negative infinity.
389384
///
390385
/// ```
391-
/// use std::f32;
392-
///
393-
/// let nan = f32::NAN;
394386
/// let f = 7.0f32;
395387
/// let g = -7.0f32;
396388
///
397389
/// assert!(!f.is_sign_negative());
398390
/// assert!(g.is_sign_negative());
399-
/// // Requires both tests to determine if is `NaN`.
400-
/// assert!(!nan.is_sign_positive() && !nan.is_sign_negative());
401391
/// ```
402392
#[stable(feature = "rust1", since = "1.0.0")]
403393
#[inline]
@@ -1186,7 +1176,7 @@ mod tests {
11861176
assert!(!nan.is_infinite());
11871177
assert!(!nan.is_finite());
11881178
assert!(!nan.is_normal());
1189-
assert!(!nan.is_sign_positive());
1179+
assert!(nan.is_sign_positive());
11901180
assert!(!nan.is_sign_negative());
11911181
assert_eq!(Fp::Nan, nan.classify());
11921182
}
@@ -1430,7 +1420,8 @@ mod tests {
14301420
assert!(!(-1f32).is_sign_positive());
14311421
assert!(!NEG_INFINITY.is_sign_positive());
14321422
assert!(!(1f32/NEG_INFINITY).is_sign_positive());
1433-
assert!(!NAN.is_sign_positive());
1423+
assert!(NAN.is_sign_positive());
1424+
assert!(!(-NAN).is_sign_positive());
14341425
}
14351426

14361427
#[test]
@@ -1443,6 +1434,7 @@ mod tests {
14431434
assert!(NEG_INFINITY.is_sign_negative());
14441435
assert!((1f32/NEG_INFINITY).is_sign_negative());
14451436
assert!(!NAN.is_sign_negative());
1437+
assert!((-NAN).is_sign_negative());
14461438
}
14471439

14481440
#[test]

src/libstd/f64.rs

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

306-
/// Returns `true` if `self`'s sign bit is positive, including
307-
/// `+0.0` and `INFINITY`.
306+
/// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with
307+
/// positive sign bit and positive infinity.
308308
///
309309
/// ```
310-
/// use std::f64;
311-
///
312-
/// let nan: f64 = f64::NAN;
313-
///
314310
/// let f = 7.0_f64;
315311
/// let g = -7.0_f64;
316312
///
317313
/// assert!(f.is_sign_positive());
318314
/// assert!(!g.is_sign_positive());
319-
/// // Requires both tests to determine if is `NaN`
320-
/// assert!(!nan.is_sign_positive() && !nan.is_sign_negative());
321315
/// ```
322316
#[stable(feature = "rust1", since = "1.0.0")]
323317
#[inline]
@@ -328,21 +322,15 @@ impl f64 {
328322
#[inline]
329323
pub fn is_positive(self) -> bool { num::Float::is_sign_positive(self) }
330324

331-
/// Returns `true` if `self`'s sign is negative, including `-0.0`
332-
/// and `NEG_INFINITY`.
325+
/// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with
326+
/// negative sign bit and negative infinity.
333327
///
334328
/// ```
335-
/// use std::f64;
336-
///
337-
/// let nan = f64::NAN;
338-
///
339329
/// let f = 7.0_f64;
340330
/// let g = -7.0_f64;
341331
///
342332
/// assert!(!f.is_sign_negative());
343333
/// assert!(g.is_sign_negative());
344-
/// // Requires both tests to determine if is `NaN`.
345-
/// assert!(!nan.is_sign_positive() && !nan.is_sign_negative());
346334
/// ```
347335
#[stable(feature = "rust1", since = "1.0.0")]
348336
#[inline]
@@ -1103,7 +1091,7 @@ mod tests {
11031091
assert!(!nan.is_infinite());
11041092
assert!(!nan.is_finite());
11051093
assert!(!nan.is_normal());
1106-
assert!(!nan.is_sign_positive());
1094+
assert!(nan.is_sign_positive());
11071095
assert!(!nan.is_sign_negative());
11081096
assert_eq!(Fp::Nan, nan.classify());
11091097
}
@@ -1346,7 +1334,8 @@ mod tests {
13461334
assert!(!(-1f64).is_sign_positive());
13471335
assert!(!NEG_INFINITY.is_sign_positive());
13481336
assert!(!(1f64/NEG_INFINITY).is_sign_positive());
1349-
assert!(!NAN.is_sign_positive());
1337+
assert!(NAN.is_sign_positive());
1338+
assert!(!(-NAN).is_sign_positive());
13501339
}
13511340

13521341
#[test]
@@ -1359,6 +1348,7 @@ mod tests {
13591348
assert!(NEG_INFINITY.is_sign_negative());
13601349
assert!((1f64/NEG_INFINITY).is_sign_negative());
13611350
assert!(!NAN.is_sign_negative());
1351+
assert!((-NAN).is_sign_negative());
13621352
}
13631353

13641354
#[test]

0 commit comments

Comments
 (0)