///////////////////////////////////////////////////////////////////// // = NMatrix // // A linear algebra library for scientific computation in Ruby. // NMatrix is part of SciRuby. // // NMatrix was originally inspired by and derived from NArray, by // Masahiro Tanaka: http://narray.rubyforge.org // // == Copyright Information // // SciRuby is Copyright (c) 2010 - 2013, Ruby Science Foundation // NMatrix is Copyright (c) 2013, Ruby Science Foundation // // Please see LICENSE.txt for additional copyright notices. // // == Contributing // // By contributing source code to SciRuby, you agree to be bound by // our Contributor Agreement: // // * https://github.com/SciRuby/sciruby/wiki/Contributor-Agreement // // == complex.h // // Functions and classes for dealing with complex numbers. #ifndef COMPLEX_H #define COMPLEX_H /* * Standard Includes */ #include #include #include /* * Project Includes */ #include "types.h" /* * Macros */ /* * Types */ namespace nm { class RubyObject; template class Rational; template class Complex; typedef Complex Complex64; typedef Complex Complex128; /* * Data */ /* * Classes and Functions */ template class Complex { public: // The real and immaginary parts of the complex number. Type r; Type i; /* * Default constructor. */ inline Complex(Type real = 0, Type imaginary = 0) : r(real), i(imaginary) {} /* * Copy constructors. */ template inline Complex(const Complex& other) : r(other.r), i(other.i) {} template ::value>::type> inline Complex(const Rational& other) : r(Type(other.n) / Type(other.d)), i(0) {} Complex(const RubyObject& other); /* * Complex conjugate function -- creates a copy, but inverted. */ inline Complex conjugate() const { return Complex(this->r, -(this->i)); } /* * Complex inverse function -- creates a copy, but inverted. * * FIXME: Check that this doesn't duplicate functionality of NativeType / Complex */ inline Complex inverse() const { Complex conj = conjugate(); Type denom = this->r * this->r + this->i * this->i; return Complex(conj.r / denom, conj.i / denom); } /* * Binary operator definitions for various types. */ //////////////////////////////// // Complex-Complex Operations // //////////////////////////////// template inline Complex operator+(const Complex& other) const { return Complex(this->r + other.r, this->i + other.i); } template inline Complex& operator+=(const Complex& other) { this->r += other.r; this->i += other.i; return *this; } template inline Complex operator-(const Complex& other) const { return Complex(this->r - other.r, this->i - other.i); } template inline Complex operator*(const Complex& other) const { return Complex(this->r * other.r - this->i * other.i, this->r * other.i + this->i * other.r); } template inline Complex& operator*=(const Complex& other) { this->r = this->r * other.r - this->i * other.i; this->i = this->r * other.i + this->i * other.r; return *this; } template inline Complex operator/(const Complex& other) const { Type new_r, new_i; Type denom = other.i * other.i + other.r * other.r; new_r = (this->r * other.r + this->i * other.i) / denom; new_i = (this->i * other.r - this->r * other.i) / denom; return Complex(new_r, new_i); } template inline bool operator<(const Complex& other) const { return (this->r < other.r) || ((this->r <= other.r) && (this->i < other.i)); } template inline bool operator>(const Complex& other) const { return (this->r > other.r) || ((this->r >= other.r) && (this->i > other.i)); } template inline bool operator==(const Complex& other) const { return FP_EQUAL(this->r, other.r) && FP_EQUAL(this->i, other.i); } template inline bool operator!=(const Complex& other) const { return !(*this == other); } template inline bool operator<=(const Complex& other) const { return (*this < other) || (*this == other); } template inline bool operator>=(const Complex& other) const { return (*this > other) || (*this == other); } template inline operator Complex () const { return Complex((OtherType)this->r, (OtherType)this->i); } ///////////////////////////////// // Complex-Rational Operations // ///////////////////////////////// template inline Complex operator+(const Rational& other) const { return *this + Complex(other); } template inline Complex operator-(const Rational& other) const { return *this - Complex(other); } template inline Complex operator*(const Rational& other) const { return *this * Complex(other); } template inline Complex operator/(const Rational& other) const { return *this / Complex(other); } template ::value>::type> inline bool operator!=(const Rational& other) const { return *this != Complex(other); } template ::value>::type> inline bool operator==(const Rational& other) const { return *this == Complex(other); } /////////////////////////////// // Complex-Native Operations // /////////////////////////////// template ::value>::type> inline Complex operator+(const NativeType& other) const { return *this + Complex(other); } template ::value>::type> inline Complex operator-(const NativeType& other) const { return *this - Complex(other); } template ::value>::type> inline Complex operator*(const NativeType& other) const { return *this * Complex(other); } template ::value>::type> inline Complex operator/(const NativeType& other) const { return *this / Complex(other); } template ::value>::type> inline bool operator<(const NativeType& other) const { return *this < Complex(other); } template ::value>::type> inline bool operator>(const NativeType& other) const { return *this > Complex(other); } template ::value>::type> inline bool operator==(const NativeType& other) const { return *this == Complex(other); } template ::value>::type> inline bool operator!=(const NativeType& other) const { return *this != Complex(other); } template ::value>::type> inline bool operator<=(const NativeType& other) const { return *this <= Complex(other); } template ::value>::type> inline bool operator>=(const NativeType& other) const { return *this >= Complex(other); } template ::value>::type> inline operator NativeType () const { return (NativeType)this->r; } }; ///////////////////////////////// // Rational-Complex Operations // ///////////////////////////////// template ::value>::type> inline bool operator==(const Rational& left, const Complex& right) { return Complex(left) == right; } template ::value>::type> inline bool operator!=(const Rational& left, const Complex& right) { return Complex(left) != right; } /////////////////////////////// // Native-Complex Operations // /////////////////////////////// template ::value>::type> inline Complex operator+(const NativeType& left, const Complex& right) { return Complex(left) + right; } template ::value>::type> inline Complex operator-(const NativeType& left, const Complex& right) { return Complex(left) - right; } template ::value>::type> inline Complex operator*(const NativeType& left, const Complex& right) { return Complex(left) * right; } template ::value>::type> inline Complex operator/(const NativeType& left, const Complex& right) { return Complex(left) / right; } template ::value>::type> inline bool operator<(const NativeType left, const Complex& right) { return Complex(left) < right; } template ::value>::type> inline bool operator>(const NativeType left, const Complex& right) { return Complex(left) > right; } template ::value>::type> inline bool operator==(const NativeType left, const Complex& right) { return Complex(left) == right; } template ::value>::type> inline bool operator!=(const NativeType left, const Complex& right) { return Complex(left) != right; } template ::value>::type> inline bool operator<=(const NativeType left, const Complex& right) { return Complex(left) <= right; } template ::value>::type> inline bool operator>=(const NativeType left, const Complex& right) { return Complex(left) >= right; } template inline std::ostream& operator<<(std::ostream& out, const Complex& rhs) { out << "(" << rhs.r << "," << rhs.i << "i)" << std::flush; return out; } // Negative operator template ::value>::type> inline Complex operator-(const Complex& rhs) { return Complex(-rhs.r, -rhs.i); } } // end of namespace nm namespace std { template ::value>::type> nm::Complex piecewise_abs(const nm::Complex& value) { return nm::Complex(value.r < 0 ? -value.r : value.r, value.i < 0 ? -value.i : value.i); } template ::value>::type> nm::Complex real_abs(const nm::Complex& value) { return nm::Complex(value.r < 0 ? -value.r : value.r, value.i); } template ::value>::type> nm::Complex imag_abs(const nm::Complex& value) { return nm::Complex(value.r, value.i < 0 ? -value.i : value.i); } template ::value>::type> double abs(const nm::Complex& value) { return std::sqrt(double(value.r)*double(value.r) + double(value.i)*double(value.i)); } } #endif // COMPLEX_H