#include #include #include #include #include typedef enum {S0, S1, S2, S3, S4, S5, S6, S7} State; bool read_double(double* value) { int sign = 1; double factor = 1; long long unsigned int mantissa = 0; int exponent = 0; int expsign = 1; bool error = false; do { State state = S0; factor = 1; mantissa = 0; exponent = 0; sign = 1; int ch = EOF; error = false; bool finished = false; while (!finished && !error && (ch = getchar()) != EOF) { switch (state) { case S0: if (ch == '+' || ch == '-') { if (ch == '-') sign = -1; state = S1; } else if (isdigit(ch)) { mantissa = ch - '0'; state = S2; } else if (ch == '.') { state = S3; } else { // stay at S0, skipping other text } break; case S1: if (isdigit(ch)) { mantissa = ch - '0'; state = S2; } else if (ch == '.') { state = S3; } else { error = true; } break; case S2: if (isdigit(ch)) { mantissa = mantissa * 10 + ch - '0'; } else if (ch == '.') { state = S4; } else if (ch == 'E' || ch == 'e') { state = S5; } else { finished = true; } break; case S3: if (isdigit(ch)) { mantissa = mantissa * 10 + ch - '0'; factor /= 10; state = S4; } else { error = true; } break; case S4: if (isdigit(ch)) { mantissa = mantissa * 10 + ch - '0'; factor /= 10; } else if (ch == 'E' || ch == 'e') { state = S5; } else { finished = true; } break; case S5: if (ch == '+' || ch == '-') { if (ch == '-') { expsign = -1; } state = S6; } else if (isdigit(ch)) { exponent = ch - '0'; state = S7; } else { error = true; } break; case S6: if (isdigit(ch)) { exponent = ch - '0'; state = S7; } else { error = true; } break; case S7: if (isdigit(ch)) { exponent = exponent * 10 + ch - '0'; } else { finished = true; } break; } } if (ch == EOF) { if ((!error && state == S2) || state == S4 || state == S7) break; return false; } if (!error) { ungetc(ch, stdin); } } while (error); *value = (double) sign * mantissa * factor * pow(10, exponent * expsign); return true; } int main() { double x; /* input value, returned by read_double */ double sum = 0; /* regular sum */ double kahan_sum = 0; double c = 0; /* Kahan sum and compensation term */ while (read_double(&x)) { /* regular sum */ sum += x; /* Kahan sum */ double y = x - c; double t = kahan_sum + y; c = (t - kahan_sum) - y; kahan_sum = t; } printf("Regular sum: %.17lg\n", sum); printf("Kahan sum: %.17lg\n", kahan_sum); printf("Difference: %lg\n", fabs(sum - kahan_sum)); }