//
//
// Quadratic.h: Quadratic with arbitrary precision.
//
// Proper Numbers Library
//
// © Copyright 2011 - 2011 by Miroslav Bonchev Bonchev. All rights reserved.
//
//
//******************************************************************************************************
// Open Source License – The MIT License
//
//
// {your product} uses the: Proper Numbers Library – Copyright © 2011 by Miroslav Bonchev Bonchev. All Rights Reserved.
// {your product} uses the: Object Contextualization Model – Copyright © 2009 - 2011 by Miroslav Bonchev Bonchev. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
// associated documentation files (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge, publish, distribute,
// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//__________________________________________________________________________________________________
// This software is OSI Certified Open Source Software.
// OSI Certified is a certification mark of the Open Source Initiative.
#pragma once
#include "stdafx.h"
#include "Common.h"
#include "StringEx.h"
#include "Specialize.h"
#include "Rational.h"
#define Minus_Char_TextSize L"22"
#define Rational_Notation_TextSize L"12"
#define Decimal_Notation_TextSize L"12"
// Functor is a function that remains as it is e.g. SRQT( 5 )
class Functor
{
protected:
Rational rElement;
public:
Functor( const Rational& rElement ) : rElement( rElement )
{
}
Functor( const Functor& function ) : rElement( function.rElement )
{
}
virtual ~Functor()
{
}
Functor& operator=( const Functor& function )
{
rElement = function.rElement;
return( *this );
}
virtual bool IsZero() const
{
return( rElement.IsZero() );
}
virtual MStringEx< TCHAR > Print() const = 0;
virtual MStringEx< TCHAR > PrintAsDoubleInDecimalNotation( const BYTE b1Precision ) const = 0;
virtual Rational ApplyInverse() const
{
return( rElement );
}
virtual Rational ApplyInverseOnValue( const Rational& rNumber ) const = 0;
virtual Rational ApplyInverseOnProduct( const Rational& rNumber ) const = 0;
virtual double GetAsDouble() const = 0;
virtual bool IsPositive() const = 0;
bool IsCompatible( const Functor& functor ) const
{
return( rElement == functor.rElement );
}
friend inline bool operator ==( const Functor& rLeft, const Functor& rRight )
{
return( rLeft.rElement == rRight.rElement );
}
friend inline bool operator !=( const Functor& rLeft, const Functor& rRight )
{
return( ! operator ==( rLeft, rRight ) );
}
};
class SquareRoot : public Functor
{
public:
SquareRoot( const Rational& rational ) : Functor( rational )
{
}
SquareRoot( const SquareRoot& squareRoot ) : Functor( squareRoot )
{
}
virtual ~SquareRoot()
{
}
SquareRoot& operator=( const SquareRoot& squareRoot )
{
__super::operator=( squareRoot );
return( *this );
}
virtual MStringEx< TCHAR > Print() const
{
return( MStringEx< TCHAR >( MStringEx< TCHAR >::FF, TEXT("sqrt( %s )"), (LPCTSTR)rElement.Print() ) );
}
virtual MStringEx< TCHAR > PrintAsDoubleInDecimalNotation( const BYTE b1Precision ) const
{
return( MStringEx< TCHAR >( MStringEx< TCHAR >::FF, TEXT("sqrt( %s )"), (LPCTSTR)rElement.PrintAsDoubleInDecimalNotation( b1Precision ) ) );
}
virtual bool IsPositive() const
{
return( true );
}
const Rational& SquarePower() const
{
return( rElement );
}
virtual Rational ApplyInverseOnValue( const Rational& rNumber ) const
{
return( rNumber.ToPower( 2 ) );
}
virtual Rational ApplyInverseOnProduct( const Rational& rNumber ) const
{
return( rNumber.ToPower( 2 ) * ApplyInverse() );
}
virtual double GetAsDouble() const
{
return( sqrt( rElement.GetAsDouble() ) );
}
};
class CubeRoot : public Functor
{
public:
CubeRoot( const Rational& rational ) : Functor( rational )
{
}
CubeRoot( const CubeRoot& cubeRoot ) : Functor( cubeRoot )
{
}
virtual ~CubeRoot()
{
}
CubeRoot& operator=( const CubeRoot& squareRoot )
{
__super::operator=( squareRoot );
return( *this );
}
virtual MStringEx< TCHAR > Print() const
{
return( MStringEx< TCHAR >( MStringEx< TCHAR >::FF, TEXT("cbrt( %s )"), (LPCTSTR)rElement.Print() ) );
}
virtual MStringEx< TCHAR > PrintAsDoubleInDecimalNotation( const BYTE b1Precision ) const
{
return( MStringEx< TCHAR >( MStringEx< TCHAR >::FF, TEXT("cbrt( %s )"), (LPCTSTR)rElement.PrintAsDoubleInDecimalNotation( b1Precision ) ) );
}
virtual bool IsPositive() const
{
return( true );
}
virtual Rational ApplyInverseOnValue( const Rational& rNumber ) const
{
return( rNumber.ToPower( 3 ) );
}
virtual Rational ApplyInverseOnProduct( const Rational& rNumber ) const
{
return( rNumber.ToPower( 3 ) * ApplyInverse() );
}
virtual double GetAsDouble() const
{
return( pow( rElement.GetAsDouble(), (double)1 / (double)3 ) );
}
};
// r1*functor(r2)
template< class tFunctor >
class Functional
{
private:
Rational rCoeff;
tFunctor fFunct;
public:
// Copy constructor.
Functional( const Functional& functional ) : rCoeff( functional.rCoeff ), fFunct( functional.fFunct )
{
}
// Constructor from unsigned numerator and denominator.
Functional( const Rational& rCoeff, const tFunctor& fFunct ) : rCoeff( rCoeff ), fFunct( fFunct )
{
}
// Destructor.
~Functional()
{
}
// Standard operator equal.
Functional& operator=( const Functional& functional )
{
rCoeff = functional.rCoeff;
fFunct = functional.fFunct;
return( *this );
}
// Returns a double approximation of the functional value.
double GetAsDouble() const
{
return( rCoeff.GetAsDouble() * fFunct.GetAsDouble() );
}
Rational ApplyInverse() const
{
return( fFunct.ApplyInverseOnProduct( rCoeff ) );
}
// Standard operator +=
Functional< tFunctor > operator +=( const Functional< tFunctor >& fSummand )
{
return( *this = *this + fSummand );
}
// Standard operator -=
Functional< tFunctor > operator -=( const Functional< tFunctor >& fSubtrahend )
{
return( *this = *this - fSubtrahend );
}
// Standard operator *=
Functional< tFunctor > operator *=( const Functional< tFunctor >& rFactor )
{
return( *this = *this * rFactor );
}
// Standard operator /=
Functional< tFunctor > operator /=( const Functional< tFunctor >& rDivisor )
{
return( *this = *this / rDivisor );
}
// Unary plus (returns the operand itself).
Functional< tFunctor > operator+() const
{
return( *this );
}
// Unary operator negation – inverts the signd.
Functional< tFunctor > operator-() const
{
return( Functional< tFunctor >( rCoeff, fFunct ) );
}
// Returns the coefficient.
const Rational& GetCoefficient() const
{
return( rCoeff );
}
// Returns the functor.
const tFunctor& GetFunctor() const
{
return( fFunct );
}
// Test if the number is zero.
bool IsZero() const
{
return( rCoeff.IsZero() || fFunct.IsZero() );
}
// Print the Functional exactly.
MStringEx< TCHAR > Print() const
{
return( MStringEx< TCHAR >( MStringEx< TCHAR >::FF, TEXT("%s.%s"), (LPCTSTR)rCoeff.Print(), (LPCTSTR)fFunct.Print() ) );
}
// This prints the Functional using double representation of the contained numbers.
// The parameter sets the required number of digits after the decimal point, max number is 16. Note that
// the floating point representation is most likely inaccurate to some degree depending on the represented
// number. Floating point numbers cannot represent proper rational numbers satisfactory.
MStringEx< TCHAR > PrintAsDoubleInDecimalNotation( const BYTE b1Precision ) const
{
return( MStringEx< TCHAR >( MStringEx< TCHAR >::FF, TEXT("%s.%s"), (LPCTSTR)rCoeff.PrintAsDoubleInDecimalNotation( b1Precision ), (LPCTSTR)fFunct.PrintAsDoubleInDecimalNotation( b1Precision ) ) );
}
// External operators - friend operators.
// Standard comparison operator equal to.
friend inline bool operator ==( const Functional< tFunctor >& fLeft, const Functional< tFunctor >& fRight )
{
NumberException< tFunctional, true >::TestCompatibility( fLeft.fFunct, fRight.fFunct );
return( fLeft.rCoeff == fRight.rCoeff );
}
// Standard comparison operator not equal to.
friend inline bool operator !=( const Functional< tFunctor >& rLeft, const Functional< tFunctor >& rRight )
{
NumberException< tFunctional, true >::TestCompatibility( fLeft.fFunct, fRight.fFunct );
return( fLeft.rCoeff != fRight.rCoeff );
}
// Standard comparison operator less than.
friend inline bool operator <( const Functional< tFunctor >& rLeft, const Functional< tFunctor >& rRight )
{
NumberException< tFunctional, true >::TestCompatibility( fLeft.fFunct, fRight.fFunct );
return( fLeft.rCoeff < fRight.rCoeff );
}
// Standard comparison operator greater than.
friend inline bool operator >( const Functional< tFunctor >& rLeft, const Functional< tFunctor >& rRight )
{
NumberException< tFunctional, true >::TestCompatibility( fLeft.fFunct, fRight.fFunct );
return( fLeft.rCoeff > fRight.rCoeff );
}
// Standard comparison operator less than or equal to.
friend inline bool operator <=( const Functional< tFunctor >& rLeft, const Functional< tFunctor >& rRight )
{
NumberException< tFunctional, true >::TestCompatibility( fLeft.fFunct, fRight.fFunct );
return( fLeft.rCoeff <= fRight.rCoeff );
}
// Standard comparison operator greater than or equal to.
friend inline bool operator >=( const Functional< tFunctor >& rLeft, const Functional< tFunctor >& rRight )
{
NumberException< tFunctional, true >::TestCompatibility( fLeft.fFunct, fRight.fFunct );
return( fLeft.rCoeff >= fRight.rCoeff );
}
// Standard arithmetic operator plus.
friend inline Functional< tFunctor > operator +( const Functional< tFunctor >& fSummandL, const Functional< tFunctor >& fSummandR )
{
NumberException< tFunctor, true >::TestCompatibility( fSummandL.fFunct, fSummandR.fFunct );
// r1*f(r) + r2*f(r) = (r1 + r2)*f(r)
return( Functional< tFunctor >( fSummandL.rCoeff + fSummandR.rCoeff, fSummandL.fFunct ) );
}
// Standard arithmetic operator minus.
friend inline Functional< tFunctor > operator -( const Functional< tFunctor >& fMinuend, const Functional< tFunctor >& fSubtrahend )
{
NumberException< tFunctor, true >::TestCompatibility( fMinuend.fFunct, fSubtrahend.fFunct );
// r1*f(r) - r2*f(r) = (r1 + r2)*f(r)
return( Functional< tFunctor >( fMinuend.rCoeff - fSubtrahend.rCoeff, fMinuend.fFunct ) );
}
// Arithmetic operator multiplication - Rational = Functional * Functional
// Big problems here. This operator must return a Functional IN GENERAL. The Coefficient part has no problems,
// But the functor part presents a large proplem, it needs to change so I need to return VARIANT type...
friend inline Rational operator *( const Functional< tFunctor >& fFactorL, const Functional< tFunctor >& fFactorR )
{
NumberException< tFunctor, true >::TestCompatibility( fFactorL.fFunct, fFactorR.fFunct );
return( fFactorL.rCoeff * fFactorR.rCoeff * fFactorL.fFunct.SquarePower() );
}
// Standard arithmetic operator multiplication.
friend inline Functional< tFunctor > operator *( const Rational& rLeft, const Functional< tFunctor >& fFactorR )
{
return( Functional< tFunctor >( rLeft * fFactorR.rCoeff, fFactorR.fFunct ) );
}
// Standard arithmetic operator multiplication.
friend inline Functional< tFunctor > operator *( const Functional< tFunctor >& fFactorL, const Rational& rRight )
{
return( Functional< tFunctor >( rRight * fFactorL.rCoeff, fFactorL.fFunct ) );
}
// Standard arithmetic operator division. This operator throws
// NumberException exception when dividing by zero.
friend inline Functional< tFunctor > operator /( const Functional< tFunctor >& rDividend, const Functional< tFunctor >& rDivisor )
{
NumberException< Functional< tFunctor >, true >::TestDivisionByZero( rDivisor );
NumberException< tFunctor, true >::TestCompatibility( rDividend.fFunct, rDivisor.fFunct );
return( Functional< tFunctor >( rDividend.rCoeff / rDivisor.rCoeff, rDividend.fFunct / rDivisor.fFunct ) );
}
};
template< class tFunctional >
class Quadratic //TBase
{
private:
Rational rNumer;
Functional< tFunctional > fFunctional;
public:
// Copy constructor.
Quadratic( const Quadratic< tFunctional >& quadratic )
: rNumer( quadratic.rNumer ),
fFunctional( quadratic.fFunctional )
{
}
// Constructor from signed integer.
Quadratic( const __int64 nInteger )
: rNumer( nInteger ),
fFunctional( 0, tFunctional( 5 ) )
{
}
// Constructor from integer.
Quadratic( const Integer& iNumer )
: rNumer( specialize< Integer as sX::Numerator >::Initialize( rNumer ),
fFunctional( 0, tFunctional( 5 ) ) )
{
}
// Constructor from Rational.
Quadratic( const Rational& rNumer )
: rNumer( rNumer ),
fFunctional( 0, tFunctional( 5 ) )
{
}
// Constructor from Rational and functional.
Quadratic( const Rational& rNumer, const Functional< tFunctional >& fFunctional )
: rNumer( rNumer ),
fFunctional( fFunctional )
{
}
// Destructor.
~Quadratic()
{
}
// Standard operator equal.
Quadratic< tFunctional >& operator=( const Quadratic< tFunctional >& quadratic )
{
rNumer = quadratic.rNumer;
fFunctional = quadratic.fFunctional ;
return( *this );
}
// Standard operator +=
Quadratic< tFunctional > operator +=( const Quadratic< tFunctional >& rSummand )
{
return( *this = *this + rSummand );
}
// Standard operator -=
Quadratic< tFunctional > operator -=( const Quadratic< tFunctional >& rSubtrahend )
{
return( *this = *this - rSubtrahend );
}
// Standard operator *=
Quadratic< tFunctional > operator *=( const Quadratic< tFunctional >& rFactor )
{
return( *this = *this * rFactor );
}
// Standard operator /=
Quadratic< tFunctional > operator /=( const Quadratic< tFunctional >& rDivisor )
{
return( *this = *this / rDivisor );
}
// Unary plus (returns the operand itself).
Quadratic< tFunctional > operator+() const
{
return( *this );
}
// Unary operator negation – inverts the sign.
Quadratic< tFunctional > operator-() const
{
return( Quadratic< tFunctional >( -rNumer, -fFunctional ) );
}
// Test if the number is zero.
bool IsZero() const
{
return( rNumer.IsZero() && fFunctional.IsZero() );
}
// This method prints a string exact representations of the quadratic number.
// This method is intended for use when the Rational is specialized with the Integer class. If used with
// another specializer type, it must have method string Print() const, where string must have LPCTSTR
// overloaded operator. Although this method returns the exact rational number, in some circumstances
// one may want to also consider using the float representations for informative purposes as their results
// may be easier to interpret.
MStringEx< TCHAR > Print() const
{
return( MStringEx< TCHAR >( MStringEx< TCHAR >::FF, TEXT("%s %s"), (LPCTSTR)rNumer.Print(), (LPCTSTR)fFunctional.Print() ) );
}
// This method returns the double representation of the rational number and functional as a string in decimal notation.
// The parameter sets the required number of digits after the decimal point, max number is 16. Note that
// the floating point representation is most likely inaccurate to some degree depending on the represented
// number. Floating point numbers cannot represent proper rational numbers satisfactory.
MStringEx< TCHAR > PrintAsDoublePartsInDecimalNotation( const BYTE b1Precision ) const
{
return( MStringEx< TCHAR >( MStringEx< TCHAR >::FF, TEXT("%s %s"), (LPCTSTR)rNumer.PrintAsDoubleInDecimalNotation( b1Precision ), (LPCTSTR)fFunctional.PrintAsDoubleInDecimalNotation( b1Precision ) ) );
}
// This method returns the double approximation of the number.
// The parameter sets the required number of digits after the decimal point, max number is 16. Note that
// the floating point representation is most likely inaccurate to some degree depending on the represented
// number. Floating point numbers cannot represent proper rational numbers satisfactory.
MStringEx< TCHAR > PrintAsDoubleInDecimalNotation( const BYTE b1Precision ) const
{
return( MStringEx< TCHAR >( MStringEx< TCHAR >::FF, MStringEx< TCHAR >( MStringEx< TCHAR >::FF, TEXT("%%.%df"), b1Precision ), rNumer.GetAsDouble() + fFunctional.GetAsDouble() ) );
}
// This method returns a HTML table containing the Quadratic number in floating point notation. This
// method is intended for use when the Rational is specialized with the Integer class. If used with
// another specializer type, it must have method double GetAsDouble() const. Note that a number from
// the Rational class may be much larger than the larger number that a double precision floating point
// could represent and is also PRECISE. Also, note that floating point numbers are not evenly
// distributed having irregularly sized gaps between them. In difference the Rational specialized
// with Integer are evenly distributed and PRECISE. This means that Rational specialized with Integer
// number could be in fact very rarely represented using a floating point number. This function is
// useful for displaying Rational numbers for informative purposes.
MStringEx< TCHAR > PrintAsHtmlCell() const
{
// |- table -------------------|-----------------------|
// | quadratic | double approximation |
// |---------------------------|-----------------------|
return( MStringEx< TCHAR >( MStringEx< TCHAR >::FF,
L"<table border='0' cellpadding='0' cellspacing='0' style='text-align: right;'>\
<tr>\
<td style='font-size: 12px; width:500px; text-align: right; font-size:" Decimal_Notation_TextSize L"px; width: 300px;'>%s</td>\
<td style='padding-left:20px; text-align: left; font-size:" Decimal_Notation_TextSize L"px; width: 200px;'>%s</td>\
</tr>\
</table>", (LPCTSTR)Print(), (LPCTSTR)PrintAsDoubleInDecimalNotation( 16 ) ) );
}
// External operators - friend operators.
// Standard comparison operator equal to.
friend inline bool operator ==( const Quadratic< tFunctional >& rLeft, const Quadratic< tFunctional >& rRight )
{
NumberException< tFunctional, true >::TestCompatibility( rLeft.fFunctional.GetFunctor(), rRight.fFunctional.GetFunctor() );
// | a1 c1 | | a2 c2 | | a1 a2 | | c2 c1 |
// |---- + ----m| ? |---- + ----m| => |---- - ----| ? |---- - ----|m => (x1 -x2) ? (y2-y1)m
// | b1 d1 | | b2 d2 | | b1 b2 | | d2 d1 |
return( rLeft.fFunctional.GetFunctor().ApplyInverseOnValue( rLeft.rNumer - rRight.rNumer ) == Functional< tFunctional >( rRight.fFunctional.GetCoefficient() - rLeft.fFunctional.GetCoefficient(), rLeft.fFunctional.GetFunctor() ).ApplyInverse() );
}
// Standard comparison operator not equal to.
friend inline bool operator !=( const Quadratic< tFunctional >& rLeft, const Quadratic< tFunctional >& rRight )
{
return( !operator==( rLeft, rRight ) );
}
// Standard comparison operator less than.
friend inline bool operator <( const Quadratic< tFunctional >& rLeft, const Quadratic< tFunctional >& rRight )
{
NumberException< tFunctional, true >::TestCompatibility( rLeft.fFunctional.GetFunctor(), rRight.fFunctional.GetFunctor() );
// | a1 c1 | | a2 c2 | | a1 a2 | | c2 c1 |
// |---- + ----m| < |---- + ----m| -> |---- - ----| < |---- - ----|m -> (x1 -x2) < (y2-y1)m -> X < Ym
// | b1 d1 | | b2 d2 | | b1 b2 | | d2 d1 |
const Rational rX( rLeft.rNumer - rRight.rNumer );
const Rational rY( rRight.fFunctional.GetCoefficient() - rLeft.fFunctional.GetCoefficient() );
const bool bX_positive( 0 < rX );
const bool bYm_positive( (0 < rY) && rRight.fFunctional.GetFunctor().IsPositive() );
if( bX_positive != bYm_positive )
{
// One side is positive, the other negative. rYm > 0 => rYm > rX.
return( bYm_positive );
}
// Both sides are of the same sign.
if( bX_positive || (rLeft.fFunctional.GetFunctor().ApplyInverseOnValue( -1 ) < 0) )
{
// Both sides are positive
// OR the inverse of the functor does not change the sign - consider m is CubeRoot.
// Compare the inverses as it is.
return( rLeft.fFunctional.GetFunctor().ApplyInverseOnValue( rX ) < Functional< tFunctional >( rY, rLeft.fFunctional.GetFunctor() ).ApplyInverse() );
}
// Both sides are negative, and the inverse changes the sign - consider m is SquareRoot.
return( rLeft.fFunctional.GetFunctor().ApplyInverseOnValue( rX ) > Functional< tFunctional >( rY, rLeft.fFunctional.GetFunctor() ).ApplyInverse() );
}
// Standard comparison operator greater than.
friend inline bool operator >( const Quadratic< tFunctional >& rLeft, const Quadratic< tFunctional >& rRight )
{
NumberException< tFunctional, true >::TestCompatibility( rLeft.fFunctional.GetFunctor(), rRight.fFunctional.GetFunctor() );
// | a1 c1 | | a2 c2 | | a1 a2 | | c2 c1 |
// |---- + ----m| > |---- + ----m| -> |---- - ----| > |---- - ----|m -> (x1 -x2) > (y2-y1)m -> X > Ym
// | b1 d1 | | b2 d2 | | b1 b2 | | d2 d1 |
const Rational rX( rLeft.rNumer - rRight.rNumer );
const Rational rY( rRight.fFunctional.GetCoefficient() - rLeft.fFunctional.GetCoefficient() );
const bool bX_positive( 0 < rX );
const bool bYm_positive( (0 < rY) && rRight.fFunctional.GetFunctor().IsPositive() );
if( bX_positive != bYm_positive )
{
// One side is positive, the other negative. rX > 0 => rX > rYm.
return( bX_positive );
}
// Both sides are of the same sign.
if( bX_positive || (rLeft.fFunctional.GetFunctor().ApplyInverseOnValue( -1 ) < 0) )
{
// Both sides are positive
// OR the inverse of the functor does not change the sign - consider m is CubeRoot.
// Compare the inverses as it is.
return( rLeft.fFunctional.GetFunctor().ApplyInverseOnValue( rX ) > Functional< tFunctional >( rY, rLeft.fFunctional.GetFunctor() ).ApplyInverse() );
}
// Both sides are negative, and the inverse changes the sign - consider m is SquareRoot.
return( rLeft.fFunctional.GetFunctor().ApplyInverseOnValue( rX ) < Functional< tFunctional >( rY, rLeft.fFunctional.GetFunctor() ).ApplyInverse() );
}
// Standard comparison operator less than or equal to.
friend inline bool operator <=( const Quadratic< tFunctional >& rLeft, const Quadratic< tFunctional >& rRight )
{
return( operator< ( rLeft, rRight ) || operator==( rLeft, rRight ) );
}
// Standard comparison operator greater than or equal to.
friend inline bool operator >=( const Quadratic< tFunctional >& rLeft, const Quadratic< tFunctional >& rRight )
{
return( operator> ( rLeft, rRight ) || operator==( rLeft, rRight ) );
}
// Standard arithmetic operator plus.
friend inline Quadratic< tFunctional > operator +( const Quadratic< tFunctional >& iSummandL, const Quadratic< tFunctional >& iSummandR )
{
return( Quadratic< tFunctional >( iSummandL.rNumer + iSummandR.rNumer, iSummandL.fFunctional + iSummandR.fFunctional ) );
}
// Standard arithmetic operator minus.
friend inline Quadratic< tFunctional > operator -( const Quadratic< tFunctional >& qMinuend, const Quadratic< tFunctional >& qSubtrahend )
{
return( Quadratic< tFunctional >( qMinuend.rNumer - qSubtrahend.rNumer, qMinuend.fFunctional - qSubtrahend.fFunctional ) );
}
// Standard arithmetic operator multiplication.
friend inline Quadratic< tFunctional > operator *( const Quadratic< tFunctional >& qFactorL, const Quadratic< tFunctional >& qFactorR )
{
return( Quadratic< tFunctional >( qFactorL.rNumer * qFactorR.rNumer + qFactorL.fFunctional * qFactorR.fFunctional, qFactorL.rNumer * qFactorR.fFunctional + qFactorL.fFunctional * qFactorR.rNumer ) );
}
// Standard arithmetic operator division. This operator throws
// NumberException exception when dividing by zero.
friend inline Quadratic< tFunctional > operator /( const Quadratic< tFunctional >& qDividend, const Quadratic< tFunctional >& qDivisor )
{
NumberException< Quadratic< tFunctional >, true >::TestDivisionByZero( qDivisor );
NumberException< tFunctional, true >::TestCompatibility( qDividend.fFunctional.GetFunctor(), qDivisor.fFunctional.GetFunctor() );
// | a1 c1 | | a2 c2 | b2.d2 mD^2
// |---- + ----m| / |---- + ----| = A = ------- . --------------------------------- .[ B = (a1.a2.d1.d2 - b1.b2.c1.c2.m^2) + C = (a2.b1.c1.d2 - a1.b2.c2.d1).m]
// | b1 d1 | | b2 d2 | b1.d1 (a2.d2)^2.mD^2 - (b2.c2)^2.mN^2
const Rational a1( qDividend.rNumer.IsNegative(), specialize< Integer as sX::Numerator >::Initialize( qDividend.rNumer.GetNumerator() ) );
const Rational b1( specialize< Integer as sX::Numerator >::Initialize( qDividend.rNumer.GetDenominator() ) );
const Rational c1( qDividend.fFunctional.GetCoefficient().IsNegative(), specialize< Integer as sX::Numerator >::Initialize( qDividend.fFunctional.GetCoefficient().GetNumerator() ) );
const Rational d1( specialize< Integer as sX::Numerator >::Initialize( qDividend.fFunctional.GetCoefficient().GetDenominator() ) );
const Rational a2( qDivisor.rNumer.IsNegative(), specialize< Integer as sX::Numerator >::Initialize( qDivisor.rNumer.GetNumerator() ) );
const Rational b2( specialize< Integer as sX::Numerator >::Initialize( qDivisor.rNumer.GetDenominator() ) );
const Rational c2( qDivisor.fFunctional.GetCoefficient().IsNegative(), specialize< Integer as sX::Numerator >::Initialize( qDivisor.fFunctional.GetCoefficient().GetNumerator() ) );
const Rational d2( specialize< Integer as sX::Numerator >::Initialize( qDivisor.fFunctional.GetCoefficient().GetDenominator() ) );
const Rational mSquare( qDividend.fFunctional.GetFunctor().SquarePower() );
// Compute the singless parts.
const Rational A( specialize< Integer as sX::Numerator >::Initialize( b2.GetNumerator() * d2.GetNumerator() * mSquare.GetDenominator() ),
specialize< Integer as sX::Denominator >::Initialize( b1.GetNumerator() * d1.GetNumerator() *
(a2.GetNumerator() *
a2.GetNumerator() *
d2.GetNumerator() *
d2.GetNumerator() *
mSquare.GetDenominator() -
c2.GetNumerator() *
c2.GetNumerator() *
b2.GetNumerator() *
b2.GetNumerator() *
mSquare.GetNumerator()) ) );
const Rational B( a1 * a2 * d1 * d2 - b1 * b2 * c1 * c2 * mSquare );
const Rational C( a2 * b1 * c1 * d2 - a1 * b2 * c2 * d1 );
return( Quadratic< tFunctional >( A * B, Functional< tFunctional >( A * C, qDividend.fFunctional.GetFunctor() ) ) );
}
const Rational& GetNumer() const
{
return( rNumer );
}
const Functional< tFunctional >& GetFunctional() const
{
return( fFunctional );
}
};