4
\$\begingroup\$

I am Relatively new to C, and did a calculator for my first year project. Could you guys, rate the calculator's efficiency and suggest some improvements?

Link to the previous version of this calculator: Math Calculator in C

Improvements added to this: I did formatting from this website: https://codebeautify.org/c-formatter-beautifier , as the clang formatter was not downloaded in windows.

Removed the nonsense loading screen, pretty useless.

Did not change the body of the main as, for the Fibonacci Series Mode, i used goto Start which cannot be called from outside of the main function, got error, so i just leave all of the modes within the main function, cause it looks ugly, to have the Fibonacci Series Mode only to be full inside the main, not the others.

Code:

#include <stdio.h> 

#include <windows.h>        //For function Sleep()

#include <math.h>           //For functions like pow(), sin(), cos(), tan()

#include <time.h>           //For time based modules and functions

#include <conio.h>          //For kbhit, input detector

#define PI 3.14159265358979323846

Exit_0(); //Function Prototype
main() {
  system("COLOR F1");
  char Opt, oper, H;
  int i = 1, Oof, Check, N, K, Numbering, F, Choice, a, b, c, d;
  float Num1, Num2, ans, CheckF, A, B, C, A1, A2, Z;
  double x, xy, y;


  system("cls"); //Clears terminal screen
  printf("Welcome to calculator HeX.\n");
  while (1) { //While loop that never ends, unless exit(0) is used
    Start: printf("\n\nWhich mode do you want to use?\n[1] Normal maths operations\n[2] Special Functions\n[3] Fibonacci Series\n[4] Random Mathematical Question\n[5] Exit\n\nYour input: ");
    scanf(" %c", & Opt);
    if (Opt == '1') {
      printf("Welcome to Normal maths operation Mode.\n\nYour two numbers: ");
      scanf("%f%f", & Num1, & Num2);
      printf("\nAVAILABLE SYMBOLS:\n\n+ for Addition\n- for Subtraction\n/ for Division\n* for Multiplication\n^ for Power function\n\\ for Rooting\nYour input: ");
      scanf(" %c", & oper);
      if (oper == '+') {
        ans = (Num1 + Num2);
        printf("Here is your answer:\n%f  %c %f = %.5f (To 5 decimal places)\n\n", Num1, oper, Num2, ans);
          
      } else if (oper == '-') {
        ans = (Num1 - Num2);
        printf("Here is your answer:\n%f  %c %f = %.5f (to 5 decimal places)\n\n", Num1, oper, Num2, ans);
          
      } else if (oper == '/') {
        ans = (Num1 / Num2);
        printf("Here is your answer:\n%f  %c %f = %.5f (to 5 decimal places)\n\n", Num1, oper, Num2, ans);
          
      } else if (oper == '*') {
        ans = (Num1 * Num2);
        printf("Here is your answer:\n%f  %c %f = %.5g (to 5 decimal places)\n\n", Num1, oper, Num2, ans);
          
      } else if (oper == '^') {
        ans = (pow(Num1, Num2));
        printf("Here is your answer:\n%f  %c %f = %.5g (to 5 decimal places)\n\n", Num1, oper, Num2, ans);
          
      } else if (oper == '\\') {
        ans = pow(Num2, 1 / Num1);
        Check = Num1;
        Oof = Check % 2;
        if (Num2 < 0) {
          system("COLOR B4");
          printf("Cannot root a negative number; ERROR 1 Sintek\a\n");
          system("pause");
          system("cls");
          system("COLOR F1");
        } else if (Oof == 0) {
          printf("Here is your answer:\n%f root(%f) = - %.5f or + %.5f (to 5 decimal places)\n\n", Num1, Num2, ans, ans);
            
        } else if (!Oof == 0) {
          printf("Here is your answer:\n%f root(%f) = + %.5f (to 5 decimal places)\n\n", Num1, Num2, ans);
            
        }
      } else {
        system("COLOR B4");
        printf("\n\nYour input operator is incorrect; ERROR 1 Sintek\n");
        printf("\a\n");
        system("pause");
        system("cls");
        system("COLOR F1");
      }
    } else if (Opt == '2') {
      printf("Welcome to Special Functions Mode.\n\n[1] Sine Function\n[2] Cosine Function\n[3] Tangent Function\n[4] Log (With base 10)\n[5] Log (With base e)\n[6] Log (With user defined base)\n[7] Sine Inverse Function\n[8] Cosine Inverse Function\n[9] Tangent Inverse Function\n[10] Quadratic Equation Solver\n\nWhich mode do you want: ");
      scanf("%d", & N);
      if (N == 1) {
        printf("Your angle: ");
        scanf("%f", & Num1);
        ans = (sin(Num1 * PI / 180));
        printf("\nHere is your answer:\nSine(%f) = %.5f (to 5 decimal places)\n\n", Num1, ans);
          
      } else if (N == 2) {
        printf("Your angle: ");
        scanf("%f", & Num1);
        ans = (cos(Num1 * PI / 180));
        printf("Here is your answer:\nCosine(%f) = %.5f (to 5 decimal places)\n\n", Num1, ans);
          
      } else if (N == 3) {
        printf("Your angle: ");
        scanf("%f", & Num1);
        ans = (tan(Num1 * PI / 180));
        printf("Here is your answer:\nTangent(%f) = %.5f (to 5 decimal places)\n\n", Num1, ans);
          
      } else if (N == 4) {
        printf("Your number: ");
        scanf("%f", & Num1);
        ans = log10(Num1);
        if (Num1 < 0) {
          system("COLOR B4");
          printf("Cannot log a negative number; ERROR 1 Sintek\a\n");
          system("pause");
          system("cls");
          system("COLOR F1");
        } else if (Num1 == 0) {
          system("COLOR B4");
          printf("Cannot log(0); ERROR 1 Sintek\a\n");
          system("pause");
          system("cls");
          system("COLOR F1");
        } else if (Num1 > 0) {
          printf("Here is your answer:\nLg(%f) = %.5f (to 5 decimal places)\n\n", Num1, ans);
            
        }
      } else if (N == 5) {
        printf("Your number: ");
        scanf("%f", & Num1);
        ans = log(Num1);
        if (Num1 < 0) {
          system("COLOR B4");
          printf("Cannot ln a negative number; ERROR 1 Sintek\n\a");
          system("pause");
          system("cls");
          system("COLOR F1");
        } else if (Num1 == 0) {
          system("COLOR B4");
          printf("Cannot ln(0); Error 1 Sintek\n\a");
          system("pause");
          system("cls");
          system("COLOR F1");
        } else if (Num1 > 0) {
          printf("Here is your answer:\nLn(%f) = %.5f (to 5 decimal places)\n\n", Num1, ans);
            
        }
      } else if (N == 6) {
        printf("Enter the base number, followed by the number: ");
        scanf("%f%f", & Num1, & Num2);
        ans = (log(Num2) / log(Num1));
        if (Num1 <= 0 || Num2 <= 0) {
          system("COLOR B4");
          printf("Cannot log a negative/zero base/number; ERROR 1 Sintek\n\a");
          system("pause");
          system("cls");
          system("COLOR F1");
        } else if (Num1 > 0 && Num2 > 0) {
          printf("Here is your answer:\nLog[base %f]%f = %.5f (to 5 decimal places)\n\n", Num1, Num2, ans);
            
        }
      } else if (N == 7) {
        printf("[1] Entering hypotenuse and opposite of triangle\n[2] Entering the value directly\n\nYour option: ");
        scanf("%d", & K);
        if (K == 1) {
          printf("Enter hypotenuse and opposite sides of the triangle: ");
          scanf("%f%f", & Num1, & Num2);
          CheckF = Num2 / Num1;
          if (CheckF < -1 || CheckF > 1) {
            system("COLOR B4");
            printf("The opposite side should not be larger than the hypotenuse side. Please recheck your values!\nERROR 1 Sintek\n\a");
            system("pause");
            system("cls");
            system("COLOR F1");
          } else {
            ans = (asin(CheckF));
            printf("Sine inverse %f/%f =\n%f (In radians)", Num2, Num1, ans);
            ans = ans * 180 / PI;
            printf("\n%f (In degrees)", ans);
              
          }
        } else if (K == 2) {
          printf("Enter your value: ");
          scanf("%f", & CheckF);
          if (CheckF < -1 || CheckF > 1) {
            system("COLOR B4");
            printf("Value cannot be higher than 1/lower than -1. Please recheck your input!\nERROR 1 Sintek\n\a");
            system("pause");
            system("cls");
            system("COLOR F1");
          } else {
            ans = (asin(CheckF));
            printf("Sine inverse %f =\n%f (In radians)", CheckF, ans);
            ans = ans * 180 / PI;
            printf("\n%f (In degrees)", ans);
              
          }
        } else if (K != 1 || K != 2) {
          system("COLOR B4");
          printf("Your input option is not found! ERROR 404\a\n");
          system("pause");
          system("cls");
          system("COLOR F1");
        }
      } else if (N == 8) {
        printf("[1] Entering adjacent and hypotenuse of triangle\n[2] Entering the value directly\n\nYour option: ");
        scanf("%d", & K);
        if (K == 1) {
          printf("Enter adjacent and hypotenuse sides of the triangle: ");
          scanf("%f%f", & Num1, & Num2);
          CheckF = Num1 / Num2;
          if (CheckF < -1 || CheckF > 1) {
            system("COLOR B4");
            printf("The adjacent side should not be larger than the hypotenuse side. Please reckeck your values!\nERROR 1 Sintek\n\a");
            system("pause");
            system("cls");
            system("COLOR F1");
          } else {
            ans = (acos(CheckF));
            printf("Cosine inverse %f/%f =\n%f (In radians)", Num1, Num2, ans);
            ans = ans * 180 / PI;
            printf("\n%f (In degrees)", ans);
              
          }
        } else if (K == 2) {
          printf("Enter your value: ");
          scanf("%f", & CheckF);
          if (CheckF < -1 || CheckF > 1) {
            system("COLOR B4");
            printf("Value cannot be higher than 1/lower than -1. Please recheck your input!\nERROR 1 Sintek\n\a");
            system("pause");
            system("cls");
            system("COLOR F1");
          } else {
            ans = (acos(CheckF));
            printf("Cosine inverse %f = \n%f (In radians)", CheckF, ans);
            ans = ans * 180 / PI;
            printf("\n%f (In degrees)", ans);
              
          }
        } else if (K != 1 || K != 2) {
          system("COLOR B4");
          printf("Your input option is not found! Error 404\a\n");
          system("pause");
          system("cls");
          system("COLOR F1");
        }
      } else if (N == 9) {
        printf("[1] Entering opposite and adjacent of triangle\n[2] Entering the value directly\n\nYour option: ");
        scanf("%d", & K);
        if (K == 1) {
          printf("Enter opposite and adjacent sides of the triangle: ");
          scanf("%f%f", & Num1, & Num2);
          CheckF = Num1 / Num2;
          ans = (atan(CheckF));
          printf("Tangent inverse %f/%f =\n%f (In radians)", Num1, Num2, ans);
          ans = ans * 180 / PI;
          printf("\n%f (In degrees)", ans);
            
        } else if (K == 2) {
          printf("Enter your value: ");
          scanf("%f", & CheckF);
          if (CheckF < -1 || CheckF > 1) {
            system("COLOR B4");
            printf("Value cannot be higher than 1/lower than -1. Please recheck your input!\nERROR 1 Sintek\n\a");
            system("pause");
            system("cls");
            system("COLOR F1");
          } else {
            ans = (atan(CheckF));
            printf("Tangent inverse %f =\n%f (In radians)", CheckF, ans);
            ans *= 180 / PI;
            printf("\n%f (In degrees)", ans);
              
          }
        } else if (K != 1 || K != 2) {
          system("COLOR B4");
          printf("Your input option is not found! ERROR 404\a\n");
          system("pause");
          system("cls");
          system("COLOR F1");
        }
      } else if (N == 10) {
        printf("Welcome to Quadratic Equation solver. Enter the coefficient of X^2, followed by\nthe coefficient of X, followed by the integer value.\n\nEnter values: ");
        scanf("%f%f%f", &A, &B, &C);
        CheckF = (B * B - 4 * A * C);
        if (A == 0) {
          ans = -C/B;
          printf("Root of equation is %f \n", ans);
            
      } else if (CheckF < 0) {
          system("COLOR B4");
          printf("This calculator HeX, currently cannot handle complex numbers.\nPlease pardon my developer. I will now redirect you to the main menu.\n");
          system("pause");
          system("cls");
          system("COLOR F1");
          goto Start;
        } else if (CheckF >= 0) {
            Z  = pow(CheckF, 0.5);
            A1 = (-B + Z)/(A+A);
            A2 = (-B - Z)/(A+A);
          if (A1 == A2) {
            ans = A1;
            printf("\nRoot of equation is %f (Repeated root)\n", ans);
              
          } else if (A1 != A2) {
            printf("Roots of equation are %f and %f \n", A1, A2);
              
          }
        }
      } else {
        system("COLOR B4");
        printf("Your input option is not found! ERROR 404\a\n");
        system("pause");
        system("cls");
        system("COLOR F1");
      }
    } else if (Opt == '3') {
      printf("Welcome to Fibonacci Series Mode.\n\nPress any key to stop while printing the numbers, to pause.\nEnter how many numbers do you want from the series, from the start: ");
      scanf("%d", & N);
      x = 0;
      y = 1;
      F = 3;
      Numbering = 3;
      printf("Here is Your Series:\n\n");
      if (N == 1) {
        printf("[1] 0\n");
        Sleep(1000);
      }
      if (N == 2) {
        printf("[1] 0\n");
        Sleep(75);
        printf("[2] 1\n");
        Sleep(1075);
      }
      if (N == 3) {
        printf("[1] 0\n");
        Sleep(75);
        printf("[2] 1\n");
        Sleep(75);
        printf("[3] 1\n");
        Sleep(1075);
      }
      if (N > 3) {
        printf("[1] 0\n");
        Sleep(75);
        printf("[2] 1\n");
        Sleep(75);
      }
      while (N > 3 && F <= N) {
        xy = x + y;
        printf("[%.0d] %.5g\n", Numbering, xy);
        Sleep(75);
        x = y;
        y = xy;
        F++;
        Numbering++;
        while (kbhit()) {
          system("COLOR B4");
          printf("\n\n[+] Interrupted\n\nE to exit\nC to continue printing\n\nOption: ");
          scanf(" %c", & H);
          if (H == 'E') {
            printf("Exiting to main menu, in 2 seconds.");
            Sleep(2000);
            system("COLOR F1");
            goto Start;
          } else if (H == 'C') {
            system("COLOR F1");
            continue;
          }
        }
      }
      Sleep(1000);
    } else if (Opt == '4') {
      srand(time(NULL));
      Choice = rand() % 3;
      if (Choice == 0) {
        a = rand() % 5001;
        b = rand() % 5001;
        c = a + b;
        printf("What is %d + %d?\nYour answer: ", a, b);
        scanf("%d", & d);
        if (d == c) {
          system("COLOR 2F");
          printf("Yes. You are right; Congratulations\n\n");
          system("pause");
          system("COLOR F1");
        } else {
          system("COLOR B4");
          printf("No. The correct answer is %.0d. Need to practice more!\n\n", c);
          system("pause");
          system("cls");
          system("COLOR F1");
        }
      }
      if (Choice == 1) {
        a = rand() % 5001;
        b = rand() % 5001;
        c = a - b;
        printf("What is %d - %d?\nYour answer: ", a, b);
        scanf("%d", & d);
        if (d == c) {
          system("COLOR 2F");
          printf("Yes. You are right; Congratulations\n\n");
          system("pause");
          system("COLOR F1");
        } else {
          system("COLOR B4");
          printf("No. The correct answer is %.0d. Need to practice more!\n\n", c);
          system("pause");
          system("cls");
          system("COLOR F1");
        }
      }
      if (Choice == 2) {
        a = rand() % 20;
        b = rand() % 20;
        c = a * b;
        printf("What is %d times %d?\nYour answer: ", a, b);
        scanf("%d", & d);
        if (d == c) {
          system("COLOR 2F");
          printf("Yes. You are right; Congratulations\n\n");
          system("pause");
          system("COLOR F1");
        } else {
          system("COLOR B4");
          printf("No. The correct answer is %.0d. Need to practice  more!\n\n", c);
          system("pause");
          system("cls");
          system("COLOR F1");
        }
      }
    } else if (Opt == '5') {
      Exit_0();
    } else if (Opt < '1' || Opt > '5') {
      system("COLOR B4");
      printf("Your option is not found! ERROR 404");
      printf("\a\n");
      system("pause");
      system("cls");
      system("COLOR F1");
    }
  }
}


