Log   |   Assignments   |   Source   |   Discussion   |   Feedback   |   About Me  |

This page lists the sixth version (v0.6) of the Quadratic Equation Solver.

Main File
UI
Solution Logic

Main File

/*
 * Advanced Computer Architecture
 * Assignment - 1
 * Read the coefficients of a Quadratic equation from the user
 * and calculate the roots using a function call. 
 *
 * Author: Kurian John (CS10M035)
 * Revision History
 * ----------------
 * 2011-03-15 - v0.6
 * 	- Re-organized code into different files. Now using a 
 * 	  Makefile for building
 * 	- Fixed nan root for X*X = 0
 * 	- Fixed UI bugs
 * 		* Ignores leading zeros 
 * 		* Ignores spaces/commas 
 * 		* Ignores special keys
 * 		* Better editing in text entry box
 * 		* Fixed missing window borders
 * 2011-02-22 - v0.5
 * 	- Added ncurses UI. Still buggy in many
 * 	  places and code not clean at all!
 * 2011-02-15 - v0.4
 * 	- Accepts leading spaces
 * 2011-02-08 - v0.3
 * 	- Accepts spaces between sign and number
 * 	- Tells user the guaranteed number of significant digits
 * 2011-02-01 - v0.2
 * 	Almost full rewrite
 * 	 - Better input validation
 * 	 - Handles equations where b*b is much larger
 * 	   than 4*a*c
 * 2011-01-18 - v0.1
 * 	Removed structure return and packed everything into 
 * 	a long double - Read comments for more info
 * 2011-01-05 - v0.0
 * 	New program - Calculate roots of a quadratic
 * 	equation using a function call and return the roots.
 */

#include "ui.h"

int main()
{
	startUI ();
	return 0;
}

User Interface

/*
 * Advanced Computer Architecture
 * Assignment - 1
 * Read the coefficients of a Quadratic equation from the user
 * and calculate the roots using a function call. 
 * This file contains UI related stuff
 * 
 * Author: Kurian John (CS10M035)
 * 
 */

#include "ui.h"


void clearTextBoxen (int Y, int X, int charCount)
{
	int i;
	for (i=X; i<charCount+X; i++)
	{
		move (Y, i);
		addch (' ');
	}
	return;
}

void drawWinLegends (int aWinY, int bWinY, int cWinY, int lMargin, int exitMessageLine)
{
	int i;
	move (0,0);
	printw ("*--------------------------------------------------*\n");
	printw ("|          Quadratic Equation Solver               |\n");
	printw ("*--------------------------------------------------*\n");
	printw ("| Please enter the coefficients of a Quadratic     |\n");
	printw ("| Equation. Coefficients are numbers having less   |\n");
	printw ("| than 10 characters (including sign and decimal)  |\n");
	printw ("*--------------------------------------------------*\n");
	for (i=7; i<24; i++)
	{
		move (i, 0);
	printw ("|                                                  |");
	}
	move (21,0);
	printw ("*--------------------------------------------------*\n");
	move (24,0);
	printw ("*--------------------------------------------------*\n");

	move (exitMessageLine, lMargin);
	printw("Press F3 to exit");
	move (aWinY+1,lMargin);
	printw ("Coefficient of X*X (a)");
	move (bWinY+1,lMargin);
	printw ("Coefficient of   X (b)");
	move (cWinY+1,lMargin);
	printw ("Constant term      (c)");

	return;
}

