it looks like the ATmega boards are capable of a 64 bit float variable. is there any way to be able to run a function that requires a "Double" variable without significantly reducing its accuracy?
Just out of interest, what do you need a double for?
Mowcius
I have tested floats and doubles with avr-gcc for ATmega328P on my Duemilanove using the Arduino environment.
Floats and doubles are the same. Both have size 4 and both contain exactly the same bytes. Exactly. The bit patterns of a few numbers that I have tested seem to be the same as for floats in any of the other GNU compilers. I mean, I haven't tested all of the NaN and other out-of-range conditions, but the numerical byte values seem to be the same as I see for gcc on my Linux (and Windows/Cygwin) workstations.
Regards,
Dave
Floats and doubles are the same.
I think the point is that floats and doubles are not the same. The arduino turns doubles into floats so when you are using an arduino they are the same.
I presume he wants some way to make them how doubles normally are (8 bytes ~15 digits).
double on arduino: http://www.arduino.cc/en/Reference/Double
I'm still unsure as to a possible way to do it though.
Mowcius
floats and doubles are not the same
Indeed, generally speaking, they are not.
But...
The statement that I made about them being the same directly followed the statement that said I had tested them within the Arduino environment and found the results to be the same.
So, maybe I misspoke. Maybe I should have emphasized that, in general, doubles and floats are not necessarily the same, but with the Arduino (using avr-gcc/avr-libc) they are treated the same. See Footnote.
In fact, maybe I could have just given a link to the Arduino reference, which states:
"The double [i]implementation[/i] on the Arduino is currently exactly the same as the float"
(Emphasis added)
However...
Note that this is not an Arduino thing. It's an avr-gcc/avr-libc thing. See Frequently Asked Questions, where it says
"float and double are 32 bits (this is the only supported floating point format)"
In fact I always like to test these things for myself. When I start using a new compiler I always test sizes of variables. Sometimes ints are 16-bits and longs are 32-bits. Sometimes ints are 32-bits and longs are 32-bits. Sometimes ints are 32-bits and longs are 64-bits. Sometimes floats are 32-bits and doubles are 32-bits. Sometimes floats are 32-bits and doubles are 64-bits. There may be other possibilities and combinations. (Also, I always test sizes of pointers and I always test endianness. Sometimes it makes a difference, especially when debugging other people's code.)
Anyhow...
In fact with avr-gcc, the code created for floats is exactly the same as the code that is created for doubles. Exactly. I mean, with avr-gcc/avr-libc you can declare something to be a double, but it generates the same code as if you had declared it to be a float.
You can check my results on any system that uses avr-gcc and avr-libc by actually inspecting the bytes:
Here's an Arduino sketch:
// Sketch TestDouble
//
// Prints bytes of a float
// Prints bytes of a double
//
// For avr-gcc and an ATMega328p, the bytes are exactly the same.
//
// Conclusion: The only floating point data type that is
// supported is 32-bits.
//
// You can declare stuff to be doubles if it suits your fancy,
// but there is no difference in the code from what it would
// have been if you had declared them to be floats.
//
// davekw7x
//
void setup()
{
Serial.begin(9600);
}
typedef union _chdoub {
double x;
unsigned char ch[sizeof(double)];
} chdoub;
typedef union _chfloat {
float x;
unsigned char ch[sizeof(float)];
} chfloat;
void loop()
{
chdoub chd;
chfloat chf;
char buffer[100];
char buf[100];
double xx = 3.14159265358979323846;
float yy = 3.14159265358979323846;
int i;
chd.x = xx;
chf.x = yy;
sprintf(buffer, "sizeof(float) = %d, sizeof(double) = %d\n",
sizeof(float), sizeof(double));
Serial.print(buffer);
sprintf(buffer, "chd: 3.14159265358979323846 --- ");
for (i = 0; i < sizeof(double); i++) {
sprintf(buf, "0x%02x ", chd.ch[i]);
strcat(buffer, buf);
}
strcat(buffer, "\n");
Serial.print(buffer);
sprintf(buffer, "chf: 3.14159265358979323846 --- ");
for (i = 0; i < sizeof(float); i++) {
sprintf(buf, "0x%02x ", chf.ch[i]);
strcat(buffer, buf);
}
strcat(buffer, "\n");
Serial.print(buffer);
delay(5000);
}
Output:
sizeof(float) = 4, sizeof(double) = 4
chd: 3.14159265358979323846 --- 0xdb 0x0f 0x49 0x40
chf: 3.14159265358979323846 --- 0xdb 0x0f 0x49 0x40
---
Regards,
Dave
Footnote: Make a C (or C++) program on your workstation (Windows or Linux). Instead of loop(), just use that code as your main(). (Of course use printf statements instead of the Serial.print stuff.)
Compile with any more-or-less standard C or C++ compiler (GNU, Microsoft, Borland, ...)
You will (probably) see something like
Output:
sizeof(float) = 4, sizeof(double) = 8
chd: 3.14159265358979323846 --- 0x18 0x2d 0x44 0x54 0xfb 0x21 0x09 0x40
chf: 3.14159265358979323846 --- 0xdb 0x0f 0x49 0x40
The reason I'm looking for a way to run a true 64 bit double on the processor is to be able to run a version of this:
http://www.psa.es/sdg/sunpos.htm
for use in a stand alone heliostat.
I understand that the current IDE support for the arduino does not support a 64 bit double, which is why I wrote this post. If it did, I wouldn't be here.
I've been looking at some of the AVR compilers, specifically this one:
http://www.mcselec.com/index.php?option=com_content&task=view&id=14&Itemid=41
which claims to support a full 8 byte double on the ATmega. I'm wondering if anyone has ever tried using this, and how it worked for them.
Well, I could have saved a lot of board bandwidth if I had waited for your response to Mowcius's question. It would be just too confusing to future readers if I tried to go back and removed my non-helpful posts so I guess I will leave them there. I'll try to be more patient in the future.
Sorry.
Regards,
Dave
It would be just too confusing to future readers if I tried to go back and removed my non-helpful posts so I guess I will leave them there.
I personally think they're germane and useful to the discussion; I already knew about the issue myself, but seeing it laid out makes me appreciate and understand it better; I am sure it will do the same for future people who view this thread.
To that end, I also wanted to post a link to this thread, since it hasn't been mentioned:
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1276236623
It won't solve any problems, but it should be mentioned.
I also seem to remember reading another thread recently where somebody mentioned a true double precision library...if I find it again, I will post it!
This makes me pleased... ;D
Here is that code modified to run on an arduino with the doubles changed to floats and some other things changed. If you want to track the sun then you simply don't need that degree of accuracy. I also removed the seconds value in my code as it was unnecessary for most uses but you could add it back in.
http://www.mowcius.co.uk/suntrackercode.html
The code is also stuck all in one sketch rather than the library as I was having some funny problems with it so I gave up and made it into a single sketch.
Mowcius
Well, rewriting it without doubles was what I was going to do next :)...I suppose being accurate to within .001 degrees is a bit of overkill.....
Have you checked the performance of the truncated algorithm against the un-truncated version over time? I'd be interested to see how the reduction in variable length affects the performance over, say, 25 years.
Have you checked the performance of the truncated algorithm against the un-truncated version over time? I'd be interested to see how the reduction in variable length affects the performance over, say, 25 years.
I can't say I have. I will clean it up a bit and try that in a few days. I would not have thought that it would affect it more than say .5deg which for the proposed projects that would not make any difference.
I will check it against stellarium (which contains a highly accurate algorithm, more accurate than this).
I will check it though (or you can ;))
Mowcius