-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathscientific_calculator.c
375 lines (336 loc) · 12.5 KB
/
scientific_calculator.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
/**
* Scientific Calculator
*
* A comprehensive console-based scientific calculator supporting various
* mathematical operations including basic arithmetic, trigonometric functions,
* logarithms, and more. Features include angle mode switching, previous result
* memory, and mathematical constant access.
*
* Author: innoxent_ghost
*/
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include<ctype.h>
#include<float.h>
/**
* Clears the input buffer to prevent unexpected behavior when reading input
* This is especially important after a failed scanf operation
*/
void clear_input_buffer() {
int c;
while ((c = getchar()) != '\n' && c != EOF);
}
/**
* Clears the console screen in a cross-platform manner
* Uses the appropriate system command based on the operating system
*/
void clear_screen() {
#ifdef _WIN32
system("cls");
#else
system("clear");
#endif
}
/**
* Validates numeric input from the user
*
* @param num Pointer to store the validated number
* @return 1 if input is valid, 0 otherwise
*/
int validate_input(double *num) {
if (scanf("%lf", num) != 1) {
clear_input_buffer();
printf("\nError: Invalid input. Please enter a valid number.\n");
return 0;
}
return 1;
}
// Mathematical constants with high precision
#define PI 3.14159265358979323846 // π (pi) value
#define E 2.71828182845904523536 // e (Euler's number)
/**
* Checks if a calculation result is valid (not NaN or infinity)
*
* @param result The calculated result to check
* @return 1 if result is valid, 0 otherwise
*/
int is_valid_result(double result) {
return !isnan(result) && !isinf(result);
}
/**
* Displays calculation results with appropriate formatting
* Uses scientific notation for very small or very large numbers
*
* @param result The result to display
*/
void display_result(double result) {
if (!is_valid_result(result)) {
printf("\nError: Calculation resulted in an invalid value (NaN or Infinity).\n");
return;
}
// Use appropriate precision based on the magnitude
if (fabs(result) < 0.0001 || fabs(result) > 100000) {
printf("\nResult: %e", result);
} else {
printf("\nResult: %.6lf", result);
}
}
/**
* Calculates factorial of a non-negative integer
* Handles potential overflow by returning INFINITY when appropriate
*
* @param n The non-negative integer input
* @return The factorial result or NAN/INFINITY for invalid inputs/overflow
*/
double factorial(int n) {
if (n < 0) return NAN;
double result = 1.0;
for (int i = 2; i <= n; i++) {
result *= i;
if (result > DBL_MAX / (i+1)) return INFINITY; // Prevent overflow
}
return result;
}
int main()
{
// Control variables
int choice; // User's menu selection
int loop = 1; // Controls the main program loop
int angle_mode = 0; // Angle mode: 0 = radians, 1 = degrees
// Calculation variables
double num1, num2; // Input numbers for operations
double result; // Current calculation result
double prev_result = 0; // Stores previous calculation result
int use_prev_result = 0; // Flag to use previous result as input
// Main program loop
while (loop) {
clear_screen();
// Display calculator menu with all available options
printf("============================= SCIENTIFIC CALCULATOR =============================\n\n");
printf("\n\t-- AVAILABLE OPERATIONS --\n");
printf("\n 1. Addition\n 2. Subtraction\n 3. Multiplication\n 4. Division\n 5. Power of a Value");
printf("\n 6. Square Root\n 7. Logarithm (base 10)\n 8. Natural Logarithm (base e)\n 9. Exponent (e^x)");
printf("\n10. Sine\n11. Cosine\n12. Tangent\n13. Factorial\n14. Absolute Value\n15. Floor\n16. Ceiling");
printf("\n\n\t-- SETTINGS --");
printf("\n17. Toggle Angle Mode (Current: %s)", angle_mode ? "Degrees" : "Radians");
printf("\n18. Use Previous Result (%s)", use_prev_result ? "Enabled" : "Disabled");
printf("\n\n\t-- CONSTANTS --");
printf("\n19. Pi (π)\n20. Euler's Number (e)");
printf("\n\nPlease enter the serial number of the operation you want to perform: ");
// Get and validate the user's choice
if (scanf("%d", &choice) != 1 || choice < 1 || choice > 20) {
clear_input_buffer();
printf("\nError: Invalid choice. Please enter a number between 1 and 20.\n");
printf("\nPress Enter to restart... ");
getchar();
continue;
}
// Handle settings and mathematical constants
if (choice == 17) {
// Toggle between radians and degrees mode
angle_mode = !angle_mode;
printf("\nAngle mode set to: %s", angle_mode ? "Degrees" : "Radians");
printf("\n\nPress Enter to continue... ");
clear_input_buffer();
getchar();
continue;
} else if (choice == 18) {
// Toggle the use of previous result
use_prev_result = !use_prev_result;
printf("\nUse previous result: %s", use_prev_result ? "Enabled" : "Disabled");
printf("\nPrevious result: %.6lf", prev_result);
printf("\n\nPress Enter to continue... ");
clear_input_buffer();
getchar();
continue;
} else if (choice == 19) {
// Display the value of Pi
printf("\nPi (π) = %.15lf", PI);
printf("\n\nPress Enter to continue... ");
clear_input_buffer();
getchar();
continue;
} else if (choice == 20) {
// Display the value of Euler's number
printf("\nEuler's Number (e) = %.15lf", E);
printf("\n\nPress Enter to continue... ");
clear_input_buffer();
getchar();
continue;
}
// Input acquisition based on operation type
if (choice >= 1 && choice <= 5) {
// Binary operations - require two operands
if (use_prev_result) {
num1 = prev_result;
printf("\nUsing previous result as first number: %.6lf", num1);
printf("\nEnter second number: ");
if (!validate_input(&num2)) {
printf("\nPress Enter to restart... ");
getchar();
continue;
}
} else {
printf("\nEnter two numbers: ");
if (!validate_input(&num1) || !validate_input(&num2)) {
printf("\nPress Enter to restart... ");
getchar();
continue;
}
}
} else if (choice >= 6 && choice <= 16) {
// Unary operations - require one operand
if (use_prev_result) {
num1 = prev_result;
printf("\nUsing previous result: %.6lf", num1);
} else {
if (choice == 13) {
printf("\nEnter a non-negative integer: ");
} else if (choice >= 10 && choice <= 12) {
printf("\nEnter an angle in %s: ", angle_mode ? "degrees" : "radians");
} else {
printf("\nEnter a number: ");
}
if (!validate_input(&num1)) {
printf("\nPress Enter to restart... ");
getchar();
continue;
}
}
}
// Angle conversion for trigonometric functions
if (angle_mode && (choice >= 10 && choice <= 12)) {
// Convert from degrees to radians
num1 = num1 * PI / 180.0;
}
// Process the selected operation
switch (choice) {
case 1:
// Addition
result = num1 + num2;
display_result(result);
break;
case 2:
// Subtraction
result = num1 - num2;
display_result(result);
break;
case 3:
// Multiplication
result = num1 * num2;
display_result(result);
break;
case 4:
// Division - check for division by zero
if (num2 == 0) {
printf("\nError: Division by zero.\n");
} else {
result = num1 / num2;
display_result(result);
}
break;
case 5:
// Power function - check for mathematical validity
if ((num1 == 0 && num2 <= 0) || (fabs(num1) < 1 && num2 == INFINITY)) {
printf("\nError: Undefined mathematical operation.\n");
} else {
result = pow(num1, num2);
display_result(result);
}
break;
case 6:
// Square root - check for negative input
if (num1 < 0) {
printf("\nError: Square root of a negative number.\n");
} else {
result = sqrt(num1);
display_result(result);
}
break;
case 7:
// Logarithm base 10 - check for non-positive input
if (num1 <= 0) {
printf("\nError: Logarithm of a non-positive number.\n");
} else {
result = log10(num1);
display_result(result);
}
break;
case 8:
// Natural logarithm - check for non-positive input
if (num1 <= 0) {
printf("\nError: Natural logarithm of a non-positive number.\n");
} else {
result = log(num1);
display_result(result);
}
break;
case 9:
// Exponential function e^x
result = exp(num1);
display_result(result);
break;
case 10:
// Sine function
result = sin(num1);
display_result(result);
break;
case 11:
// Cosine function
result = cos(num1);
display_result(result);
break;
case 12:
// Tangent function - check for undefined points (where cos = 0)
if (cos(num1) == 0) {
printf("\nError: Tangent is undefined at this angle.\n");
} else {
result = tan(num1);
display_result(result);
}
break;
case 13:
// Factorial - check for valid input (non-negative integer < 171)
if (num1 < 0 || num1 != floor(num1) || num1 > 170) {
printf("\nError: Factorial requires a non-negative integer less than 171.\n");
} else {
result = factorial((int)num1);
display_result(result);
}
break;
case 14:
// Absolute value
result = fabs(num1);
display_result(result);
break;
case 15:
// Floor function (greatest integer less than or equal to x)
result = floor(num1);
display_result(result);
break;
case 16:
// Ceiling function (smallest integer greater than or equal to x)
result = ceil(num1);
display_result(result);
break;
}
// Store valid results for future operations
if (is_valid_result(result)) {
prev_result = result;
}
// Prompt user to continue or exit
printf("\n\nPress 0 to exit or any other key to continue: ");
if (scanf("%d", &loop) != 1) {
// Handle invalid input by continuing the program
clear_input_buffer();
loop = 1; // Default to restart if invalid input
}
if (loop != 0) {
// Reset loop to continue and clear buffer
loop = 1;
clear_input_buffer();
}
}
return 0;
}