// fp.h
// class fp
#ifndef FP_H
#define FP_H
#include <iosfwd>
#include <limits>
#include <string>
class fp;
template <> class std::numeric_limits<fp>;
class fp
{ // naive floating point implementation
public:
fp();
explicit fp(const char *);
explicit fp(double);
fp& operator += (const fp&);
fp& operator -= (const fp&);
fp& operator *= (const fp&);
fp& operator /= (const fp&);
friend fp operator - (const fp&);
friend bool operator == (const fp&, const fp&);
friend bool operator != (const fp&, const fp&);
friend bool operator < (const fp&, const fp&);
friend bool operator <= (const fp&, const fp&);
friend bool operator > (const fp&, const fp&);
friend bool operator >= (const fp&, const fp&);
static const fp zero;
static const fp one;
static const fp two;
friend std::string to_string(const fp&);
friend std::ostream& operator << (std::ostream&, const fp&);
enum round_mode
{
rm_nearest,
rm_down,
rm_up,
rm_zero
};
static void set_round(round_mode m) {rm = m;}
static round_mode get_round() {return rm;}
private:
friend class std::numeric_limits<fp>;
fp(int e, int f);
bool eq(const fp&) const;
bool lt(const fp&) const;
fp& add(const fp&, const fp&);
fp& normalize(int, long);
void round(long&);
void convert(double);
long lf() const;
enum fp_exception
{
div_by_zero,
exp_underflow,
exp_overflow
};
void exception(fp_exception);
bool is_neg;
unsigned char exp;
int frac;
static round_mode rm;
};
fp operator + (const fp&, const fp&);
fp operator - (const fp&, const fp&);
fp operator * (const fp&, const fp&);
fp operator / (const fp&, const fp&);
inline bool operator == (const fp& f1, const fp& f2)
{ // return f1 equal to f2
return f1.eq(f2);
}
inline bool operator != (const fp& f1, const fp& f2)
{ // return f1 not equal to f2
return !f1.eq(f2);
}
inline bool operator < (const fp& f1, const fp& f2)
{ // return f1 less than f2
return f1.lt(f2);
}
inline bool operator <= (const fp& f1, const fp& f2)
{ // return f1 less than or equal to f2
return !f2.lt(f1);
}
inline bool operator > (const fp& f1, const fp& f2)
{ // return f1 greater than f2
return f2.lt(f1);
}
inline bool operator >= (const fp& f1, const fp& f2)
{ // return f1 greater than or equal to f2
return !f1.lt(f2);
}
template <> class std::numeric_limits<fp>
{ // specialization of std::numeric_limits for class fp
public:
static const bool is_specialized = true;
static fp min()
{ // return minimum normalized value
return fp(min_exponent,0x4000);
}
static fp max()
{ // return maximum finite value
return fp(max_exponent, 0x7fff);
}
static const int digits = 15;
static const int digits10 = 4;
static const bool is_signed = true;
static const bool is_integer = false;
static const bool is_exact = false;
static const int radix = 2;
static fp epsilon()
{ // return f - 1.0, where f is smallest value
// greater than 1.0 that can be represented
return fp(-13, 0x4000);
}
static fp round_error()
{ // return estimate of the maximum rounding error
return fp(0.5);
}
static const int min_exponent = -128;
static const int min_exponent10 = -38;
static const int max_exponent = 127;
static const int max_exponent10 = 38;
static const bool has_infinity = false;
static const bool has_quiet_NaN = false;
static const bool has_signaling_NaN = false;
static const std::float_denorm_style has_denorm =
std::denorm_absent;
static const bool has_denorm_loss = false;
static fp infinity() throw();
static fp quiet_NaN() throw();
static fp signaling_NaN() throw();
static fp denorm_min()
{ // return minimum denormalized value
// (denormals not supported)
return min();
}
static const bool is_iec559 = false;
static const bool is_bounded = true;
static const bool is_modulo = false;
static const bool traps = false;
static const bool tinyness_before = false;
static const std::float_round_style round_style =
std::round_to_nearest;
};
#endif /* FP_H */