void  startUI()
{	WINDOW *aWin, *bWin, *cWin;
	int startX, aWinY, bWinY, cWinY, width, height, lMargin;
	int ch,errorLine,exitMessageLine, rootLine;
	int currXPos, currYPos, i, valuesEntered=0;
	int decimalEntered=0, waitingForDigits=1, signEntered=0;
	float a,b,c;
	char* currString, *tempString;

	initscr();		
	cbreak();			
	noecho ();
	keypad(stdscr, TRUE); // To catch F3 to exit

	height = 3;
	width = 20;
	lMargin = 3;
	aWinY = 8;
	bWinY = aWinY+3;
	cWinY = aWinY+6;
	rootLine = 18;
	errorLine=22;
	exitMessageLine=23;
	startX = 25;	
	currXPos=startX+1;
	currYPos=aWinY+1;

	// Print the window border and legends
	drawWinLegends (aWinY, bWinY, cWinY, lMargin, exitMessageLine);
	refresh();

	// Draw the text boxen
	aWin = create_newwin(height, width, aWinY, startX);
	bWin = create_newwin(height, width, bWinY, startX);
	cWin = create_newwin(height, width, cWinY, startX);

	currString = (char*) malloc (sizeof(char) * 2);
	currString[0]='\0';
	currString[1]='\0';
	move (aWinY+1, startX+1);
	while((ch = getch()) != KEY_F(3))
	{
		clearTextBoxen (rootLine, lMargin, 45);
		clearTextBoxen (rootLine+1, lMargin, 45);
		clearTextBoxen (rootLine+2, lMargin, 45);
		clearTextBoxen (errorLine, lMargin, 45);
		move (currYPos, currXPos );
		switch (ch)
		{
			case KEY_LEFT:
				if (currXPos > (startX+1))
					currXPos--;
				//move (LINES-2,lMargin);
				//printw ("Curr char: %c", currString[currXPos-startX-1]);
				break;
			case KEY_RIGHT:
				if ((currXPos-startX-1) < strlen(currString))
					currXPos++;
				//move (LINES-2,lMargin);
				//printw ("Curr char: %c", currString[currXPos-startX-1]);
				break;
			case 10://KEY_ENTER:
				if ( (strlen(currString) == 0) || waitingForDigits )
				{
					move (errorLine, lMargin);
					printw ("Coefficient cannot be empty!");
					flash ();
				}
				else
				{
					currYPos+=3;
					currXPos=startX+1;
					move (currYPos, currXPos );
					waitingForDigits=1;
					decimalEntered=0;
					signEntered=0;
					valuesEntered++;
					if (valuesEntered == 1)
					{
						sscanf (currString, "%f", &a);
					}
					else if (valuesEntered == 2)
					{
						sscanf (currString, "%f", &b);
					}
					else if (valuesEntered == 3)
					{
						sscanf (currString, "%f", &c);
						// Solve the equation here
						callSolver (a,b,c);

						clearTextBoxen (rootLine, lMargin, 40);
						clearTextBoxen (rootLine+1, lMargin, 40);
						clearTextBoxen (rootLine+2, lMargin, 40);
						for (i=0; i<3; i++)
						{
							move (rootLine+i, lMargin);
							printw ("%s",responseString[i]);
							strcpy (responseString[i],"\0\0");
						}
						currYPos = aWinY+1;
						clearTextBoxen (aWinY+1, startX+1, 25);
						clearTextBoxen (bWinY+1, startX+1, 25);
						clearTextBoxen (cWinY+1, startX+1, 25);
						valuesEntered = 0;
					}
					free (currString);
					currString = (char*) malloc (sizeof(char) * 2);
					currString[0]='\0';
					currString[1]='\0';
				}
				break;
			case KEY_BACKSPACE:
				if (strlen(currString) > 0)
				{
					move (currYPos, currXPos-1);
					if (currString[currXPos-startX-2] == '.')
						decimalEntered=0;

					if ((currString[currXPos-startX-2] == '+')  ||
							(currString[currXPos-startX-2] == '-') )
					{
						signEntered = 0;
					}
					for (i=currXPos-startX-2; i<strlen(currString);i++)
					{
						currString[i] = currString[i+1];
					}
					currXPos--;
				}
				if ( (strlen(currString) == 0) ||
						( (strlen(currString) == 1) && 
						  ( (currString[0]=='+') || 
						    (currString[0]=='-') || 
						    (currString[0]=='+') 
						  ) 
						) 
				   )
				{
					signEntered = 0;
					waitingForDigits=1;
				}
				break;

			case KEY_DC:
				if (currString[currXPos-startX-1] == '.')
					decimalEntered=0;
				if ((currString[currXPos-startX-1] == '+')  ||
						(currString[currXPos-startX-1] == '-') )
				{
					signEntered = 0;
				}
				for (i=currXPos-startX-1; i<strlen(currString);i++)
				{
					currString[i] = currString[i+1];
				}
				if ( (strlen(currString) == 0) ||
						( (strlen(currString) == 1) && 
						  ( (currString[0]=='+') || 
						    (currString[0]=='-') || 
						    (currString[0]=='+') 
						  ) 
						) 
				   )
				{
					signEntered = 0;
					waitingForDigits=1;
				}
				break;
			default:
				if (strlen(currString) == 10)
				{
					move (errorLine, lMargin);
					printw ("Coefficients must be less than 10 digits long");
					move (currYPos, currXPos );
					flash ();
					continue;
				}	

				// See if the character received is a number
				if ( (ch < 0x30 ) || (ch > 0x39) ) 
				{
					if (ch == '.')
					{
						if (signEntered && currXPos == startX+1)
						{
							flash ();
							move (errorLine, lMargin);
							printw ("Warning: Decimal cannot precede the sign!");
							move (currYPos, currXPos );
							continue;
						}
						if (!decimalEntered)
						{
							decimalEntered = 1;
							tempString =  (char*) malloc (sizeof(char) * strlen(currString) + 16);
							currString = (char*) realloc (currString, sizeof(char) * strlen(currString) + 16);
							strcpy (tempString, currString);

							for (i=strlen(currString)+1;i>(currXPos-startX-1);i--)
							{
								currString[i] = currString[i-1];
							}
							currString[i] = ch;
							currString[strlen(tempString)+1] = '\0';
							currXPos++;
							free(tempString);

							//currString[strlen(currString)] = ch;
							//currString[strlen(currString)+1] = '\0';
							//currXPos++;
						}
						else
						{
							flash ();
							move (errorLine, lMargin);
							printw ("Warning: Duplicate decimal point ignored");
							move (currYPos, currXPos );
						}
					}
					else if ( ((ch=='-') || (ch=='+'))) 
					{
						if (((strlen(currString) == 0)  || (currXPos == startX+1) ) &&
								(!signEntered) )
						{
							/*
							   currString = (char*) realloc (currString, sizeof(char) * strlen(currString) + 16);
							   currString[strlen(currString)] = ch;
							   currString[strlen(currString)+1] = '\0';
							   currXPos++;
							   */
							signEntered = 1;
							tempString =  (char*) malloc (sizeof(char) * strlen(currString) + 16);
							currString = (char*) realloc (currString, sizeof(char) * strlen(currString) + 16);
							strcpy (tempString, currString);

							for (i=strlen(currString)+1;i>(currXPos-startX-1);i--)
							{
								currString[i] = currString[i-1];
							}
							currString[i] = ch;
							currString[strlen(tempString)+1] = '\0';
							currXPos++;
							free(tempString);
						}
						else
						{
							move (errorLine, lMargin);
							printw ("Warning: Sign entered already");
							move (currYPos, currXPos );
						}
					}
					else
					{
						if ((ch < 128) && 
								(ch != ',') &&
								(ch != ' ') )
						{
							flash ();
							move (errorLine, lMargin);
							printw ("Warning: Invalid key pressed (%c)", ch);
							move (currYPos, currXPos );
						}
					}
				}
				else
				{

					if (ch == '0')
					{
						if ((currXPos == startX+1) || 
						   ((currXPos == startX+2) && signEntered) )
						{
							move (errorLine, lMargin);
							printw ("Warning: Leading zeros ignored!");
							move (currYPos, currXPos );
							continue;
						}
					}

					waitingForDigits=0;
					if (signEntered && currXPos == startX+1)
					{
						flash ();
						move (errorLine, lMargin);
						printw ("Warning: Numbers cannot precede the sign!");
						move (currYPos, currXPos );
						continue;
					}
					tempString =  (char*) malloc (sizeof(char) * strlen(currString) + 16);
					currString = (char*) realloc (currString, sizeof(char) * strlen(currString) + 16);
					strcpy (tempString, currString);

					for (i=strlen(currString)+1;i>(currXPos-startX-1);i--)
					{
						currString[i] = currString[i-1];
					}
					currString[i] = ch;
					currString[strlen(tempString)+1] = '\0';
					currXPos++;
					free(tempString);
				}
		}
		clearTextBoxen (currYPos, startX+1, 15);
		move (currYPos, startX+1);
		for (i=0; i<strlen(currString); i++)
		{
			addch (currString[i]);
		}
		move (currYPos, currXPos );
	}
	endwin();		
	return;
}

