How to optimise my C code to solve quadratic equations in R? - c

I just wanna know how I can optimize my C code. My program works fine, I tested it with many different values, all is good. However, I'd like to reduce the number of lines and write my program in better quality.
Here's the source code:
#include <stdio.h>
#include <math.h>
int main(void) {
float a,b,c,x,x1,x2;
printf("aX^2 + bX + c = 0\n");
printf("Type the value of a: ");
scanf("%f", &a);
printf("Type the value of b: ");
scanf("%f", &b);
printf("Type the value of c: ");
scanf("%f", &c);
if ( a!=0 && b!=0 && c!=0){
float delta = b*b - 4*a*c;
if (delta>0){
x1 = (-b-sqrt(delta))/(2*a);
x2 = (-b+sqrt(delta))/(2*a);
printf("Solutions are x1 = %f and x2 = %f\n",x1,x2);
}
else if (delta == 0){
x = -b/(2*a);
printf("One unique solution is x = %f\n", x);
}
else {
printf("No solutions !\n");
}
}
if ( a==0 && b!=0 && c!=0)
printf("One unique solution x = %f\n", -c/b);
if ( a==0 && b==0 && c!=0)
printf("No solutions !\n");
if ( a==0 && b==0 && c==0 )
printf("Set of solutions is R\n");
if (a!=0 && b==0 & c!=0) {
x = -c/a;
if(x>=0)
printf("Two soltions x = %f et -x = %f\n", sqrt(x),-sqrt(x));
else{
printf("No solutions !\n");
}
}
if (a!=0 && b==0 && c==0)
printf("One unique x = 0\n");
}

One small optimization: use else if instead of all raw ifs. This will avoid unnecessary comparisons after one if condition is matched.
You can also experiment with the order of the if statements. If any conditions are more often to be true for your use cases, then they should be first.

Since you are basically building a state machine, let's actually do so:
int state = (a == 0) ? 0 : 1;
state |= (b == 0) ? 0 : 2;
state |= (c == 0) ? 0 : 4;
switch(state)
{
case 0: // All co-efficents 0 Domain R print
break;
case 1: // Only a coefficient: 0 case
break;
case 2: // Only b coefficient 0 case.
break;
case 3: // a and b coefficient case - one root 0, other linear.
break;
case 4: // Only c case - no solutions
break;
case 5: // a and c case
break;
case 6: // b and c case (linear)
break;
case 7: // a,b,c all here - do full quadratic solve.
break;
default:
// This should never happen - assert and exit.
break;
}
This way, all your cases are explicitly defined. Each case could also then call a function. Or, one step further, an array of function pointers for each case, fully and properly named.

1) Some of the parts of calculations are being repeated. Break the calculations into smaller pieces, store the results in variables, and use them to build your needed results.
2) You can avoid the special handling of the case a!=0 && b==0 & c!=0 entirely (albeit you need to change some of the other tests).
3) Some operations (e.g. prompting and reading) are repeated. Do these in a function which takes an argument (e.g. a string for prompt).
4) The first line where you are printing "No solutions" there are actually complex or imaginary solutions. The second place is another type of solution.
5) Possibly break some of the repeated calculations (point 1) into separate functions too.
6) Slightly advanced: your code will not deal well with a user who enters rubbish (non-numeric) input.

You can use this example to optimise your code:
#include <stdio.h>
#include <math.h>
int main()
{
double a, b, c, determinant, root1,root2, realPart, imaginaryPart;
printf("Enter coefficients a, b and c: ");
scanf("%lf %lf %lf",&a, &b, &c);
if(a==0 && b!=0 && c!=0){
root1 = -c/b;
printf("linear equation root = -c/b = %.2lf", root1);
}else{
determinant = b*b-4*a*c;
// condition for real and different roots
if (determinant > 0)
{
// sqrt() function returns square root
root1 = (-b+sqrt(determinant))/(2*a);
root2 = (-b-sqrt(determinant))/(2*a);
printf("root1 = %.2lf and root2 = %.2lf",root1 , root2);
}
//condition for real and equal roots
else if (determinant == 0)
{
root1 = root2 = -b/(2*a);
printf("root1 = root2 = %.2lf;", root1);
}
// if roots are not real
else
{
realPart = -b/(2*a);
imaginaryPart = sqrt(-determinant)/(2*a);
printf("root1 = %.2lf+%.2lfi and root2 = %.2f-%.2fi", realPart, imaginaryPart, realPart, imaginaryPart);
}
}
return 0;
}
If determinant is greater than 0, the roots are real and different.
If determinant is equal to 0, the roots are real and equal.
If determinant is less than 0, the roots are complex and different.
So,
Sample image

