//

//

// 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 );

   }

};