WINDOW *create_newwin(int height, int width, int startY, int startX)
{	WINDOW *local_win;

	local_win = newwin(height, width, startY, startX);
	box(local_win, 0 , 0);	
	wrefresh(local_win);		

	return local_win;
}

void destroy_win(WINDOW *local_win)
{	
	wborder(local_win, ' ', ' ', ' ',' ',' ',' ',' ',' ');
	wrefresh(local_win);
	delwin(local_win);
}

Solution Logic

/*
 * Advanced Computer Architecture
 * Assignment - 1
 * Read the coefficients of a Quadratic equation from the user
 * and calculate the roots using a function call. 
 * This file contains the equation solving logic
 * 
 * Author: Kurian John (CS10M035)
 * 
 */

#include "solveEqn.h"

char** callSolver (float a, float b, float c)
{
	float p;
	float p1, p2, q;
	// Sanity checks
	p = solveEquation (a,b,c, 0);
	switch ((int)p)
	{
		case 0:
			{
				//printf ("b: %20.6f Delta: %20.6f Sqrt(Delta): %20.6f\n",b, b*b-4*a*c, sqrt(b*b-4*a*c));  
				if (c > EPSILON)
				{
					if (b*b / (4*a*c) > 1.0e3)
					{
						strcpy (responseString[0], "b^2 >> 4ac. Only 5 significant figures\0");
						// Because we would have lost precision in the last digit when we
						// did sqrt (b*b - 4*a*c) and got the result b
					}
				}
				p1 = solveEquation (a,b,c,1);
				p2 = solveEquation (a,b,c,2);
				sprintf (responseString[1], "Root 1: %+1.6e", p1);
				strcat (responseString[1], "\0");
				sprintf (responseString[2], "Root 2: %+1.6e", p2);
				strcat (responseString[2], "\0");
				break;
			}
		case 1:
			{
				if (c > EPSILON)
				{
					//printf ("b: %20.6f Delta: %20.6f Sqrt(Delta): %20.6f\n",b, b*b-4*a*c, sqrt(b*b-4*a*c));  
					if (b*b / (4*a*c) > 1.0e3)
					{
						strcpy (responseString[0], "b^2 >> 4ac. Only 5 significant figures\0");
						// Because we would have lost precision in the last digit when we
						// did sqrt (b*b - 4*a*c) and got the result b
					}
				}
				p = solveEquation (a,b,c,3);
				q = solveEquation (a,b,c, 4);
				sprintf (responseString[1], "Root 1: %+1.6e%+1.6ei", p,q);
				sprintf (responseString[2], "Root 2: %+1.6e%+1.6ei", p,-q);
				strcat (responseString[1], "\0");
				strcat (responseString[2], "\0");
				break;
			}
		case 2:
			{
				sprintf (responseString[0],"Equation is linear");
				sprintf (responseString[1],"Solution is %+1.6e", solveEquation (a,b,c,1) );
				strcat (responseString[0], "\0");
				strcat (responseString[1], "\0");
				strcpy (responseString[2],"\0");
				break;
			}
		case 3:
			{
				sprintf (responseString[0], "The equation is invalid!");
				strcat (responseString[0], "\0");
				strcpy (responseString[1],"\0");
				strcpy (responseString[2],"\0");
			}
	}
	return (char**)NULL;
}

