Skip to content

Commit 9cdf402

Browse files
committed
Propagate NaNs for Orderable methods impled on floating-point primitives
1 parent c9d099d commit 9cdf402

File tree

3 files changed

+75
-15
lines changed

3 files changed

+75
-15
lines changed

src/libcore/num/f32.rs

+26-5
Original file line numberDiff line numberDiff line change
@@ -225,16 +225,26 @@ impl Ord for f32 {
225225
}
226226

227227
impl Orderable for f32 {
228+
/// Returns `NaN` if either of the numbers are `NaN`.
228229
#[inline(always)]
229-
fn min(&self, other: &f32) -> f32 { fmin(*self, *other) }
230+
fn min(&self, other: &f32) -> f32 {
231+
if self.is_NaN() || other.is_NaN() { Float::NaN() } else { fmin(*self, *other) }
232+
}
230233

234+
/// Returns `NaN` if either of the numbers are `NaN`.
231235
#[inline(always)]
232-
fn max(&self, other: &f32) -> f32 { fmax(*self, *other) }
236+
fn max(&self, other: &f32) -> f32 {
237+
if self.is_NaN() || other.is_NaN() { Float::NaN() } else { fmax(*self, *other) }
238+
}
233239

240+
/// Returns the number constrained within the range `mn <= self <= mx`.
241+
/// If any of the numbers are `NaN` then `NaN` is returned.
234242
#[inline(always)]
235243
fn clamp(&self, mn: &f32, mx: &f32) -> f32 {
236-
if *self > *mx { *mx } else
237-
if *self < *mn { *mn } else { *self }
244+
if self.is_NaN() { *self }
245+
else if !(*self <= *mx) { *mx }
246+
else if !(*self >= *mn) { *mn }
247+
else { *self }
238248
}
239249
}
240250

@@ -828,14 +838,25 @@ mod tests {
828838
}
829839

