...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
Template version:
explicit octonion(T const & requested_a = T(), T const & requested_b = T(), T const & requested_c = T(), T const & requested_d = T(), T const & requested_e = T(), T const & requested_f = T(), T const & requested_g = T(), T const & requested_h = T()); explicit octonion(::std::complex<T> const & z0, ::std::complex<T> const & z1 = ::std::complex<T>(), ::std::complex<T> const & z2 = ::std::complex<T>(), ::std::complex<T> const & z3 = ::std::complex<T>()); explicit octonion(::boost::math::quaternion<T> const & q0, ::boost::math::quaternion<T> const & q1 = ::boost::math::quaternion<T>()); template<typename X> explicit octonion(octonion<X> const & a_recopier);
Float specialization version:
explicit octonion(float const & requested_a = 0.0f, float const & requested_b = 0.0f, float const & requested_c = 0.0f, float const & requested_d = 0.0f, float const & requested_e = 0.0f, float const & requested_f = 0.0f, float const & requested_g = 0.0f, float const & requested_h = 0.0f); explicit octonion(::std::complex<float> const & z0, ::std::complex<float> const & z1 = ::std::complex<float>(), ::std::complex<float> const & z2 = ::std::complex<float>(), ::std::complex<float> const & z3 = ::std::complex<float>()); explicit octonion(::boost::math::quaternion<float> const & q0, ::boost::math::quaternion<float> const & q1 = ::boost::math::quaternion<float>()); explicit octonion(octonion<double> const & a_recopier); explicit octonion(octonion<long double> const & a_recopier);
Double specialization version:
explicit octonion(double const & requested_a = 0.0, double const & requested_b = 0.0, double const & requested_c = 0.0, double const & requested_d = 0.0, double const & requested_e = 0.0, double const & requested_f = 0.0, double const & requested_g = 0.0, double const & requested_h = 0.0); explicit octonion(::std::complex<double> const & z0, ::std::complex<double> const & z1 = ::std::complex<double>(), ::std::complex<double> const & z2 = ::std::complex<double>(), ::std::complex<double> const & z3 = ::std::complex<double>()); explicit octonion(::boost::math::quaternion<double> const & q0, ::boost::math::quaternion<double> const & q1 = ::boost::math::quaternion<double>()); explicit octonion(octonion<float> const & a_recopier); explicit octonion(octonion<long double> const & a_recopier);
Long double specialization version:
explicit octonion(long double const & requested_a = 0.0L, long double const & requested_b = 0.0L, long double const & requested_c = 0.0L, long double const & requested_d = 0.0L, long double const & requested_e = 0.0L, long double const & requested_f = 0.0L, long double const & requested_g = 0.0L, long double const & requested_h = 0.0L); explicit octonion( ::std::complex<long double> const & z0, ::std::complex<long double> const & z1 = ::std::complex<long double>(), ::std::complex<long double> const & z2 = ::std::complex<long double>(), ::std::complex<long double> const & z3 = ::std::complex<long double>()); explicit octonion(::boost::math::quaternion<long double> const & q0, ::boost::math::quaternion<long double> const & q1 = ::boost::math::quaternion<long double>()); explicit octonion(octonion<float> const & a_recopier); explicit octonion(octonion<double> const & a_recopier);
A default constructor is provided for each form, which initializes each component to the default values for their type (i.e. zero for floating numbers). This constructor can also accept one to eight base type arguments. A constructor is also provided to build octonions from one to four complex numbers sharing the same base type, and another taking one or two quaternions sharing the same base type. The unspecialized template also sports a templarized copy constructor, while the specialized forms have copy constructors from the other two specializations, which are explicit when a risk of precision loss exists. For the unspecialized form, the base type's constructors must not throw.
Destructors and untemplated copy constructors (from the same type) are provided by the compiler. Converting copy constructors make use of a templated helper function in a "detail" subnamespace.
T real() const; octonion<T> unreal() const;
Like complex number, octonions do have a meaningful notion of "real part", but unlike them there is no meaningful notion of "imaginary part". Instead there is an "unreal part" which itself is a octonion, and usually nothing simpler (as opposed to the complex number case). These are returned by the first two functions.
T R_component_1() const; T R_component_2() const; T R_component_3() const; T R_component_4() const; T R_component_5() const; T R_component_6() const; T R_component_7() const; T R_component_8() const;
A octonion having eight real components, these are returned by these eight functions. Hence real and R_component_1 return the same value.
::std::complex<T> C_component_1() const; ::std::complex<T> C_component_2() const; ::std::complex<T> C_component_3() const; ::std::complex<T> C_component_4() const;
A octonion likewise has four complex components. Actually, octonions are indeed
a (left) vector field over the complexes, but beware, as for any octonion
o = α + βi + γj + δk + εe' + ζi' + ηj' + θk'
we also have o
= (α + βi) + (γ + δi)j + (ε + ζi)e' + (η - θi)j'
(note the minus sign
in the last factor). What the C_component_n functions return, however, are
the complexes which could be used to build the octonion using the constructor,
and not the components of the octonion on
the basis (1, j, e', j')
.
::boost::math::quaternion<T> H_component_1() const; ::boost::math::quaternion<T> H_component_2() const;
Likewise, for any octonion o = α + βi + γj + δk + εe' + ζi' + ηj' + θk'
we
also have o = (α + βi + γj + δk) + (ε + ζi + ηj - θj)e'
, though there is no
meaningful vector-space-like structure based on the quaternions. What the H_component_n
functions return are the quaternions which could be used to build the octonion
using the constructor.
octonion<T> & operator = (octonion<T> const & a_affecter); template<typename X> octonion<T> & operator = (octonion<X> const & a_affecter); octonion<T> & operator = (T const & a_affecter); octonion<T> & operator = (::std::complex<T> const & a_affecter); octonion<T> & operator = (::boost::math::quaternion<T> const & a_affecter);
These perform the expected assignment, with type modification if necessary (for instance, assigning from a base type will set the real part to that value, and all other components to zero). For the unspecialized form, the base type's assignment operators must not throw.
octonion<T> & operator += (T const & rhs) octonion<T> & operator += (::std::complex<T> const & rhs); octonion<T> & operator += (::boost::math::quaternion<T> const & rhs); template<typename X> octonion<T> & operator += (octonion<X> const & rhs);
These perform the mathematical operation (*this)+rhs
and store the result in *this
.
The unspecialized form has exception guards, which the specialized forms do
not, so as to insure exception safety. For the unspecialized form, the base
type's assignment operators must not throw.
octonion<T> & operator -= (T const & rhs) octonion<T> & operator -= (::std::complex<T> const & rhs); octonion<T> & operator -= (::boost::math::quaternion<T> const & rhs); template<typename X> octonion<T> & operator -= (octonion<X> const & rhs);
These perform the mathematical operation (*this)-rhs
and store the result in *this
.
The unspecialized form has exception guards, which the specialized forms do
not, so as to insure exception safety. For the unspecialized form, the base
type's assignment operators must not throw.
octonion<T> & operator *= (T const & rhs) octonion<T> & operator *= (::std::complex<T> const & rhs); octonion<T> & operator *= (::boost::math::quaternion<T> const & rhs); template<typename X> octonion<T> & operator *= (octonion<X> const & rhs);
These perform the mathematical operation (*this)*rhs
in this order (order is important as multiplication is not commutative for
octonions) and store the result in *this
. The unspecialized form has exception guards,
which the specialized forms do not, so as to insure exception safety. For the
unspecialized form, the base type's assignment operators must not throw. Also,
for clarity's sake, you should always group the factors in a multiplication
by groups of two, as the multiplication is not even associative on the octonions
(though there are of course cases where this does not matter, it usually does).
octonion<T> & operator /= (T const & rhs) octonion<T> & operator /= (::std::complex<T> const & rhs); octonion<T> & operator /= (::boost::math::quaternion<T> const & rhs); template<typename X> octonion<T> & operator /= (octonion<X> const & rhs);
These perform the mathematical operation (*this)*inverse_of(rhs)
in this order (order is important as multiplication is not commutative for
octonions) and store the result in *this
. The unspecialized form has exception guards,
which the specialized forms do not, so as to insure exception safety. For the
unspecialized form, the base type's assignment operators must not throw. As
for the multiplication, remember to group any two factors using parenthesis.