Exit_0() {
  printf("Thank you for using my calculator. Hope to see you again!!");
  Sleep(1250);
  system("cls");
  system("COLOR 0F");
  exit(0);
}

Any help will be nice.

\$\endgroup\$
0
2
\$\begingroup\$

float vs. double

Little reason to use float here, suggest double instead. Save float for selective space/speed issues - which are not present here.

If code uses float variables, use float functions like sinf(), log10f(), powf(), ... than sin(), log10(), pow().

Printing floating point

Rather than printf("%f", ans), print using "%g" or "%e". When values are much smaller than 1.0, "%f" prints as 0.000000 and large values with many uninformative digits.

// printf("%f", ans);
printf("%g", ans);

Form 1 scale factor

ans * 180 / PI can differ from ans * (180 / PI). First performs a multiplication and division at run time. 2nd multiplies once at run-time and 1 division at compile time. Which one do you want?

I recommend ans * (180 / PI) here.

Advanced: With sin(Num1 * PI / 180) though, consider the advantages of range reduction in degrees first.

Call srand(time(NULL)); once

Seeding is only needed once per program run.

Use protection

User input is evil. Watch out for bad input.

//scanf("%f", & Num1);
if (scanf("%f", & Num1) != 1) { Handle_Nonnumeric_Input(); ... }
if (Num1 <= 0.0) { Handle_Bad_Domain_Input(); ... }

