598 lines
13 KiB
C++
598 lines
13 KiB
C++
// This may look like C code, but it is really -*- C++ -*-
|
|
/*
|
|
Copyright (C) 1988 Free Software Foundation
|
|
written by Kurt Baudendistel (gt-eedsp!baud@gatech.edu)
|
|
adapted for libg++ by Doug Lea (dl@rocky.oswego.edu)
|
|
|
|
This file is part of the GNU C++ Library. This library is free
|
|
software; you can redistribute it and/or modify it under the terms of
|
|
the GNU Library General Public License as published by the Free
|
|
Software Foundation; either version 2 of the License, or (at your
|
|
option) any later version. This library is distributed in the hope
|
|
that it will be useful, but WITHOUT ANY WARRANTY; without even the
|
|
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
PURPOSE. See the GNU Library General Public License for more details.
|
|
You should have received a copy of the GNU Library General Public
|
|
License along with this library; if not, write to the Free Software
|
|
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
#ifndef _Fix24_h
|
|
#ifdef __GNUG__
|
|
#pragma interface
|
|
#endif
|
|
#define _Fix24_h 1
|
|
|
|
#include <stream.h>
|
|
#include <std.h>
|
|
|
|
// extra type definitions
|
|
|
|
typedef struct {
|
|
_G_int32_t u;
|
|
_G_uint32_t l;
|
|
} twolongs;
|
|
|
|
// constant definitions
|
|
|
|
static const int
|
|
Fix24_shift = 31;
|
|
|
|
static const double
|
|
Fix24_fs = 2147483648., // 2^Fix24_shift
|
|
Fix24_mult = Fix24_fs,
|
|
Fix24_div = 1./Fix24_fs,
|
|
Fix24_max = 1. - .5/Fix24_fs,
|
|
Fix24_min = -1.;
|
|
|
|
static const _G_uint32_t
|
|
Fix24_msb = 0x80000000L,
|
|
Fix24_lsb = 0x00000100L,
|
|
Fix24_m_max = 0x7fffff00L,
|
|
Fix24_m_min = 0x80000000L;
|
|
|
|
static const double
|
|
Fix48_fs = 36028797018963968., // 2^(24+Fix24_shift)
|
|
Fix48_max = 1. - .5/Fix48_fs,
|
|
Fix48_min = -1.,
|
|
Fix48_div_u = 1./Fix24_fs,
|
|
Fix48_div_l = 1./Fix48_fs;
|
|
|
|
static const twolongs
|
|
Fix48_msb = { 0x80000000L, 0L },
|
|
Fix48_lsb = { 0L, 0x00000100L },
|
|
Fix48_m_max = { 0x7fffff00L, 0xffffff00L },
|
|
Fix48_m_min = { 0x80000000L, 0L };
|
|
|
|
//
|
|
// Fix24 class: 24-bit Fixed point data type
|
|
//
|
|
// consists of a 24-bit mantissa (sign bit & 23 data bits).
|
|
//
|
|
|
|
class Fix24
|
|
{
|
|
friend class Fix48;
|
|
|
|
_G_int32_t m;
|
|
|
|
_G_int32_t assign(double d);
|
|
operator double() const;
|
|
Fix24(long i);
|
|
Fix24(int i);
|
|
|
|
|
|
public:
|
|
Fix24();
|
|
Fix24(const Fix24& f);
|
|
Fix24(double d);
|
|
Fix24(const Fix48& f);
|
|
|
|
~Fix24();
|
|
|
|
Fix24& operator=(const Fix24& f);
|
|
Fix24& operator=(double d);
|
|
Fix24& operator=(const Fix48& f);
|
|
|
|
friend _G_int32_t& mantissa(Fix24& f);
|
|
friend const _G_int32_t& mantissa(const Fix24& f);
|
|
friend double value(const Fix24& f);
|
|
|
|
Fix24 operator + () const;
|
|
Fix24 operator - () const;
|
|
|
|
friend Fix24 operator + (const Fix24& f, const Fix24& g);
|
|
friend Fix24 operator - (const Fix24& f, const Fix24& g);
|
|
friend Fix48 operator * (const Fix24& f, const Fix24& g);
|
|
friend Fix24 operator * (const Fix24& f, int g);
|
|
friend Fix24 operator * (int g, const Fix24& f);
|
|
friend Fix24 operator / (const Fix24& f, const Fix24& g);
|
|
friend Fix24 operator << (const Fix24& f, int b);
|
|
friend Fix24 operator >> (const Fix24& f, int b);
|
|
|
|
Fix24& operator += (const Fix24& f);
|
|
Fix24& operator -= (const Fix24& f);
|
|
Fix24& operator *= (const Fix24& f);
|
|
Fix24& operator *= (int b);
|
|
Fix24& operator /= (const Fix24& f);
|
|
|
|
Fix24& operator <<=(int b);
|
|
Fix24& operator >>=(int b);
|
|
|
|
friend int operator == (const Fix24& f, const Fix24& g);
|
|
friend int operator != (const Fix24& f, const Fix24& g);
|
|
friend int operator >= (const Fix24& f, const Fix24& g);
|
|
friend int operator <= (const Fix24& f, const Fix24& g);
|
|
friend int operator > (const Fix24& f, const Fix24& g);
|
|
friend int operator < (const Fix24& f, const Fix24& g);
|
|
|
|
friend istream& operator >> (istream& s, Fix24& f);
|
|
friend ostream& operator << (ostream& s, const Fix24& f);
|
|
|
|
void overflow(_G_int32_t&) const;
|
|
void range_error(_G_int32_t&) const;
|
|
};
|
|
|
|
|
|
//
|
|
// Fix48 class: 48-bit Fixed point data type
|
|
//
|
|
// consists of a 48-bit mantissa (sign bit & 47 data bits).
|
|
//
|
|
|
|
class Fix48
|
|
{
|
|
friend class Fix24;
|
|
|
|
twolongs m;
|
|
|
|
twolongs assign(double d);
|
|
operator double() const;
|
|
Fix48(twolongs i);
|
|
|
|
public:
|
|
Fix48();
|
|
Fix48(const Fix48& f);
|
|
Fix48(const Fix24& f);
|
|
Fix48(double d);
|
|
~Fix48();
|
|
|
|
Fix48& operator = (const Fix48& f);
|
|
Fix48& operator = (const Fix24& f);
|
|
Fix48& operator = (double d);
|
|
|
|
friend twolongs& mantissa(Fix48& f);
|
|
friend const twolongs& mantissa(const Fix48& f);
|
|
friend double value(const Fix48& f);
|
|
|
|
Fix48 operator + () const;
|
|
Fix48 operator - () const;
|
|
|
|
friend Fix48 operator + (const Fix48& f, const Fix48& g);
|
|
friend Fix48 operator - (const Fix48& f, const Fix48& g);
|
|
friend Fix48 operator * (const Fix48& f, int g);
|
|
friend Fix48 operator * (int g, const Fix48& f);
|
|
friend Fix48 operator << (const Fix48& f, int b);
|
|
friend Fix48 operator >> (const Fix48& f, int b);
|
|
|
|
friend Fix48 operator * (const Fix24& f, const Fix24& g);
|
|
|
|
Fix48& operator += (const Fix48& f);
|
|
Fix48& operator -= (const Fix48& f);
|
|
Fix48& operator *= (int b);
|
|
Fix48& operator <<=(int b);
|
|
Fix48& operator >>=(int b);
|
|
|
|
friend int operator == (const Fix48& f, const Fix48& g);
|
|
friend int operator != (const Fix48& f, const Fix48& g);
|
|
friend int operator >= (const Fix48& f, const Fix48& g);
|
|
friend int operator <= (const Fix48& f, const Fix48& g);
|
|
friend int operator > (const Fix48& f, const Fix48& g);
|
|
friend int operator < (const Fix48& f, const Fix48& g);
|
|
|
|
friend istream& operator >> (istream& s, Fix48& f);
|
|
friend ostream& operator << (ostream& s, const Fix48& f);
|
|
|
|
void overflow(twolongs& i) const;
|
|
void range_error(twolongs& i) const;
|
|
};
|
|
|
|
|
|
// active error handler declarations
|
|
|
|
typedef void (*Fix24_peh)(_G_int32_t&);
|
|
typedef void (*Fix48_peh)(twolongs&);
|
|
|
|
extern Fix24_peh Fix24_overflow_handler;
|
|
extern Fix48_peh Fix48_overflow_handler;
|
|
|
|
extern Fix24_peh Fix24_range_error_handler;
|
|
extern Fix48_peh Fix48_range_error_handler;
|
|
|
|
|
|
// error handler declarations
|
|
|
|
#if defined(SHORT_NAMES) || defined(VMS)
|
|
#define set_overflow_handler sohndl
|
|
#define set_range_error_handler srnghdl
|
|
#endif
|
|
|
|
extern Fix24_peh set_Fix24_overflow_handler(Fix24_peh);
|
|
extern Fix48_peh set_Fix48_overflow_handler(Fix48_peh);
|
|
extern void set_overflow_handler(Fix24_peh, Fix48_peh);
|
|
|
|
extern Fix24_peh set_Fix24_range_error_handler(Fix24_peh);
|
|
extern Fix48_peh set_Fix48_range_error_handler(Fix48_peh);
|
|
extern void set_range_error_handler(Fix24_peh, Fix48_peh);
|
|
|
|
extern void
|
|
Fix24_ignore(_G_int32_t&),
|
|
Fix24_overflow_saturate(_G_int32_t&),
|
|
Fix24_overflow_warning_saturate(_G_int32_t&),
|
|
Fix24_warning(_G_int32_t&),
|
|
Fix24_abort(_G_int32_t&);
|
|
|
|
extern void
|
|
Fix48_ignore(twolongs&),
|
|
Fix48_overflow_saturate(twolongs&),
|
|
Fix48_overflow_warning_saturate(twolongs&),
|
|
Fix48_warning(twolongs&),
|
|
Fix48_abort(twolongs&);
|
|
|
|
|
|
inline Fix24::~Fix24() {}
|
|
|
|
inline Fix24::Fix24(long i)
|
|
{
|
|
m = i;
|
|
}
|
|
|
|
inline Fix24::Fix24(int i)
|
|
{
|
|
m = i;
|
|
}
|
|
|
|
inline Fix24::operator double() const
|
|
{
|
|
return Fix24_div * m;
|
|
}
|
|
|
|
inline Fix24::Fix24()
|
|
{
|
|
m = 0;
|
|
}
|
|
|
|
inline Fix24::Fix24(const Fix24& f)
|
|
{
|
|
m = f.m;
|
|
}
|
|
|
|
inline Fix24::Fix24(double d)
|
|
{
|
|
m = assign(d);
|
|
}
|
|
|
|
inline Fix24::Fix24(const Fix48& f)
|
|
{
|
|
m = f.m.u;
|
|
}
|
|
|
|
inline Fix24& Fix24::operator=(const Fix24& f)
|
|
{
|
|
m = f.m;
|
|
return *this;
|
|
}
|
|
|
|
inline Fix24& Fix24::operator=(double d)
|
|
{
|
|
m = assign(d);
|
|
return *this;
|
|
}
|
|
|
|
inline Fix24& Fix24::operator=(const Fix48& f)
|
|
{
|
|
m = f.m.u;
|
|
return *this;
|
|
}
|
|
|
|
inline _G_int32_t& mantissa(Fix24& f)
|
|
{
|
|
return f.m;
|
|
}
|
|
|
|
inline const _G_int32_t& mantissa(const Fix24& f)
|
|
{
|
|
return f.m;
|
|
}
|
|
|
|
inline double value(const Fix24& f)
|
|
{
|
|
return double(f);
|
|
}
|
|
|
|
inline Fix24 Fix24::operator+() const
|
|
{
|
|
return m;
|
|
}
|
|
|
|
inline Fix24 Fix24::operator-() const
|
|
{
|
|
return -m;
|
|
}
|
|
|
|
inline Fix24 operator+(const Fix24& f, const Fix24& g)
|
|
{
|
|
_G_int32_t sum = f.m + g.m;
|
|
if ( (f.m ^ sum) & (g.m ^ sum) & Fix24_msb )
|
|
f.overflow(sum);
|
|
return sum;
|
|
}
|
|
|
|
inline Fix24 operator-(const Fix24& f, const Fix24& g)
|
|
{
|
|
_G_int32_t sum = f.m - g.m;
|
|
if ( (f.m ^ sum) & (-g.m ^ sum) & Fix24_msb )
|
|
f.overflow(sum);
|
|
return sum;
|
|
}
|
|
|
|
inline Fix24 operator*(const Fix24& a, int b)
|
|
{
|
|
return a.m * b;
|
|
}
|
|
|
|
inline Fix24 operator*(int b, const Fix24& a)
|
|
{
|
|
return a * b;
|
|
}
|
|
|
|
inline Fix24 operator<<(const Fix24& a, int b)
|
|
{
|
|
return a.m << b;
|
|
}
|
|
|
|
inline Fix24 operator>>(const Fix24& a, int b)
|
|
{
|
|
return (a.m >> b) & ~0xff;
|
|
}
|
|
|
|
inline Fix24& Fix24:: operator+=(const Fix24& f)
|
|
{
|
|
return *this = *this + f;
|
|
}
|
|
|
|
inline Fix24& Fix24:: operator-=(const Fix24& f)
|
|
{
|
|
return *this = *this - f;
|
|
}
|
|
|
|
inline Fix24& Fix24::operator*=(const Fix24& f)
|
|
{
|
|
return *this = *this * f;
|
|
}
|
|
|
|
inline Fix24& Fix24:: operator/=(const Fix24& f)
|
|
{
|
|
return *this = *this / f;
|
|
}
|
|
|
|
inline Fix24& Fix24:: operator<<=(int b)
|
|
{
|
|
return *this = *this << b;
|
|
}
|
|
|
|
inline Fix24& Fix24:: operator>>=(int b)
|
|
{
|
|
return *this = *this >> b;
|
|
}
|
|
|
|
inline Fix24& Fix24::operator*=(int b)
|
|
{
|
|
return *this = *this * b;
|
|
}
|
|
|
|
inline int operator==(const Fix24& f, const Fix24& g)
|
|
{
|
|
return f.m == g.m;
|
|
}
|
|
|
|
inline int operator!=(const Fix24& f, const Fix24& g)
|
|
{
|
|
return f.m != g.m;
|
|
}
|
|
|
|
inline int operator>=(const Fix24& f, const Fix24& g)
|
|
{
|
|
return f.m >= g.m;
|
|
}
|
|
|
|
inline int operator<=(const Fix24& f, const Fix24& g)
|
|
{
|
|
return f.m <= g.m;
|
|
}
|
|
|
|
inline int operator>(const Fix24& f, const Fix24& g)
|
|
{
|
|
return f.m > g.m;
|
|
}
|
|
|
|
inline int operator<(const Fix24& f, const Fix24& g)
|
|
{
|
|
return f.m < g.m;
|
|
}
|
|
|
|
inline istream& operator>>(istream& s, Fix24& f)
|
|
{
|
|
double d;
|
|
s >> d;
|
|
f = d;
|
|
return s;
|
|
}
|
|
|
|
inline ostream& operator<<(ostream& s, const Fix24& f)
|
|
{
|
|
return s << double(f);
|
|
}
|
|
|
|
inline Fix48::~Fix48() {}
|
|
|
|
inline Fix48::Fix48(twolongs i)
|
|
{
|
|
m = i;
|
|
}
|
|
|
|
inline Fix48:: operator double() const
|
|
{
|
|
/*
|
|
* Note: can't simply do Fix48_div_u * m.u + Fix48_div_l * m.l, because
|
|
* m.u is signed and m.l is unsigned.
|
|
*/
|
|
return (m.u >= 0)? Fix48_div_u * m.u + Fix48_div_l * m.l :
|
|
(Fix48_div_u * ((_G_uint32_t)(m.u & 0xffffff00))
|
|
+ Fix48_div_l * m.l) - 2;
|
|
}
|
|
|
|
inline Fix48::Fix48()
|
|
{
|
|
m.u = 0;
|
|
m.l = 0;
|
|
}
|
|
|
|
inline Fix48::Fix48(const Fix48& f)
|
|
{
|
|
m = f.m;
|
|
}
|
|
|
|
inline Fix48::Fix48(const Fix24& f)
|
|
{
|
|
m.u = f.m;
|
|
m.l = 0;
|
|
}
|
|
|
|
inline Fix48::Fix48(double d)
|
|
{
|
|
m = assign(d);
|
|
}
|
|
|
|
inline Fix48& Fix48::operator=(const Fix48& f)
|
|
{
|
|
m = f.m;
|
|
return *this;
|
|
}
|
|
|
|
inline Fix48& Fix48::operator=(const Fix24& f)
|
|
{
|
|
m.u = f.m;
|
|
m.l = 0;
|
|
return *this;
|
|
}
|
|
|
|
inline Fix48& Fix48::operator=(double d)
|
|
{
|
|
m = assign(d);
|
|
return *this;
|
|
}
|
|
|
|
inline twolongs& mantissa(Fix48& f)
|
|
{
|
|
return f.m;
|
|
}
|
|
|
|
inline const twolongs& mantissa(const Fix48& f)
|
|
{
|
|
return f.m;
|
|
}
|
|
|
|
inline double value(const Fix48& f)
|
|
{
|
|
return double(f);
|
|
}
|
|
|
|
inline Fix48 Fix48::operator+() const
|
|
{
|
|
return m;
|
|
}
|
|
|
|
inline Fix48 Fix48::operator-() const
|
|
{
|
|
twolongs n;
|
|
n.l = -m.l;
|
|
n.u = ~m.u + ((n.l ^ m.l) & Fix24_msb ? 0 : Fix24_lsb);
|
|
return Fix48(n);
|
|
}
|
|
|
|
inline Fix48 operator*(int b, const Fix48& a)
|
|
{
|
|
return a * b;
|
|
}
|
|
|
|
inline Fix48& Fix48::operator+=(const Fix48& f)
|
|
{
|
|
return *this = *this + f;
|
|
}
|
|
|
|
inline Fix48& Fix48::operator-=(const Fix48& f)
|
|
{
|
|
return *this = *this - f;
|
|
}
|
|
|
|
inline Fix48& Fix48::operator*=(int b)
|
|
{
|
|
return *this = *this * b;
|
|
}
|
|
|
|
inline Fix48& Fix48::operator<<=(int b)
|
|
{
|
|
return *this = *this << b;
|
|
}
|
|
|
|
inline Fix48& Fix48::operator>>=(int b)
|
|
{
|
|
return *this = *this >> b;
|
|
}
|
|
|
|
inline int operator==(const Fix48& f, const Fix48& g)
|
|
{
|
|
return f.m.u == g.m.u && f.m.l == g.m.l;
|
|
}
|
|
|
|
inline int operator!=(const Fix48& f, const Fix48& g)
|
|
{
|
|
return f.m.u != g.m.u || f.m.l != g.m.l;
|
|
}
|
|
|
|
inline int operator>=(const Fix48& f, const Fix48& g)
|
|
{
|
|
return f.m.u >= g.m.u || (f.m.u == g.m.u && f.m.l >= g.m.l);
|
|
}
|
|
|
|
inline int operator<=(const Fix48& f, const Fix48& g)
|
|
{
|
|
return f.m.u <= g.m.u || (f.m.u == g.m.u && f.m.l <= g.m.l);
|
|
}
|
|
|
|
inline int operator>(const Fix48& f, const Fix48& g)
|
|
{
|
|
return f.m.u > g.m.u || (f.m.u == g.m.u && f.m.l > g.m.l);
|
|
}
|
|
|
|
inline int operator<(const Fix48& f, const Fix48& g)
|
|
{
|
|
return f.m.u < g.m.u || (f.m.u == g.m.u && f.m.l < g.m.l);
|
|
}
|
|
|
|
inline istream& operator>>(istream& s, Fix48& f)
|
|
{
|
|
double d;
|
|
s >> d;
|
|
f = d;
|
|
return s;
|
|
}
|
|
|
|
inline ostream& operator<<(ostream& s, const Fix48& f)
|
|
{
|
|
return s << double(f);
|
|
}
|
|
|
|
#endif
|