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.
242 lines
7.8 KiB
242 lines
7.8 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.08.22
|
|
|
|
#pragma once
|
|
|
|
#include <algorithm>
|
|
#include <cstdint>
|
|
#include <limits>
|
|
|
|
// Support for determining the number of bits of precision required to compute
|
|
// an expression using BSNumber or BSRational.
|
|
|
|
namespace gte
|
|
{
|
|
class BSPrecision
|
|
{
|
|
public:
|
|
enum Type
|
|
{
|
|
IS_FLOAT,
|
|
IS_DOUBLE,
|
|
IS_INT32,
|
|
IS_INT64,
|
|
IS_UINT32,
|
|
IS_UINT64
|
|
};
|
|
|
|
struct Parameters
|
|
{
|
|
Parameters()
|
|
:
|
|
minExponent(0),
|
|
maxExponent(0),
|
|
maxBits(0),
|
|
maxWords(0)
|
|
{
|
|
}
|
|
|
|
Parameters(int inMinExponent, int inMaxExponent, int inMaxBits)
|
|
:
|
|
minExponent(inMinExponent),
|
|
maxExponent(inMaxExponent),
|
|
maxBits(inMaxBits),
|
|
maxWords(GetMaxWords())
|
|
{
|
|
}
|
|
|
|
inline int GetMaxWords() const
|
|
{
|
|
return maxBits / 32 + ((maxBits % 32) > 0 ? 1 : 0);
|
|
}
|
|
|
|
int minExponent, maxExponent, maxBits, maxWords;
|
|
};
|
|
|
|
Parameters bsn, bsr;
|
|
|
|
BSPrecision() = default;
|
|
|
|
BSPrecision(Type type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case IS_FLOAT:
|
|
bsn = Parameters(-149, 127, 24);
|
|
break;
|
|
case IS_DOUBLE:
|
|
bsn = Parameters(-1074, 1023, 53);
|
|
break;
|
|
case IS_INT32:
|
|
bsn = Parameters(0, 30, 31);
|
|
break;
|
|
case IS_INT64:
|
|
bsn = Parameters(0, 62, 63);
|
|
break;
|
|
case IS_UINT32:
|
|
bsn = Parameters(0, 31, 32);
|
|
break;
|
|
case IS_UINT64:
|
|
bsn = Parameters(0, 63, 64);
|
|
break;
|
|
}
|
|
bsr = bsn;
|
|
}
|
|
|
|
BSPrecision(int minExponent, int maxExponent, int maxBits)
|
|
:
|
|
bsn(minExponent, maxExponent, maxBits),
|
|
bsr(minExponent, maxExponent, maxBits)
|
|
{
|
|
}
|
|
};
|
|
|
|
inline BSPrecision operator+(BSPrecision const& bsp0, BSPrecision const& bsp1)
|
|
{
|
|
BSPrecision result;
|
|
|
|
result.bsn.minExponent = std::min(bsp0.bsn.minExponent, bsp1.bsn.minExponent);
|
|
if (bsp0.bsn.maxExponent >= bsp1.bsn.maxExponent)
|
|
{
|
|
result.bsn.maxExponent = bsp0.bsn.maxExponent;
|
|
if (bsp0.bsn.maxExponent - bsp0.bsn.maxBits + 1 <= bsp1.bsn.maxExponent)
|
|
{
|
|
++result.bsn.maxExponent;
|
|
}
|
|
|
|
result.bsn.maxBits = bsp0.bsn.maxExponent - bsp1.bsn.minExponent + 1;
|
|
if (result.bsn.maxBits <= bsp0.bsn.maxBits + bsp1.bsn.maxBits - 1)
|
|
{
|
|
++result.bsn.maxBits;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result.bsn.maxExponent = bsp1.bsn.maxExponent;
|
|
if (bsp1.bsn.maxExponent - bsp1.bsn.maxBits + 1 <= bsp0.bsn.maxExponent)
|
|
{
|
|
++result.bsn.maxExponent;
|
|
}
|
|
|
|
result.bsn.maxBits = bsp1.bsn.maxExponent - bsp0.bsn.minExponent + 1;
|
|
if (result.bsn.maxBits <= bsp0.bsn.maxBits + bsp1.bsn.maxBits - 1)
|
|
{
|
|
++result.bsn.maxBits;
|
|
}
|
|
}
|
|
result.bsn.maxWords = result.bsn.GetMaxWords();
|
|
|
|
// Addition is n0/d0 + n1/d1 = (n0*d1 + n1*d0)/(d0*d1). The numerator
|
|
// and denominator of a number are assumed to have the same
|
|
// parameters, so for the addition, the numerator is used for the
|
|
// parameter computations.
|
|
|
|
// Compute the parameters for the multiplication.
|
|
int mulMinExponent = bsp0.bsr.minExponent + bsp1.bsr.minExponent;
|
|
int mulMaxExponent = bsp0.bsr.maxExponent + bsp1.bsr.maxExponent + 1;
|
|
int mulMaxBits = bsp0.bsr.maxBits + bsp1.bsr.maxBits;
|
|
|
|
// Compute the parameters for the addition. The number n0*d1 and n1*d0
|
|
// are in the same arbitrary-precision set.
|
|
result.bsr.minExponent = mulMinExponent;
|
|
result.bsr.maxExponent = mulMaxExponent + 1; // Always a carry-out.
|
|
result.bsr.maxBits = mulMaxExponent - mulMinExponent + 1;
|
|
if (result.bsr.maxBits <= 2 * mulMaxBits - 1)
|
|
{
|
|
++result.bsr.maxBits;
|
|
}
|
|
result.bsr.maxWords = result.bsr.GetMaxWords();
|
|
|
|
return result;
|
|
}
|
|
|
|
inline BSPrecision operator-(BSPrecision const& bsp0, BSPrecision const& bsp1)
|
|
{
|
|
return bsp0 + bsp1;
|
|
}
|
|
|
|
inline BSPrecision operator*(BSPrecision const& bsp0, BSPrecision const& bsp1)
|
|
{
|
|
BSPrecision result;
|
|
|
|
result.bsn.minExponent = bsp0.bsn.minExponent + bsp1.bsn.minExponent;
|
|
result.bsn.maxExponent = bsp0.bsn.maxExponent + bsp1.bsn.maxExponent + 1;
|
|
result.bsn.maxBits = bsp0.bsn.maxBits + bsp1.bsn.maxBits;
|
|
result.bsn.maxWords = result.bsn.GetMaxWords();
|
|
|
|
// Multiplication is (n0/d0) * (n1/d1) = (n0 * n1) / (d0 * d1). The
|
|
// parameters are the same as for numerator/denominator.
|
|
result.bsr.minExponent = bsp0.bsr.minExponent + bsp1.bsr.minExponent;
|
|
result.bsr.maxExponent = bsp0.bsr.maxExponent + bsp1.bsr.maxExponent + 1;
|
|
result.bsr.maxBits = bsp0.bsr.maxBits + bsp1.bsr.maxBits;
|
|
result.bsr.maxWords = result.bsr.GetMaxWords();
|
|
|
|
return result;
|
|
}
|
|
|
|
inline BSPrecision operator/(BSPrecision const& bsp0, BSPrecision const& bsp1)
|
|
{
|
|
BSPrecision result;
|
|
|
|
// BSNumber does not support division, so result.bsr has all members
|
|
// set to zero.
|
|
|
|
// Division is (n0/d0) / (n1/d1) = (n0 * d1) / (n1 * d0). The
|
|
// parameters are the same as for multiplication.
|
|
result.bsr.minExponent = bsp0.bsr.minExponent + bsp1.bsr.minExponent;
|
|
result.bsr.maxExponent = bsp0.bsr.maxExponent + bsp1.bsr.maxExponent + 1;
|
|
result.bsr.maxBits = bsp0.bsr.maxBits + bsp1.bsr.maxBits;
|
|
result.bsr.maxWords = result.bsr.GetMaxWords();
|
|
|
|
return result;
|
|
}
|
|
|
|
// Comparisons for BSNumber do not involve dynamic allocations, so
|
|
// the results are the extremes of the inputs. Comparisons for BSRational
|
|
// involve multiplications of numerators and denominators.
|
|
inline BSPrecision operator==(BSPrecision const& bsp0, BSPrecision const& bsp1)
|
|
{
|
|
BSPrecision result;
|
|
|
|
result.bsn.minExponent = std::min(bsp0.bsn.minExponent, bsp1.bsn.minExponent);
|
|
result.bsn.maxExponent = std::max(bsp0.bsn.maxExponent, bsp1.bsn.maxExponent);
|
|
result.bsn.maxBits = std::max(bsp0.bsn.maxBits, bsp1.bsn.maxBits);
|
|
result.bsn.maxWords = result.bsn.GetMaxWords();
|
|
|
|
result.bsr.minExponent = bsp0.bsr.minExponent + bsp1.bsr.minExponent;
|
|
result.bsr.maxExponent = bsp0.bsr.maxExponent + bsp1.bsr.maxExponent + 1;
|
|
result.bsr.maxBits = bsp0.bsr.maxBits + bsp1.bsr.maxBits;
|
|
result.bsr.maxWords = result.bsr.GetMaxWords();
|
|
|
|
return result;
|
|
}
|
|
|
|
inline BSPrecision operator!=(BSPrecision const& bsp0, BSPrecision const& bsp1)
|
|
{
|
|
return operator==(bsp0, bsp1);
|
|
}
|
|
|
|
inline BSPrecision operator<(BSPrecision const& bsp0, BSPrecision const& bsp1)
|
|
{
|
|
return operator==(bsp0, bsp1);
|
|
}
|
|
|
|
inline BSPrecision operator<=(BSPrecision const& bsp0, BSPrecision const& bsp1)
|
|
{
|
|
return operator==(bsp0, bsp1);
|
|
}
|
|
|
|
inline BSPrecision operator>(BSPrecision const& bsp0, BSPrecision const& bsp1)
|
|
{
|
|
return operator==(bsp0, bsp1);
|
|
}
|
|
|
|
inline BSPrecision operator>=(BSPrecision const& bsp0, BSPrecision const& bsp1)
|
|
{
|
|
return operator==(bsp0, bsp1);
|
|
}
|
|
}
|
|
|