// Now OK to call log()
ans = log(Num1);

...

if (Num1 != 0)  { Handle_Bad_Domain_Input(); ... }
ans = pow(Num2, 1 / Num1);

Advanced: FP constant precision

Below is not much concern here, given the lower precision of printing, but is for a more advanced uses of FP code.

Depending on FLT_EVAL_METHOD, code can evaluate expressions at higher than the usual precision, perhaps even as long double.

Consider the effects of using the various PI definitions.

#define PI_a 3.14159265358979323846  /* OP's */
#define PI_b 3.14159265358979323846264338327950288420  /* 3 more than LDBL_DECIMAL_DIG */
//           1 23456789012345678901234567890123456789
#define PI_c (22.0/7) // not a serious choice, but illustrative of a coarse approximation
#define PI_d acos(-1) // Let the implementation provide the best pi

Avoid using insufficient precision. So what is a reasonable upper bound?

I recommend to use 3 digits more than LDBL_DECIMAL_DIG. For long double, encoded as a very precise binary128, this is 36 + 3.

Notes: LDBL_DECIMAL_DIG is the round trip long double to text to long double needed precision. IEEE math allows implementations to only use the first LDBL_DECIMAL_DIG + 3 significant digits on evaluating decimal floating point text.

For me I would use M_PI (many systems provide this pi) if available or a high precision one and let the compiler approximate as needed.