/*
 * solveEquation
 * Solves a quadratic equation given the coefficients a, b and c.
 * Returns a float value. The meaning of the return value depeneds
 * on the whatToDo flag
 *   0  : Do sanity checks
 *   1  : First real root / linear solution
 *   2  : Second real root 
 *   3  : Complex root - Real part
 *   4  : Complex root - Imaginary part
 * When called with whatToDo = 0, the return value indicates:
 *   0  : Roots are real
 *   1  : Roots are imaginary
 *   2  : Equation is linear
 *   3  : Equation is invalid
 */
float solveEquation (float a, float b, float c, unsigned char whatToDo)
{
	float discriminant;	
	float p, q;
	switch (whatToDo)
	{
		case 0:
			{
				// If the coefficient of x^2 is 0, solve the linear equation
				//  bx + c = 0 
				if ( fabs (a) < EPSILON)  
				{
					if ( fabs (b) >= EPSILON )
					{
						p = 2; // i = 2 => linear eqn
					}
					// If coefficient of x is also 0, invalid equation
					else
					{
						p = 3; // i = 3 => invalid eqn
					}
				}
				else
				{	
					// Roots are -b/2a + sqrt(discriminant) and 
					// -b/2a - sqrt(discriminant) 
					discriminant = b*b - 4.0*a*c;
					// Roots are imaginary
					if (discriminant < 0.0) 
					{
						p = 1;
					}
					// Roots are real
					else
					{
						p = 0;
					}
				}
				break;

			}
		case 1:
			{
				// If the coefficient of x^2 is 0, solve the linear equation
				//  bx + c = 0 
				if ( fabs (a) < EPSILON)  
				{
					if ( fabs (b) >= EPSILON )
					{
						if (fabs (c) >= EPSILON )
						{
							p=-b / c;
						}
						else
						{
							p=0;
						}
					}
				}
				else
				{	
					// Roots are -b/2a + sqrt(discriminant) and 
					// -b/2a - sqrt(discriminant) 
					discriminant = b*b - 4.0*a*c;
					// Roots are real
					q = sqrt (discriminant);
					if (b > 0)
					{
						p = (b + q) / (-2.0);
					}
					else
					{
						p = (b - q) / (-2.0);
					}
					p = p/a;
				}
				break;
			}
		case 2: // Find the second real root
			{
				discriminant = b*b - 4.0*a*c;

				q = sqrt (discriminant);
				if (b > 0)
				{
					p = (b + q) / (-2.0);
				}
				else
				{
					p = (b - q) / (-2.0);
				}
				if (fabs(p) > EPSILON)
				p = c / p;
				else
				p = 0.0;
				break;
			}
		case 3: // Find real part of complex solution
			{
				p = b / (-2.0 * a);
				break;
			}
		case 4: // Find imaginary part of complex solution
			{
				discriminant = 4.0*a*c - b*b;
				q = sqrt (discriminant);
				p = q / (2.0 * a);
			}
	}
	return p;			

}