Reputation: 15010
I want to do the following calculation without losing precision in C.
uint64_t ts_1 = 0x5212cb03ca115ac0;
uint64_t ts_2 = 0x5212cb03ca115cc0;
uint64_t ts_delta = (ts_2 - ts_1)
double scale_factor = ts_delta/(2^32)
I am getting the value of ts_delta as 0x200.
However the value of scale_factor as 15.000000
.Basically I am losing precision during the calculation.
How do I do it without losing precision.?
Here is a short self contained example on how I am trying to print.
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main()
{
uint64_t ts_1 = 0x5212cb03ca115ac0;
uint64_t ts_2 = 0x5212cb03ca115cc0;
uint64_t ts_delta = (ts_2 - ts_1);
double scale_factor = ((double)ts_delta) / (((uint64_t)1) << 32);
printf("ts_delta %"PRIx64" scale factor %f \n",ts_delta,scale_factor);
return 0;
}
Upvotes: 0
Views: 2938
Reputation: 140846
You're not doing the calculation you think you're doing. The ^
operator in C does not perform exponentiation, it performs bitwise exclusive OR. You are actually dividing ts_delta
by 2 xor 32 == 34
. I'm not sure how you got 15.000000
from that, it should have come out 15.058823529411764
.
The calculation you wanted to do is expressed in C like this:
double scale_factor = ((double)ts_delta) / (((uint64_t)1) << 32);
EDIT: From the other answer: if your compiler supports C99's hexadecimal floating-point literals, you can also write
double scale_factor = ts_delta * 0x1p-32;
Written this way, no casts are necessary, because one side of the multiplication is already a double
, so the integer on the other side will be converted to match. Unfortunately, several compilers have uint64_t
but no other features of C99, e.g. recent MSVC.
Upvotes: 3
Reputation: 477560
You need to compute floating point values, and get the expression for raising to a power right. You can use the standard function ldexp
:
#include <math.h>
double scale_factor = ldexp(ts_2 - ts_1, -32)
Or just multiply by a constant (thanks @Eric Postpischil!):
double scale_factor = (ts_2 - ts_1) * 0x1p-32;
Upvotes: 2