2

I need to accurately convert a long representing bits to a double and my soluton shall be portable to different architectures (being able to be standard across compilers as g++ and clang++ woulf be great too).

I'm writing a fast approximation for computing the exp function as suggested in this question answers.

double fast_exp(double val)
{
    double result = 0;

    unsigned long temp = (unsigned long)(1512775 * val + 1072632447);
    /* to convert from long bits to double,
   but must check if they have the same size... */
    temp = temp << 32;
    memcpy(&result, &temp, sizeof(temp));

    return result;
}

and I'm using the suggestion found here to convert the long into a double. The issue I'm facing is that whereas I got the following results for int values in [-5, 5] under OS X with clang++ and libc++:

0.00675211846828461
0.0183005779981613
0.0504353642463684
0.132078289985657
0.37483024597168
0.971007823944092
2.7694206237793
7.30961990356445
20.3215942382812
54.8094177246094
147.902587890625

I always get 0 under Ubuntu with clang++ (3.4, same version) and libstd++. The compiler there even tells me (through a warning) that the shifting operation can be problematic since the long has size equal or less that the shifting parameter (indicating that longs and doubles have not the same size probably)

Am I doing something wrong and/or is there a better way to solve the problem being as more compatible as possible?

Community
  • 1
  • 1
rano
  • 5,616
  • 4
  • 40
  • 66
  • What is a "long representing bits"? Bits of what? – David Schwartz Nov 07 '13 at 18:27
  • 1
    You can try `unsigned long long`, it is represented in 64 bits whereas double is more than 32 anyway and doing a memcpy using sizeof(unsigned long) could lead to nans – Raxvan Nov 07 '13 at 18:29

1 Answers1

6

First off, using "long" isn't portable. Use the fixed length integer types found in stdint.h. This will alleviate the need to check for the same size, since you'll know what size the integer will be.

The reason you are getting a warning is that left shifting 32 bits on the 32 bit intger is undefined behavior. What's bad about shifting a 32-bit variable 32 bits?

Also see this answer: Is it safe to assume sizeof(double) >= sizeof(void*)? It should be safe to assume that a double is 64bits, and then you can use a uint64_t to store the raw hex. No need to check for sizes, and everything is portable.

Community
  • 1
  • 1
It'sPete
  • 5,083
  • 8
  • 39
  • 72
  • That gives more insight of the problem, if the double size is fixed I could use a fixed same sized long type – rano Nov 07 '13 at 18:31
  • 2
    `uint64_t`'s not a perfect solution, however. On a 32-bit system, this may be provided but will not be atomic. That is, it will take multiple instructions to manipulate. This could be an issue in multi-threaded software, though considering the level of hackery already going on in this code, I have to imagine the OP doesn't care ;) – Andon M. Coleman Nov 08 '13 at 04:09