3
\$\begingroup\$

I attached below a small working example of a function that is able to perform x^y. As it is possible to see the base (x) takes double and the power takes an int. As last the main loop will also round up or down the result accordingly.

Not always I have these type of formats, and I could have base as int and power as double or base as long int and power as additional type. How can I improve this function to make it more general with different type format using template template <class identifier> or/and template <typename identifier>?

#include <cmath>

using namespace std;

class Power {
public:
    double raiseToPower(double x, int power)
    {
        double result;
        int i;
        result = 1.0;
        for(i = 1; i <=power; i++){
            result = result*x;
        }
        return result;
    }

    double floor0(double num)
      {
        if( (num + 0.5) >= (int(num) + 1) )
        return int(num)+1;
        else
        return int(num);
    }
};


int main()
{
    double x;
    int i;
    Power example;
    std::cout<<"please enter the number"<<std::endl;
    std::cin>>x;
    std::cout<<"please enter the integer power that you want this number raised to"<<std::endl;
    std::cin>>i;
    std::cout<<"rise to power "<<i<<" is equal to "<<example.raiseToPower(x,i)<<std::endl;
    std::cout<<"the result rounded is "<< example.floor0(example.raiseToPower(x,i))<<std::endl;
}

Thank for any insight and point to the right direction.

\$\endgroup\$
  • \$\begingroup\$ Is something wrong with std::pow though? \$\endgroup\$ – Juho May 9 at 16:30
  • \$\begingroup\$ @Juho, thank for reading my question, there is nothing wrong with std::pow but I would like to have another way of expressing this type of function or future functions \$\endgroup\$ – Emanuele May 9 at 16:37
  • \$\begingroup\$ The logic you have for raiseToPower currently will only work for positive integer exponents. So before you can meaningfully support other types as exponents, you need to expand that. \$\endgroup\$ – Errorsatz May 9 at 20:38
  • \$\begingroup\$ @Errorsatz, thanks for your comment and for reading the question, how could I modify the function and make it better then? \$\endgroup\$ – Emanuele May 9 at 21:21
  • \$\begingroup\$ Are you from Java? Your functions make more sense being free functions in C++. \$\endgroup\$ – L. F. May 10 at 9:01
4
\$\begingroup\$

Headers and namespaces

Don't using namespace, especially a big and growing namespace like std that's not designed for it.

There's no need to include <cmath>. On the other hand, there is a clear need for <iostream>, which has been omitted.

Structure

There's no need for the Power class; it maintains no state. The functions should simply be free functions, perhaps in a namespace.

Consider full range of types

raiseToPower() only works with non-negative exponents; it should either accept an unsigned type or be modified to work correctly with negative inputs. Perhaps like this:

    if (power < 0) {
        return raiseToPower(1/x, -power);
    }

Improve the algorithm

For large power, the loop is executed many times. We can use binary exponentation to reduce that to log₂ power iterations of the loop.

Avoid over-complication

floor0() doesn't need that if/else; simply add 0.5 before truncating:

constexpr double floor0(double num)
{
    return int(num + 0.5);
}

It might be better to use long or long long there; in any case, you'll still suffer bugs when the value is too big for the integer type. std::floor() doesn't have that problem.

Validate inputs

If I enter a non-number, I don't get a clear error message. Instead, the program uses uninitialised values, which is Undefined Behaviour. Don't do that; instead check that std::cin is still good before using x or i.

Avoid std::endl unless you need output flushing

None of the uses of std::endl here are necessary, and we can use \n instead. (Remember that using std::cin flushes the output streams, and returning from main() also flushes outputs).


Modified code

double raiseToPower(double x, int power)
{
    if (power < 0) {
        return raiseToPower(1/x, -power);
    }

    double result = 1.0;
    double m = x;

    for (;  power;  power /= 2) {
        if (power % 2) {
            result *= m;
        }
        m *= m;
    }
    return result;
}

constexpr double floor0(double num)
{
    return int(num + 0.5);
}
#include <iostream>

int main()
{
    double x;
    int i;
    std::cout << "Please enter the number\n";
    std::cin >> x;
    std::cout << "Please enter the integer power that "
                 "you want this number raised to\n";
    std::cin >> i;
    if (!std::cin) {
        std::cerr << "Input format error\n";
        return 1;
    }
    auto const result = raiseToPower(x,i);
    std::cout << x << " raised to power " << i << " is equal to "
              << result << '\n';
    std::cout << "The result rounded is "
              << floor0(result) << '\n';
}
\$\endgroup\$
  • \$\begingroup\$ thank you very much for the very detailed and comprehensive explanation on how to improve the code! Exactly what I was looking for! :) \$\endgroup\$ – Emanuele Jun 6 at 20:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.