I believe George99 is right according to the IEEE-754 standard. The numbers should be represented exactly if they are read in (with scanf, for example) and can be represented exactly in the given number of bits.
I find it particularly strange that only the (integral) numbers in a few ranges between 1000 and 8191 seem to have their LSB set (I tested from zero to one hundred million with the program below, so there could be more above that).
Take note that I'm only talking about floating-point literals in the code or ones read in with scanf (presumably both use the same algorithm). If, on the other hand, you start a double at 0 (d = 0.0) and increment it (d += 1.0), the LSB does not get set within the range 0 to one hundred million (and presumably much higher). I'm not talking about the results of operations on floating point numbers.
The following program demonstrates the above. It generates a string with the numbers 0 to 10000000 (or whatever) then reads them in with sscanf. It outputs the ranges of the numbers that have their LSB set.
My results (positive numbers):
1000 - 1023
1390 - 2047
2780 - 4095
5560 - 8191
My results (negative numbers):
-1000 - -1023
-1390 - -2047
-2780 - -4095
-5560 - -8191
You have to admit it's odd that only those numbers of all numbers between zero and a hundred million have their LSB set. Is it possible that the scanf algorithm is a little off (and the one that reads literal doubles in the source code)?
#include <stdio.h>
#include <stdlib.h>
//#define USEFLOAT // uncomment to test float instead of double
// if USEFLOAT is defined, UPPERBOUND should be no more than 8388608 (pow(2,23))
//#define TEST_NEGATIVE // uncomment to test negative numbers
#ifdef USEFLOAT
# define FPTYPE float
# define SAME_SIZE_UNSIGNED unsigned
# define SCANF_FORMAT "%f"
# define EXPONENT_BITS 8
# define UPPERBOUND 8388608
#else
# define FPTYPE double
# define SAME_SIZE_UNSIGNED long long unsigned
# define SCANF_FORMAT "%lf"
# define EXPONENT_BITS 11
# define UPPERBOUND 10000000 // ten million executes fairly quickly
#endif
int testFPBit(FPTYPE d, int n) { // returns 0 or 1
return (int)(*(SAME_SIZE_UNSIGNED*)&d >> n) & 1;
}
/*
void printFPBits(FPTYPE d) {
int i;
for (i = sizeof(FPTYPE)*8-1; i >= 0; i--) {
if (i == sizeof(FPTYPE)*8-2 || i == sizeof(FPTYPE)*8-2-EXPONENT_BITS)
printf(" ");
printf("%d", testFPBit(d, i));
}
printf("\n");
}
*/
void scanFPs(void) {
const int SIZE = 100;
char line[SIZE];
FPTYPE d;
int i, n = 0, bInSpan = 0;
printf("begin scanFPs...\n");
#ifdef TEST_NEGATIVE
for (i = 0; i > -UPPERBOUND; i--) {
#else
for (i = 0; i < UPPERBOUND; i++) {
#endif
sprintf(line, "%d", i);
sscanf(line, SCANF_FORMAT, &d);
if (testFPBit(d, 0)) {
n = (int)d;
if (!bInSpan) {
printf("%d - ", n); // begin range
bInSpan = 1;
}
}
else {
if (bInSpan) {
printf("%d\n", n); // end range
bInSpan = 0;
}
}
}
printf("end scanFPs\n");
}
void testIncrement(void) {
FPTYPE d = 0.0;
printf("testIncrement... ");
#ifdef TEST_NEGATIVE
for (d = 0.0; d >= -UPPERBOUND; d -= 1.0)
#else
for (d = 0.0; d <= UPPERBOUND; d += 1.0)
#endif
if (testFPBit(d, 0))
printf("%f\n", d); // Doesn't happen
printf("end testIncrement\n");
}
int main(void) {
testIncrement();
scanFPs();
return 0;
}