/* "Smart" printer using imperial/metric units * depending on what can be written in fewer * significant digits * * by Andrew Poelstra, April 2011, no copyright * */ #include #include /* Appears to work with N_DIGITS set to 10; i.e., * it correctly sees that .3240000001 needs all 10 * digits, while adding an extra zero drops it down * to three. */ #define N_DIGITS 10 int min_sig_figs(double d) { int stack[N_DIGITS] = {0}; int idx = 0; int sum = 0, sum2 = 0, count = 0; if(d == 0) return 0; /* Normalize to x.xxxx... form */ if(d < 0) d *= -1; while(d >= 10) d /= 10; while(d < 1) d *= 10; /* Load digits into stack */ for(idx = 0; idx < N_DIGITS; ++idx) { stack[idx] = floor(d + 1e-5); d = (d - stack[idx]) * 10; sum += stack[idx]; } /* Determine how many digits were actually needed */ for(idx = 0; sum2 < sum; ++idx) { sum2 += stack[idx]; ++count; } return count; } /* Converts a measurement to a string, with units, * choosing metric/imperial to use least sig.figs. */ char *CoordToString(double nanos) { static char buff[255]; int b_units_mm = 0; const char *units; if(min_sig_figs(nanos) < min_sig_figs(nanos / 254.0)) b_units_mm = 1; if(b_units_mm) { nanos /= 1000000; units = "mm"; if(nanos < 0.00001) { nanos *= 1000000; units = "nm"; } if(nanos < 0.01) { nanos *= 1000; units = "um"; } } else { nanos /= 25400; units = "mil"; if(nanos < 0.00001) { nanos *= 1000000; units = "umil"; } if(nanos < 0.01) { nanos *= 1000; units = "mmil"; } if(nanos < 0.1) { nanos *= 100; units = "cmil"; } } sprintf(buff, "%.2f%s", nanos, units); return buff; } /* TEST DRIVER */ int main(void) { double d; for(d = 127; d < 500; d += 12.7) printf("Inputted %s.\n", CoordToString(d)); return 0; }