The task goes like this:
Write a program that calculates the power of a number (as a pow function from the "math.h" library), except the limitation here is that the exponent can only be an integer. The base and exponent are entered from the keyboard, where the base can be of the real type, while the exponent is a positive or negative integer. Attention should be paid to checking data entry; special treatment should be given to cases where the number is not entered and when the number entered is not an integer when entering the exponent!
Example input/output:
Enter a base number: abc
You didn't enter a number!
Enter a base number: 3.3
Enter exponent: something
You didn't enter a number!
Enter a base number: 3.3
Enter exponent: 5
3.3^5 = 391.354
Enter a base number: 12
Enter exponent: 2.5
Entered number is not an integer!
This is my code so far:
#include <stdio.h>
int main() {
double base, result = 1;
int exp, i;
printf("Enter a base number: ");
scanf("%lf", &base);
printf("Enter exponent: ");
scanf("%d", &exp);
for (i=1; i<=exp; i ) {
result *= base;
}
printf("%.2lf^%d = %.2lf", base,exp,result);
return 0;
}
It calculates the power of n successfully. But how do I add the "You didn't enter a number!" text when the input is wrong. Also, some results should be printed with 3 decimals, some with 6, etc.(depends on the result).
CodePudding user response:
... how do I add the "You didn't enter a number!" text when the input is wrong.
To validate that a line of input is a double
:
Do not use scanf()
anywhere until you know why it is bad.
Instead, read the line of user input with fgets()
which forms a string.
char buf[1024]; // Ample size buffer for very large and tiny precise values.
if (fgets(buf, sizeof buf, stdin)) {
double x;
int error_code = validate_double(buf, &x);
if (error_code == 0) printf("%.17g\n", x);
else printf("Error %d, invalid double <%s>\n", error_code, buf);
}
Validate with strdod()
int validate_double(const char *buf, double *x) {
errno = 0;
char *endptr;
*x = strtod(buf, &endptr);
if (buf == endptr) return 1; // Non numeric input
// First skip over trailing white-space
while (isspace(((const unsigned char *)endptr)[0])) {
endptr ;
}
if (*endptr) return 2; // Junk after numeric input
if (errno == ERANGE && (*x > 1.0 || *x < -1.0)) { // overflow
return 0; // or maybe 3 if you want to flag this
}
if (errno == ERANGE && (*x <= 1.0 && *x >= -1.0)) { // underflow
return 0; // or maybe 4 if you want to flag this
}
return 0;
}
To validate input is an integer, could use strtol()
or the above and simply add.
double expo;
int error_code = validate_double(buf, &expo);
if (error_code == 0) {
if (!(expo >= 0.0 && expo <= INT_MAX && (int)expo == expo)) {
error_code = 5; // Out of int range or non-integer.
}
}
... some results should be printed with 3 decimals, some with 6, etc.(depends on the result).
Try printing with %g
with ample precision. This format does not print trailing precision '0'
digits.
printf("%.17g\n", result);
CodePudding user response:
Your exponentiation algorithm is [very] inefficient:
for (i = 1; i <= exp; i ) {
result *= base;
}
It is the equivalent of doing multiplication by repetitive addition.
To do it efficiently, do "exponentiation by squaring". See: https://en.wikipedia.org/wiki/Exponentiation_by_squaring
Change your loop to:
for (i = exp; i != 0; i /= 2) {
if (i % 2)
result *= base;
base *= base;
}
Also, look at the xpow
function in the second code block of my recent answer: What's the problem in the code which was supposed to print Armstrong numbers up to 999