8 Bytes to Double Conversion

Howdy All.. hopefully someone will be able to help me. I have the following byte array:

byte vals[] = { 0xC6, 0x6B, 0x80, 0xE8, 0x69, 0xF5, 0xB0, 0x3F };

and I need to convert that that to a double or a decimal equivalent for example: 1.6345634542

How can I accomplish this?

Thanks in advance..

Hello

Try this

double f;
memcpy( &f, vals, 8 );

Thanks….. When I try that and do a Serial.println(f); I get ovf assuming overflow.

Which board do you use ? On many Arduino boards (8-bits) there is no 8 bytes double, they are 4 bytes like float

I have tried your array with an ESP32 and it gives 0.0662447159415215

@randy2101
I tried the following sketch (with union, memcpy, and pointer) on DUE and got the following output:

The memcpy() method @guix is simpler. The union method is not recommended. The pointer method is an expanded version of memcpy().

0.0662447159    //using union{} structure
0.0662447159   //using memcpy() function
0.0662447159   //using pointer

Sketch:

byte vals [] = {0xC6, 0x6B, 0x80, 0xE8, 0x69, 0xF5, 0xB0, 0x3F };

union
{
  double y;
  uint8_t myData[8];
} data;

void setup()
{
  Serial.begin(9600);
  //----- using union{}---------------
  for (int i = 0; i < 8; i++)
  {
    data.myData[i] = vals[i];
  }
  Serial.println(data.y, 10);

  //---------using memcpy()----------
  double f;
  memcpy( &f, vals, 8 );
  Serial.println(f, 10);

//--------using pointer-------
  long long int x = 0x3FB0F569E8806BC6;
  double y;
  long long *ptr;
  ptr = (long long*) &y;
  *ptr = x;
  Serial.println(y, 10);
}

void loop()
{

}

Thank you all this does work on a DUE … here is the next issues… the BYTE array

byte vals[] = {0xC6, 0x6B, 0x80, 0xE8, 0x69, 0xF5, 0xB0, 0x3F};

is actually being passed as an array of int

byte vals[] = { InBytes[2], InBytes[3], InBytes[4],InBytes[5],InBytes[6], InBytes[7], InBytes[8], InBytes[9] };

however it doesn’t for the array above with the int values. How can I either convert each InByte back to a HEX value or get the int array to convert to a double.

Thanks..

Show with example what you want to achieve.

In c++ the right way to do this is memcpy() but this assumes you have the exact byte representation needed for the job.

first you need to make sure that sizeof double On your architecture is 8 bytes.

Then If you have an array of int then they are each on multiple bytes and you can’t use that array straight with memcpy, you need to take the LSB of each int to create a new byte array with 8 bytes

Byte order might also matter but most platforms would probably represent floating points value in the same way.

I used a integer array to start with and used the memcpy as @GolamMostafa showed and run it on a Raspberry Pi Pico in Wokwi. I get the same result as GolamMostafa, so it should be right :smiley:

// 28 January 2022, Version 1, by Koepel, Public Domain
// For: https://forum.arduino.cc/t/8-bytes-to-double-conversion/952352/


// The Wokwi simulation uses Serial1 for the Raspberry Pi Pico
#define _SERIAL Serial1

const int InBytes[10] =
{
  0x0000, 0x0000,
  0x00C6, 0x006B, 0x0080, 0x00E8, 0x0069, 0x00F5, 0x00B0, 0x003F,
};

void setup() 
{
  _SERIAL.begin(115200);
  _SERIAL.println("Hello, the sketch has started");

  _SERIAL.print( "The sizeof(double) = ");
  _SERIAL.println( sizeof( double));

  // No union, just low level converting
  byte myBytes[8];
  for( int i=0; i<8; i++)
  {
    myBytes[i] = (byte) InBytes[i+2];      // take the lowest byte of every int
  }
  double myDouble;
  memcpy( &myDouble, myBytes, 8);

  _SERIAL.print( "My double = ");
  _SERIAL.println( myDouble, 15);
}

void loop() 
{
  delay( 100);
}

Try it in Wokwi:

Assume from my previous examples InBytes [x] is represented as this where each InByte[x] is an int:

const int vals[8] =

{

  198, 107, 128, 232, 105, 245, 176, 243

};

and then I use the following:

double f;
  memcpy( &f, vals, 8 );
  Serial.println(f, 10);

