You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1045 lines
32 KiB

// David Eberly, Geometric Tools, Redmond WA 98052
// Copyright (c) 1998-2021
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
// https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
// Version: 4.0.2020.07.21
#pragma once
#include <Mathematics/BSNumber.h>
// See the comments in BSNumber.h about the UInteger requirements. The
// denominator of a BSRational is chosen to be positive, which allows some
// simplification of comparisons. Also see the comments about exposing the
// GTE_BINARY_SCIENTIFIC_SHOW_DOUBLE conditional define.
namespace gte
{
template <typename UInteger>
class BSRational
{
public:
// Construction. The default constructor generates the zero
// BSRational. The constructors that take only numerators set the
// denominators to one.
BSRational()
:
mNumerator(0),
mDenominator(1)
{
#if defined(GTE_BINARY_SCIENTIFIC_SHOW_DOUBLE)
mValue = (double)*this;
#endif
}
BSRational(BSRational const& r)
{
*this = r;
}
BSRational(float numerator)
:
mNumerator(numerator),
mDenominator(1.0f)
{
#if defined(GTE_BINARY_SCIENTIFIC_SHOW_DOUBLE)
mValue = (double)*this;
#endif
}
BSRational(double numerator)
:
mNumerator(numerator),
mDenominator(1.0)
{
#if defined(GTE_BINARY_SCIENTIFIC_SHOW_DOUBLE)
mValue = (double)*this;
#endif
}
BSRational(int32_t numerator)
:
mNumerator(numerator),
mDenominator(1)
{
#if defined(GTE_BINARY_SCIENTIFIC_SHOW_DOUBLE)
mValue = (double)*this;
#endif
}
BSRational(uint32_t numerator)
:
mNumerator(numerator),
mDenominator(1)
{
#if defined(GTE_BINARY_SCIENTIFIC_SHOW_DOUBLE)
mValue = (double)*this;
#endif
}
BSRational(int64_t numerator)
:
mNumerator(numerator),
mDenominator(1)
{
#if defined(GTE_BINARY_SCIENTIFIC_SHOW_DOUBLE)
mValue = (double)*this;
#endif
}
BSRational(uint64_t numerator)
:
mNumerator(numerator),
mDenominator(1)
{
#if defined(GTE_BINARY_SCIENTIFIC_SHOW_DOUBLE)
mValue = (double)*this;
#endif
}
BSRational(BSNumber<UInteger> const& numerator)
:
mNumerator(numerator),
mDenominator(1)
{
#if defined(GTE_BINARY_SCIENTIFIC_SHOW_DOUBLE)
mValue = (double)*this;
#endif
}
BSRational(float numerator, float denominator)
:
mNumerator(numerator),
mDenominator(denominator)
{
LogAssert(mDenominator.mSign != 0, "Division by zero.");
if (mDenominator.mSign < 0)
{
mNumerator.mSign = -mNumerator.mSign;
mDenominator.mSign = 1;
}
#if defined(GTE_BINARY_SCIENTIFIC_SHOW_DOUBLE)
mValue = (double)*this;
#endif
}
BSRational(double numerator, double denominator)
:
mNumerator(numerator),
mDenominator(denominator)
{
LogAssert(mDenominator.mSign != 0, "Division by zero.");
if (mDenominator.mSign < 0)
{
mNumerator.mSign = -mNumerator.mSign;
mDenominator.mSign = 1;
}
#if defined(GTE_BINARY_SCIENTIFIC_SHOW_DOUBLE)
mValue = (double)*this;
#endif
}
BSRational(int32_t numerator, int32_t denominator)
:
mNumerator(numerator),
mDenominator(denominator)
{
LogAssert(mDenominator.mSign != 0, "Division by zero.");
if (mDenominator.mSign < 0)
{
mNumerator.mSign = -mNumerator.mSign;
mDenominator.mSign = 1;
}
#if defined(GTE_BINARY_SCIENTIFIC_SHOW_DOUBLE)
mValue = (double)*this;
#endif
}
BSRational(uint32_t numerator, uint32_t denominator)
:
mNumerator(numerator),
mDenominator(denominator)
{
LogAssert(mDenominator.mSign != 0, "Division by zero.");
if (mDenominator.mSign < 0)
{
mNumerator.mSign = -mNumerator.mSign;
mDenominator.mSign = 1;
}
#if defined(GTE_BINARY_SCIENTIFIC_SHOW_DOUBLE)
mValue = (double)*this;
#endif
}
BSRational(int64_t numerator, int64_t denominator)
:
mNumerator(numerator),
mDenominator(denominator)
{
LogAssert(mDenominator.mSign != 0, "Division by zero.");
if (mDenominator.mSign < 0)
{
mNumerator.mSign = -mNumerator.mSign;
mDenominator.mSign = 1;
}
#if defined(GTE_BINARY_SCIENTIFIC_SHOW_DOUBLE)
mValue = (double)*this;
#endif
}
BSRational(uint64_t numerator, uint64_t denominator)
:
mNumerator(numerator),
mDenominator(denominator)
{
LogAssert(mDenominator.mSign != 0, "Division by zero.");
if (mDenominator.mSign < 0)
{
mNumerator.mSign = -mNumerator.mSign;
mDenominator.mSign = 1;
}
#if defined(GTE_BINARY_SCIENTIFIC_SHOW_DOUBLE)
mValue = (double)*this;
#endif
}
BSRational(BSNumber<UInteger> const& numerator, BSNumber<UInteger> const& denominator)
:
mNumerator(numerator),
mDenominator(denominator)
{
LogAssert(mDenominator.mSign != 0, "Division by zero.");
if (mDenominator.mSign < 0)
{
mNumerator.mSign = -mNumerator.mSign;
mDenominator.mSign = 1;
}
// Set the exponent of the denominator to zero, but you can do so
// only by modifying the biased exponent. Adjust the numerator
// accordingly. This prevents large growth of the exponents in
// both numerator and denominator simultaneously.
mNumerator.mBiasedExponent -= mDenominator.GetExponent();
mDenominator.mBiasedExponent = -(mDenominator.GetUInteger().GetNumBits() - 1);
#if defined(GTE_BINARY_SCIENTIFIC_SHOW_DOUBLE)
mValue = (double)*this;
#endif
}
BSRational(std::string const& number)
{
LogAssert(number.size() > 0, "A number must be specified.");
// Get the leading '+' or '-' if it exists.
std::string fpNumber;
int sign;
if (number[0] == '+')
{
fpNumber = number.substr(1);
sign = +1;
LogAssert(fpNumber.size() > 1, "Invalid number format.");
}
else if (number[0] == '-')
{
fpNumber = number.substr(1);
sign = -1;
LogAssert(fpNumber.size() > 1, "Invalid number format.");
}
else
{
fpNumber = number;
sign = +1;
}
size_t decimal = fpNumber.find('.');
if (decimal != std::string::npos)
{
if (decimal > 0)
{
if (decimal < fpNumber.size())
{
// The number is "x.y".
BSNumber<UInteger> intPart = BSNumber<UInteger>::ConvertToInteger(fpNumber.substr(0, decimal));
BSRational frcPart = ConvertToFraction(fpNumber.substr(decimal + 1));
mNumerator = intPart * frcPart.mDenominator + frcPart.mNumerator;
mDenominator = frcPart.mDenominator;
}
else
{
// The number is "x.".
mNumerator = BSNumber<UInteger>::ConvertToInteger(fpNumber.substr(0,fpNumber.size()-1));
mDenominator = 1;
}
}
else
{
// The number is ".y".
BSRational frcPart = ConvertToFraction(fpNumber.substr(1));
mNumerator = frcPart.mNumerator;
mDenominator = frcPart.mDenominator;
}
}
else
{
// The number is "x".
mNumerator = BSNumber<UInteger>::ConvertToInteger(fpNumber);
mDenominator = 1;
}
mNumerator.SetSign(sign);
#if defined(GTE_BINARY_SCIENTIFIC_SHOW_DOUBLE)
mValue = (double)*this;
#endif
}
BSRational(const char* number)
:
BSRational(std::string(number))
{
}
// Implicit conversions. These always use the default rounding mode,
// round-to-nearest-ties-to-even.
operator float() const
{
float output;
Convert(*this, FE_TONEAREST, output);
return output;
}
operator double() const
{
double output;
Convert(*this, FE_TONEAREST, output);
return output;
}
// Assignment.
BSRational& operator=(BSRational const& r)
{
mNumerator = r.mNumerator;
mDenominator = r.mDenominator;
#if defined(GTE_BINARY_SCIENTIFIC_SHOW_DOUBLE)
mValue = (double)*this;
#endif
return *this;
}
// Support for move semantics.
BSRational(BSRational&& r) noexcept
{
*this = std::move(r);
}
BSRational& operator=(BSRational&& r) noexcept
{
mNumerator = std::move(r.mNumerator);
mDenominator = std::move(r.mDenominator);
#if defined(GTE_BINARY_SCIENTIFIC_SHOW_DOUBLE)
mValue = (double)*this;
#endif
return *this;
}
// Member access.
inline void SetSign(int sign)
{
mNumerator.SetSign(sign);
mDenominator.SetSign(1);
#if defined(GTL_BINARY_SCIENTIFIC_SHOW_DOUBLE)
mValue = sign * std::fabs(mValue);
#endif
}
inline int GetSign() const
{
return mNumerator.GetSign() * mDenominator.GetSign();
}
inline BSNumber<UInteger> const& GetNumerator() const
{
return mNumerator;
}
inline BSNumber<UInteger>& GetNumerator()
{
return mNumerator;
}
inline BSNumber<UInteger> const& GetDenominator() const
{
return mDenominator;
}
inline BSNumber<UInteger>& GetDenominator()
{
return mDenominator;
}
// Comparisons.
bool operator==(BSRational const& r) const
{
// Do inexpensive sign tests first for optimum performance.
if (mNumerator.mSign != r.mNumerator.mSign)
{
return false;
}
if (mNumerator.mSign == 0)
{
// The numbers are both zero.
return true;
}
return mNumerator * r.mDenominator == mDenominator * r.mNumerator;
}
bool operator!=(BSRational const& r) const
{
return !operator==(r);
}
bool operator< (BSRational const& r) const
{
// Do inexpensive sign tests first for optimum performance.
if (mNumerator.mSign > 0)
{
if (r.mNumerator.mSign <= 0)
{
return false;
}
}
else if (mNumerator.mSign == 0)
{
return r.mNumerator.mSign > 0;
}
else if (mNumerator.mSign < 0)
{
if (r.mNumerator.mSign >= 0)
{
return true;
}
}
return mNumerator * r.mDenominator < mDenominator * r.mNumerator;
}
bool operator<=(BSRational const& r) const
{
return !r.operator<(*this);
}
bool operator> (BSRational const& r) const
{
return r.operator<(*this);
}
bool operator>=(BSRational const& r) const
{
return !operator<(r);
}
// Unary operations.
BSRational operator+() const
{
return *this;
}
BSRational operator-() const
{
return BSRational(-mNumerator, mDenominator);
}
// Arithmetic.
BSRational operator+(BSRational const& r) const
{
BSNumber<UInteger> product0 = mNumerator * r.mDenominator;
BSNumber<UInteger> product1 = mDenominator * r.mNumerator;
BSNumber<UInteger> numerator = product0 + product1;
// Complex expressions can lead to 0/denom, where denom is not 1.
if (numerator.mSign != 0)
{
BSNumber<UInteger> denominator = mDenominator * r.mDenominator;
return BSRational(numerator, denominator);
}
else
{
return BSRational(0);
}
}
BSRational operator-(BSRational const& r) const
{
BSNumber<UInteger> product0 = mNumerator * r.mDenominator;
BSNumber<UInteger> product1 = mDenominator * r.mNumerator;
BSNumber<UInteger> numerator = product0 - product1;
// Complex expressions can lead to 0/denom, where denom is not 1.
if (numerator.mSign != 0)
{
BSNumber<UInteger> denominator = mDenominator * r.mDenominator;
return BSRational(numerator, denominator);
}
else
{
return BSRational(0);
}
}
BSRational operator*(BSRational const& r) const
{
BSNumber<UInteger> numerator = mNumerator * r.mNumerator;
// Complex expressions can lead to 0/denom, where denom is not 1.
if (numerator.mSign != 0)
{
BSNumber<UInteger> denominator = mDenominator * r.mDenominator;
return BSRational(numerator, denominator);
}
else
{
return BSRational(0);
}
}
BSRational operator/(BSRational const& r) const
{
LogAssert(r.mNumerator.mSign != 0, "Division by zero in BSRational::operator/.");
BSNumber<UInteger> numerator = mNumerator * r.mDenominator;
// Complex expressions can lead to 0/denom, where denom is not 1.
if (numerator.mSign != 0)
{
BSNumber<UInteger> denominator = mDenominator * r.mNumerator;
if (denominator.mSign < 0)
{
numerator.mSign = -numerator.mSign;
denominator.mSign = 1;
}
return BSRational(numerator, denominator);
}
else
{
return BSRational(0);
}
}
BSRational& operator+=(BSRational const& r)
{
*this = operator+(r);
return *this;
}
BSRational& operator-=(BSRational const& r)
{
*this = operator-(r);
return *this;
}
BSRational& operator*=(BSRational const& r)
{
*this = operator*(r);
return *this;
}
BSRational& operator/=(BSRational const& r)
{
*this = operator/(r);
return *this;
}
// Disk input/output. The fstream objects should be created using
// std::ios::binary. The return value is 'true' iff the operation
// was successful.
bool Write(std::ostream& output) const
{
return mNumerator.Write(output) && mDenominator.Write(output);
}
bool Read(std::istream& input)
{
return mNumerator.Read(input) && mDenominator.Read(input);
}
private:
// Helper for converting a string to a BSRational, where the string
// is the fractional part "y" of the string "x.y".
static BSRational ConvertToFraction(std::string const& number)
{
LogAssert(number.find_first_not_of("0123456789") == std::string::npos, "Invalid number format.");
BSRational y(0), ten(10), pow10(10);
for (size_t i = 0; i < number.size(); ++i)
{
int digit = static_cast<int>(number[i]) - static_cast<int>('0');
if (digit > 0)
{
y += BSRational(digit) / pow10;
}
pow10 *= ten;
}
return y;
}
#if defined(GTE_BINARY_SCIENTIFIC_SHOW_DOUBLE)
public:
// List this first so that it shows up first in the debugger watch
// window.
double mValue;
private:
#endif
BSNumber<UInteger> mNumerator, mDenominator;
};
// Explicit conversion to a user-specified precision. The rounding
// mode is one of the flags provided in <cfenv>. The modes are
// FE_TONEAREST: round to nearest ties to even
// FE_DOWNWARD: round towards negative infinity
// FE_TOWARDZERO: round towards zero
// FE_UPWARD: round towards positive infinity
template <typename UInteger>
void Convert(BSRational<UInteger> const& input, int32_t precision,
int32_t roundingMode, BSNumber<UInteger>& output)
{
if (precision <= 0)
{
LogError("Precision must be positive.");
}
size_t const maxNumBlocks = UInteger::GetMaxSize();
size_t const numPrecBlocks = static_cast<size_t>((precision + 31) / 32);
if (numPrecBlocks >= maxNumBlocks)
{
LogError("The maximum precision has been exceeded.");
}
if (input.GetSign() == 0)
{
output = BSNumber<UInteger>(0);
return;
}
BSNumber<UInteger> n = input.GetNumerator();
BSNumber<UInteger> d = input.GetDenominator();
// The ratio is abstractly of the form n/d = (1.u*2^p)/(1.v*2^q).
// Convert to the form
// (1.u/1.v)*2^{p-q}, if 1.u >= 1.v
// 2*(1.u/1.v)*2^{p-q-1} if 1.u < 1.v
// which are in the interval [1,2).
int32_t sign = n.GetSign() * d.GetSign();
n.SetSign(1);
d.SetSign(1);
int32_t pmq = n.GetExponent() - d.GetExponent();
n.SetExponent(0);
d.SetExponent(0);
if (n < d)
{
n.SetExponent(n.GetExponent() + 1);
--pmq;
}
// Let p = precision. At this time, n/d = 1.c in [1,2). Define the
// sequence of bits w = 1c = w_{p-1} w_{p-2} ... w_0 r, where
// w_{p-1} = 1. The bits r after w_0 are used for rounding based on
// the user-specified rounding mode.
// Compute p bits for w, the leading bit guaranteed to be 1 and
// occurring at index (1 << (precision-1)).
BSNumber<UInteger> one(1), two(2);
UInteger& w = output.GetUInteger();
w.SetNumBits(precision);
w.SetAllBitsToZero();
int32_t const size = w.GetSize();
int32_t const precisionM1 = precision - 1;
int32_t const leading = precisionM1 % 32;
uint32_t mask = (1 << leading);
auto& bits = w.GetBits();
int32_t current = size - 1;
int32_t lastBit = -1;
for (int i = precisionM1; i >= 0; --i)
{
if (n < d)
{
n = two * n;
lastBit = 0;
}
else
{
n = two * (n - d);
bits[current] |= mask;
lastBit = 1;
if (n.GetSign() == 0)
{
// The input rational has a finite number of bits in its
// representation, so it is exactly a BSNumber.
if (i > 0)
{
// The number n is zero for the remainder of the loop,
// so the last bit of the p-bit precision pattern is
// a zero. There is no need to continue looping.
lastBit = 0;
}
break;
}
}
if (mask == 0x00000001u)
{
--current;
mask = 0x80000000u;
}
else
{
mask >>= 1;
}
}
// At this point as a sequence of bits, r = n/d = r0 r1 ...
if (roundingMode == FE_TONEAREST)
{
n = n - d;
if (n.GetSign() > 0 || (n.GetSign() == 0 && lastBit == 1))
{
// round up
pmq += w.RoundUp();
}
// else round down, equivalent to truncating the r bits
}
else if (roundingMode == FE_UPWARD)
{
if (n.GetSign() > 0 && sign > 0)
{
// round up
pmq += w.RoundUp();
}
// else round down, equivalent to truncating the r bits
}
else if (roundingMode == FE_DOWNWARD)
{
if (n.GetSign() > 0 && sign < 0)
{
// Round down. This is the round-up operation applied to
// w, but the final sign is negative which amounts to
// rounding down.
pmq += w.RoundUp();
}
// else round down, equivalent to truncating the r bits
}
else if (roundingMode != FE_TOWARDZERO)
{
// Currently, no additional implementation-dependent modes
// are supported for rounding.
LogError("Implementation-dependent rounding mode not supported.");
}
// else roundingMode == FE_TOWARDZERO. Truncate the r bits, which
// requires no additional work.
// Shift the bits if necessary to obtain the invariant that BSNumber
// objects have bit patterns that are odd integers.
if ((w.GetBits()[0] & 1) == 0)
{
UInteger temp = w;
auto shift = w.ShiftRightToOdd(temp);
pmq += shift;
}
// Do not use SetExponent(pmq) at this step. The number of
// requested bits is 'precision' but w.GetNumBits() will be
// different when round-up occurs, and SetExponent accesses
// w.GetNumBits().
output.SetSign(sign);
output.SetBiasedExponent(pmq - precisionM1);
#if defined(GTE_BINARY_SCIENTIFIC_SHOW_DOUBLE)
output.mValue = (double)output;
#endif
}
// This conversion is used to avoid having to expose BSNumber in the
// APConversion class as well as other places where BSRational<UInteger>
// is passed via a template parameter named Rational.
template <typename UInteger>
void Convert(BSRational<UInteger> const& input, int32_t precision,
int32_t roundingMode, BSRational<UInteger>& output)
{
BSNumber<UInteger> numerator;
Convert(input, precision, roundingMode, numerator);
output = BSRational<UInteger>(numerator);
}
// Convert to 'float' or 'double' using the specified rounding mode.
template <typename UInteger, typename FPType>
void Convert(BSRational<UInteger> const& input, int32_t roundingMode, FPType& output)
{
static_assert(std::is_floating_point<FPType>::value, "Invalid floating-point type.");
BSNumber<UInteger> number;
Convert(input, std::numeric_limits<FPType>::digits, roundingMode, number);
output = static_cast<FPType>(number);
}
}
namespace std
{
// TODO: Allow for implementations of the math functions in which a
// specified precision is used when computing the result.
template <typename UInteger>
inline gte::BSRational<UInteger> acos(gte::BSRational<UInteger> const& x)
{
return (gte::BSRational<UInteger>)std::acos((double)x);
}
template <typename UInteger>
inline gte::BSRational<UInteger> acosh(gte::BSRational<UInteger> const& x)
{
return (gte::BSRational<UInteger>)std::acosh((double)x);
}
template <typename UInteger>
inline gte::BSRational<UInteger> asin(gte::BSRational<UInteger> const& x)
{
return (gte::BSRational<UInteger>)std::asin((double)x);
}
template <typename UInteger>
inline gte::BSRational<UInteger> asinh(gte::BSRational<UInteger> const& x)
{
return (gte::BSRational<UInteger>)std::asinh((double)x);
}
template <typename UInteger>
inline gte::BSRational<UInteger> atan(gte::BSRational<UInteger> const& x)
{
return (gte::BSRational<UInteger>)std::atan((double)x);
}
template <typename UInteger>
inline gte::BSRational<UInteger> atanh(gte::BSRational<UInteger> const& x)
{
return (gte::BSRational<UInteger>)std::atanh((double)x);
}
template <typename UInteger>
inline gte::BSRational<UInteger> atan2(gte::BSRational<UInteger> const& y, gte::BSRational<UInteger> const& x)
{
return (gte::BSRational<UInteger>)std::atan2((double)y, (double)x);
}
template <typename UInteger>
inline gte::BSRational<UInteger> ceil(gte::BSRational<UInteger> const& x)
{
return (gte::BSRational<UInteger>)std::ceil((double)x);
}
template <typename UInteger>
inline gte::BSRational<UInteger> cos(gte::BSRational<UInteger> const& x)
{
return (gte::BSRational<UInteger>)std::cos((double)x);
}
template <typename UInteger>
inline gte::BSRational<UInteger> cosh(gte::BSRational<UInteger> const& x)
{
return (gte::BSRational<UInteger>)std::cosh((double)x);
}
template <typename UInteger>
inline gte::BSRational<UInteger> exp(gte::BSRational<UInteger> const& x)
{
return (gte::BSRational<UInteger>)std::exp((double)x);
}
template <typename UInteger>
inline gte::BSRational<UInteger> exp2(gte::BSRational<UInteger> const& x)
{
return (gte::BSRational<UInteger>)std::exp2((double)x);
}
template <typename UInteger>
inline gte::BSRational<UInteger> fabs(gte::BSRational<UInteger> const& x)
{
return (x.GetSign() >= 0 ? x : -x);
}
template <typename UInteger>
inline gte::BSRational<UInteger> floor(gte::BSRational<UInteger> const& x)
{
return (gte::BSRational<UInteger>)std::floor((double)x);
}
template <typename UInteger>
inline gte::BSRational<UInteger> fmod(gte::BSRational<UInteger> const& x, gte::BSRational<UInteger> const& y)
{
return (gte::BSRational<UInteger>)std::fmod((double)x, (double)y);
}
template <typename UInteger>
inline gte::BSRational<UInteger> frexp(gte::BSRational<UInteger> const& x, int* exponent)
{
gte::BSRational<UInteger> result = x;
auto& numer = result.GetNumerator();
auto& denom = result.GetDenominator();
int32_t e = numer.GetExponent() - denom.GetExponent();
numer.SetExponent(0);
denom.SetExponent(0);
int32_t saveSign = numer.GetSign();
numer.SetSign(1);
if (numer >= denom)
{
++e;
numer.SetExponent(-1);
}
numer.SetSign(saveSign);
*exponent = e;
return result;
}
template <typename UInteger>
inline gte::BSRational<UInteger> ldexp(gte::BSRational<UInteger> const& x, int exponent)
{
gte::BSRational<UInteger> result = x;
int biasedExponent = result.GetNumerator().GetBiasedExponent();
biasedExponent += exponent;
result.GetNumerator().SetBiasedExponent(biasedExponent);
return result;
}
template <typename UInteger>
inline gte::BSRational<UInteger> log(gte::BSRational<UInteger> const& x)
{
return (gte::BSRational<UInteger>)std::log((double)x);
}
template <typename UInteger>
inline gte::BSRational<UInteger> log2(gte::BSRational<UInteger> const& x)
{
return (gte::BSRational<UInteger>)std::log2((double)x);
}
template <typename UInteger>
inline gte::BSRational<UInteger> log10(gte::BSRational<UInteger> const& x)
{
return (gte::BSRational<UInteger>)std::log10((double)x);
}
template <typename UInteger>
inline gte::BSRational<UInteger> pow(gte::BSRational<UInteger> const& x, gte::BSRational<UInteger> const& y)
{
return (gte::BSRational<UInteger>)std::pow((double)x, (double)y);
}
template <typename UInteger>
inline gte::BSRational<UInteger> sin(gte::BSRational<UInteger> const& x)
{
return (gte::BSRational<UInteger>)std::sin((double)x);
}
template <typename UInteger>
inline gte::BSRational<UInteger> sinh(gte::BSRational<UInteger> const& x)
{
return (gte::BSRational<UInteger>)std::sinh((double)x);
}
template <typename UInteger>
inline gte::BSRational<UInteger> sqrt(gte::BSRational<UInteger> const& x)
{
return (gte::BSRational<UInteger>)std::sqrt((double)x);
}
template <typename UInteger>
inline gte::BSRational<UInteger> tan(gte::BSRational<UInteger> const& x)
{
return (gte::BSRational<UInteger>)std::tan((double)x);
}
template <typename UInteger>
inline gte::BSRational<UInteger> tanh(gte::BSRational<UInteger> const& x)
{
return (gte::BSRational<UInteger>)std::tanh((double)x);
}
// Type trait that says BSRational is a signed type.
template <typename UInteger>
struct is_signed<gte::BSRational<UInteger>> : true_type {};
}
namespace gte
{
template <typename UInteger>
inline BSRational<UInteger> atandivpi(BSRational<UInteger> const& x)
{
return (BSRational<UInteger>)atandivpi((double)x);
}
template <typename UInteger>
inline BSRational<UInteger> atan2divpi(BSRational<UInteger> const& y, BSRational<UInteger> const& x)
{
return (BSRational<UInteger>)atan2divpi((double)y, (double)x);
}
template <typename UInteger>
inline BSRational<UInteger> clamp(BSRational<UInteger> const& x, BSRational<UInteger> const& xmin, BSRational<UInteger> const& xmax)
{
return (BSRational<UInteger>)clamp((double)x, (double)xmin, (double)xmax);
}
template <typename UInteger>
inline BSRational<UInteger> cospi(BSRational<UInteger> const& x)
{
return (BSRational<UInteger>)cospi((double)x);
}
template <typename UInteger>
inline BSRational<UInteger> exp10(BSRational<UInteger> const& x)
{
return (BSRational<UInteger>)exp10((double)x);
}
template <typename UInteger>
inline BSRational<UInteger> invsqrt(BSRational<UInteger> const& x)
{
return (BSRational<UInteger>)invsqrt((double)x);
}
template <typename UInteger>
inline int isign(BSRational<UInteger> const& x)
{
return isign((double)x);
}
template <typename UInteger>
inline BSRational<UInteger> saturate(BSRational<UInteger> const& x)
{
return (BSRational<UInteger>)saturate((double)x);
}
template <typename UInteger>
inline BSRational<UInteger> sign(BSRational<UInteger> const& x)
{
return (BSRational<UInteger>)sign((double)x);
}
template <typename UInteger>
inline BSRational<UInteger> sinpi(BSRational<UInteger> const& x)
{
return (BSRational<UInteger>)sinpi((double)x);
}
template <typename UInteger>
inline BSRational<UInteger> sqr(BSRational<UInteger> const& x)
{
return (BSRational<UInteger>)sqr((double)x);
}
// See the comments in Math.h about traits is_arbitrary_precision
// and has_division_operator.
template <typename UInteger>
struct is_arbitrary_precision_internal<BSRational<UInteger>> : std::true_type {};
template <typename UInteger>
struct has_division_operator_internal<BSRational<UInteger>> : std::true_type {};
}