📄 calc.c
字号:
//////////////////////////////////////////////////////////////////////////////
// calc.c
// Implements a generic calculator.
// Copyright (c) 1999, Robert Mykland. All rights reserved.
//////////////////////////////////////////////////////////////////////////////
//////////////
// Includes //
//////////////
#include "app.h" // The definitions for this application
#include "calc.h" // The definitions for this module
///////////////////////
// Global Prototypes //
///////////////////////
void calcAdd( void ); // Queue an add operation
void calcAppend( int ); // Append a digit
void calcChangeSign( void ); // Change the sign of the entry
void calcClear( void ); // Clear/reset the calculator
void calcDivide( void ); // Queue a divide operation
void calcEquals( void ); // Finish the current operation
void calcExponent( void ); // Start gathering the exponent
void calcMultiply( void ); // Queue a multiply operation
void calcPoint( void ); // Start gathering the fraction
void calcSubtract( void ); // Queue a subtraction operation
//////////////////////
// Local Prototypes //
//////////////////////
static double ca2n( char* ); // Converts an ascii string to a double
static void n2ca( double, char* ); // Changes a double to a string
/////////////////////
// Local Constants //
/////////////////////
#define MAX_DIGITS 8
#define MAX_EXP_DIGITS 2
enum {
OPERATION_NONE = 0,
OPERATION_ADD,
OPERATION_DIVIDE,
OPERATION_MULTIPLY,
OPERATION_SUBTRACT
};
/////////////////////
// Local Variables //
/////////////////////
static char caNumber[MAX_NUMBER_SIZE] = "+0";
static int iDigitCount;
static int iOperator;
static double nOperand;
static int oExponent;
static int oFraction;
//////////////////////
// Global Functions //
//////////////////////
//----------------------------------------------------------------------------
void calcAdd(
//----------------------------------------------------------------------------
// Queues an add operation.
//----------------------------------------------------------------------------
void )
//----------------------------------------------------------------------------
{
// Resolve any pending operations
calcEquals();
// Queue the operation
iOperator = OPERATION_ADD;
// We're done
return;
}
//----------------------------------------------------------------------------
void calcAppend(
//----------------------------------------------------------------------------
// Appends a digit to the entry.
//----------------------------------------------------------------------------
int iDigit ) // The digit to append
//----------------------------------------------------------------------------
{
char caDigit[2];
// If we are entering the exponent part
if( oExponent )
{
// If the exponent digit count is at maximum, then signal an error
if( iDigitCount >= MAX_EXP_DIGITS )
{
calcSignalError();
return;
}
}
else
// If we are entering the number part
{
// If the digit count is at maximum, then signal an error
if( iDigitCount >= MAX_DIGITS )
{
calcSignalError();
return;
}
}
// Destroy leading zeroes
if( (oFraction == false) && (iDigitCount < 2) && (caNumber[1] == '0') )
caNumber[1] = '\0';
// Append the digit
caDigit[0] = iDigit + 0x30;
caDigit[1] = '\0';
strcat( caNumber, caDigit );
// Increase the digit count if it wasn't a leading zero
if( (oFraction == true) || (iDigitCount == 0) || (caNumber[1] != '0') )
iDigitCount++;
// Display the new number
calcDisplay( caNumber );
return;
}
//----------------------------------------------------------------------------
void calcChangeSign(
//----------------------------------------------------------------------------
// Changes the sign of the number or exponent.
//----------------------------------------------------------------------------
void )
//----------------------------------------------------------------------------
{
int iPlace;
// Find the last sign in the number
for( iPlace = strlen( caNumber ) - 1; iPlace >= 0; iPlace-- )
{
// If it's a plus, change to minus
if( caNumber[iPlace] == '+' )
{
caNumber[iPlace] = '-';
break;
}
// If it's a minus, change to plus
if( caNumber[iPlace] == '-' )
{
caNumber[iPlace] = '+';
break;
}
}
// Display the new number
calcDisplay( caNumber );
return;
}
//----------------------------------------------------------------------------
void calcClear(
//----------------------------------------------------------------------------
// Clears/resets the calculator.
//----------------------------------------------------------------------------
void )
//----------------------------------------------------------------------------
{
// Set our local variables in a default state
strcpy( caNumber, "+0" );
iDigitCount = 0;
iOperator = OPERATION_NONE;
nOperand = 0.0;
oExponent = false;
oFraction = false;
// Display the new number
calcDisplay( caNumber );
return;
}
//----------------------------------------------------------------------------
void calcDivide(
//----------------------------------------------------------------------------
// Queues a divide operation.
//----------------------------------------------------------------------------
void )
//----------------------------------------------------------------------------
{
// Resolve any pending operations
calcEquals();
// Queue the operation
iOperator = OPERATION_DIVIDE;
// We're done
return;
}
//----------------------------------------------------------------------------
void calcEquals(
//----------------------------------------------------------------------------
// Resolves a math operation.
//----------------------------------------------------------------------------
void )
//----------------------------------------------------------------------------
{
double nOperand2;
// If there is an entry
if( iDigitCount > 0 )
// Convert the entry to floating point
nOperand2 = ca2n( caNumber );
else
// If there is no entry
// The entry is the last operand
nOperand2 = nOperand;
// Perform the operation
switch( iOperator )
{
case OPERATION_ADD:
nOperand = nOperand + nOperand2;
break;
case OPERATION_DIVIDE:
nOperand = nOperand / nOperand2;
break;
case OPERATION_MULTIPLY:
nOperand = nOperand * nOperand2;
break;
case OPERATION_SUBTRACT:
nOperand = nOperand - nOperand2;
break;
default:
nOperand = nOperand2;
break;
}
// Clear the operator
iOperator = OPERATION_NONE;
// Convert the result from floating point for display
n2ca( nOperand, caNumber );
// Display the new number
calcDisplay( caNumber );
// Reset the entry
iDigitCount = 0;
strcpy( caNumber, "+0" );
oExponent = false;
oFraction = false;
// We're done
return;
}
//----------------------------------------------------------------------------
void calcExponent(
//----------------------------------------------------------------------------
// Starts gathering the exponent.
//----------------------------------------------------------------------------
void )
//----------------------------------------------------------------------------
{
// If we're not already doing the exponent
if( (oExponent == false) &&
// and if the number is nonzero
(ca2n( caNumber ) != 0.0) )
{
// Set up the exponent part
oExponent = true;
iDigitCount = 0;
strcat( caNumber, "e+0" );
// Display the new number
calcDisplay( caNumber );
}
else
// This was done in error
calcSignalError();
// We're done
return;
}
//----------------------------------------------------------------------------
void calcMultiply(
//----------------------------------------------------------------------------
// Queues a multiply operation.
//----------------------------------------------------------------------------
void )
//----------------------------------------------------------------------------
{
// Resolve any pending operations
calcEquals();
// Queue the operation
iOperator = OPERATION_MULTIPLY;
// We're done
return;
}
//----------------------------------------------------------------------------
void calcPoint(
//----------------------------------------------------------------------------
// Appends a decimal point to the entry.
//----------------------------------------------------------------------------
void )
//----------------------------------------------------------------------------
{
// If we are not collecting the fractional part already
if( (oFraction == false) &&
// If we are not doing the exponent
(oExponent == false) &&
// If we are not maxed out on digits
(iDigitCount != MAX_DIGITS) )
{
// If no digit has been entered, enter a zero
if( iDigitCount == 0 )
calcAppend( 0 );
// Now we will have a fractional part
oFraction = true;
// Append the decimal point
strcat( caNumber, "." );
}
else
// This was done in error
calcSignalError();
// Display the new number
calcDisplay( caNumber );
return;
}
//----------------------------------------------------------------------------
void calcSubtract(
//----------------------------------------------------------------------------
// Queues a subtract operation.
//----------------------------------------------------------------------------
void )
//----------------------------------------------------------------------------
{
// Resolve any pending operations
calcEquals();
// Queue the operation
iOperator = OPERATION_SUBTRACT;
// We're done
return;
}
/////////////////////
// Local Functions //
/////////////////////
//----------------------------------------------------------------------------
static double ca2n(
//----------------------------------------------------------------------------
// Converts a decimal ascii string to a double.
//----------------------------------------------------------------------------
char* cpNumber ) // The string to convert
//----------------------------------------------------------------------------
{
double nSign;
int oDecimal;
int iDivisor;
int iCount;
char caInt[MAX_DIGITS + 1];
int iNumber;
double nNumber;
// Get any leading sign
nSign = 1.0;
if( *cpNumber == '+' )
cpNumber++;
if( *cpNumber == '-' )
{
nSign = -1.0;
cpNumber++;
}
// Convert to an integer string
oDecimal = false;
iDivisor = 0;
for( iCount = 0; (iCount <= MAX_DIGITS) && *cpNumber &&
(*cpNumber != 'e'); iCount++ )
{
// Do the decimal point thing
if( *cpNumber == '.' )
{
oDecimal = true;
iCount--;
cpNumber++;
continue;
}
// If we are gathering the fraction
if( oDecimal )
iDivisor++;
// Otherwise, copy the digit
caInt[iCount] = *cpNumber++;
}
// Zero delimit the string
caInt[iCount] = '\0';
// Use atoi
iNumber = atoi( caInt );
// Convert to a double
nNumber = nSign * (double)iNumber * pow( 10.0, -(double)iDivisor );
// If there is an exponent
if( *cpNumber == 'e' )
{
cpNumber++;
// Get any leading sign
nSign = 1.0;
if( *cpNumber == '+' )
cpNumber++;
if( *cpNumber == '-' )
{
nSign = -1.0;
cpNumber++;
}
// Convert to an integer string
for( iCount = 0; (iCount <= MAX_EXP_DIGITS) && *cpNumber; iCount++ )
caInt[iCount] = *cpNumber++;
// Zero delimit the string
caInt[iCount] = '\0';
// Use atoi
iNumber = atoi( caInt );
// Multiply the number
nNumber *= pow( 10.0, (double)iNumber );
}
// Return the number
return( nNumber );
}
//----------------------------------------------------------------------------
static void n2ca(
//----------------------------------------------------------------------------
// Converts a double to an ascii string.
//----------------------------------------------------------------------------
double nNumber, // The number to convert
char* cpNumber ) // Storage for the converted number
//----------------------------------------------------------------------------
{
double nExp;
int iExp;
int iNumber;
char caInt[9];
int iZeroes;
// Handle zero
if( nNumber == 0.0 )
{
strcpy( cpNumber, "+0" );
return;
}
// Grab the sign
*cpNumber = '+';
if( nNumber < 0.0 )
{
nNumber = -nNumber;
*cpNumber = '-';
}
cpNumber++;
// Normalize
nExp = log10( nNumber );
iExp = (int)nExp;
if( nExp < 0 )
iExp--;
iExp -= MAX_DIGITS - 1;
nNumber /= pow( 10.0, (double)iExp );
// Convert to an integer
iNumber = (int)(nNumber + 0.5);
// Convert to an integer string
itoa( caInt, iNumber );
// Count trailing zeroes
for( iZeroes = 0; caInt[strlen( caInt ) - 1 - iZeroes] == '0'; iZeroes++ )
;
// Handle decimal notation
if( (iExp <= 0) && (iExp > -MAX_DIGITS) )
{
// Integer part
strncpy( cpNumber, caInt, MAX_DIGITS + iExp );
cpNumber[MAX_DIGITS + iExp] = '\0';
// Decimal point
strcat( cpNumber, "." );
// Mantissa part
strcat( cpNumber, caInt + MAX_DIGITS + iExp );
// Eliminate trailing zeroes
while( cpNumber[strlen( cpNumber ) - 1] == '0' )
cpNumber[strlen( cpNumber ) - 1] = '\0';
}
// Handle decimal notation with leading zeroes
else if( (iExp <= -MAX_DIGITS) && (iExp > -(MAX_DIGITS + iZeroes)) )
{
// Integer part and decimal point
strcpy( cpNumber, "0." );
iExp += MAX_DIGITS;
// Other zeroes
for( ; iExp; iExp++ )
strcat( cpNumber, "0" );
// Eliminate trailing zeroes
while( caInt[strlen( caInt ) - 1] == '0' )
caInt[strlen( caInt ) - 1] = '\0';
// The rest of the number
strcat( cpNumber, caInt );
}
else
// Handle exponential notation
{
// Build the number part
*cpNumber++ = *caInt;
*cpNumber++ = '.';
strcpy( cpNumber, caInt + 1 );
// Convert the exponent to ascii
iExp += MAX_DIGITS - 1;
itoa( caInt, iExp );
// Build the exponent part
strcat( cpNumber, "e" );
if( iExp > 0 )
strcat( cpNumber, "+" );
strcat( cpNumber, caInt );
// Eliminate trailing zeroes
while( cpNumber[strlen( cpNumber ) - 1] == '0' )
cpNumber[strlen( cpNumber ) - 1] = '\0';
}
// We're done
return;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -