Andrei Cristian - 8 months ago 25

C Question

I have a small code which does some number transformations. I want to turn a number from double to long and then using right bit shift to cast it to short. But it gives me different results and I don't know why.

I have 3 numbers in an array and I make the sum of them using a

`for`

`short`

There is a number with

`.000000007`

`63897600.000000007`

I can't figure out why does this occur and how can I manage this particular case.

Here is my code:

`#include <stdio.h>`

#define DOUBLETOLONG(number) (long)(number)

#define NEAREST(number) ((short)((number + 32768) >> 16))

#define LONGTOSHORT(number) NEAREST(DOUBLETOLONG(number))

int main() {

int k = 0;

double array[3] ={ 41451520.000000, 63897600.000000007, -63897600.000000007 };

double total_x = array[0];

short j = LONGTOSHORT(total_x);

printf("j = %d\n", j);

for (k = 1; k < 3; k++) {

total_x = total_x+array[k];

j = LONGTOSHORT(total_x);

printf("j = %d\n", j);

}

return 0;

}

This are the results:

`j = 633`

j = 1608

j = 632

Answer

In a `double`

this integer can still be accurately represented. However, we didn't account for the fractional part `0.000000007`

. Let's check what the next biggest `double`

is:

```
#include <stdio.h>
#include <math.h>
int main(int argc, char** argv) {
printf("%.23f\n", nextafter(105349120.0, INFINITY));
return 0;
}
```

Turns out, it's `105349120.000000014901...`

. Let's put those next to eachother:

```
105349120.000000014901...
0.000000007
```

This means that `105349120.000000007`

is closer to `105349120`

than the next bigger `double`

, so it correctly gets rounded down to `105349120`

.

However, when we subtract again, `105349120 - 63897600.000000007`

gets rounded down, because the next smaller double than `41451520`

is (`nextafter(41451520.0, 0)`

) `41451519.999999992549...`

. Put them next to eachother:

```
41451519.999999992549...
41451519.999999993
```

Yep, closer to the first double below `41451520`

than `41451520`

itself. So it correctly gets rounded down to `41451519.999999992549...`

.

When you convert `41451519.999999992549...`

to an integer it **floors** the number, resulting in one less than what you expect.

Floating point math is full of surprises. You should read What Every Computer Scientist Should Know About Floating-Point Arithmetic, but perhaps it's still too advanced for now. But it's important to be aware that yes, floating point is full of surprises, but no it isn't magic, and you can learn the pitfalls.