Related

Issue in calculating LCM of two -ve numbers or if either one is negative in C lang

The code is running perfectly for finding
LCM of 2 and 3 , LCM of 0 and 2 BUT
not able to execute for (-2 and 3) or (-2 and -3). I have written code for this type.
Check else if block that's the problem.
I expect LCM of -2 and -3 to get printed as 6. And LCM of -2 and 3 to get printed as 6.
#include <stdio.h>
int main()
{
int a,b;
printf("\n\t\t\t\t\tThis program calculate LCM of two numbers");
printf("\nEnter two numbers: ");
scanf("%d%d",&a,&b);
int i=0;
if(a!=0 && b!=0)
{
if(a>0 && b>0)
{
for(i=1; i<=a*b; ++i)
{
if((i%a==0)&&(i%b==0))
break;
}//for loop end
printf("LCM is %d",i);
}
else if(a<0 || b<0) //if any one number is -ve or both are -ve
{
// while(1)
// {
// int max = (a > b) ? a : b;
// if ((max % a == 0) && (max % b == 0))
// {
// printf("The LCM of %d and %d is %d.", a, b, max);
// break;
// }
// ++max;
// }
//Above commented portion not working for -ve numbers. This is my issue.
}
}
else
{
printf("LCM is %d",i);
}
return 0;
}
Potential infinite loop
When (max % a == 0) && (max % b == 0) is not true, loop goes on forever.
// OP's code
while(1) {
int max = (a > b) ? a : b; // Did OP want this before the loop?
if ((max % a == 0) && (max % b == 0)) {
printf("The LCM of %d and %d is %d.", a, b, max);
break;
}
++max; // This line serves no purpose.
}
Since OP wants a positive result, consider 1) using the absolute value of both arguments. 2) Use long long math to avoid int overflow in the absolute value and in a*b.
There are faster approaches than iterating [1...a*b].

C Newbie/ not understanding what might the problem be

