/* ** DBL2LONG.C - Functions to round doubles to longs ** Public domain by Ross G. Cottrell, June 1992 */ #include #include #include /* Assume IEEE doubles, little-endian CPU, 32-bit 2's complement longs. */ /* (Actually, the assumptions made here aren't quite that gross.) */ unsigned long dbl2ulong(double t) { assert(1 == FLT_ROUNDS); t += 1.0 / DBL_EPSILON; return *(unsigned long *)&t; } long dbl2long(double t) { assert(1 == FLT_ROUNDS); t += 1.0 / DBL_EPSILON + 2.0 * (LONG_MAX + 1.0); return *(long *)&t; } #ifdef TEST #include #include int main(int argc, char **argv) { while (*++argv) { printf("'%s', as a long: %ld, as an unsigned long: %lu\n", *argv, dbl2long(atof(*argv)), dbl2ulong(atof(*argv))); } return 0; } #endif /* TEST */ /* EXPLANATION: The offset of 1.0/DBL_EPSILON forces the least significant bit of the mantissa to represent the integer 1. This may not work on all formats of doubles, but I think it's a safe bet for IEEE compliant doubles, and any other floating point format with a radix of 2. When this offset is added, the number should be rounded to the nearest representable value. The assertion that FLT_ROUNDS has the value of 1 is an attempt to guarantee this. You might check your float.h; if this isn't #defined as a constant 1 you should investigate how to ensure that it will always round to the nearest. If it is #defined as 1 you can safely rip out the assertions. The addition of 2.0*(LONG_MAX+1.0) for the signed long is to prevent the the MSB of the mantissa being borrowed for negative inputs - if this happened, the exponent would change and the LSB of the mantissa would no longer be worth 1. This offset would be perfectly okay to use with the unsigned longs too but it's unnecessary for them, unless you want to get the answer correct modulo 2^^32 for negatives. */