KKsan KKsan - 10 months ago 59
C Question

C - Unsigned long long to double on 32-bit machine

Hi I have two questions:

  1. uint64_t vs double, which has a higher range limit for covering positive numbers?

  2. How to convert double into uint64_t if only the whole number part of double is needed.

Direct casting apparently doesn't work due to how double is defined.

Sorry for any confusion, I'm talking about the 64bit double in C on a 32bit machine.

As for an example:

//operation for convertion I used:
double sampleRate = (
(union { double i; uint64_t sampleRate; })
{ .i = r23u.outputSampleRate}

//the following are printouts on command line
// double uint64_t
//printed by %.16llx %.16llx
outputSampleRate 0x41886a0000000000 0x41886a0000000000 sampleRate

//printed by %f %llu
outputSampleRate 51200000.000000 4722140757530509312 sampleRate

So the two numbers remain the same bit pattern but when print out as decimals, the uint64_t is totally wrong.
Thank you.


double can hold substantially larger numbers than uint64_t, as the value range for 8 bytes IEEE 754 is 4.94065645841246544e-324d to 1.79769313486231570e+308d (positive or negative) [taken from here][more detailed explanation]. However if you do addition of small values in that range, you will be in for a surprise, because at some point the precision will not be able to represent e.g. an addition of 1 and will round down to the lower value, essentially making a loop steadily incremented by 1 non-terminating.

This code for example:

#include <stdio.h>
2 int main()
3 {
4     for (double i = 100000000000000000000000000000000.0; i < 1000000000000000000000000000000000000000000000000.0; ++i)
5         printf("%lf\n", i);
6     return 0;
7 }

gives me a constant output of 100000000000000005366162204393472.000000. That's also why we have nextafter and nexttoward functions in math.h. You can also find ceil and floor functions there, which, in theory, will allow you to solve your second problem: removing the fraction part.

However, if you really need to hold large numbers you should look at bigint implementations instead, e.g. GMP. Bigints were designed to do operations on very large integers, and operations like an addition of one will truly increment the number even for very large values.