830840
#[test]
831-
fn test_orderable() {
841+
fn test_min() {
832842
assert_eq!(1f32.min(&2f32), 1f32);
833843
assert_eq!(2f32.min(&1f32), 1f32);
844+
}
845+
846+
#[test]
847+
fn test_max() {
834848
assert_eq!(1f32.max(&2f32), 2f32);
835849
assert_eq!(2f32.max(&1f32), 2f32);
850+
}
851+
852+
#[test]
853+
fn test_clamp() {
836854
assert_eq!(1f32.clamp(&2f32, &4f32), 2f32);
837855
assert_eq!(8f32.clamp(&2f32, &4f32), 4f32);
838856
assert_eq!(3f32.clamp(&2f32, &4f32), 3f32);
857+
assert!(3f32.clamp(&Float::NaN::<f32>(), &4f32).is_NaN());
858+
assert!(3f32.clamp(&2f32, &Float::NaN::<f32>()).is_NaN());
859+
assert!(Float::NaN::<f32>().clamp(&2f32, &4f32).is_NaN());
839860
}
840861

841862
#[test]

src/libcore/num/f64.rs

+30-5
Original file line numberDiff line numberDiff line change
@@ -246,16 +246,26 @@ impl Ord for f64 {
246246
}
247247

248248
impl Orderable for f64 {
249+
/// Returns `NaN` if either of the numbers are `NaN`.
249250
#[inline(always)]
250-
fn min(&self, other: &f64) -> f64 { fmin(*self, *other) }
251+
fn min(&self, other: &f64) -> f64 {
252+
if self.is_NaN() || other.is_NaN() { Float::NaN() } else { fmin(*self, *other) }
253+
}
251254

255+
/// Returns `NaN` if either of the numbers are `NaN`.
252256
#[inline(always)]
253-
fn max(&self, other: &f64) -> f64 { fmax(*self, *other) }
257+
fn max(&self, other: &f64) -> f64 {
258+
if self.is_NaN() || other.is_NaN() { Float::NaN() } else { fmax(*self, *other) }
259+
}
254260

261+
/// Returns the number constrained within the range `mn <= self <= mx`.
262+
/// If any of the numbers are `NaN` then `NaN` is returned.
255263
#[inline(always)]
256264
fn clamp(&self, mn: &f64, mx: &f64) -> f64 {
257-
if *self > *mx { *mx } else
258-
if *self < *mn { *mn } else { *self }
265+
if self.is_NaN() { *self }
266+
else if !(*self <= *mx) { *mx }
267+
else if !(*self >= *mn) { *mn }
268+
else { *self }
259269
}
260270
}
261271

@@ -869,14 +879,29 @@ mod tests {
869879
}
870880

871881
#[test]
872-
fn test_orderable() {
882+
fn test_min() {
873883
assert_eq!(1f64.min(&2f64), 1f64);
874884
assert_eq!(2f64.min(&1f64), 1f64);
885+
assert!(1f64.min(&Float::NaN::<f64>()).is_NaN());
886+
assert!(Float::NaN::<f64>().min(&1f64).is_NaN());
887+
}
888+
889+
#[test]
890+
fn test_max() {
875891
assert_eq!(1f64.max(&2f64), 2f64);
876892
assert_eq!(2f64.max(&1f64), 2f64);
893+
assert!(1f64.max(&Float::NaN::<f64>()).is_NaN());
894+
assert!(Float::NaN::<f64>().max(&1f64).is_NaN());
895+
}
896+
897+
#[test]
898+
fn test_clamp() {
877899
assert_eq!(1f64.clamp(&2f64, &4f64), 2f64);
878900
assert_eq!(8f64.clamp(&2f64, &4f64), 4f64);
879901
assert_eq!(3f64.clamp(&2f64, &4f64), 3f64);
902+
assert!(3f64.clamp(&Float::NaN::<f64>(), &4f64).is_NaN());
903+
assert!(3f64.clamp(&2f64, &Float::NaN::<f64>()).is_NaN());
904+
assert!(Float::NaN::<f64>().clamp(&2f64, &4f64).is_NaN());
880905
}
881906

882907
#[test]

src/libcore/num/float.rs

+19-5
Original file line numberDiff line numberDiff line change
@@ -385,20 +385,23 @@ impl Ord for float {
385385
}
386386
387387
impl Orderable for float {
388+
/// Returns `NaN` if either of the numbers are `NaN`.
388389
#[inline(always)]
389390
fn min(&self, other: &float) -> float {
390-
fmin(*self as f64, *other as f64) as float
391+
(*self as f64).min(&(*other as f64)) as float
391392
}
392393
394+
/// Returns `NaN` if either of the numbers are `NaN`.
393395
#[inline(always)]
394396
fn max(&self, other: &float) -> float {
395-
fmax(*self as f64, *other as f64) as float
397+
(*self as f64).max(&(*other as f64)) as float
396398
}
397399
400+
/// Returns the number constrained within the range `mn <= self <= mx`.
401+
/// If any of the numbers are `NaN` then `NaN` is returned.
398402
#[inline(always)]
399403
fn clamp(&self, mn: &float, mx: &float) -> float {
400-
if *self > *mx { *mx } else
401-
if *self < *mn { *mn } else { *self }
404+
(*self as f64).clamp(&(*mn as f64), &(*mx as f64)) as float
402405
}
403406
}
404407
@@ -802,14 +805,25 @@ mod tests {
802805
}
803806
804807
#[test]
805-
fn test_orderable() {
808+
fn test_min() {
806809
assert_eq!(1f.min(&2f), 1f);
807810
assert_eq!(2f.min(&1f), 1f);
811+
}
812+
813+
#[test]
814+
fn test_max() {
808815
assert_eq!(1f.max(&2f), 2f);
809816
assert_eq!(2f.max(&1f), 2f);
817+
}
818+
819+
#[test]
820+
fn test_clamp() {
810821
assert_eq!(1f.clamp(&2f, &4f), 2f);
811822
assert_eq!(8f.clamp(&2f, &4f), 4f);
812823
assert_eq!(3f.clamp(&2f, &4f), 3f);
824+
assert!(3f.clamp(&Float::NaN::<float>(), &4f).is_NaN());
825+
assert!(3f.clamp(&2f, &Float::NaN::<float>()).is_NaN());
826+
assert!(Float::NaN::<float>().clamp(&2f, &4f).is_NaN());
813827
}
814828
815829
#[test]

0 commit comments

Comments
 (0)