#ifdef M_PI
#define PI M_PI
#else
#define PI 3.14159265358979323846264338327950288420   
#endif
\$\endgroup\$
3
  • \$\begingroup\$ Re. Form 1 scale factor - When you say can differ from, I think that "can" is limited to some rather old or obscure compilers. Modern optimizing compilers will be able to squash that expression into a constant regardless of where the programmer adds parens. \$\endgroup\$
    – Reinderien
    Jul 20 '20 at 3:30
  • \$\begingroup\$ @Reinderien Consider FP multiplications are not associative - it is not an obscure issue. \$\endgroup\$ Jul 20 '20 at 3:41
  • \$\begingroup\$ This is surprising. Thanks. \$\endgroup\$
    – Reinderien
    Jul 20 '20 at 13:46
3
\$\begingroup\$

Pi

There are some dissenting opinions on this, but: most compilers offer an M_PI if they are configured to do so. I prefer to do that rather than defining my own.

Implicit return types

Leaving these return types implicit:

load(); //Function Prototype
Exit_0(); //Function Prototype
main() {

is not great. main should be int main. Exit_0 should be void. load seems to be missing and should be deleted.

Monster functions

You need to expend a significant amount of effort into dividing the bulk of your code up into subroutines. As it stands, it's difficult to read and maintain.

While doing this refactoring, keep in mind that your goto will likely be able to be replaced with a return once this is done. goto should be avoided.

Predeclaration of variables

You should use (at least) C99, which obviates the need for these:

char Opt, oper, H;
int i = 1, Oof, Check, N, K, Numbering, F, Choice, a, b, c, d;
float Num1, Num2, ans, CheckF, A, B, C, A1, A2, Z;
double x, xy, y;

to be declared at the beginning of the function. Declare them where they're used. Also, make an attempt to avoid single-letter variable names unless it's crystal clear what they do (it isn't here).

Why sleep?

    Sleep(75);

There is no advantage to doing this; it just slows down the program and may frustrate the user.

\$\endgroup\$
5
  • \$\begingroup\$ The Sleep(75);, is required because it is in the series mode. if the user input some 100 numbers of the series, for example 400, that function prints the numbers from the start, so by using sleep for that mode, it it more nice to see the whole series rather than the series being printed out instantly. Moreover, if it is printed instantly, the user will need to scroll up a lot to see smaller numbers of the series. Then the use of kbhit(), goto will have no use also \$\endgroup\$
    – UnfreeHeX
    Jul 19 '20 at 1:45
  • \$\begingroup\$ If you're concerned about a screen buffer being scrolled out of view, sleeping is the wrong solution; you should pause to continue instead. \$\endgroup\$
    – Reinderien
    Jul 19 '20 at 1:48
  • \$\begingroup\$ but system("pause"); is bit more time consuming right? like for every number there is a system("pause"); will take more time then just printing the list, then letting the user decide when he wants to pause the list and continue by the kbhit() right? Correct me if i am wrong. \$\endgroup\$
    – UnfreeHeX
    Jul 19 '20 at 1:53
  • 3
    \$\begingroup\$ The idea is that you would not pause after every number; you would pause after "a screenful of numbers". \$\endgroup\$
    – Reinderien
    Jul 19 '20 at 2:21
  • \$\begingroup\$ Oh, now i get it. Thank you. I will add that change in to my code. \$\endgroup\$
    – UnfreeHeX
    Jul 19 '20 at 2:28

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.