1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
use core::intrinsics::{sqrtf32, sqrtf64};
use core::{f32, f64};
use core::num::Wrapping;

use libc::{c_float, c_double};


#[link_name = "m"]
extern {
    pub fn cbrtf(n: c_float) -> c_float;
    pub fn cbrt(n: c_double) -> c_double;
}


pub trait Radical {

    fn sqrt(&self) -> Self;
    fn sq(&self) -> Self;

    fn cbrt(&self) -> Self;
    fn cb(&self) -> Self;
}

macro_rules! trait_radical {
    ($t:ident, $a:ident, $cbrt:ident, $sqrt:ident) => (
        impl Radical for $t {
            #[inline(always)]
            fn sqrt(&self) -> Self {
                if *self <= 0 as $t {
                    0 as $t
                } else {
                    unsafe {
                        $sqrt(*self as $a) as $t
                    }
                }
            }
            #[inline(always)]
            fn sq(&self) -> Self { self * self }

            #[inline(always)]
            fn cbrt(&self) -> Self {
                if *self <= 0 as $t {
                    0 as $t
                } else {
                    unsafe {
                        $cbrt(*self as $a) as $t
                    }
                }
            }
            #[inline(always)]
            fn cb(&self) -> Self { self * self * self }
        }
    );
}

macro_rules! trait_radical_no_cast {
    ($t:ident, $cbrt:ident, $sqrt:ident) => (
        impl Radical for $t {
            #[inline(always)]
            fn sqrt(&self) -> Self {
                if *self < 0.0 {
                    $t::NAN
                } else {
                    unsafe {
                        $sqrt(*self)
                    }
                }
            }
            #[inline(always)]
            fn sq(&self) -> Self { self * self }

            #[inline(always)]
            fn cbrt(&self) -> Self {
                if *self < 0.0 {
                    $t::NAN
                } else {
                    unsafe {
                        $cbrt(*self)
                    }
                }
            }
            #[inline(always)]
            fn cb(&self) -> Self { self * self * self }
        }
    );
}

trait_radical!(usize, f64, cbrt, sqrtf64);
trait_radical!(u8, f32, cbrtf, sqrtf32);
trait_radical!(u16, f32, cbrtf, sqrtf32);
trait_radical!(u32, f64, cbrt, sqrtf64);
trait_radical!(u64, f64, cbrt, sqrtf64);
trait_radical!(u128, f64, cbrt, sqrtf64);

trait_radical!(isize, f64, cbrt, sqrtf64);
trait_radical!(i8, f32, cbrtf, sqrtf32);
trait_radical!(i16, f32, cbrtf, sqrtf32);
trait_radical!(i32, f64, cbrt, sqrtf64);
trait_radical!(i64, f64, cbrt, sqrtf64);
trait_radical!(i128, f64, cbrt, sqrtf64);

trait_radical_no_cast!(f32, cbrtf, sqrtf32);
trait_radical_no_cast!(f64, cbrt, sqrtf64);


impl<T> Radical for Wrapping<T>
    where T: Radical,
{
    #[inline(always)]
    fn sqrt(&self) -> Self { Wrapping(Radical::sqrt(&self.0)) }
    #[inline(always)]
    fn sq(&self) -> Self { Wrapping(Radical::sq(&self.0)) }

    #[inline(always)]
    fn cbrt(&self) -> Self { Wrapping(Radical::cbrt(&self.0)) }
    #[inline(always)]
    fn cb(&self) -> Self { Wrapping(Radical::cb(&self.0)) }
}


#[cfg(test)]
mod test {
    use super::Radical;

    fn sqrt<T: Radical>(x: T) -> T {
        x.sqrt()
    }
    #[test]
    fn test_sqrt() {
        assert_eq!(sqrt(4), 2);
        assert_eq!(sqrt(4.0), 2.0);
    }

    fn sq<T: Radical>(x: T) -> T {
        x.sq()
    }
    #[test]
    fn test_sq() {
        assert_eq!(sq(2), 4);
        assert_eq!(sq(2.0), 4.0);
    }

    fn cbrt<T: Radical>(x: T) -> T {
        x.cbrt()
    }
    #[test]
    fn test_cbrt() {
        assert_eq!(cbrt(8), 2);
        assert_eq!(cbrt(8.0), 2.0);
    }

    fn cb<T: Radical>(x: T) -> T {
        x.cb()
    }
    #[test]
    fn test_cb() {
        assert_eq!(cb(2), 8);
        assert_eq!(cb(2.0), 8.0);
    }
}