this doesn't work.. However is the val's array about is represented by HEX instead of INT like this:

byte vals [] = {0xC6, 0x6B, 0x80, 0xE8, 0x69, 0xF5, 0xB0, 0x3F };

if converts to double with no issues..

My array is coming over to the Arduino as int.

--Randy

Coming over from where?

You could store the values as bytes as these numbers arrive from wherever, or you could just copy the arrived array of int values to an array of bytes.

a7

Every element of an int-type array is 16-bit. There are 8 items/elements in your array, which amount to 128 bit data (8x16).

There are only two IEEE-754 standards to convert floating point number into bits and vice versa --

1. binary32 (single precision) standard: It converts float number into 32-bit and vice versa.

2. binary64 (double precision) standard: It converts float number into 64-bit and vice versa.

3. There is no binary128 standard to convert your 128-bit data back to float.

Thanks... I understand a bit more of what is going on here. I'm going to try and fix what is being sent over via serial to the Arduino.

Maybe I should simplify this(or try to).

My initial input is:
byte vals = { InBytes[2], InBytes[3], InBytes[4],InBytes[5],InBytes[6], InBytes[7], InBytes[8], InBytes[9] };

When evaluated it is actually this:
byte vals[] =

{

198 , 107, 128, 232, 105, 245, 176, 243

};

That would represent 0xC6, 0x6B, 0x80, 0xE8, 0x69, 0xF5, 0xB0, 0x3F

but the actual value needs to be 0xC66B80E869F5B03F

And that (0xC66B80E869F5B03F) Converted into a double

which the final result should be: 0.0662447159

I've tried just about everything I can think of using the examples in this thread.

Thanks

This is represented as 0x3FB0F569E852C486…. So you have 3 wrong bytes

Run this code to see how bytes are laid out


void setup() {
  Serial.begin(115200);
  double d = 0.0662447159;
  uint8_t* ptr = (uint8_t*) &d;
  for (size_t i=0; i<sizeof d; i++) {
    Serial.print("0x"); Serial.println(ptr[i], HEX);
  }
}

void loop() {}

You should see

0x86
0xC4
0x52
0xE8
0x69
0xF5
0xB0
0x3F

This is the same idea in @Koepel's simulation, see #9 and the link there to the simuklation

I am not sure why the array is 10 and the 8 meaningful bytes used are from indices 2..9.

I had hacked something but was waylaid by the Raspberry Pi somehow, eventually I arrived at the same thing

#define _SERIAL Serial1

const  int vals[10] = {


  0x00C6, 0x006B, 0x0080, 0x00E8, 0x0069, 0x00F5, 0x00B0, 0x003F,
};

byte byteMe[8];

double f;
  
void setup() {
  _SERIAL.begin(9600);
  _SERIAL.println("Hello World!\n");

  for (uint8_t ii = 0; ii < 8; ii++)
    byteMe[ii] = vals[ii];

  memcpy(&f, byteMe, 8);

  _SERIAL.print("using byteMe ");
  _SERIAL.println(f, 10);

  _SERIAL.println("That's All, Folks!");
}

void loop() {
  // no code here, to run repeatedly doing nothing
}

So you could use that (copy the int array to a byte array, then convert) until you ever get around to fixing the transmission format.

@Koepel why the extra two entries jkust to skip them?

@ Anyone, is this

     byteMe[ii] = vals[ii];

OK to copy from an array of ints to an array of bytes? Just getting the last byte?

I used & 0xff, worked OPK and of course it seems the cast is OK, just wondering about the simple expression in this case.

Hello World!

using byteMe 0.0662447159

That's All, Folks!

Third vote for ~0.066 :=|

You can also use a

 double *f;

instead, then you don't need to copy the byte array at all.

  double *f;
  f = (double *) byteMe;

  _SERIAL.print("using byteMe ");
  _SERIAL.println(*f, 10);

Old school.

a7

I saw this: byte vals = { InBytes[2], InBytes[3], ...
so that is what I used.

Yes, the language fully defines what it means and what happens when you assign a variable into a smaller unsigned type

If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source integer (modulo 2^n where n is the number of bits used to represent the unsigned type). [Note: In a two's complement representation, this conversion is conceptual and there is no change in the bit pattern (if there is no truncation).]

If the destination type is signed, the value is unchanged if it can be represented in the destination type (and bit-field width); otherwise, the value is implementation-defined.