Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations SkipVought on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

An open-source project for members of this forum... PLEASE READ!

Status
Not open for further replies.

qednick

Programmer
Jul 26, 2002
516
0
0
US
We've had a member asking why the equality operator doesn't work with doubles and we've had a new member coming to C++ from PERL asking about open-source to help him learn.
Well, I thought why don't we kill two birds with one stone: let's work on an open-source C++ class which can be used as an alternative to the double/float floating-point data types. That way, our PERL user can see how we do such things and our member who's been having double troubles with euality operator can use an alternative data type which may actually work.

I've included a basic class definition and member functions below. It is by no means complete and there's possibly a lot that could be improved. I WOULD LIKE YOUR INPUT ON THIS!
The whole point of these forums is that members help other members. So, let's all get our heads together and see if we can create a fully working CDouble class which can be used as an alternative to double/float types.

If you think there's an improvement or addition to be made, feel free to tack it on the end of this thread. PLEASE DON'T REPOST THE ENTIRE CODE!


[tt]

/* The class definition for CDouble - this is by no means
complete and perhaps some members can be improved upon. */


#include "math.h"
#include "float.h"

class CDouble
{
// Friend non-member operators
friend CDouble operator+(CDouble&,CDouble&);
friend CDouble operator+(CDouble&,double);
friend CDouble operator+(double,CDouble&);
friend CDouble operator+(CDouble&,int);
friend CDouble operator+(int,CDouble&);
friend CDouble operator+(CDouble&,long);
friend CDouble operator+(long,CDouble&);
friend CDouble operator+(CDouble&,short);
friend CDouble operator+(short,CDouble&);
friend CDouble& operator++(CDouble&);
friend CDouble& operator--(CDouble&);
friend bool operator==(CDouble&,CDouble&);
friend bool operator!=(CDouble&,CDouble&);
friend bool operator>(CDouble&,CDouble&);
friend bool operator<(CDouble&,CDouble&);
friend bool operator>=(CDouble&,CDouble&);
friend bool operator<=(CDouble&,CDouble&);
friend CArchive& operator<<(CArchive&,CDouble&);
friend CArchive& operator>>(CArchive&,CDouble&);

public:
CDouble(); // Default constructor
CDouble(long,long); // Alt constructor
CDouble(double); // Alt constructor
CDouble(CDouble&); // Copy constructor
virtual ~CDouble(); // Destructor

// Member operators (assignment)
CDouble& operator=(CDouble&);
CDouble& operator=(double);
CDouble& operator=(float);
CDouble& operator=(int);
CDouble& operator=(long);
CDouble& operator=(short);

// Casting operators
operator double();
operator float();
operator int();
operator long();
operator short();

// Utility functions
CString ToString(void);


long m_Int;
long m_Fract;
};

///////////////////////////////////////////////////////


/* CDouble implementation. The CDouble object contains two
long variables. The first defines the whole integer
part of a number. The second defines the fractional
part to a precision of eight places (as opposed to the
precision of ten with a double). Hopefully, this will
eliminate our problems of double precision. */





/* Standard construction initializes members */

CDouble::CDouble()
{
m_Int = 0;
m_Fract = 0;
}


/* Alternative construction
Perhaps a better way to extract the fractional
part of the value would be to convert the double
to a string, delete everything to the left of
the decimal point and convert the remainder
to a long value using atol() - who knows??????
We use the labs() function to get the absolute
value of the fraction because this MUST be a
positive number */

CDouble::CDouble(long l,long f)
{
m_Int = l;
m_Fract = labs(f);
while(m_Fract<10000000) m_Fract*=10;
}


/* A quick note about the floor() function in case
you're not familiar with it: floor() takes a
double value and returns the whole integer value
of the double (minus the fraction). Therefore, we
can extract just the fractional part of a double
by subtracting the return value of floor() from
the double. floor() is defined in 'math.h'.
Incidentally, we have to tack on the 0.000000005
to keep our fractional part from dropping in
value due to inconsistencies with the double
data type. */

CDouble::CDouble(double d)
{
m_Int = (long)floor(d);
double x=((d-m_Int)+0.000000005)*100000000;
m_Fract = (long)floor(x);
}


/* Copy constructor */

CDouble::CDouble(CDouble& cd)
{
*this = cd;
}


/* No memory to deallocate in destructor */

CDouble::~CDouble()
{
}




/* Assignment operators for most numercial types
including our own CDouble type. */

CDouble& CDouble::operator=(CDouble& cd)
{
m_Int = cd.m_Int;
m_Fract = cd.m_Fract;
return (*this);
}

CDouble& CDouble::operator=(double d)
{
m_Int = (long)floor(d);
double x=((d-m_Int)+0.000000005)*100000000;
m_Fract = (long)floor(x);
return (*this);
}

CDouble& CDouble::operator=(float f)
{
m_Int = (long)floor((double)f);
double x=((f-m_Int)+0.000000005)*100000000;
m_Fract = (long)floor(x);
return (*this);
}

CDouble& CDouble::operator=(int i)
{
m_Int = i;
m_Fract = 0;
return (*this);
}

CDouble& CDouble::operator=(long l)
{
m_Int = l;
m_Fract = 0;
return (*this);
}

