简体   繁体   中英

Turn two uint32_t into a uint64_t, then turn back into a double based on the bit pattern not the value

the code that hands me the two uint32_t essentially takes a double, in binary cuts it in half so half the bytes are in one variable and the other half are in the other.

My program need to take them and stitch it back together.

int x = 0b00111101110100011101110111110111;
int y = 0b11100111001100101010000110111001;

uint64_t int64 = (long long) x << 32 | y;
double d = static_cast<double> (int64);

this is what i have so far and it doesnt give the correct output at all.

it gives: 1.84467e+19 it should be: 6.49999999999999952595094363798E-11

Thanks

For C, you can do it this way:

const uint32_t x = 0x3DD1DDF7;
const uint32_t y = 0xE732A1B9;
const uint64_t z = ((uint64_t) x << 32) | y;
double d;
memcpy(&d, &z, sizeof d);

But I'm not sure, there could be an endian issue here since this code is quite hairy. I'm getting 6.5e-11 as the output.

This works:

unsigned int x = 0b00111101110100011101110111110111;
unsigned int y = 0b11100111001100101010000110111001; // Must be unsigned!

uint64_t int64 = ((long long) x << 32) | y; // Parentheses highly recommended for
                                            // readability (but not strictly necessary)
double d = reinterpret_cast<double&> (int64); // Definitely not portable!

Your code had two problems:

  • the signed integer y was being converted to long long , which meant that the high word was 0xFFFFFFFF . x and y should be declared unsigned .
  • static_cast converts the value, not the bit pattern. Use reinterpret_cast to retain the bit pattern. (As Mgetz points out in a comment, there is now (since C++20) an official way to get this done: std::bit_cast . This doesn't rely on undefined behaviour, as long as double and int64 are the same size.)

How about this code for your purpose. example

#include <cstdio>
#include <cinttypes>
#include <type_traits>
#include <cstddef>
#include <iostream>

int main()
{
    uint64_t tsc = 0xdeaddeadc0dec0de;
    uint32_t MSB = *((uint32_t*)&tsc+1);
    uint32_t LSB = *((uint32_t*)&tsc);
    std::printf("low   %x high %x \n", LSB,MSB);
    uint64_t MLSB = 0;
    *((uint32_t*)&MLSB) = LSB;
    *((uint32_t*)&MLSB+1) = MSB;
    std::printf("highlow %lx \n", MLSB);
    uint64_t LMSB = 0;
    *((uint32_t*)&LMSB+1) = LSB;
    *((uint32_t*)&LMSB) = MSB;
    std::printf("lowhigh %lx \n", LMSB);
}

solution to your problem

#include <cstdio>
#include <cinttypes>
#include <type_traits>
#include <cstddef>
#include <iostream>

int main()
{
int x = 0b01000000001101110000000000000000;
int y = 0b00000000000000000000000000000000;
    uint64_t int64 = 0;
    *((uint32_t*)&int64+1) = x;
    *((uint32_t*)&int64) = y;
    double d = *((double*)&int64);
    std::printf("double d %e \n", d);
    std::printf("int int64 %llx \n", int64);
    
x = 0b00111101110100011101110111110111;
y = 0b11100111001100101010000110111001;
    *((uint32_t*)&int64+1) = x;
    *((uint32_t*)&int64) = y;
    d = *((double*)&int64);
    std::printf("double d %e \n", d);
    std::printf("int int64 %llx \n", int64);

}

result
double d 2.300000e+01
int int64 4037000000000000
double d 6.500000e-11
int int64 3dd1ddf7e732a1b9

or without referencing problem

#include <cstdio>
#include <cinttypes>
#include <type_traits>
#include <cstddef>
#include <iostream>

int main()
{
unsigned char  x[] = {0b01000000,0b00110111,0b00000000,0b00000000};
unsigned char  y[] = {0b00000000,0b00000000,0b00000000,0b00000000};
    uint64_t int64 = 0;
    *((unsigned char*)&int64+7) = x[0];
    *((unsigned char*)&int64+6) = x[1];
    *((unsigned char*)&int64+5) = x[2];
    *((unsigned char*)&int64+4) = x[3];
    *((unsigned char*)&int64+3) = y[0];
    *((unsigned char*)&int64+2) = y[1];
    *((unsigned char*)&int64+1) = y[2];
    *((unsigned char*)&int64+0) = y[3];
    double d =0;
    *((unsigned char*)&d+7) = x[0];
    *((unsigned char*)&d+6) = x[1];
    *((unsigned char*)&d+5) = x[2];
    *((unsigned char*)&d+4) = x[3];
    *((unsigned char*)&d+3) = y[0];
    *((unsigned char*)&d+2) = y[1];
    *((unsigned char*)&d+1) = y[2];
    *((unsigned char*)&d+0) = y[3];
    //*((double*)&int64);
    std::printf("double d %e \n", d);
    std::printf("int int64 %lu \n", int64);
    
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM