C
CBFalconer
Here is an amusing toy, which may be of especial interest to the
Forthians who use rational fractions to represent real numbers.
The handling of criterion may also be interesting to some.
/* Find best rational approximation to a double */
/* by C.B. Falconer, 2006-09-07. Released to public domain */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <float.h>
#include <limits.h>
#include <errno.h>
int main(int argc, char **argv)
{
int num, approx, bestnum, bestdenom;
int lastnum = 500;
double error, leasterr, value, criterion, tmp;
char *eptr;
value = 4 * atan(1.0);
if (argc > 2) lastnum = strtol(argv[2], NULL, 10);
if (lastnum <= 0) lastnum = 500;
if (argc > 1) {
tmp = strtod(argv[1], &eptr);
if ((0.0 >= tmp) || (tmp > INT_MAX) || (ERANGE == errno)) {
puts("Invalid number, using PI");
}
else value = tmp;
}
criterion = 2 * value * DBL_EPSILON;
puts("Usage: ratvalue [number [maxnumerator]]\n"
"number defaults to PI, maxnumerator to 500");
printf("Rational approximation to %.*f\n", DBL_DIG, value);
for (leasterr = value, num = 1; num < lastnum; num++) {
approx = (int)(num / value + 0.5);
error = fabs((double)num / approx - value);
if (error < leasterr) {
bestnum = num;
bestdenom = approx;
leasterr = error;
printf("%8d / %-8d = %.*f with error %.*f\n",
bestnum, bestdenom,
DBL_DIG, (double)bestnum / bestdenom,
DBL_DIG, leasterr);
if (leasterr <= criterion) break;
}
}
return 0;
} /* main */
Forthians who use rational fractions to represent real numbers.
The handling of criterion may also be interesting to some.
/* Find best rational approximation to a double */
/* by C.B. Falconer, 2006-09-07. Released to public domain */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <float.h>
#include <limits.h>
#include <errno.h>
int main(int argc, char **argv)
{
int num, approx, bestnum, bestdenom;
int lastnum = 500;
double error, leasterr, value, criterion, tmp;
char *eptr;
value = 4 * atan(1.0);
if (argc > 2) lastnum = strtol(argv[2], NULL, 10);
if (lastnum <= 0) lastnum = 500;
if (argc > 1) {
tmp = strtod(argv[1], &eptr);
if ((0.0 >= tmp) || (tmp > INT_MAX) || (ERANGE == errno)) {
puts("Invalid number, using PI");
}
else value = tmp;
}
criterion = 2 * value * DBL_EPSILON;
puts("Usage: ratvalue [number [maxnumerator]]\n"
"number defaults to PI, maxnumerator to 500");
printf("Rational approximation to %.*f\n", DBL_DIG, value);
for (leasterr = value, num = 1; num < lastnum; num++) {
approx = (int)(num / value + 0.5);
error = fabs((double)num / approx - value);
if (error < leasterr) {
bestnum = num;
bestdenom = approx;
leasterr = error;
printf("%8d / %-8d = %.*f with error %.*f\n",
bestnum, bestdenom,
DBL_DIG, (double)bestnum / bestdenom,
DBL_DIG, leasterr);
if (leasterr <= criterion) break;
}
}
return 0;
} /* main */