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.
1 Answer 1
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 log2 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';
}
-
\$\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– Emanuele2019年06月06日 20:43:20 +00:00Commented Jun 6, 2019 at 20:43
std::pow
though? \$\endgroup\$std::pow
but I would like to have another way of expressing this type of function or future functions \$\endgroup\$