1

I am writing a simple program to calculate 6^5 using a function. Here's my code

#include <iostream>
using namespace std;

int raiseToPower(int &base, int exponent){
 for (int i = 1; i < exponent; i = i + 1){
   base= base * base;
   }
 return base;
}

int main() {
 int base = 6;
 cout << "6^5 is " << raiseToPower(base, 5)<< endl;

 return 0;
}

The result is

 6^5 is -683606016

instead of 7776

Can you guys explain to me why I got this result? I am not looking for another way to write this code. I know there are simpler ways but I am trying to understand what went wrong

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
Ximz
  • 87
  • 7
  • 6
    You are not calculating base^exponent, you are calculating base^(2^(exponent-1)). – DeducibleSteak Feb 16 '20 at 12:45
  • 1
    You are computing much much bigger than `6^5`. `base = base*base;` This is computing in the order of 2 power of the exponent – Wander3r Feb 16 '20 at 12:46
  • 1
    Your first iteration does `base = 6 * 6` which is `36` and you assign it to `base`. So the next iteration is `36 * 36` which is `1296` and you assign that to `base` again, ... – t.niese Feb 16 '20 at 12:47
  • 1
    And there is not really a point in passing `base` as a reference here. What benefit do you expect from that? – t.niese Feb 16 '20 at 12:57
  • 2
    @t.niese don't suggest using std::pow for integers. At least not without mentioning this whole can of worms: https://stackoverflow.com/questions/9704195/why-pow10-5-9-999-in-c – DeducibleSteak Feb 16 '20 at 12:59

4 Answers4

3

Why are you using pass by reference. Setting as much const as possible reduces the odd of making mistakes:

#include <iostream>
using namespace std;

int raiseToPower(const int base, const int exponent) {
    int result = base;
    for (int i = 1; i < exponent; i = i + 1){
        result = result * base;
    }
    return result;
}

int main() {
    int base = 6;
    cout << "6^5 is " << raiseToPower(base, 5)<< endl;

    return 0;
}

If it has to be pass by reference you could do this:

#include <iostream>
using namespace std;

void raiseToPower(const int base,
                 const int exponent,
                 int &result)
{
    result = base;
    for (int i = 1; i < exponent; i = i + 1){
        result = result * base;
    }
}

int main() {
    int base = 6;
    int result;
    raiseToPower(base, 5, result);

    cout << "6^5 is " << result << endl;

    return 0;
}
Gerhard Stein
  • 1,543
  • 13
  • 25
  • The qualifiers const does not make great sense. They are redundant. – Vlad from Moscow Feb 16 '20 at 13:08
  • 3
    They are not redundant. They prevent you from accidentally changing values you never meant to change. They literally change whether or not code will compile. That is the definition of the opposite of redundant. – DeducibleSteak Feb 16 '20 at 13:10
  • @DeducibleSteak The arguments are passed by value. So the function deals with copies of its arguments. The qualifier const does not make sense. – Vlad from Moscow Feb 16 '20 at 13:12
  • 3
    It prevents you from changing values _inside_ the function, that you did not want to change. – DeducibleSteak Feb 16 '20 at 13:13
  • @DeducibleSteak Do you understand what I have written? The function deals with copies of arguments. For the user it is unimportant what the function is doing with the copies. – Vlad from Moscow Feb 16 '20 at 13:14
  • @VladfromMoscow They are documentation if nothing else, promising the only mutable bit is the result. – George Feb 16 '20 at 13:17
  • @George Again this is totally unimportant for the user of the function. This "documentation" does not make sense. – Vlad from Moscow Feb 16 '20 at 13:18
  • 3
    We are not talking about the user of the function, we are talking about the implementer of the function. – DeducibleSteak Feb 16 '20 at 13:19
  • @DeducibleSteak Declaration of the function is its open interface for the user. How the function is implemented has nothing common with whether you specified the qualifier or not. Moreover the function declaration is in any case void( int, int, int & ). The compiler itself ignores your qualifier const when determines the type of the function. It seems C++ and C are not your programming languages.:) – Vlad from Moscow Feb 16 '20 at 13:22
  • 3
    I did mean the user in fairness. They are unimportant to the function interface, but personally I think they make the implementation slightly quicker to read, I know exactly where I'm looking without having to consider what the rest of the function does. – George Feb 16 '20 at 13:22
  • 4
    @VladfromMoscow, I don't know what you're not getting here, but let me just say one last time that I am not talking about the interface of the function, or its signature, or whether or not constness of pass-by-value parameters is included in the signature. I am not even talking about function parameters - I'm talking about any old variable, even local function variables. Making them const prevents you from accidentally changing them later. If you try to, you will get a compile time error. That's it. Are you saying this is not true? – DeducibleSteak Feb 16 '20 at 13:30
  • @DeducibleSteak Why may not the parameters be changed in this function?! What is the meaning of this? This makes the function implementation more complicated because you will need to introduce intermediate variables that will be changed instead of changing the parameters. – Vlad from Moscow Feb 16 '20 at 13:36
  • 2
    I'm going to assume that either you are trolling right now, or indeed English is not your speaking language, but I can't continue this discussion. – DeducibleSteak Feb 16 '20 at 13:41
  • It is correct that you can skip ```const``` but I consider it more elegant, even though the compiler would optimize it away. I recommend using ```const``` in general, where you really mean constants for the scope you are targeting. It reduces the probability when working on the code that you mess something up. With ```const``` you are being clear in what you want, and the compiler gives you full support when inspecting your code. – Gerhard Stein Feb 17 '20 at 08:00
2

Your calculation is incorrect. The value of variable base should not change. Try this:

 int raiseToPower(int &base, int exponent){
   int result = 1;
   for (int i = 1; i <= exponent; i = i + 1){
      result = result * base;
    }
    return result;
 }
seccpur
  • 4,996
  • 2
  • 13
  • 21
2

You probably want your loop like this:

int result = 1;
for (int i = 0; i < exponent; i = i + 1) {
    result = result * base;
}
return result;

Also, you are taking your base parameter to raiseToPower by reference - which means you are changing the base variable in main - probably not what you want to do.

DeducibleSteak
  • 1,398
  • 11
  • 23
2

Let's consider this loop

 for (int i = 1; i < exponent; i = i + 1){
   base= base * base;
   }

After the first iteration when i is equal to 1 you have

   base= base * base;

that is the result is base ^ 2.

When i = 2 you have

   base= base^2 * base^2;

that is the result is base^4.

When i is equal to 3 you have

   base= base^4 * base^4;

that is the result is base^8.

When i is equal to 4 you have

   base= base^8 * base^8;

that is the result is base^16.

It seems the resulted value is too big to be accomodated in an object of the type int.

Also it is not a good idea when an argument is passed by reference. And the second parameter should have the type unsigned int.

Here is a demonstrative program that shows how the function can be implemented.

#include <iostream>

long long int raiseToPower( int base, unsigned int exponent )
{
    long long int result = 1;

    while ( exponent-- )
    {
        result *= base;
    }

    return result;
}

int main() 
{
    int base = 6;

    std::cout << "6^5 is " << raiseToPower(base, 5) << std::endl;

    return 0;
}

Its output is

6^5 is 7776
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335