diff --git a/doc/tutorial-tasks.md b/doc/tutorial-tasks.md
index 892908dc0a0..bf97c86b5c9 100644
--- a/doc/tutorial-tasks.md
+++ b/doc/tutorial-tasks.md
@@ -318,7 +318,7 @@ be distributed on the available cores.
 fn partial_sum(start: uint) -> f64 {
     let mut local_sum = 0f64;
     for uint::range(start*100000, (start+1)*100000) |num| {
-        local_sum += (num as f64 + 1.0).pow(-2.0);
+        local_sum += (num as f64 + 1.0).pow(&-2.0);
     }
     local_sum
 }
@@ -355,7 +355,7 @@ a single large vector of floats. Each task needs the full vector to perform its
 use extra::arc::ARC;
 
 fn pnorm(nums: &~[float], p: uint) -> float {
-    nums.iter().fold(0.0, |a,b| a+(*b).pow(p as float) ).pow(1f / (p as float))
+    nums.iter().fold(0.0, |a,b| a+(*b).pow(&(p as float)) ).pow(&(1f / (p as float)))
 }
 
 fn main() {
diff --git a/src/libextra/num/complex.rs b/src/libextra/num/complex.rs
index 10bfe9409da..1bb364f3a1c 100644
--- a/src/libextra/num/complex.rs
+++ b/src/libextra/num/complex.rs
@@ -35,7 +35,7 @@ pub type Complex = Cmplx<float>;
 pub type Complex32 = Cmplx<f32>;
 pub type Complex64 = Cmplx<f64>;
 
-impl<T: Copy + Num> Cmplx<T> {
+impl<T: Clone + Num> Cmplx<T> {
     /// Create a new Cmplx
     #[inline]
     pub fn new(re: T, im: T) -> Cmplx<T> {
@@ -55,7 +55,7 @@ impl<T: Copy + Num> Cmplx<T> {
     /// Returns the complex conjugate. i.e. `re - i im`
     #[inline]
     pub fn conj(&self) -> Cmplx<T> {
-        Cmplx::new(self.re, -self.im)
+        Cmplx::new(self.re.clone(), -self.im)
     }
 
 
@@ -80,42 +80,71 @@ impl<T: Copy + Num> Cmplx<T> {
     }
 }
 
+#[cfg(not(stage0))] // Fixed by #4228
+impl<T: Clone + Algebraic + Num> Cmplx<T> {
+    /// Calculate |self|
+    #[inline(always)]
+    pub fn norm(&self) -> T {
+        self.re.hypot(&self.im)
+    }
+}
+
+#[cfg(not(stage0))] // Fixed by #4228
+impl<T: Clone + Trigonometric + Algebraic + Num> Cmplx<T> {
+    /// Calculate the principal Arg of self.
+    #[inline(always)]
+    pub fn arg(&self) -> T {
+        self.im.atan2(&self.re)
+    }
+    /// Convert to polar form (r, theta), such that `self = r * exp(i
+    /// * theta)`
+    #[inline]
+    pub fn to_polar(&self) -> (T, T) {
+        (self.norm(), self.arg())
+    }
+    /// Convert a polar representation into a complex number.
+    #[inline]
+    pub fn from_polar(r: &T, theta: &T) -> Cmplx<T> {
+        Cmplx::new(r * theta.cos(), r * theta.sin())
+    }
+}
+
 /* arithmetic */
 // (a + i b) + (c + i d) == (a + c) + i (b + d)
-impl<T: Copy + Num> Add<Cmplx<T>, Cmplx<T>> for Cmplx<T> {
+impl<T: Clone + Num> Add<Cmplx<T>, Cmplx<T>> for Cmplx<T> {
     #[inline]
     fn add(&self, other: &Cmplx<T>) -> Cmplx<T> {
         Cmplx::new(self.re + other.re, self.im + other.im)
     }
 }
 // (a + i b) - (c + i d) == (a - c) + i (b - d)
-impl<T: Copy + Num> Sub<Cmplx<T>, Cmplx<T>> for Cmplx<T> {
+impl<T: Clone + Num> Sub<Cmplx<T>, Cmplx<T>> for Cmplx<T> {
     #[inline]
     fn sub(&self, other: &Cmplx<T>) -> Cmplx<T> {
         Cmplx::new(self.re - other.re, self.im - other.im)
     }
 }
 // (a + i b) * (c + i d) == (a*c - b*d) + i (a*d + b*c)
-impl<T: Copy + Num> Mul<Cmplx<T>, Cmplx<T>> for Cmplx<T> {
+impl<T: Clone + Num> Mul<Cmplx<T>, Cmplx<T>> for Cmplx<T> {
     #[inline]
     fn mul(&self, other: &Cmplx<T>) -> Cmplx<T> {
         Cmplx::new(self.re*other.re - self.im*other.im,
-                     self.re*other.im + self.im*other.re)
+                   self.re*other.im + self.im*other.re)
     }
 }
 
 // (a + i b) / (c + i d) == [(a + i b) * (c - i d)] / (c*c + d*d)
 //   == [(a*c + b*d) / (c*c + d*d)] + i [(b*c - a*d) / (c*c + d*d)]
-impl<T: Copy + Num> Div<Cmplx<T>, Cmplx<T>> for Cmplx<T> {
+impl<T: Clone + Num> Div<Cmplx<T>, Cmplx<T>> for Cmplx<T> {
     #[inline]
     fn div(&self, other: &Cmplx<T>) -> Cmplx<T> {
         let norm_sqr = other.norm_sqr();
         Cmplx::new((self.re*other.re + self.im*other.im) / norm_sqr,
-                     (self.im*other.re - self.re*other.im) / norm_sqr)
+                   (self.im*other.re - self.re*other.im) / norm_sqr)
     }
 }
 
-impl<T: Copy + Num> Neg<Cmplx<T>> for Cmplx<T> {
+impl<T: Clone + Num> Neg<Cmplx<T>> for Cmplx<T> {
     #[inline]
     fn neg(&self) -> Cmplx<T> {
         Cmplx::new(-self.re, -self.im)
@@ -123,7 +152,7 @@ impl<T: Copy + Num> Neg<Cmplx<T>> for Cmplx<T> {
 }
 
 /* constants */
-impl<T: Copy + Num> Zero for Cmplx<T> {
+impl<T: Clone + Num> Zero for Cmplx<T> {
     #[inline]
     fn zero() -> Cmplx<T> {
         Cmplx::new(Zero::zero(), Zero::zero())
@@ -131,11 +160,11 @@ impl<T: Copy + Num> Zero for Cmplx<T> {
 
     #[inline]
     fn is_zero(&self) -> bool {
-        *self == Zero::zero()
+        self.re.is_zero() && self.im.is_zero()
     }
 }
 
-impl<T: Copy + Num> One for Cmplx<T> {
+impl<T: Clone + Num> One for Cmplx<T> {
     #[inline]
     fn one() -> Cmplx<T> {
         Cmplx::new(One::one(), Zero::zero())
@@ -166,7 +195,7 @@ impl<T: ToStrRadix + Num + Ord> ToStrRadix for Cmplx<T> {
 #[cfg(test)]
 mod test {
     use super::*;
-    use core::num::{Zero,One};
+    use core::num::{Zero,One,Real};
 
     pub static _0_0i : Complex = Cmplx { re: 0f, im: 0f };
     pub static _1_0i : Complex = Cmplx { re: 1f, im: 0f };
@@ -193,9 +222,10 @@ mod test {
     }
 
     #[test]
-    fn test_norm_sqr() {
+    fn test_norm() {
         fn test(c: Complex, ns: float) {
             assert_eq!(c.norm_sqr(), ns);
+            assert_eq!(c.norm(), ns.sqrt())
         }
         test(_0_0i, 0f);
         test(_1_0i, 1f);
@@ -235,6 +265,25 @@ mod test {
         _0_0i.inv();
     }
 
+    #[test]
+    fn test_arg() {
+        fn test(c: Complex, arg: float) {
+            assert!(c.arg().approx_eq(&arg))
+        }
+        test(_1_0i, 0f);
+        test(_1_1i, 0.25f * Real::pi());
+        test(_neg1_1i, 0.75f * Real::pi());
+        test(_05_05i, 0.25f * Real::pi());
+    }
+
+    #[test]
+    fn test_polar_conv() {
+        fn test(c: Complex) {
+            let (r, theta) = c.to_polar();
+            assert!((c - Cmplx::from_polar(&r, &theta)).norm() < 1e-6);
+        }
+        for all_consts.each |&c| { test(c); }
+    }
 
     mod arith {
         use super::*;
diff --git a/src/libstd/num/f32.rs b/src/libstd/num/f32.rs
index 62ce5ed65e1..7f981187300 100644
--- a/src/libstd/num/f32.rs
+++ b/src/libstd/num/f32.rs
@@ -391,7 +391,7 @@ impl Fractional for f32 {
 
 impl Algebraic for f32 {
     #[inline(always)]
-    fn pow(&self, n: f32) -> f32 { pow(*self, n) }
+    fn pow(&self, n: &f32) -> f32 { pow(*self, *n) }
 
     #[inline(always)]
     fn sqrt(&self) -> f32 { sqrt(*self) }
@@ -403,7 +403,7 @@ impl Algebraic for f32 {
     fn cbrt(&self) -> f32 { cbrt(*self) }
 
     #[inline(always)]
-    fn hypot(&self, other: f32) -> f32 { hypot(*self, other) }
+    fn hypot(&self, other: &f32) -> f32 { hypot(*self, *other) }
 }
 
 impl Trigonometric for f32 {
@@ -426,7 +426,7 @@ impl Trigonometric for f32 {
     fn atan(&self) -> f32 { atan(*self) }
 
     #[inline(always)]
-    fn atan2(&self, other: f32) -> f32 { atan2(*self, other) }
+    fn atan2(&self, other: &f32) -> f32 { atan2(*self, *other) }
 
     /// Simultaneously computes the sine and cosine of the number
     #[inline(always)]
@@ -450,7 +450,7 @@ impl Exponential for f32 {
 
     /// Returns the logarithm of the number with respect to an arbitrary base
     #[inline(always)]
-    fn log(&self, base: f32) -> f32 { self.ln() / base.ln() }
+    fn log(&self, base: &f32) -> f32 { self.ln() / base.ln() }
 
     /// Returns the base 2 logarithm of the number
     #[inline(always)]
diff --git a/src/libstd/num/f64.rs b/src/libstd/num/f64.rs
index de44d861645..6303e304576 100644
--- a/src/libstd/num/f64.rs
+++ b/src/libstd/num/f64.rs
@@ -403,7 +403,7 @@ impl Fractional for f64 {
 
 impl Algebraic for f64 {
     #[inline(always)]
-    fn pow(&self, n: f64) -> f64 { pow(*self, n) }
+    fn pow(&self, n: &f64) -> f64 { pow(*self, *n) }
 
     #[inline(always)]
     fn sqrt(&self) -> f64 { sqrt(*self) }
@@ -415,7 +415,7 @@ impl Algebraic for f64 {
     fn cbrt(&self) -> f64 { cbrt(*self) }
 
     #[inline(always)]
-    fn hypot(&self, other: f64) -> f64 { hypot(*self, other) }
+    fn hypot(&self, other: &f64) -> f64 { hypot(*self, *other) }
 }
 
 impl Trigonometric for f64 {
@@ -438,7 +438,7 @@ impl Trigonometric for f64 {
     fn atan(&self) -> f64 { atan(*self) }
 
     #[inline(always)]
-    fn atan2(&self, other: f64) -> f64 { atan2(*self, other) }
+    fn atan2(&self, other: &f64) -> f64 { atan2(*self, *other) }
 
     /// Simultaneously computes the sine and cosine of the number
     #[inline(always)]
@@ -462,7 +462,7 @@ impl Exponential for f64 {
 
     /// Returns the logarithm of the number with respect to an arbitrary base
     #[inline(always)]
-    fn log(&self, base: f64) -> f64 { self.ln() / base.ln() }
+    fn log(&self, base: &f64) -> f64 { self.ln() / base.ln() }
 
     /// Returns the base 2 logarithm of the number
     #[inline(always)]
diff --git a/src/libstd/num/float.rs b/src/libstd/num/float.rs
index a96a854e6a0..267a8890e82 100644
--- a/src/libstd/num/float.rs
+++ b/src/libstd/num/float.rs
@@ -475,8 +475,8 @@ impl Fractional for float {
 
 impl Algebraic for float {
     #[inline(always)]
-    fn pow(&self, n: float) -> float {
-        (*self as f64).pow(n as f64) as float
+    fn pow(&self, n: &float) -> float {
+        (*self as f64).pow(&(*n as f64)) as float
     }
 
     #[inline(always)]
@@ -495,8 +495,8 @@ impl Algebraic for float {
     }
 
     #[inline(always)]
-    fn hypot(&self, other: float) -> float {
-        (*self as f64).hypot(other as f64) as float
+    fn hypot(&self, other: &float) -> float {
+        (*self as f64).hypot(&(*other as f64)) as float
     }
 }
 
@@ -532,8 +532,8 @@ impl Trigonometric for float {
     }
 
     #[inline(always)]
-    fn atan2(&self, other: float) -> float {
-        (*self as f64).atan2(other as f64) as float
+    fn atan2(&self, other: &float) -> float {
+        (*self as f64).atan2(&(*other as f64)) as float
     }
 
     /// Simultaneously computes the sine and cosine of the number
@@ -566,8 +566,8 @@ impl Exponential for float {
 
     /// Returns the logarithm of the number with respect to an arbitrary base
     #[inline(always)]
-    fn log(&self, base: float) -> float {
-        (*self as f64).log(base as f64) as float
+    fn log(&self, base: &float) -> float {
+        (*self as f64).log(&(*base as f64)) as float
     }
 
     /// Returns the base 2 logarithm of the number
diff --git a/src/libstd/num/num.rs b/src/libstd/num/num.rs
index 91631d3c9b9..a9893579721 100644
--- a/src/libstd/num/num.rs
+++ b/src/libstd/num/num.rs
@@ -106,11 +106,11 @@ pub trait Fractional: Num
 }
 
 pub trait Algebraic {
-    fn pow(&self, n: Self) -> Self;
+    fn pow(&self, n: &Self) -> Self;
     fn sqrt(&self) -> Self;
     fn rsqrt(&self) -> Self;
     fn cbrt(&self) -> Self;
-    fn hypot(&self, other: Self) -> Self;
+    fn hypot(&self, other: &Self) -> Self;
 }
 
 pub trait Trigonometric {
@@ -120,7 +120,7 @@ pub trait Trigonometric {
     fn asin(&self) -> Self;
     fn acos(&self) -> Self;
     fn atan(&self) -> Self;
-    fn atan2(&self, other: Self) -> Self;
+    fn atan2(&self, other: &Self) -> Self;
     fn sin_cos(&self) -> (Self, Self);
 }
 
@@ -128,7 +128,7 @@ pub trait Exponential {
     fn exp(&self) -> Self;
     fn exp2(&self) -> Self;
     fn ln(&self) -> Self;
-    fn log(&self, base: Self) -> Self;
+    fn log(&self, base: &Self) -> Self;
     fn log2(&self) -> Self;
     fn log10(&self) -> Self;
 }