Is this a good start?

Pages: 12
Is this a good start for my Integer/Math class?
 ``123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138`` ``````#ifndef INTEGER_H #define INTEGER_H #include #include class Integer { public: Integer( void ); Integer( const Integer& ); Integer( const std::string numerator , const std::string denominator ); Integer( const std::string fraction ); const Integer operator+( const Integer& ); const Integer operator-( const Integer& ); const Integer operator*( const Integer& ); const Integer operator/( const Integer& ); const Integer operator%( const Integer& ); Integer& operator=( const Integer& ); Integer& operator+=( const Integer& ); Integer& operator-=( const Integer& ); Integer& operator*=( const Integer& ); Integer& operator/=( const Integer& ); Integer& operator%=( const Integer& ); friend const bool operator==( const Integer& , const Integer& ); friend const bool operator!=( const Integer& , const Integer& ); friend const bool operator<( const Integer& , const Integer& ); friend const bool operator<=( const Integer& , const Integer& ); friend const bool operator>( const Integer& , const Integer& ); friend const bool operator>=( const Integer& , const Integer& ); friend const bool operator!( const Integer& ); friend const bool operator&&( const Integer& , const Integer& ); friend const bool operator||( const Integer& , const Integer& ); void operator++( void ); void operator++( int ); void operator--( void ); void operator--( int ); const Integer operator&( const Integer& ); const Integer operator|( const Integer& ); const Integer operator^( const Integer& ); const Integer operator~( void ); const Integer operator<<( const Integer& ); const Integer operator>>( const Integer& ); const Integer& operator&=( const Integer& ); const Integer& operator|=( const Integer& ); const Integer& operator^=( const Integer& ); const Integer& operator<<=( const Integer& ); const Integer& operator>>=( const Integer& ); const Integer operator[]( const Integer& ); const Integer operator[]( const int ); friend std::ostream& operator<<( std::ostream& , Integer& ); /***Trig***/ const Integer cos( const Integer& ); const Integer sin( const Integer& ); const Integer tan( const Integer& ); const Integer acos( const Integer& ); const Integer asin( const Integer& ); const Integer atan( const Integer& ); const Integer atan( const Integer& , const Integer& ); //x & y const Integer cosh( const Integer& ); const Integer sinh( const Integer& ); const Integer tanh( const Integer& ); const Integer acosh( const Integer& ); const Integer asinh( const Integer& ); const Integer atanh( const Integer& ); /***Exponention/Log arithmics***/ const Integer exp( const Integer& ); const Integer frexp( const Integer& ); const Integer ldexp( const Integer& ); const Integer log( const Integer& ); const Integer log10( const Integer& ); const Integer exp2( const Integer& ); const Integer expm1( const Integer& ); const Integer ilogb( const Integer& ); const Integer logp1( const Integer& ); const Integer log2( const Integer& ); const Integer logb( const Integer& ); const Integer scalbn( const Integer& ); const Integer scalbln( const Integer& ); /***Power***/ const Integer pow( const Integer& , const Integer& ); const Integer sq( const Integer& ); const Integer sqrt( const Integer& ); const Integer cbrt( const Integer& ); const Integer hypot( const Integer& , const Integer& ); /***Error and Gamma***/ const Integer erf( const Integer& ); const Integer erfc( const Integer& ); const Integer tgamma( const Integer& ); const Integer lgamma( const Integer& ); /***Rounding/Remainder***/ const Integer ceil( const Integer& ); const Integer floor( const Integer& ); const Integer fmod( const Integer& ); const Integer trunc( const Integer& ); const Integer round( const Integer& ); const Integer remainder( const Integer& , const Integer& ); const Integer remquo( const Integer& , const Integer& , Integer& ); /***Min/Max***/ const Integer dif( const Integer& ); const Integer pdif( const Integer& ); const Integer imax( const Integer& ); const Integer imin( const Integer& ); /***Other***/ const Integer pi( void ); //<- const Integer e( void ); //<- Probably will be macros or const values and not functions. const Integer i( void ); //<- const bool positive( const Integer& ); const bool negative( const Integer& ); const Integer GCF( const Integer& , const Integer& ); const Integer LCD( const Integer& , const Integer& ); const Integer abs( const Integer& ); const Integer to_binary( void ); const Integer to_decimal( void ); const Integer to_fraction( void ); private: std::string numerator , denominator; }; #endif // INTEGER_H ``````

Also should I move the math functions outside of the class and put somewhere else?

Any tips would be appreciated.
Thanks for your time and paitence.
~Giblit
You have two main problems.

Position of const keyword. (I think, unless you are doing something messy like linking integers together.)