CDouble& CDouble::operator=(short s)
{
m_Int = s;
m_Fract = 0;
return (*this);
}




/* Typecast operators for most numercial types. */

CDouble::operator double()
{
double d = m_Fract;
while (d>1) d/=10;
return ((double)m_Int+d);
}

CDouble::operator float()
{
float f = (float)m_Fract;
while (f>1) f/=10;
return ((float)m_Int+f);
}

CDouble::operator int()
{
return ((int)m_Int);
}

CDouble::operator long()
{
return (m_Int);
}

CDouble::operator short()
{
return ((short)m_Int);
}




/* ToString() converts our CDouble to a CString object */

CString CDouble::ToString()
{
char buffer[20];
_ltoa((long)m_Int,buffer,10);
CString str = buffer;
str += &quot;.&quot;;
_ltoa((long)m_Fract,buffer,10);
str += buffer;
return (str);
}




/* Addition operator for adding two CDouble objects */

CDouble operator+(CDouble& cd1,CDouble& cd2)
{
CDouble cd = (double)cd1+(double)cd2;
return (cd);
}




/* Addition operators for most numercial types */

CDouble operator+(CDouble& cd1,double d)
{
CDouble cd = (double)cd1+d;
return (cd);
}

CDouble operator+(double d,CDouble& cd1)
{
CDouble cd = d+(double)cd1;
return (cd);
}

CDouble operator+(CDouble& cd1,int i)
{
CDouble cd(cd1.m_Int+i,cd1.m_Fract);
return (cd);
}

CDouble operator+(int i,CDouble& cd1)
{
CDouble cd(cd1.m_Int+i,cd1.m_Fract);
return (cd);
}

CDouble operator+(CDouble& cd1,long l)
{
CDouble cd(cd1.m_Int+l,cd1.m_Fract);
return (cd);
}

CDouble operator+(long l,CDouble& cd1)
{
CDouble cd(cd1.m_Int+l,cd1.m_Fract);
return (cd);
}

CDouble operator+(CDouble& cd1,short s)
{
CDouble cd(cd1.m_Int+s,cd1.m_Fract);
return (cd);
}

CDouble operator+(short s,CDouble& cd1)
{
CDouble cd(cd1.m_Int+s,cd1.m_Fract);
return (cd);
}




/* Incremental operator */

CDouble& operator++(CDouble& cd)
{
cd.m_Int++;
return (cd);
}




/* Decremental operator */

CDouble& operator--(CDouble& cd)
{
cd.m_Int--;
return (cd);
}




/* Equality/comparison checking operators
NB: The whole point of the exercise is to avoid
checking equality between two doubles. Therefore,
we only have equality checkers against CDoubles */

bool operator==(CDouble& cd1,CDouble& cd2)
{
if (cd1.m_Int != cd2.m_Int) return false;
if (cd1.m_Fract != cd2.m_Fract) return false;
return true;
}

bool operator!=(CDouble& cd1,CDouble& cd2)
{
if (cd1 == cd2) return false;
return true;
}




/* It should be safe to compare 'double' equivalents
for the remaining comparisons */

bool operator>(CDouble& cd1,CDouble& cd2)
{
return ((double)cd1>(double)cd2);
}

bool operator<(CDouble& cd1,CDouble& cd2)
{
return ((double)cd1<(double)cd2);
}

bool operator>=(CDouble& cd1,CDouble& cd2)
{
return ((double)cd1>=(double)cd2);
}

bool operator<=(CDouble& cd1,CDouble& cd2)
{
return ((double)cd1<=(double)cd2);
}




/* Archiving operators for serialization */

CArchive& operator<<(CArchive& ar,CDouble& cd)
{
ar << cd.m_Int;
ar << cd.m_Fract;
return (ar);
}

CArchive& operator>>(CArchive& ar,CDouble& cd)
{
ar >> cd.m_Int;
ar >> cd.m_Fract;
return (ar);
}
[/tt]
tellis.gif

[sup]programmer (prog'ram'er), n A hot-headed, anorak wearing, pimple-faced computer geek.[/sup]​
 
How about another ToString() function that works to a precision:

CString CDouble::ToString(int precision)
{
char buffer[20];
_ltoa((long)m_Int,buffer,10);
CString str = buffer;
str += &quot;.&quot;;
_ltoa((long)m_Fract,buffer,10);
CString fStr = buffer;
str += fStr.Left(precision);
return (str);
}

so we could:

CDouble d = 123.45600212;
CString str = d.ToString(4);
ASSERT(str==&quot;123.4560&quot;);

 
Excellent idea!! I think we would need some way of handling precisions which are out of range:

[tt]
CString CDouble::ToString(int precision)
{
precision=(precision<1||precision>8)?8:precision;
char buffer[20];
_ltoa((long)m_Int,buffer,10);
CString str = buffer;
str += &quot;.&quot;;
_ltoa((long)m_Fract,buffer,10);
CString fStr = buffer;
str += fStr.Left(precision);
return (str);
}
[/tt]
tellis.gif

[sup]programmer (prog'ram'er), n A hot-headed, anorak wearing, pimple-faced computer geek.[/sup]​
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top