C++ Primer ex 7.3

A

arnuld

i wanted to know if that's a good design style (upto the knowledge i have
gained till chpater 7):

/* C++ Primer - 4/e
*
* exercise 7.4
* STATEMENT
* write a programme to take two int paramaters and generate the
result of raising the first to the power of the second. write a
programme to call your function passing it two ints. verify the
result.
*
*/

#include <iostream>

int raise_power(int x, int y)
{
int mult = 1;

while( y )
{
mult = mult * x;
--y;
}

return mult;
}

int main()
{
int i = 2;
int j = 3;
int mult_result = 8;

std::cout << static_cast<bool>(mult_result == raise_power(i, j))
<< std::endl;
/* well, never got converted to "true", it alwasy remains 1 :( */
return 0;
}
 
I

int2str

i wanted to know if that's a good design style (upto the knowledge i have
gained till chpater 7):

/* C++ Primer - 4/e
*
* exercise 7.4
* STATEMENT
* write a programme to take two int paramaters and generate the
result of raising the first to the power of the second. write a
programme to call your function passing it two ints. verify the
result.
*
*/

#include <iostream>

int raise_power(int x, int y)

I would suggest using more meaningful variable names other than 'x'
and 'y'. 'base' and 'exponent' come to mind.
{
int mult = 1;

while( y )

If 'y' is a negative number (which is allowed since it's defined as an
int), this while condition will cause a major bug n your program.
{
mult = mult * x;
--y;

Your while condition is wrong. But if it was correct, you could have
simply written "while( y-- )" to achieve the same result without the
stand-alone decrement.
}

return mult;

}

int main()
{
int i = 2;
int j = 3;
int mult_result = 8;

std::cout << static_cast<bool>(mult_result == raise_power(i, j))
<< std::endl;
/* well, never got converted to "true", it alwasy remains 1 :( */
return 0;

}

--http://arnuld.blogspot.com


Cheers,
Andre
 
I

Ian Collins

arnuld said:
i wanted to know if that's a good design style (upto the knowledge i have
gained till chpater 7):

/* C++ Primer - 4/e
*
* exercise 7.4
* STATEMENT
* write a programme to take two int paramaters and generate the
result of raising the first to the power of the second. write a
programme to call your function passing it two ints. verify the
result.
*
*/

#include <iostream>