Idea that an integer is a superclass of rationals.

A lot of those functions, like log() cannot reasonably work on integers. Make a Rational class and do that stuff.

 ``123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140`` ``````#ifndef INTEGER_H #define INTEGER_H #include #include class Integer { public: Integer(); Integer( const Integer& ); Integer( const std::string numerator , const std::string denominator ); // Why does an Integer class represent a rational number? Integer( const std::string fraction ); // Or a fraction? Integer operator+( const Integer& ) const; Integer operator-( const Integer& ) const; Integer operator*( const Integer& ) const; Integer operator/( const Integer& ) const; Integer operator%( const Integer& ) const; Integer& operator=( const Integer& ); Integer& operator+=( const Integer& ); Integer& operator-=( const Integer& ); Integer& operator*=( const Integer& ); Integer& operator/=( const Integer& ); Integer& operator%=( const Integer& ); bool operator==( const Integer& ) const; bool operator!=( const Integer& ) const; bool operator< ( const Integer& ) const; bool operator<=( const Integer& ) const; bool operator> ( const Integer& ) const; bool operator>=( const Integer& ) const; bool operator! () const; bool operator&&( const Integer& ) const; bool operator||( const Integer& ) const; Integer& operator++(); Integer operator++( int ); Integer& operator--(); Integer operator--( int ); Integer operator&( const Integer& ) const; Integer operator|( const Integer& ) const; Integer operator^( const Integer& ) const; Integer operator~() const; Integer operator<<( const Integer& ) const; Integer operator>>( const Integer& ) const; Integer& operator&=( const Integer& ); Integer& operator|=( const Integer& ); Integer& operator^=( const Integer& ); Integer& operator<<=( const Integer& ); Integer& operator>>=( const Integer& ); const Integer operator[]( const Integer& ); // What is this for? const Integer operator[]( const int ); // And why are you returning an Integer? friend std::ostream& operator<<( std::ostream& , const Integer& ); /***Trig***/ Integer cos( const Integer& ) const; Integer sin( const Integer& ) const; Integer tan( const Integer& ) const; Integer acos( const Integer& ) const; Integer asin( const Integer& ) const; Integer atan( const Integer& ) const; Integer atan( const Integer& , const Integer& ) const; Integer cosh( const Integer& ) const; Integer sinh( const Integer& ) const; Integer tanh( const Integer& ) const; Integer acosh( const Integer& ) const; Integer asinh( const Integer& ) const; Integer atanh( const Integer& ) const; /***Exponention/Log arithmics***/ Integer exp( const Integer& ) const; Integer frexp( const Integer& ) const; Integer ldexp( const Integer& ) const; Integer log( const Integer& ) const; Integer log10( const Integer& ) const; Integer exp2( const Integer& ) const; Integer expm1( const Integer& ) const; Integer ilogb( const Integer& ) const; Integer logp1( const Integer& ) const; Integer log2( const Integer& ) const; Integer logb( const Integer& ) const; Integer scalbn( const Integer& ) const; Integer scalbln( const Integer& ) const; /***Power***/ Integer pow( const Integer& , const Integer& ) const; Integer sq( const Integer& ) const; Integer sqrt( const Integer& ) const; Integer cbrt( const Integer& ) const; Integer hypot( const Integer& , const Integer& ) const; /***Error and Gamma***/ Integer erf( const Integer& ) const; Integer erfc( const Integer& ) const; Integer tgamma( const Integer& ) const; Integer lgamma( const Integer& ) const; /***Rounding/Remainder***/ Integer ceil( const Integer& ) const; Integer floor( const Integer& ) const; Integer fmod( const Integer& ) const; Integer trunc( const Integer& ) const; Integer round( const Integer& ) const; Integer remainder( const Integer& , const Integer& ) const; Integer remquo( const Integer& , const Integer& , Integer& ) const; /***Min/Max***/ Integer dif( const Integer& ) const; Integer pdif( const Integer& ) const; Integer imax( const Integer& ) const; Integer imin( const Integer& ) const; /***Other***/ Integer pi() const; // Integer stores pi? nteger e() const; // Integer stores e? Integer i() const; // Integer stores irrational numbers? bool positive( const Integer& ) const; bool negative( const Integer& ) const; Integer GCF( const Integer& , const Integer& ) const; Integer LCD( const Integer& , const Integer& ) const; Integer abs( const Integer& ) const; std::string to_binary() const; // binary, decimal are text representations. Return a string. std::string to_decimal() const; std::string to_fraction() const; // Integer is a fraction? private: std::string numerator , denominator; // Again, integer is a rational number? }; #endif // INTEGER_H ``````

