Last active
December 5, 2016 05:31
-
-
Save iamarkdev/95827fc2f49d46a42eb44dcce0c7675e to your computer and use it in GitHub Desktop.
ATOF with support for scientific notation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#define MAX_LINE_LENGTH 100 | |
enum PositionState { | |
POSITION_STATE_WHOLE, | |
POSITION_STATE_DECIMAL, | |
POSITION_STATE_NOTATION | |
}; | |
int mygetline(char line[], int max) { | |
int c, i; | |
for (i = 0; i < max && (c = getchar()) != EOF && c != '\n'; i++) { | |
line[i] = c; | |
} | |
if (i >= max) { | |
i = i - 1; | |
} | |
line[i] = '\0'; | |
return i; | |
} | |
int isDigit(char input) { | |
return (input >= '0' && input <= '9') ? 1 : 0; | |
} | |
long power(int base, int exponent) { | |
long result = (exponent > 0) ? base : 0; | |
for (int i = 0; i < exponent - 1; i++) { | |
result *= base; | |
} | |
return result; | |
} | |
float atof(char input[]) { | |
int sign = 1; | |
int whole = 0; | |
float decimal = 0; | |
int decimalCount = 0; | |
int notationExponents = 0; | |
int notationSign = 1; | |
int i = 0; | |
while ((input[i] < '0' || input[i] > '9') && input[i] != '+' && input[i] != '-') { | |
i++; | |
} | |
if (input[i] == '+' || input[i] == '-') { | |
sign = (input[i++] == '-') ? -1 : sign; | |
} | |
enum PositionState state = POSITION_STATE_WHOLE; | |
while (input[i] != '\n' && input[i] != ' ' && input[i] != '\t' && input[i] != '\0') { | |
// Return 0 for invalid characters. | |
if ((input[i] < '0' || input[i] > '9') && input[i] != 'e' && input[i] != 'E' && input[i] != '-' && input[i] != '+' && input[i] != '.') { | |
fprintf(stderr, "Invalid char \"%c\" found in atof() input.\n", input[i]); | |
return 0; | |
} | |
// Handle whole numbers | |
if (state == POSITION_STATE_WHOLE) { | |
if (isDigit(input[i])) { | |
whole = whole * 10 + (input[i] - '0'); | |
} | |
} | |
// Handle decimals | |
if (state == POSITION_STATE_DECIMAL) { | |
if (isDigit(input[i])) { | |
decimalCount++; | |
decimal = decimal * 10 + (input[i] - '0'); | |
} | |
} | |
state = (input[i] == '.') ? POSITION_STATE_DECIMAL : state; | |
// Handle notation | |
if (state == POSITION_STATE_NOTATION) { | |
if (input[i] == '-') { | |
notationSign = -1; | |
i++; | |
} | |
if (isDigit(input[i])) { | |
notationExponents = notationExponents * 10 + (input[i] - '0'); | |
} | |
} | |
state = (input[i] == 'e' || input[i] == 'E') ? POSITION_STATE_NOTATION : state; | |
// Next char in input | |
i++; | |
} | |
// Calculate result | |
double result = whole; | |
if (decimalCount > 0) { | |
result += decimal / power(10, decimalCount); | |
} | |
if (notationExponents > 0) { | |
if (notationSign > 0) { | |
result *= power(10, notationExponents); | |
} else { | |
result /= power(10, notationExponents); | |
} | |
} | |
return sign * result; | |
}; | |
int main() { | |
int c; | |
char line[MAX_LINE_LENGTH]; | |
while (mygetline(line, MAX_LINE_LENGTH)) { | |
printf("%f\n", atof(line)); | |
} | |
} |
The name of the position
variable name is misleading. This variable is the position state, not the position.
How about this for a power() implementation?
double power(int base, int exponent) {
if (exponent == 0) {
return 1;
}
double result = base;
int negative = 0;
if (exponent < 0) {
negative = 1;
exponent *= -1;
}
for (int i = 0; i < exponent - 1; i++) {
result *= base;
}
if (negative) {
result = 1.f / result;
}
return result;
}
then instead of this code:
if (notationExponents > 0) {
if (notationSign > 0) {
result *= power(10, notationExponents);
} else {
result /= power(10, notationExponents);
}
}
it could simply be:
result *= power(10, notationExponents);
where notationExponents can be a negative, positive, or zero value
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
You have an isdigit() function but you're not using it as much as you can. Instead of this,
you can use