-1

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).

Gerhardh
  • 11,688
  • 4
  • 17
  • 39
lula
  • 1
  • 1
  • 3
    Welcome to SO. Your title ask about calculating power of n but your question is about something completely different. Please edit your post to provide a matching title and question body. And focus on one question. Either detecting type of input or printing with different numbers of decimals. – Gerhardh Mar 18 '22 at 16:54
  • Hint: what does the man page for scanf say about its return value? https://stackoverflow.com/a/10469649/530160 – Nick ODell Mar 18 '22 at 16:55
  • For one of your questions you might take a look at the serach results of [how to check if input is a number](https://stackoverflow.com/search?q=%5Bc%5D+how+to+check+if+input+is+a+number) – Gerhardh Mar 18 '22 at 17:00
  • Forget input validation for the moment until you're more proficient in C. Anyway, it can't be done easily (or not even at all) with `scanf`. – Jabberwocky Mar 18 '22 at 17:04
  • 1
    You can use [exponentiation](https://stackoverflow.com/a/11552955/4142924) when the power is an integer (the base need not be). The solution you have is *very* inefficient for say, 1.23 ^ 987654321. – Weather Vane Mar 18 '22 at 17:10
  • The question in the title is unrelated to the question in the body. That is bad form. I suggest you fix it. – Clifford Mar 18 '22 at 20:34

2 Answers2

0

... 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);
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • Just curious: why `isspace(((const unsigned char *)endptr)[0])` instead of `isspace((unsigned char)endptr[0])` ? – chqrlie Mar 18 '22 at 18:17
  • Also the exponent can be a negative integer. – chqrlie Mar 18 '22 at 18:19
  • @chqrlie `isspace((unsigned char)endptr[0])` is incorrect for rare non-2's complement - perhaps irrelevant in next version of C. `isspace(((const unsigned char *)endptr)[0])` is good for all encodings. – chux - Reinstate Monica Mar 18 '22 at 19:19
  • @chqrlie Given OP's `for (i=1; i<=exp; i++) { result *= base; }` and "It calculates the power of n successfully", it looks like OP does not want to handle negative exponents - in any case, that is not OP's main issue - even though the loop is also inefficient. – chux - Reinstate Monica Mar 18 '22 at 21:15
0

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

Craig Estey
  • 30,627
  • 4
  • 24
  • 48