since im learning C language i decided to make a simple program that adds, substracts and calculates the product of two variables . Depending on users' input whether its 1,2 or 3 to choose addition/substraction/folding.
#include <stdio.h>
int main (void) {
int a, b, c, d, e, f, g;
a=19; b=11; c=a+b; d=a-b; e=a*b; f=-1;
while (f<0 && f>3) {
printf("-press 1 to calculate the sum of a and b\n");
printf("-press 2 to calculate the difference between a and b\n");
printf("-press 3 to calculate the product of a and b\n");
scanf("%d\n",&g);
f=g;
return;
}
if (f == 1) {
printf("A+B= %ls\n", &c);
} else if (f == 2) {
printf("A-B= %ls\n", &d);
} else if (f == 3) {
printf(" A*B= %ls\n", &e);
}
return 0;
}
When i run the program its reads "g" and then it stops.
any suggestions to why is this happening
btw i also tried removing the while statement.
I think you mean the following while loop
while ( f < 0 || f > 3 )
{
printf("-press 1 to calculate the sum of a and b\n");
printf("-press 2 to calculate the difference between a and b\n");
printf("-press 3 to calculate the product of a and b\n");
scanf( "%d", &g );
f = g;
}
That is pay attention to 1) the condition of the while loop, 2) removed the return statement and 3) removed the character '\n' in scanf because it is redundant.
And in printf calls remove the operator & and use the conversion specifier %d.
if ( f == 1 ) {
printf(" A+B= %d\n", c) ;
}
else if ( f == 2) {
printf(" A-B= %d\n", d );
}
else if ( f == 3 ) {
printf(" A*B= %d\n",e );
}
I fixed you code and added some comments to it. Hope you can understand it! If you have questions, just comment them.
#include <stdio.h>
int main (void) {
// values can be given to ints by int a = value
int a = 19, b = 11, c, d, e, f = -1, g;
// '||' means OR, while '&&' means AND.
// A value can't be smaller then and bigger then 3 at the same time
while (f < 0 || f > 3) {
printf("-press 1 to calculate the sum of a and b\n");
printf("-press 2 to calculate the difference between a and b\n");
printf("-press 3 to calculate the product of a and b\n");
scanf("%d", &g); //you don't need \n for scanf
f=g;
// return stops the program. In this case, this is not what you want
}
// For printf you don't need &e, &f, etc.
// Instead of calculating a value and storing it in a different int,
// you can just print the outcome of the calculation.
if (f == 1) {
printf("A + B = %d\n", a + b);
} else if (f == 2) {
printf("A - B = %d\n", a - b);
} else if (f == 3) {
printf(" A * B = %d\n", a * b);
}
return 0;
}
Try this:
while (f<0 && f>3){
printf("-press 1 to calculate the sum of a and b\n");
printf("-press 2 to calculate the difference between a and b\n");
printf("-press 3 to calculate the product of a and b\n");
scanf("%d\n",&g);
f=g;
// remove the "return" from here;
}
Also change :
printf(" A+B= %ls\n",&c);
To:
printf(" A+B= %d\n",c);
You don't need the '&' operator to print values, if used it will print the address and not the resultant value.
I would like to add that you could replace your if/else if statements with the switch/case . To be more specific (after changing some small mistakes in your code %d instead %ls and so on) the section of your code should look like this:
// code above
switch(f) {
case 1:
printf(" A+B= %d\n", c) ;
break; // if you want the program to stop after doing this operation
case 2:
printf(" A-B= %d\n", d );
break;
case 3:
printf(" A*B= %d\n",e );
break;
// default: // if the input is not one of the above(1,2 or 3)
// printf(" Please give a valid option. \n");
// break;

Why am I receiving an error at my "for" loop saying 'break' statement not in loop or switch?

incredibly new to programming I am receiving an error on line 12 stating that my break statement is not in the loop or switch. Can anyone explain where my error is and how to fix it?
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main()
{
int n1, n2, i, gcd, lcm;
printf("Enter two positive integers: ");
scanf("%d %d",&n1,&n2);
for(i=1; i <= n1 && i <= n2; ++i) {
printf("Enter two positive integers: ");
scanf("%d %d",&n1,&n2);
if(n1==-1,n2==-1) break;
// Checks if i is factor of both integers
if(n1%i==0 && n2%i==0)
gcd = i;
}
lcm = (n1*n2)/gcd;
printf("The LCM of two numbers %d and %d is %d.", n1, n2, lcm);
return 0;
}
If you are "receiving an error on line 12 stating that my break statement is not in the loop or switch" then either you have a very deficient compiler or you've posted the wrong code. That code has a few problems but a break in the wrong place is not one of them.
That particular error message often occurs when you've mislaid some braces, along the lines of:
int i;
for (i = 0; i < 10; ++i)
printf("%d\n", i);
if (someCondition)
break;
That's because, despite the fact it looks like you're breaking out of a loop, the actual break statement is not within the loop. Only the printf is.
In terms of the code you have provided, there are numerous ways to clean it up:
Remove unneeded includes.
Refactor out the number input to a common function.
Allow a single non-positive number to terminate the program.
Use DRY principle for input, there's really any need to duplicate code segments if you structure it corretly.
Make input more robust, allowing for invalid numbers.
Add more comments, these will greatly assist you (or others who have to maintain your code) in the future.
Use better variable names. Other than i for small localised loops, I almost never use single-character variable names.
Fix the if(n1==-1,n2==-1) bit. That doesn't do what you appear to think it does. The comma operator will evaluate both expressions but the result of the full expression is the rightmost one. So it's effectively if(n2==-1).
To that end, the following is how I would write the code:
#include <stdio.h>
#define ERR_NON_POS -1
#define ERR_INVALID -2
// Gets a single number.
// If non-positive or invalid, returns error (a negative value ERR_*).
// Otherwise, returns the (positive) number.
int getNumber(void) {
int number;
if (scanf("%d", &number) != 1) return -2;
if (number <= 0) return -1;
return number;
}
int main(void) {
// Infinite loop, we'll break from within as needed.
for (;;) {
printf("Enter two positive integers (a negative number will stop): ");
// Do it one at a time so a SINGLE negative number can stop.
int number1 = getNumber();
if (number1 == ERR_INVALID) {
puts("** Non-integral value entered");
break;
}
if (number1 == ERR_NON_POS) break;
int number2 = getNumber();
if (number2 == ERR_INVALID) {
puts("** Non-integral value entered");
break;
}
if (number2 == ERR_NON_POS) break;
// Work out greatest common divisor (though there are better ways
// to do this than checking EVERY possibility).
int gcd = 1;
for (int i = 2; (i <= number1) && (i <= number2); ++i) {
if (number1 % i == 0 && number2 % i == 0) {
gcd = i;
}
}
// Work out the lowest common multiple.
int lcm = number1 * number2 / gcd;
// Print them both and go get more.
printf("For numbers %d and %d, GCD is %d and LCM is %d.\n", number1, number2, gcd, lcm);
}
return 0;
}
And, if you're wondering about the more efficient way of calculating GCD, you should look into Euclid's algorithm. This can be defined as (for non-negative a and b):
gcd(a,b) = a if b is zero
gcd(b, a mod b) if b is non-zero
That means you can have a recursive function:
int gcd(int a, int b) {
if (b == 0) return a;
return gcd(b, a % b);
}
Or an iterative one if you're vehemently opposed to recursion:
int gcd(int a, int b) {
while (b != 0) {
int t = a % b;
a = b;
b = t;
}
return a;
}

Quadratic Equation in C

Here is a program that I'm trying to fix. I entered 1,5,6 and there should be 2 solutions and it said only 1 solution exists. I'm also trying to make it display decimal values(should I use double?). Below is my code, What am I doing wrong?
#include <stdio.h>
#include <math.h>
int main(void)
{
int inputs[3], a, b, c, d, x, x1, x2, i, lastDigit;
char *os, *noSol = "No solution\n", *cont = 'y';
while (cont == 'Y' || cont == 'y')
{
printf("This program solves a quadratic equation\n");
for (i = 1; i <= 3; i++)
{
lastDigit = i % 10;
if (i >= 4 && i <= 20)
os = "th";
if (i == 1 || lastDigit == 1)
os = "st";
else if (i == 2 || lastDigit == 2)
os = "nd";
else if (i == 3 || lastDigit == 3)
os = "rd";
else
os = "th";
printf("Enter your %d%s number: ", i, os);
scanf("%d", &inputs[i - 1]);
}
a = inputs[0];
b = inputs[1];
c = inputs[2];
while (1)
{
if (a == 0)
{
if (b == 0)
{
printf(noSol);
break;
}
else
{
x = -c / b;
printf("The equation is not quadratic and the solution is %d\n", x);
break;
}
}
else
{
d = pow(b, 2) - 4 * a * c;
if (d < 0)
{
printf(noSol);
break;
}
else if (d == 0)
{
x1 = -b / 2 * a;
printf("One solution: %d\n", x1);
break;
}
else if (d > 0)
{
x1 = (-b + sqrt(d)) / 2 * a;
x2 = (-b - sqrt(d)) / 2 * a;
printf("Two solutions: %d and %d\n", x1, x2);
break;
}
}
}
printf("Run program second time? ( Y / N )\n");
scanf("%s", &cont);
}
getch();
}
Many issues
The math part should use double (or float) instead of int.
double inputs[3], a, b, c, d, x, x1, x2;
printf() & scanf() for double, format specifier needs to change from %d to %le (or the like) to match double.
Math error: in 3 places, / 2 * a; should be / (2 * a);
char *cont = 'y' should be char cont[2] = "y"
scanf("%s", &cont); should be scanf("%1s", cont);.
Error handling: the return value of scanf() should be checked as in
if (1 != scanf("%lf", &inputs[i - 1])) { ; /* Handle error */ }
Minor math: if (d == 0) case results in a "double root", not a single solution. Practically speaking, given floating point math rounding, one does not always know d should have been mathematically exactly zero and thus the "single" root is really 2 very close roots. Further, with select values, the "Two solutions" will have the same value should sqrt(d) be much much smaller than b.

Unexpected output using the switch statement for this complex logic

I am trying to use a switch statement for 3 conditions. Conditions were:
When a, b, and c are all zero, any value of x is a solution. Print: Any value of x is a solution.
When a and b are zero and c is not, no solution exists. Print: No solution exists.
When a is zero and b is not zero, the only solution is x = -c/b. Calculate the value of x and print the solution.
When I tried to run my program, it displayed the wrong results. My input were
a = 0
b = 0
c = 0
So it's supposed to print "Any value of x is a solution", but it didn't.
My program is:
#include <stdio.h>
//Function declarations
void getData (int* a, int* b, int* c);
float calculateX (int a, int b, int c);
//===================================================
int main (void)
{
//Local declarations
int a;
int b;
int c;
float x;
//Statements
getData (&a, &b, &c);
calculateX (a, b, c);
int temp;
printf("\nEnter an integer and press enter to exit the program: ");
scanf("%d", &temp);
return 0;
}
//----------------------------------------------------
void getData (int* a, int* b, int* c)
{
printf("Enter three integers: ");
scanf("%d %d %d", a, b, c);
return;
}
//----------------------------------------------------
float calculateX (int a, int b, int c)
{
float x;
printf("Input is: %d %d %d\n", a, b, c);
switch(a, b, c)
{
case 1: (a, b, c == 0);
printf("Any value of x is a solution.");
break;
case 2: (a, b == 0 && c!= 0);
printf("No solution exists.");
break;
case 3: (a == 0 && b!= 0);
x = (float)(-c/b);
printf("The value of x is: %.1f", x);
break;
default: printf("Cannot calculate.");
}
return a, b, c;
}
And my output was:
Enter three integers: 0 0 0
Input is: 0 0 0
Cannot calculate.
Enter an integer and press enter to exit the program:
This is not how a switch statement works. It compiles, but for very obscure reasons. Obviously, it doesn't do what you expect when it runs.
Generally speaking, you use a switch statement on a single expression, and each of the case labels represents one possible value of that expression. e.g.:
switch (x)
{
case 1:
// Code here runs when x == 1
break;
case 2:
// Code here runs when x == 2
break;
default:
// Code here runs for all other values of x
break;
}
In your application, you want to test multiple variables, and combine them in complex ways. There is no neat way to do that with switch. You should consider a set of if statements instead.
Is there any reason you have to use switch? Just do
if (a == 0 && b == 0 && c == 0)
...
else if (a == 0 && b == 0 && c != 0)
....
...
Actually, here's a valid way to use the switch statement for this problem:
switch ((a != 0) * 4 + (b != 0) * 2 + (c != 0))
{
case 0: // a, b, c == 0
printf("Any value of x is a solution.");
break;
case 1: // a, b == 0 && c!= 0
printf("No solution exists.");
break;
case 2: // a == 0 && b!= 0
case 3:
x = (float)(-c/b);
printf("The value of x is: %.1f", x);
break;
default:
printf("Cannot calculate.");
}
I've based this on your code, except that I use conditionals (which evaluate to 0 or 1) to encode the state of each variable (zero or not, respectively) in the expression, assigning each to a separate bit. The switch then decodes it -- the interesting part for you, as a beginner, is that case 2 falls through to case 3 because we don't care whether c is zero.
Your code has some other issues, but I'm restricting myself to the switch that you asked about. Best of luck.

Resources