Skip to content

Commit dd6956a

Browse files
authored
Implement Pow (#132)
Added Pow implementation for OrderedFloat and NotNan. Closes #118
1 parent 8b54373 commit dd6956a

File tree

2 files changed

+273
-4
lines changed

2 files changed

+273
-4
lines changed

src/lib.rs

Lines changed: 200 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@ use core::str::FromStr;
2626

2727
#[cfg(not(feature = "std"))]
2828
use num_traits::float::FloatCore as Float;
29-
#[cfg(feature = "std")]
30-
pub use num_traits::Float;
3129
use num_traits::{
3230
AsPrimitive, Bounded, FloatConst, FromPrimitive, Num, NumCast, One, Signed, ToPrimitive, Zero,
3331
};
32+
#[cfg(feature = "std")]
33+
pub use num_traits::{Float, Pow};
3434

3535
// masks for the parts of the IEEE 754 float
3636
const SIGN_MASK: u64 = 0x8000000000000000u64;
@@ -345,6 +345,104 @@ impl_ordered_float_binop! {Mul, mul, MulAssign, mul_assign}
345345
impl_ordered_float_binop! {Div, div, DivAssign, div_assign}
346346
impl_ordered_float_binop! {Rem, rem, RemAssign, rem_assign}
347347

348+
macro_rules! impl_ordered_float_pow {
349+
($inner:ty, $rhs:ty) => {
350+
#[cfg(feature = "std")]
351+
impl Pow<$rhs> for OrderedFloat<$inner> {
352+
type Output = OrderedFloat<$inner>;
353+
#[inline]
354+
fn pow(self, rhs: $rhs) -> OrderedFloat<$inner> {
355+
OrderedFloat(<$inner>::pow(self.0, rhs))
356+
}
357+
}
358+
359+
#[cfg(feature = "std")]
360+
impl<'a> Pow<&'a $rhs> for OrderedFloat<$inner> {
361+
type Output = OrderedFloat<$inner>;
362+
#[inline]
363+
fn pow(self, rhs: &'a $rhs) -> OrderedFloat<$inner> {
364+
OrderedFloat(<$inner>::pow(self.0, *rhs))
365+
}
366+
}
367+
368+
#[cfg(feature = "std")]
369+
impl<'a> Pow<$rhs> for &'a OrderedFloat<$inner> {
370+
type Output = OrderedFloat<$inner>;
371+
#[inline]
372+
fn pow(self, rhs: $rhs) -> OrderedFloat<$inner> {
373+
OrderedFloat(<$inner>::pow(self.0, rhs))
374+
}
375+
}
376+
377+
#[cfg(feature = "std")]
378+
impl<'a, 'b> Pow<&'a $rhs> for &'b OrderedFloat<$inner> {
379+
type Output = OrderedFloat<$inner>;
380+
#[inline]
381+
fn pow(self, rhs: &'a $rhs) -> OrderedFloat<$inner> {
382+
OrderedFloat(<$inner>::pow(self.0, *rhs))
383+
}
384+
}
385+
};
386+
}
387+
388+
impl_ordered_float_pow! {f32, i8}
389+
impl_ordered_float_pow! {f32, i16}
390+
impl_ordered_float_pow! {f32, u8}
391+
impl_ordered_float_pow! {f32, u16}
392+
impl_ordered_float_pow! {f32, i32}
393+
impl_ordered_float_pow! {f64, i8}
394+
impl_ordered_float_pow! {f64, i16}
395+
impl_ordered_float_pow! {f64, u8}
396+
impl_ordered_float_pow! {f64, u16}
397+
impl_ordered_float_pow! {f64, i32}
398+
impl_ordered_float_pow! {f32, f32}
399+
impl_ordered_float_pow! {f64, f32}
400+
impl_ordered_float_pow! {f64, f64}
401+
402+
macro_rules! impl_ordered_float_self_pow {
403+
($base:ty, $exp:ty) => {
404+
#[cfg(feature = "std")]
405+
impl Pow<OrderedFloat<$exp>> for OrderedFloat<$base> {
406+
type Output = OrderedFloat<$base>;
407+
#[inline]
408+
fn pow(self, rhs: OrderedFloat<$exp>) -> OrderedFloat<$base> {
409+
OrderedFloat(<$base>::pow(self.0, rhs.0))
410+
}
411+
}
412+
413+
#[cfg(feature = "std")]
414+
impl<'a> Pow<&'a OrderedFloat<$exp>> for OrderedFloat<$base> {
415+
type Output = OrderedFloat<$base>;
416+
#[inline]
417+
fn pow(self, rhs: &'a OrderedFloat<$exp>) -> OrderedFloat<$base> {
418+
OrderedFloat(<$base>::pow(self.0, rhs.0))
419+
}
420+
}
421+
422+
#[cfg(feature = "std")]
423+
impl<'a> Pow<OrderedFloat<$exp>> for &'a OrderedFloat<$base> {
424+
type Output = OrderedFloat<$base>;
425+
#[inline]
426+
fn pow(self, rhs: OrderedFloat<$exp>) -> OrderedFloat<$base> {
427+
OrderedFloat(<$base>::pow(self.0, rhs.0))
428+
}
429+
}
430+
431+
#[cfg(feature = "std")]
432+
impl<'a, 'b> Pow<&'a OrderedFloat<$exp>> for &'b OrderedFloat<$base> {
433+
type Output = OrderedFloat<$base>;
434+
#[inline]
435+
fn pow(self, rhs: &'a OrderedFloat<$exp>) -> OrderedFloat<$base> {
436+
OrderedFloat(<$base>::pow(self.0, rhs.0))
437+
}
438+
}
439+
};
440+
}
441+
442+
impl_ordered_float_self_pow! {f32, f32}
443+
impl_ordered_float_self_pow! {f64, f32}
444+
impl_ordered_float_self_pow! {f64, f64}
445+
348446
/// Adds a float directly.
349447
impl<T: Float + Sum> Sum for OrderedFloat<T> {
350448
fn sum<I: Iterator<Item = OrderedFloat<T>>>(iter: I) -> Self {
@@ -1316,6 +1414,106 @@ impl_not_nan_binop! {Mul, mul, MulAssign, mul_assign}
13161414
impl_not_nan_binop! {Div, div, DivAssign, div_assign}
13171415
impl_not_nan_binop! {Rem, rem, RemAssign, rem_assign}
13181416

1417+
// Will panic if NaN value is return from the operation
1418+
macro_rules! impl_not_nan_pow {
1419+
($inner:ty, $rhs:ty) => {
1420+
#[cfg(feature = "std")]
1421+
impl Pow<$rhs> for NotNan<$inner> {
1422+
type Output = NotNan<$inner>;
1423+
#[inline]
1424+
fn pow(self, rhs: $rhs) -> NotNan<$inner> {
1425+
NotNan::new(<$inner>::pow(self.0, rhs)).expect("Pow resulted in NaN")
1426+
}
1427+
}
1428+
1429+
#[cfg(feature = "std")]
1430+
impl<'a> Pow<&'a $rhs> for NotNan<$inner> {
1431+
type Output = NotNan<$inner>;
1432+
#[inline]
1433+
fn pow(self, rhs: &'a $rhs) -> NotNan<$inner> {
1434+
NotNan::new(<$inner>::pow(self.0, *rhs)).expect("Pow resulted in NaN")
1435+
}
1436+
}
1437+
1438+
#[cfg(feature = "std")]
1439+
impl<'a> Pow<$rhs> for &'a NotNan<$inner> {
1440+
type Output = NotNan<$inner>;
1441+
#[inline]
1442+
fn pow(self, rhs: $rhs) -> NotNan<$inner> {
1443+
NotNan::new(<$inner>::pow(self.0, rhs)).expect("Pow resulted in NaN")
1444+
}
1445+
}
1446+
1447+
#[cfg(feature = "std")]
1448+
impl<'a, 'b> Pow<&'a $rhs> for &'b NotNan<$inner> {
1449+
type Output = NotNan<$inner>;
1450+
#[inline]
1451+
fn pow(self, rhs: &'a $rhs) -> NotNan<$inner> {
1452+
NotNan::new(<$inner>::pow(self.0, *rhs)).expect("Pow resulted in NaN")
1453+
}
1454+
}
1455+
};
1456+
}
1457+
1458+
impl_not_nan_pow! {f32, i8}
1459+
impl_not_nan_pow! {f32, i16}
1460+
impl_not_nan_pow! {f32, u8}
1461+
impl_not_nan_pow! {f32, u16}
1462+
impl_not_nan_pow! {f32, i32}
1463+
impl_not_nan_pow! {f64, i8}
1464+
impl_not_nan_pow! {f64, i16}
1465+
impl_not_nan_pow! {f64, u8}
1466+
impl_not_nan_pow! {f64, u16}
1467+
impl_not_nan_pow! {f64, i32}
1468+
impl_not_nan_pow! {f32, f32}
1469+
impl_not_nan_pow! {f64, f32}
1470+
impl_not_nan_pow! {f64, f64}
1471+
1472+
// This also should panic on NaN
1473+
macro_rules! impl_not_nan_self_pow {
1474+
($base:ty, $exp:ty) => {
1475+
#[cfg(feature = "std")]
1476+
impl Pow<NotNan<$exp>> for NotNan<$base> {
1477+
type Output = NotNan<$base>;
1478+
#[inline]
1479+
fn pow(self, rhs: NotNan<$exp>) -> NotNan<$base> {
1480+
NotNan::new(self.0.pow(rhs.0)).expect("Pow resulted in NaN")
1481+
}
1482+
}
1483+
1484+
#[cfg(feature = "std")]
1485+
impl<'a> Pow<&'a NotNan<$exp>> for NotNan<$base> {
1486+
type Output = NotNan<$base>;
1487+
#[inline]
1488+
fn pow(self, rhs: &'a NotNan<$exp>) -> NotNan<$base> {
1489+
NotNan::new(self.0.pow(rhs.0)).expect("Pow resulted in NaN")
1490+
}
1491+
}
1492+
1493+
#[cfg(feature = "std")]
1494+
impl<'a> Pow<NotNan<$exp>> for &'a NotNan<$base> {
1495+
type Output = NotNan<$base>;
1496+
#[inline]
1497+
fn pow(self, rhs: NotNan<$exp>) -> NotNan<$base> {
1498+
NotNan::new(self.0.pow(rhs.0)).expect("Pow resulted in NaN")
1499+
}
1500+
}
1501+
1502+
#[cfg(feature = "std")]
1503+
impl<'a, 'b> Pow<&'a NotNan<$exp>> for &'b NotNan<$base> {
1504+
type Output = NotNan<$base>;
1505+
#[inline]
1506+
fn pow(self, rhs: &'a NotNan<$exp>) -> NotNan<$base> {
1507+
NotNan::new(self.0.pow(rhs.0)).expect("Pow resulted in NaN")
1508+
}
1509+
}
1510+
};
1511+
}
1512+
1513+
impl_not_nan_self_pow! {f32, f32}
1514+
impl_not_nan_self_pow! {f64, f32}
1515+
impl_not_nan_self_pow! {f64, f64}
1516+
13191517
impl<T: Float> Neg for NotNan<T> {
13201518
type Output = Self;
13211519

tests/test.rs

Lines changed: 73 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ extern crate ordered_float;
55

66
#[cfg(not(feature = "std"))]
77
pub use num_traits::float::FloatCore as Float;
8-
#[cfg(feature = "std")]
9-
pub use num_traits::Float;
108
pub use num_traits::{Bounded, FloatConst, FromPrimitive, Num, One, Signed, ToPrimitive, Zero};
9+
#[cfg(feature = "std")]
10+
pub use num_traits::{Float, Pow};
1111
pub use ordered_float::*;
1212

1313
pub use std::cmp::Ordering::*;
@@ -747,6 +747,77 @@ fn float_consts_equal_inner() {
747747
test_float_const_methods!(NotNan<f32>);
748748
}
749749

750+
#[cfg(feature = "std")]
751+
macro_rules! test_pow_ord {
752+
($type:ident < $inner:ident >) => {
753+
assert_eq!($type::<$inner>::from(3.0).pow(2i8), OrderedFloat(9.0));
754+
assert_eq!($type::<$inner>::from(3.0).pow(2i16), OrderedFloat(9.0));
755+
assert_eq!($type::<$inner>::from(3.0).pow(2i32), OrderedFloat(9.0));
756+
assert_eq!($type::<$inner>::from(3.0).pow(2u8), OrderedFloat(9.0));
757+
assert_eq!($type::<$inner>::from(3.0).pow(2u16), OrderedFloat(9.0));
758+
assert_eq!($type::<$inner>::from(3.0).pow(2f32), OrderedFloat(9.0));
759+
};
760+
}
761+
762+
#[cfg(feature = "std")]
763+
macro_rules! test_pow_nn {
764+
($type:ident < $inner:ident >) => {
765+
assert_eq!(
766+
$type::<$inner>::new(3.0).unwrap().pow(2i8),
767+
NotNan::new(9.0).unwrap()
768+
);
769+
assert_eq!(
770+
$type::<$inner>::new(3.0).unwrap().pow(2u8),
771+
NotNan::new(9.0).unwrap()
772+
);
773+
assert_eq!(
774+
$type::<$inner>::new(3.0).unwrap().pow(2i16),
775+
NotNan::new(9.0).unwrap()
776+
);
777+
assert_eq!(
778+
$type::<$inner>::new(3.0).unwrap().pow(2u16),
779+
NotNan::new(9.0).unwrap()
780+
);
781+
assert_eq!(
782+
$type::<$inner>::new(3.0).unwrap().pow(2i32),
783+
NotNan::new(9.0).unwrap()
784+
);
785+
assert_eq!(
786+
$type::<$inner>::new(3.0).unwrap().pow(2f32),
787+
NotNan::new(9.0).unwrap()
788+
);
789+
};
790+
}
791+
792+
#[cfg(feature = "std")]
793+
#[test]
794+
fn test_pow_works() {
795+
assert_eq!(OrderedFloat(3.0).pow(OrderedFloat(2.0)), OrderedFloat(9.0));
796+
test_pow_ord!(OrderedFloat<f32>);
797+
test_pow_ord!(OrderedFloat<f64>);
798+
assert_eq!(
799+
NotNan::new(3.0).unwrap().pow(NotNan::new(2.0).unwrap()),
800+
NotNan::new(9.0).unwrap()
801+
);
802+
test_pow_nn!(NotNan<f32>);
803+
test_pow_nn!(NotNan<f64>);
804+
// Only f64 have Pow<f64> impl by default, so checking those seperate from macro
805+
assert_eq!(OrderedFloat::<f64>::from(3.0).pow(2f64), OrderedFloat(9.0));
806+
assert_eq!(
807+
NotNan::<f64>::new(3.0).unwrap().pow(2f64),
808+
NotNan::new(9.0).unwrap()
809+
);
810+
}
811+
812+
#[cfg(feature = "std")]
813+
#[test]
814+
#[should_panic]
815+
fn test_pow_fails_on_nan() {
816+
let a = not_nan(-1.0);
817+
let b = f32::NAN;
818+
a.pow(b);
819+
}
820+
750821
#[cfg(feature = "arbitrary")]
751822
mod arbitrary_test {
752823
use super::{NotNan, OrderedFloat};

0 commit comments

Comments
 (0)