Hi,
Is there a way to convert 4 byte double (UNO) to 8 byte double? My soft accepts only 8 byte double. Seems to be very simple but I I am very much beginner. And there is not much in Google about it. Thank you.
muhash:
Is there a way to convert 4 byte double (UNO) to 8 byte double? My soft accepts only 8 byte double.
What software is that and what protocol are you using to communicate the double to it?
muhash:
Hi,
Is there a way to convert 4 byte double (UNO) to 8 byte double? My soft accepts only 8 byte double. Seems to be very simple but I I am very much beginner. And there is not much in Google about it. Thank you.
There are ways to do the conversion, but since the GCC compiler used by the AVR chips in most Arduinos, has decided that 'double' should be equivalent to 'float', you will have to do the conversion manually. If you do a search for IEEE 754, it should give you the basic format for single precision and double precision.
Alternatively, if you are shipping the bits to a host computer, add an extra step to read the value as 'float' and then do a conversion to 'double', and it will do the conversion in a few instructions, and you won't have to learn the details of IEEE floating point. Note, if you are shipping raw bits across a wire, note that depending on what your host computer is, you will have possibly swap the bytes if the host is big endian.
ok, thanks.
I am using hodini. Here is a link on what I am looking for: http://www.sidefx.com/docs/houdini12.0/nodes/chop/pipein. I got everything except 4 byte double to 8 byte double. What is the way for manual conversation? thanks a lot.
You want to send samples to Hodini, but Hodini accepts only double as sample data.
The avr gcc compiler has no double support for the 8-bit microcontrollers.
You have a really tough problem.
http://arduino.cc/en/Reference/Double
You need to do some magical bits and byte shuffling, like this:
Hodini wants 8 bytes for a double, if it wants it in binary format you have to make a struct resembling the double specification consisting of
sign, mantissa, exponent
extract these 3 values from the arduino flat and assign them to the fields according to specs (not trivial but doable)
Then send the 8 bytes you just filled.
Two helper functions I wrote some ago, so you can started
// HELPER FUNCTIONS
// check IEEE754 bit layout to understand code below.
// note the exponent is a power of 2
byte getExponentByte(float number)
{
uint8_t e = (*(((byte*) &number)+3) & 0x7F) << 1;
if (*(((byte*) &number)+2) & 0x80) e++;
return e;
}
uint8_t getSign(float number)
{
return (*(((byte*) &number)+3) & 0x80);
}
did some prototyping and this is almost working
//
// FILE: float2double.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.00
// PURPOSE: experimental expands a float in a IEEE 754 double to be posted to PC.
//
// http://en.wikipedia.org/wiki/Double_precision
// http://en.wikipedia.org/wiki/Single-precision_floating-point_format
//
// Released to the public domain
//
struct DBL
{
unsigned long f:29; // filler
unsigned long m:23;
unsigned int e:11;
unsigned int s:1;
}
dbl;
union FLTCONV
{
struct
{
unsigned long m:23;
unsigned int e:8;
unsigned int s:1;
}
p;
float f;
}
flt;
union DBLCONV
{
struct DBL p;
byte b[8];
}
da;
void setup()
{
Serial.begin(115200);
Serial.println(sizeof(dbl));
Serial.println();
for (float f = -50.0; f < 50.0; f += 10.0)
{
dumpFLOAT(f);
float2DA(f);
dumpDA();
Serial.println();
}
dumpFLOAT(0.15625);
dumpFLOAT(PI);
float2DA(PI);
dumpDA();
Serial.println("done");
}
void loop()
{
}
///////////////////////////////////////////////////////////////////////////////////
void dumpFLOAT(float number)
{
flt.f = number;
Serial.print(flt.p.s, HEX);
Serial.print("\t");
Serial.print(flt.p.e, HEX);
Serial.print("\t");
Serial.println(flt.p.m, HEX);
}
void dumpDBL(struct DBL dbl)
{
Serial.print(dbl.s, HEX);
Serial.print("\t");
Serial.print(dbl.e, HEX);
Serial.print("\t");
Serial.println(dbl.m, HEX);
}
void dumpDA()
{
Serial.print(da.p.s, HEX);
Serial.print("\t");
Serial.print(da.p.e, HEX);
Serial.print("\t");
Serial.println(da.p.m, HEX);
for (int i=0; i<8; i++)
{
Serial.print(da.b[7-i], HEX);
Serial.print('\t');
}
Serial.println();
}
void float2DA(float number)
{
flt.f = number;
da.p.s = flt.p.s;
da.p.e = flt.p.e-127 +1023; // exponent differ
da.p.m = flt.p.m;
}
output of the lines above that convert PI to a double
dumpFLOAT(PI);
float2DA(PI);
dumpDA();
0 80 490FDB // sign, exponent, mantisse float
0 400 490FDB // sign, exponent, mantisse double
40 9 21 FB 60 0 0 0 << byte array == dump of the double
Then I did a quick check in Python t check the byte array
>> from struct import *
>> unpack('d', '\x00\x00\x00\x60\xFB\x21\x09\x40') <<< note that the order is inverse here
output : (3.1415927410125732,)
Yes!, that looks like PI
Arduino printing PI = 3.14159274101257324218
Python printing PI = 3.14159265359 (7 digits right)
the above code proofs Arduino can convert a 32bit IEEE754 float to an array of bytes representing a 64 bit IEEE754 double.
The way back can also be done in a similar way, main point of attention is the overflow for the exponent.
if exponent is too big mapping to INFinity seems logical
and yes the code still needs a to be cleaned up into proper functions without global vars
void float2DoublePacked(float number; byte* ar; int byteOrder);
float DoublePacked2float(byte ar*; int byteOrder);
maybe part of a IEEE754 conversion class?
Note, this code will only work on a little endian system (like the Arduino) sending data to another little endian system (like a PC). If you have either system that is big endian, then this code will not work.
If you were doing the conversion from double precision down to single precision, you would have to worry about setting the float to infinity if the exponent is too large, doing an appropriate rounding mode, and creating denomalized numbers if the value can be represented as a denormalized number. However, since you only need to worry about converting from single precision to double, you don't have to worry about it.
Your code does not handle Infinities, NaN's (not a number), nor does it handle denormalized numbers (numbers that cannot be represented in 32-bit floating point directly, but can represent some bits, if you convert these to double precision, you should normalize the bits you have, and fill the remaining bits with 0).
Whether these corner cases will be important in you application, I don't know. If you don't decide to handle them, you should at least put a comment in the text saying you aren't handling the corner cases, for the next person who uses your code.
Very true!
Impressive work robtillaart.
Perhaps you can make a playground page for it. Even if it is completely finished yet.
Thank you guys!!! Everything is working. I feel as I invented a wheel and it is tuning around. I still do not fully understand how it works even though I got a concept.
Mr. robtillaart - you are the best!!! If I were in Netherlands I'd buy you 10^99... liters of beer. I am so happy but now is time to go inside Houdini where I am much more comfortable...
Erdin:
Impressive work robtillaart.
Perhaps you can make a playground page for it. Even if it is completely finished yet.
Working on unpacking "incoming double" too and collect some IEEE snippets from the trenches of my hard disk
see - Manipulating IEEE754 32bit floats (incl mapping 64bit double) - Libraries - Arduino Forum - for a draft IEEE754tools lib + ref to playground article