I am using the Mega2560. I want to calculate some larger numbers, but I have some problems I don't understand.
a = (-2500) * (-4000000);
a = (-2500.0) * (-4000000.0);
on the serial monitor.
The result of my multiplication should be -1 * 10^10.
According to the reference for the datatype float it is a 32 bit value and
"Floating-point numbers can be as large as 3.4028235E+38 and as low as -3.4028235E+38."
I am confused. Where does the overflow come from?
Your calculation #1 overflows on the right side of the "=". You multiply two constants, one representable as int, and one representable as long. The caclulation is done as long, and then converted to float. It overflows as long, and the result isn't correct. If you check, you'll see that 1410065408 is (10^10) % (2^31), which is what I'd expect from a calculation with signed long. The C standards may describe the result of this calculation as undefined. I'll leave that clarification to guys who know the standards better than I.
Your calculation #2 works just fine. What's not working for you is Serial.print(). It isn't able to print the full range of values that a float can take on.
Here's the first few lines of printFloat(), the function that prints floating point values. It does a couple of checks to see that the input is a valid float, and then checks to see that it's within a range of + or - roughly 4.3 * 10^9. If the input is too big, it prints the characters "ovf" and gives up. It looks like the code is written that way in order to use the same function that prints unsigned long to print the integer part of a float. I presume that's done to keep the code small. I'd be wiser not to speculate at all, and to again leave the explanation to others that know more about it.
size_t Print::printFloat(double number, uint8_t digits)
size_t n = 0;
if (isnan(number)) return print("nan");
if (isinf(number)) return print("inf");
if (number > 4294967040.0) return print ("ovf"); // constant determined empirically
if (number <-4294967040.0) return print ("ovf"); // constant determined empirically
In IDE 1.5.4, I found this code in this file:
You can verify that the calculation works with float arguments by dividing the result by some appropriate number - in this case, 10 will do - and printing the result. You'll find that the value stored in variable a is correct, but that you just can't Serial.print() it directly when it's very big.
Furthermore even if the multiply didn't overflow 32 bits you would have to use
long constants, not int constants, since int is 16 bits only on most Arduinos (Due
is an exception to this):
long foo = 2500 * 40000L ; // 40000 is larger than largest int, use L
unsigned long bar = 250 * 500000UL ; // unsigned long constant, use UL.
Provided each constant that's too large to be an int is long constant, and if at least
one of them is a long constant, then the result will reliably be long.
25 * 40 // result is int, 16 bits, no problem
25 * 40000 // BAD, use 40000L
25 * 40000L // GOOD
25L * 40000L // GOOD too, ultra-clear.
40000 * 25L // BAD, but may happen to work, but still its luck only.
40000L * 80000L // BAD, overflows long (use float?)
40000UL * 80000UL // GOOD, just fits in unsigned long.
The L and UL are allowed to be either case, but always use upper case L so
its not mistaken for digit 1.
First make copy your print.cpp and print.h
Then you can refactor the print class as I did here - Proposed update for the printFloat code of print.cpp - #11 by robtillaart - Libraries - Arduino Forum -
and some other places. I added code to support scientific formatting of floats.
code is already send to the Arduino develop team
Again: first make copy your print.cpp and print.h
So its the Serial.print!
Never thought of that. Thank you; you saved my chrismas week.
I will try your new print class when I am done with visiting my relatives and eating something heavy.
Wich means tomorrow.
Thank you so much for your help; I was quite desperate and now the world seems right again.
I did a bit of messing around with Print.cpp, and here is my version.
I hope this speeds things up a bit, as well as fixing a bug in some edge cases.
Print.cpp (6.51 KB)