Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C/C++ equivalent to Java's doubleToRawLongBits()

Tags:

java

c++

c

In Java Double.doubleToLongBits() is useful for implementing hashCode() methods.

I'm trying to do the same in C++ and write my own doubleToRawLongBits() method, as after trawling through Google I can't find a suitable implementation.

I can get the signif and exponent from std::frexp(numbr,&exp) and can determine the sign but can't figure out the use of the bitwise operators to get the Java equivalent.

For example, Java's Double.doubleToLongBits() returns the following for the double 3.94:

4616054510065937285

Thanks for any help.

Graham

Below is the documentation copied and pasted from Double.doubleToRawLongBits()

===Java Double.doubleToRawLongBits() description===

/**
     * Returns a representation of the specified floating-point value
     * according to the IEEE 754 floating-point "double
     * format" bit layout, preserving Not-a-Number (NaN) values.
     * <p>
     * Bit 63 (the bit that is selected by the mask 
     * <code>0x8000000000000000L</code>) represents the sign of the 
     * floating-point number. Bits 
     * 62-52 (the bits that are selected by the mask 
     * <code>0x7ff0000000000000L</code>) represent the exponent. Bits 51-0 
     * (the bits that are selected by the mask 
     * <code>0x000fffffffffffffL</code>) represent the significand 
     * (sometimes called the mantissa) of the floating-point number. 
     * <p>
     * If the argument is positive infinity, the result is
     * <code>0x7ff0000000000000L</code>.
     * <p>
     * If the argument is negative infinity, the result is
     * <code>0xfff0000000000000L</code>.
     * <p>
     * If the argument is NaN, the result is the <code>long</code>
     * integer representing the actual NaN value.  Unlike the
     * <code>doubleToLongBits</code> method,
     * <code>doubleToRawLongBits</code> does not collapse all the bit
     * patterns encoding a NaN to a single &quot;canonical&quot; NaN
     * value.
     * <p>
     * In all cases, the result is a <code>long</code> integer that,
     * when given to the {@link #longBitsToDouble(long)} method, will
     * produce a floating-point value the same as the argument to
     * <code>doubleToRawLongBits</code>.
     *
     * @param   value   a <code>double</code> precision floating-point number.
     * @return the bits that represent the floating-point number.
     * @since 1.3
     */
    public static native long doubleToRawLongBits(double value);
like image 963
Graham Seed Avatar asked Oct 31 '11 15:10

Graham Seed


3 Answers

A simple cast will do:

double d = 0.5;

const unsigned char * buf = reinterpret_cast<const unsigned char *>(&d);

for (unsigned int i = 0; i != sizeof(double); ++i)
  std::printf("The byte at position %u is 0x%02X.\n", i, buf[i]);

Where the sign bit and exponent bits are depends on your platform and the endianness. If your floats are IEE754, if the sign and exponent are at the front and if CHAR_BIT == 8, you can try this:

const bool sign = buf[0] & 0x80;
const int exponent = ((buf[0] & 0x7F) << 4) + (buf[1] >> 4) - 1023;

(In C, say (const unsigned char *)(&d) for the cast.)

Update: To create an integer with the same bits, you have to make the integer first and then copy:

unsigned long long int u;
unsigned char * pu = reinterpret_cast<unsigned char *>(&u);
std::copy(buf, buf + sizeof(double), pu);

For this you have to bear several things in mind: the size of the integer has to be sufficient (a static assertion for sizeof(double) <= sizeof(unsigned long long int) should do the trick), and if the integer is in fact larger, then you're only copying into parts of it. I'm sure you'll figure that out, though :-) (You could use some template magic to create an integer of the correct size, if you really wanted.)

like image 88
Kerrek SB Avatar answered Nov 15 '22 00:11

Kerrek SB


#include <stdint.h>

static inline uint64_t doubleToRawBits(double x) {
    uint64_t bits;
    memcpy(&bits, &x, sizeof bits);
    return bits;
}
like image 26
Stephen Canon Avatar answered Nov 14 '22 23:11

Stephen Canon


I like unions for these kinds of things.

union double_and_buffer {
    double d;
    unsigned char byte_buff[ sizeof(double) ];
} dab;

dab.d = 1.0;
for ( int i = 0; i < sizeof(dab.byte_buff); ++i )
{
    cout << hex byte_buff[ i ];
}

I think it makes it more clear what you're doing and lets the compiler do all the math.

like image 2
Rob K Avatar answered Nov 15 '22 01:11

Rob K