232 lines
4.3 KiB
C
232 lines
4.3 KiB
C
|
#ifndef EXPANSION_H
|
||
|
#define EXPANSION_H
|
||
|
|
||
|
// Released into the public-domain by Robert Bridson, 2009.
|
||
|
// Modified by Tyson Brochu, 2011.
|
||
|
// Simple functions for manipulating multiprecision floating-point
|
||
|
// expansions, with simplicity favoured over speed.
|
||
|
|
||
|
#include <vector>
|
||
|
|
||
|
// The basic type is essentially a vector of *increasing* and
|
||
|
// *nonoverlapping* doubles, apart from allowed zeroes anywhere.
|
||
|
namespace CCD
|
||
|
{
|
||
|
class expansion;
|
||
|
|
||
|
void negative(const expansion& input, expansion& output);
|
||
|
|
||
|
int sign( const expansion& a );
|
||
|
|
||
|
bool
|
||
|
is_zero( const expansion& a );
|
||
|
|
||
|
void
|
||
|
add(double a, double b, expansion& sum);
|
||
|
|
||
|
// a and sum may be aliased to the same expansion for in-place addition
|
||
|
void
|
||
|
add(const expansion& a, double b, expansion& sum);
|
||
|
|
||
|
inline void
|
||
|
add(double a, const expansion& b, expansion& sum)
|
||
|
{ add(b, a, sum); }
|
||
|
|
||
|
// aliasing a, b and sum is safe
|
||
|
void
|
||
|
add(const expansion& a, const expansion& b, expansion& sum);
|
||
|
|
||
|
void
|
||
|
subtract( const double& a, const double& b, expansion& difference);
|
||
|
|
||
|
// aliasing a, b and difference is safe
|
||
|
void
|
||
|
subtract(const expansion& a, const expansion& b, expansion& difference);
|
||
|
|
||
|
// aliasing input and output is safe
|
||
|
void
|
||
|
negative(const expansion& input, expansion& output);
|
||
|
|
||
|
void
|
||
|
multiply(double a, double b, expansion& product);
|
||
|
|
||
|
void
|
||
|
multiply(double a, double b, double c, expansion& product);
|
||
|
|
||
|
void
|
||
|
multiply(double a, double b, double c, double d, expansion& product);
|
||
|
|
||
|
void
|
||
|
multiply(const expansion& a, double b, expansion& product);
|
||
|
|
||
|
inline void
|
||
|
multiply(double a, const expansion& b, expansion& product)
|
||
|
{ multiply(b, a, product); }
|
||
|
|
||
|
// Aliasing NOT safe
|
||
|
void
|
||
|
multiply(const expansion& a, const expansion& b, expansion& product);
|
||
|
|
||
|
void compress( const expansion& e, expansion& h );
|
||
|
|
||
|
// Aliasing NOT safe
|
||
|
bool divide( const expansion& x, const expansion& y, expansion& q );
|
||
|
|
||
|
void
|
||
|
remove_zeros(expansion& a);
|
||
|
|
||
|
double
|
||
|
estimate(const expansion& a);
|
||
|
|
||
|
bool equals( const expansion& a, const expansion& b );
|
||
|
|
||
|
void
|
||
|
print_full( const expansion& e );
|
||
|
|
||
|
|
||
|
// ----------------------------------------------------
|
||
|
|
||
|
class expansion
|
||
|
{
|
||
|
|
||
|
public:
|
||
|
|
||
|
std::vector<double> v;
|
||
|
|
||
|
expansion()
|
||
|
: v(0)
|
||
|
{}
|
||
|
|
||
|
explicit expansion( double val )
|
||
|
: v(1, val)
|
||
|
{}
|
||
|
|
||
|
expansion( std::size_t n, double val )
|
||
|
: v(n,val)
|
||
|
{}
|
||
|
|
||
|
virtual ~expansion() {}
|
||
|
|
||
|
expansion& operator+=(const expansion &rhs)
|
||
|
{
|
||
|
add( *this, rhs, *this );
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
expansion& operator-=(const expansion &rhs)
|
||
|
{
|
||
|
subtract( *this, rhs, *this );
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
expansion& operator*=(const expansion &rhs)
|
||
|
{
|
||
|
expansion p;
|
||
|
multiply( *this, rhs, p );
|
||
|
*this = p;
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
inline expansion operator+(const expansion &other) const
|
||
|
{
|
||
|
expansion result = *this;
|
||
|
result += other;
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
inline expansion operator-(const expansion &other) const
|
||
|
{
|
||
|
expansion result = *this;
|
||
|
result -= other;
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
inline expansion operator*(const expansion &other) const
|
||
|
{
|
||
|
expansion result = *this;
|
||
|
result *= other;
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
inline expansion operator-( ) const
|
||
|
{
|
||
|
expansion result;
|
||
|
negative( *this, result );
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
bool is_certainly_negative() const{
|
||
|
return sign(*this) < 0;
|
||
|
}
|
||
|
|
||
|
bool is_certainly_positive() const{
|
||
|
return sign(*this) > 0;
|
||
|
}
|
||
|
|
||
|
bool is_certainly_zero() const{
|
||
|
return is_zero(*this);
|
||
|
}
|
||
|
|
||
|
bool same_sign(const expansion& b) const{
|
||
|
return sign(*this) == sign(b);
|
||
|
}
|
||
|
|
||
|
inline double estimate() const
|
||
|
{
|
||
|
return CCD::estimate( *this );
|
||
|
}
|
||
|
|
||
|
inline bool indefinite_sign() const
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
static void begin_special_arithmetic()
|
||
|
{}
|
||
|
|
||
|
static void end_special_arithmetic()
|
||
|
{}
|
||
|
|
||
|
inline void clear()
|
||
|
{
|
||
|
v.clear();
|
||
|
}
|
||
|
|
||
|
inline void resize( std::size_t new_size )
|
||
|
{
|
||
|
v.resize(new_size);
|
||
|
}
|
||
|
|
||
|
};
|
||
|
|
||
|
|
||
|
inline void make_expansion( double a, expansion& e )
|
||
|
{
|
||
|
if(a)
|
||
|
{
|
||
|
e = expansion(1, a);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
e.clear();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
inline void
|
||
|
make_zero(expansion& e)
|
||
|
{ e.resize(0); }
|
||
|
|
||
|
inline void create_from_double( double a, expansion& out )
|
||
|
{
|
||
|
make_expansion( a, out );
|
||
|
}
|
||
|
|
||
|
inline bool certainly_opposite_sign( const expansion& a, const expansion& b )
|
||
|
{
|
||
|
return ( sign(a) > 0 && sign(b) < 0 ) || ( sign(a) < 0 && sign(b) > 0 );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif
|