int raise_power(int x, int y)
{
int mult = 1;

while( y )
{
mult = mult * x;
--y;
}

return mult;
}
That's OK for positive numbers, but what about negative?
int main()
{
int i = 2;
int j = 3;
int mult_result = 8;

std::cout << static_cast<bool>(mult_result == raise_power(i, j))
<< std::endl;

Be brutal,

assert( raise_power(i, j) == mult_result );

Don't forget to include <cassert>
 
A

arnuld

arnuld wrote:
...[SNIP]...
std::cout << static_cast<bool>(mult_result == raise_power(i, j))
<< std::endl;

Be brutal,

assert( raise_power(i, j) == mult_result );

Don't forget to include <cassert>

that raises an error:

/home/arnuld/programming/cpp $ g++ -ansi -pedantic -Wall -Wextra
ex_07-03.cpp
ex_07-03.cpp: In function 'int main()':
ex_07-03.cpp:32: error: no match for 'operator<<' in 'std::cout <<
((raise_power(i, ((unsigned int)j)) != mult_result) ?
__assert_fail(((const char*)"mult_result == raise_power(i, j)"),
((const char*)"ex_07-03.cpp"), 32u, ((const char*)(&
__PRETTY_FUNCTION__))) : 0)'
/usr/lib/gcc/i686-pc-linux-gnu/4.2.1/../../../../include/c++/4.2.1/
ostream:112: note: candidates are: std::basic_ostream<_CharT,
_Traits>& std::basic_ostream<_CharT,
_Traits>::eek:perator<<(std::basic_ostream<_CharT, _Traits>& (*)
(std::basic_ostream<_CharT, _Traits>&)) [with _CharT = char, _Traits =
std::char_traits<char>]


line 32, is where i use "assert".
 
A

arnuld

that raises an error:

/home/arnuld/programming/cpp $ g++ -ansi -pedantic -Wall -Wextra
ex_07-03.cpp
ex_07-03.cpp: In function 'int main()':
ex_07-03.cpp:32: error: no match for 'operator<<' in 'std::cout <<
((raise_power(i, ((unsigned int)j)) != mult_result) ?
__assert_fail(((const char*)"mult_result == raise_power(i, j)"),
((const char*)"ex_07-03.cpp"), 32u, ((const char*)(&
__PRETTY_FUNCTION__))) : 0)'
/usr/lib/gcc/i686-pc-linux-gnu/4.2.1/../../../../include/c++/4.2.1/
ostream:112: note: candidates are: std::basic_ostream<_CharT,
_Traits>& std::basic_ostream<_CharT,
_Traits>::eek:perator<<(std::basic_ostream<_CharT, _Traits>& (*)
(std::basic_ostream<_CharT, _Traits>&)) [with _CharT = char, _Traits =
std::char_traits<char>]

line 32, is where i use "assert".

sorry, forgot to post code:

std::cout << assert(mult_result == raise_power(i, j))
<< std::endl;
 
I

Ian Collins

arnuld said:
that raises an error:

/home/arnuld/programming/cpp $ g++ -ansi -pedantic -Wall -Wextra
ex_07-03.cpp
ex_07-03.cpp: In function 'int main()':
ex_07-03.cpp:32: error: no match for 'operator<<' in 'std::cout <<
((raise_power(i, ((unsigned int)j)) != mult_result) ?
__assert_fail(((const char*)"mult_result == raise_power(i, j)"),
((const char*)"ex_07-03.cpp"), 32u, ((const char*)(&
__PRETTY_FUNCTION__))) : 0)'
/usr/lib/gcc/i686-pc-linux-gnu/4.2.1/../../../../include/c++/4.2.1/
ostream:112: note: candidates are: std::basic_ostream<_CharT,
_Traits>& std::basic_ostream<_CharT,
_Traits>::eek:perator<<(std::basic_ostream<_CharT, _Traits>& (*)
(std::basic_ostream<_CharT, _Traits>&)) [with _CharT = char, _Traits =
std::char_traits<char>]

line 32, is where i use "assert".

sorry, forgot to post code:

std::cout << assert(mult_result == raise_power(i, j))
<< std::endl;
No, just use what I wrote.
 
A

arnuld

No, just use what I wrote.


i did use that, now i just modified it to:

std::cout << std::assert( raise_power(i, j) == mult_result )
<< std::endl;

and the error is:

ex_07-03.cpp:32: error: expected unqualified-id before '(' token


what now ?
 
I

Ian Collins

arnuld said:
i did use that, now i just modified it to:

std::cout << std::assert( raise_power(i, j) == mult_result )
<< std::endl;

and the error is:

ex_07-03.cpp:32: error: expected unqualified-id before '(' token
Don't output it, just use the assert to validate your test. If the
assertion fails, your program will abort with an error message.
 
A

arnuld

i did use that, now i just modified it to:

std::cout << std::assert( raise_power(i, j) == mult_result )
<< std::endl;

and the error is:

ex_07-03.cpp:32: error: expected unqualified-id before '(' token

what now ?

ok i got it. "assert" is a preprocessor-macro that does not return
anything and hence causes conflict with the overloaded operator "<<"

but then i have to write more-code:

assert( raise_power(i, j) == mult_result );
std::cout << ( raise_power(i, j) == mult_result ) << std::endl;

but then, is writing more code a good idea ? (when i know that
expression works fine)
 
I

Ian Collins

arnuld said:
ok i got it. "assert" is a preprocessor-macro that does not return
anything and hence causes conflict with the overloaded operator "<<"

but then i have to write more-code:

assert( raise_power(i, j) == mult_result );
std::cout << ( raise_power(i, j) == mult_result ) << std::endl;

but then, is writing more code a good idea ? (when i know that
expression works fine)
No, the point was if your test passes, the program exits cleanly, if it
fails it aborts and you get an error message.

you could just write

assert( raise_power(i, j) == mult_result );
std::cout << "OK" << std::endl;

You can add more assertions,

assert( raise_power(2, 2) == 4 );

and so on.

I had assumed your book would have covered assert!
 
I

Ian Collins

arnuld said:
ok i got it. "assert" is a preprocessor-macro that does not return
anything and hence causes conflict with the overloaded operator "<<"
Sorry to have distracted you with this, the more interesting problem to
solve and test is supporting negative numbers! Let's see how you get on
with those...
 
J

James Kanze

arnuld wrote:
Sorry to have distracted you with this, the more interesting problem to
solve and test is supporting negative numbers!

Especially for a function which returns an int. (But it
probably shouldn't, because of the risk of overflow.)

Note too that handling negatives intelligently is definitly
non-trivial. You can't just do something like:

double
power( int i, int n )
{
double r = 1.0 ;
double m = i ;
bool invert = n < 0 ;
if ( invert ) {
n = -n ;
}
while ( n > 0 ) {
r *= m ;
m *= m ;
n >>= 1 ;
}
return invert ? 1.0 / r : r ;
}

-n might still be negative. (Formally, you'd have undefined
behavior in that case, but in practice, on the usual machines,
it's a no-op.)
 
A

arnuld

Especially for a function which returns an int. (But it
probably shouldn't, because of the risk of overflow.)

hmm.. that is why you used double return type.

Note too that handling negatives intelligently is definitly
non-trivial. You can't just do something like:

double
power( int i, int n )
{
double r = 1.0 ;
double m = i ;
bool invert = n < 0 ;
if ( invert ) {
n = -n ;
}
while ( n > 0 ) {
r *= m ;
m *= m ;
n >>= 1 ;
}
return invert ? 1.0 / r : r ;
}

your programme works fine both with +ve and -ve numbers but i do not
understand the meaning of "n >>= 1". you are shifting bits one by one
but what exactly will be the value of "n" after shifting one bit
right ? i am not able to know the value of "n". yes, it works but what
happens to the vale of "n" each time ?


to understand that i used this code:


#include <iostream>



int main()
{
int x = 3;

std::cout << "x: " << x << "\n\n";

while(x > 0)
{
std::cout << "x: "
<< (x >>= 1)
<< std::endl;
}

return 0;
}

====== OUTPUT ==========
/home/arnuld/programming/cpp $ g++ -ansi -pedantic -Wall -Wextra
test.cpp
/home/arnuld/programming/cpp $ ./a.out
x: 3

x: 1
x: 0
/home/arnuld/programming/cpp $

comparing it with your solution i do not understand anything at all.
-n might still be negative. (Formally, you'd have undefined
behavior in that case, but in practice, on the usual machines,
it's a no-op.)

--
James Kanze (GABI Software) email:[email protected]
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

you said "n = -n" in if clause, so how can "n" still be a -ve number ?
 
F

Frank Birbacher

Hi!
your programme works fine both with +ve and -ve numbers but i do not
understand the meaning of "n >>= 1". you are shifting bits one by one
but what exactly will be the value of "n" after shifting one bit
right ? i am not able to know the value of "n". yes, it works but what
happens to the vale of "n" each time ?

What happens if you shift "82341" one digit right? It is "8234" which is
a tenth of "82341". What happens if you shift a binary number one bit
right? It gets divided by two.
"n >>= 1" is equivalent to "n /= 2" but maybe faster
(propably not faster because the optimizer will generate identical code
for both).

What I don't understand is why the dopped bit is not looked at in each
iteration. I thought of:

while(n>0)
{
if( n & 1 )
r *= m;
m *= m;
n >>= 1;
}
you said "n = -n" in if clause, so how can "n" still be a -ve number ?

There is a negative int number "n" such that "-n" is too large to be
represented. It happens to usually come out as n again. That is "n ==
-n" is true (technically it is still undefined behaviour as James
already said).

Magic? No. Just take the least int number available:
std::numeric_limits<int>::min(). This is usually 0x80000000. To invert
it (according to 2-complements representation which is common) you need
to first flip all bits and then add 1:
0x80000000
flip: 0x7fffffff
add 1: 0x80000000
Same as before. Notice that 0x7fffffff is
std::numeric_limits<int>::max(). So adding 1 will overflow.

In short: there are usually more negative than positive numbers in the
domain of "int".

Frank
 
A

arnuld

Sorry to have distracted you with this, the more interesting problem to
solve and test is supporting negative numbers! Let's see how you get on
with those...

that is not distraction, it is a good exercise to. i used simple
logic to come up with my new code:

2 ^ 3 = 8
2 ^ -3 == 1/8 == 0.125

so i can use the same code and i only need to add something like "if
(y < 0) then (1/mult)". here is it and it works. BTW, thanks for the
simple but mind-bending exercise :)


/* C++ Primer - 4/e
*
* exercise 7.3
* STATEMENT
* write a programme to take two int paramaters and generate the
result of raising
* the first to the power of the second. write a programme to call
your function passing
* it two ints. verify the result.
*
*/

#include <iostream>
#include <cassert>

/* raises "x" to the power "y" */
double raise_power(int x, int y)
{
double mult = 1.0;
double temp = y;
/* if y < 0 then make it positive */
if( y < 0)
{
y = -y;
}

while( y-- )
{
mult = mult * x;
}

return ( temp < 0 ) ? (1.0 / mult) : mult;
}


int main()
{
int i = 2;
int j = -3;

std::cout << ( raise_power( i, j ) ) << std::endl;

return 0;
}
 
V

Victor Bazarov

arnuld said:
that is not distraction, it is a good exercise to. i used simple
logic to come up with my new code:

2 ^ 3 = 8
2 ^ -3 == 1/8 == 0.125

so i can use the same code and i only need to add something like "if
(y < 0) then (1/mult)". here is it and it works. BTW, thanks for the
simple but mind-bending exercise :)


/* C++ Primer - 4/e
*
* exercise 7.3
* STATEMENT
* write a programme to take two int paramaters and generate the
result of raising
* the first to the power of the second. write a programme to call
your function passing
* it two ints. verify the result.
*
*/

#include <iostream>
#include <cassert>

/* raises "x" to the power "y" */
double raise_power(int x, int y)
{
double mult = 1.0;
double temp = y;

'temp' doesn't need to be "double". An 'int' will do.
/* if y < 0 then make it positive */
if( y < 0)
{
y = -y;
}

while( y-- )
{
mult = mult * x;
}

return ( temp < 0 ) ? (1.0 / mult) : mult;
}

[..]

V
 
J

James Kanze

hmm.. that is why you used double return type.

Partially. Also because it makes no sense to allow a negative
power otherwise.

There's actually a serious error here. This line should be:

if ( (n & 1) != 0 ) {
r *= m ;
}
your programme works fine both with +ve and -ve numbers but i do not
understand the meaning of "n >>= 1".

First, it fails for some specific negative values, at least on
most machines. Did you try it with n == INT_MIN? Even with the
above correction. (To make it work right, you have to use
unsigned int.)
you are shifting bits one by one
but what exactly will be the value of "n" after shifting one bit
right ?

I'm tempted to say: who cares:). The point is that you're not
dealing with the numeric value of n, but rather with it's
representation in binary bits. All that you're interested in is
that what's left in n is the bits that you haven't yet
processed. (It's slightly more subtle: you do have to process
the bits in the correct order.)

In fact, if n is positive, the numeric value is the same as if
you'd divided by 2. I use the >>= 1 here, instead of /= 2,
because I'm really thinking in terms of bits, and not numeric
values.
i am not able to know the value of "n". yes, it works but what
happens to the vale of "n" each time ?
to understand that i used this code:
#include <iostream>

int main()
{
int x = 3;

std::cout << "x: " << x << "\n\n";

while(x > 0)
{
std::cout << "x: "
<< (x >>= 1)
<< std::endl;
}
return 0;
}
====== OUTPUT ==========
/home/arnuld/programming/cpp $ g++ -ansi -pedantic -Wall -Wextra
test.cpp
/home/arnuld/programming/cpp $ ./a.out
x: 3
x: 1
x: 0
/home/arnuld/programming/cpp $
comparing it with your solution i do not understand anything at all.

Think about how a binary representation works. What does each
bit represent? Think about where the bit being
you said "n = -n" in if clause, so how can "n" still be a -ve number ?

As I said, you've encountered undefined behavior. You might
want to try printing out the values of INT_MIN and INT_MAX.
Then ask yourself what -INT_MIN should be, as an int.
 
J

James Kanze

[...]
What I don't understand is why the dopped bit is not looked at in each
iteration. I thought of:
while(n>0)
{
if( n & 1 )
r *= m;
m *= m;
n >>= 1;
}

Because I typed the code in too fast, and only tested it with
some simple values for which it happened to work.
There is a negative int number "n" such that "-n" is too large to be
represented. It happens to usually come out as n again. That is "n ==
-n" is true (technically it is still undefined behaviour as James
already said).

And of course, it depends on the implementation. It's only a
problem on machines using 2's complement---it works fine with
1's complement and signed magnitude. Of course, off hand, I
only know of one, relatively exotic mainframe that uses 1's
complement today, and as far as I know, the last signed
magnitude machine went out of production some years ago. So
it's probably a safe bet that the machine he's programming on
uses 2's complement.
 
J

James Kanze

[...]
/* raises "x" to the power "y" */
double raise_power(int x, int y)
{
double mult = 1.0;
double temp = y;
/* if y < 0 then make it positive */
if( y < 0)
{
y = -y;
}
while( y-- )
{
mult = mult * x;
}
return ( temp < 0 ) ? (1.0 / mult) : mult;
}

I tried it with 5, -2147483648. The result was 1. Somehow, I
don't think that's right.
 
A

arnuld

I tried it with 5, -2147483648. The result was 1. Somehow, I
don't think that's right.

i think, -2147483648 is too big to fit in a double.

then you can also use these arguments:

-343458234892348914789789,
789234897023478901234689234232342347842342347894123478247812378

but why i need such big values ? may be they are specific
requirements for some specific domain like scientific
programming, ....... why do i even need -2147483648 ?

i think just making it work for values which fit in a double is ok.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

C++ Primer ex 7.6 17
C++ Primer ex 6.20 36
C++ Primer ex 8.3 21
C++ Primer ex 4.30 10
C++ Primer ex 9.27 4
C++ Primer ex 7.20 - finding factorial 13
C++ Primer ex 7.14 2
C++ Primer ex 7.16 - arguments to main 15

Members online

Forum statistics

Threads
473,995
Messages
2,570,236
Members
46,822
Latest member
israfaceZa

Latest Threads

Top