There is no reason why those functions cannot be members of the integer class -- it would keep things simpler, IMO.

However, I would also overload many of them outside your class to handle your integers:

 ``1234`` ``````Integer pow( const Integer& b, const Integer& p ) { return b.pow( b, p ); // This should instead be writable return b.pow( p ); }``````

Hope this helps.
Oh alright cool thanks for your suggestions I will rework it into a rational and an integer the reason I combined was I figured it'd be more accurate with fractions for something like 1/3 vs .333 though I guess I could go to say the 10th decimal or so.

I'll fix the class and get back to you appreciate your time.

*edit
Also can you correct me if I am wrong
is a suffix const for a function that does not modify any of the member variable ? I guess that would make more sense than just returning a read-only value which is the only way to return as far as I am aware. I was just told to use const as much as possible or is that not always true?

*edit 2
as far as for lines 56 and 57 those are for if you wanted a specific digit say the 10th digit of the number. The int library doesn't have that but could be handy you never know
say you want to multiply the 10th digit by the 21st digit :p

*edit3
as for edit number two with the operator[] you think it would be better to just do a function digitat( .. ) instead?
Last edited on
re:edit
Yes, it says that the member function will not modify the object.

No, you should be "const correct". Use const to signal that you are personally guaranteeing that a piece of code will not modify the object. You should not force others to obey your guarantee, though, which is why returning const Integers is not right -- you are impacting someone else's ability to modify a variable that they legitimately got from you.

For example, suppose you couldn't say this:
`double k = pow( 2.0, 12 );`
That's what returning a const Integer does...

re:edit 2
Nah, useless to people using your code, and IMO, exposes the insides of your class to untrusted code (the stuff using your class).

re:edit 3
Make it private. And don't return an Integer, return a char.

Hope this helps.
Alright cool thanks and I was wondering how would I go about templating my operators or would it be better for me to just overload them?

ex:
 ``123456789`` ``````//header Rational operator+( const Rational& ); Rational operator+( const Integer& ); //To something like this -> template Rational operator+( const T& ); //source Rational Rational::operator+( const Rational &rhs ){} Rational Rationa::operator+( const Integer &rhs ){} //to something like template<> Rational Rational::operator+( const Rational &rhs ){}... ``````

Actually after asking it seems pointless to even use a template for something like this.

Here is the updated code I have so far ( didn't get too much done on the Rational class yet so I'll post that later. )

 ``1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677`` ``````class Integer { public: Integer( void ); Integer( const Integer& ); Integer( const std::string value ); Integer operator+( const Integer& ) const; Integer operator-( const Integer& ) const; Integer operator*( const Integer& ) const; Integer operator/( const Integer& ) const; Integer operator%( const Integer& ) const; Integer& operator=( const Integer& ); Integer& operator+=( const Integer& ); Integer& operator-=( const Integer& ); Integer& operator*=( const Integer& ); Integer& operator/=( const Integer& ); Integer& operator%=( const Integer& ); friend bool operator==( const Integer& , const Integer& ); friend bool operator!=( const Integer& , const Integer& ); friend bool operator<( const Integer& , const Integer& ); friend bool operator<=( const Integer& , const Integer& ); friend bool operator>( const Integer& , const Integer& ); friend bool operator>=( const Integer& , const Integer& ); friend bool operator!( const Integer& ); friend bool operator&&( const Integer& , const Integer& ); friend bool operator||( const Integer& , const Integer& ); Integer& operator++( void ); Integer operator++( int ); Integer& operator--( void ); Integer operator--( int ); Integer operator&( const Integer& ) const; Integer operator|( const Integer& ) const; Integer operator^( const Integer& ) const; Integer operator~( void ) const; Integer operator<<( const Integer& ) const; Integer operator>>( const Integer& ) const; Integer& operator&=( const Integer& ); Integer& operator|=( const Integer& ); Integer& operator^=( const Integer& ); Integer& operator<<=( const Integer& ); Integer& operator>>=( const Integer& ); friend std::ostream& operator<<( std::ostream& , const Integer& ); /***Power***/ Integer pow( const Integer& ) const; //*this to power of param Integer sq( void ) const; //square of *this Integer sqrt( void ) const; //square root of *this Integer cbrt( void ) const; //cube root of *this Integer hypot( const Integer& ) const; //*this == a | param == b | return == c /***Min/Max***/ Integer dif( const Integer& ) const; //difference between *this and param Integer imax( const Integer& ) const; //return the greatest value *this or param Integer imin( const Integer& ) const; //return the minimum value *this or param /***Other***/ bool positive( void ) const; //return true if positive number bool negative( void ) const; //return true if negative number Integer GCF( const Integer& ) const; //return the greatest common factor between *this and param Integer abs( void ) const; //return the absolute value of *this Integer digit( const Integer ) const; //return *this -> digit at position param std::string to_binary( void ) const; //return a string of the binary value private: std::string value; bool real; };``````

Does this look much better than the original?
Also I think I will work on finishing up the integer class before working on the rational again I don't like having a bunch of stuff unfinished at one time.

Thanks for your time and answers :) I appreciate it.

*crossed out stuff
Last edited on
Why is everything a member??
Should they not be members? I thought making them members of the object would make it easier. Instead of having another file that contained the math functions and then I wouldn't even be able to access the private variables so then I would have to make the value public which is a bad thing I thought or make them all friends. How would you do it Cubbi?
 You should not force others to obey your guarantee, though, which is why returning const Integers is not right -- you are impacting someone else's ability to modify a variable that they legitimately got from you. For example, suppose you couldn't say this: `double k = pow( 2.0, 12 );` That's what returning a const Integer does...
You are confused.
You cannot modify the returned object, but in that case you are making a copy (and later you may modify it)

The reason to return a const object is to make code as `a+b = c` to generate a compile error, as it would if the variables were int

So the prototype should be `const Integer operator+( const Integer& ) const;`
or better, use a global function `const Integer operator+( const Integer&, const Integer &);` that can be implementing in base to += with metaprogramming. (check out boost operators)
Last edited on
If I made it a global though wouldn't I need to make the private variables public in order to add them together? Also are you saying like Cubbi not to put them as class members?

You'll use the interface that you spend so much work to make
 ``12345678`` ``````const Integer operator+( const Integer &a, const Integer &b){ Integer result(a); return result += b; } bool operator>(const Integer &a, const Integer &b){ return b
The idea is to make the compound assignment (+=, -=, *=, /=, ... ) members
and to implement the binary arithmetic operators as global based on those

as you may see the code is quite generic (it does not matter the type of the variables)
so you can use template magic to generate the rest of the operators http://www.boost.org/doc/libs/1_50_0/libs/utility/operators.htm

Also see http://courses.cms.caltech.edu/cs11/material/cpp/donnie/cpp-ops.html
ne555 wrote:
You are confused.
I think he was referring to the fact that it disables your ability to call non-const member functions on the rvalue.
 Should they not be members?

Absolutely. Like with any class interface, non-member non-friend functions offer the best encapsulation, least coupling, best genericity, and clean conscience.
(and by the time I got to a computer, ne555 already explained how)
Oh I see what you mean by making them global now. Also I haven't used boost library yet only SDL I'll have to give that a shot. Also that link you sent me is nice I'll have to pull all the binary operators out of my class. Thanks for all the help guys.
Is this much better or does it still need improvements?
 ``123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475`` ``````#ifndef INTEGER_H #define INTEGER_H #include #include Integer operator+( const Integer& ) const; Integer operator-( const Integer& ) const; Integer operator*( const Integer& ) const; Integer operator/( const Integer& ) const; Integer operator%( const Integer& ) const; bool operator!=( const Integer& , const Integer& ); bool operator<=( const Integer& , const Integer& ); bool operator>=( const Integer& , const Integer& ); Integer operator&( const Integer& ) const; Integer operator|( const Integer& ) const; Integer operator^( const Integer& ) const; Integer operator<<( const Integer& ) const; Integer operator>>( const Integer& ) const; class Integer { public: Integer( void ); Integer( const Integer& ); Integer( const std::string value ); Integer& operator=( const Integer& ); Integer& operator+=( const Integer& ); Integer& operator-=( const Integer& ); Integer& operator*=( const Integer& ); Integer& operator/=( const Integer& ); Integer& operator%=( const Integer& ); friend bool operator==( const Integer& , const Integer& ); friend bool operator<( const Integer& , const Integer& ); friend bool operator>( const Integer& , const Integer& ); Integer& operator++( void ); Integer operator++( int ); Integer& operator--( void ); Integer operator--( int ); Integer& operator&=( const Integer& ); Integer& operator|=( const Integer& ); Integer& operator^=( const Integer& ); Integer& operator<<=( const Integer& ); Integer& operator>>=( const Integer& ); Integer operator~( void ) const; friend std::ostream& operator<<( std::ostream& , const Integer& ); /***Power***/ Integer pow( const Integer& ) const; //*this to power of param Integer sq( void ) const; //square of *this Integer sqrt( void ) const; //square root of *this Integer cbrt( void ) const; //cube root of *this Integer hypot( const Integer& ) const; //*this == a | param == b | return == c /***Min/Max***/ Integer dif( const Integer& ) const; //difference between *this and param Integer imax( const Integer& ) const; //return the greatest value *this or param Integer imin( const Integer& ) const; //return the minimum value *this or param /***Other***/ Integer GCF( const Integer& ) const; //return the greatest common factor between *this and param Integer abs( void ) const; //return the absolute value of *this std::string to_binary( void ) const; //return a string of the binary value private: std::string value; bool real; }; #endif // INTEGER_H ``````

*edit accidently put the ~ operator outside of the class.
Last edited on
Yes, my non-const return value answer was "confused". Sorry, my brain didn't come up with a good answer, but yes, the reason is that it disables your ability to call non-const member functions.

If the compiler doesn't pick up a+b=c for you, it's crap.

 Should they not be members?

It still doesn't matter. Being able to compute a standard mathematical function over a user type is part of that type's API.

It is not a violation of encapsulation to use friend functions, and I think it is an extremist POV to teach that it is. Friends are part of the encapsulation..

That said, I agree that you should try to keep it down to as few things that know how to handle the innards of a class as possible. But at this point, we're overloading OP.

The following are equivalent when calling quux( a, b ):

 ``123456789101112`` ``````struct foo { foo quux( const foo& z ) const { ... } }; foo quux( const foo& a, const foo& b ) { return a.quux( b ); }``````

 ``123456789`` ``````struct foo { friend foo quux( const foo& a, const foo& b ); }; foo quux( const foo& a, const foo& b ) { ... }``````

The difference is that you are confusing encapsulation and style. If a function needs to access an object's internals to accomplish its goal, then it must be a part of that object's encapsulating API.

Being able to implement things in terms of other things is a nice, handy trick, and can help keep maintenance nightmares down. These kinds of things should be recognized and used whenever possible, but in some cases it isn't something that should get your knickers twisted.

 ``12`` ``````bool operator == ( const foo& z ) { return digits == z.digits; } bool operator != () { holy crap! should I use !operator==() or not? }``````

You are wasting your time if you let the decision take more time than it would to write the code, because in this case it doesn't matter.

If anyone intends to modify the way that operator == works, he should know enough to look at all the other operators as well, and for such a simple piece of code it takes nothing to make any needed adjustments.

Don't overload the OP.
> the reason is that it disables your ability to call non-const member functions.
> If the compiler doesn't pick up a+b=c for you, it's crap.
First you want to call non-const functions, then you want it to fail.
Make up your mind.

> `Integer operator/( const Integer& ) const;`
You declared it as a global function, there is no `this` pointer
It should be `const Integer operator/( const Integer &, const Integer & );`

A binary function must always take two parameter.
In a member function you already got `this'
Last edited on
Yeah sorry I changed in my source right as I noticed but didn't change here thanks though =]

Okay I created a += operator is this an efficient way to do it or should I try some other methods tomorrow?
 ``123456789101112131415161718192021222324252627`` ``````Integer& Integer::operator+=( Integer i ) { std::string temp( "" ); unsigned short remainder( 0 ) , carry( 0 ); while( value.size() != i.value.size() ) { value.size() > i.value.size() ? i.value.insert( 0 , "0" ) : value.insert( 0 , "0" ); } for( std::string::iterator it1( value.end() - 1 ) , it2( i.value.end() - 1); it1 > value.begin() - 1; --it1 , --it2 ) { remainder = *it1 - '0' + *it2 - '0' + carry; if( remainder > 9 ) { carry = remainder / 10; remainder %= 10; } else { carry = 0; } std::cout << "Remainder - " << remainder << std::endl; std::cout << "Carry - " << carry << std::endl; temp.insert( temp.begin() , static_cast( remainder + '0' ) ); } value = temp; return( *this ); }``````

*edit
its not finished all the way though because I have to take into consideration positive/negative numbers and possibly EE but how effective/fast is the code vs other methods? I just did the hard method like on paper start from the right and move to the left going from top to bottom.
Last edited on
ne555 wrote:
First you want to call non-const functions, then you want it to fail.
Make up your mind.
Pretty sure he expects a warning and not an error.
I don't really care if it fails or gives a warning.

`a+b=c;`

Don't write code like that.
¿would this be any better `a+b *= 2`?
¿or `(a+b).duplicate()`?

@OP: Inserting at the beginning of an array is O(n), making your algorithm O(n^2) where n is the number of digits.
You can improve it to O(n)
Pages: 12