3

I'm trying to execute an algorithm on an Arduino UNO, it needs const table with some larges numbers and sometimes, I get overflow values. This is the case for this number : 628331966747.0

Okay, this is a big one, but its type is float (32 bit) where maximum is 3.4028235e38. So it should work, theoretically ?

What can I do against this ? Do you know a solution ?

EDIT : On Arduino UNO, double are exaclty the same type that floats (32 bits)

Here is a code that leads to the error :

float A; 

void setup() {
  A = 628331966747.0; 
  Serial.begin(9600);
}

void loop() {
  Serial.println(A);
  delay(1000); 
}

it print "ovf, ovf, ..., ovf"

snoob dogg
  • 2,491
  • 3
  • 31
  • 54
  • What is the error? – GManNickG Feb 04 '17 at 00:14
  • 1
    FWIW `628331966747` cannot be accurately stored as a float due to how a floating point number is stored. The nearest representation possible in a 32-bit float is `628331970560`. A double, however, will fit it fine. –  Feb 04 '17 at 00:16
  • @GManNickG following the code I posted I receive "ovf, ovf, ovf..." for me it should return something like : 6.283319e011, no ? – snoob dogg Feb 04 '17 at 00:17
  • 2
    @Thebluefish I must precise that, unfortunately, on Arduino UNO, double are exactly the same type that floats... :( – snoob dogg Feb 04 '17 at 00:18
  • @snoobdogg thanks for letting me know! –  Feb 04 '17 at 00:19
  • 2
    Not really an answer, but it looks like you're getting hit by this check here: https://github.com/arduino/Arduino/blob/master/hardware/arduino/avr/cores/arduino/Print.cpp#L229. Not sure why that's even there, but adds to my huge pile of evidence that the maintainers of the Arduino libraries have no idea what they're doing. You may need to write your own routine that prints floats by sprintf'ing it into a null-terminated string, and then printing that. – GManNickG Feb 04 '17 at 00:24
  • @GManNickG :o !!! maybe there is a unknown reason for this :/ – snoob dogg Feb 04 '17 at 00:27
  • read this: https://github.com/arduino/Arduino/blob/b77957eb59499643aca0749165c3440b77c9e841/hardware/arduino/avr/cores/arduino/Print.cpp – eyllanesc Feb 04 '17 at 01:08
  • ```if (number > 4294967040.0) return print ("ovf"); // constant determined empirically if (number <-4294967040.0) return print ("ovf"); // constant determined empirically``` – eyllanesc Feb 04 '17 at 01:08
  • Yes thank you all, I verified and my float is correctly handled, If I multiply my variable test by 10^-6 the Serial.println returns a good value. I was cheated by the fews lines of codes mentioned by @GManNickG and. Should I answer myself to the question myself ? – snoob dogg Feb 04 '17 at 01:27
  • It does not "return ovf", it *prints* "ovf" - your imprecise description only serves to confuse. @GManNickG, that is an answer; you should post it as such (though perhaps moderated). It looks like a limitation of `printLn(double)`. – Clifford Feb 04 '17 at 01:32
  • Note that a 32bit float is precise to only 6 significant figures. – Clifford Feb 04 '17 at 01:34
  • @GManNickG Apparently, there is an issue ( https://github.com/arduino/Arduino/issues/1412 ) open at their github repository that addresses this exact problem.. and it dates back to 12 May 2013. – Patrick Trentin Feb 04 '17 at 07:26
  • 1
    @snoobdogg : As to whether you should post an answer to your own question, it would be far better for those that have answered it in comments to have posted an answer! That is not what comments are for on SO. As it happens I have posted an answer - credit perhaps to GManNickG, but if you choose not to answer, you don't get the credit. – Clifford Feb 04 '17 at 13:14
  • @Clifford: I have enough rep, I'm fine with giving comments and letting others post proper answers. :) – GManNickG Feb 06 '17 at 04:18

1 Answers1

4

There is nothing wrong with the constant itself (except for its rather optimistic number of significant figures), but the problem is with the implementation of the Arduino's library support for printing floating point values. Print::printFloat() contains the following pre-condition tests:

  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

It seems that the range of printable values is deliberately restricted in order presumably to reduce complexity and code size. The subsequent code reveals why:

// Extract the integer part of the number and print it
  unsigned long int_part = (unsigned long)number;
  double remainder = number - (double)int_part;
  n += print(int_part);

The somewhat simplistic implementation requires that the absolute value of the integer part is itself a 32bit integer.

The worrying thing perhaps is the comment "constant determined empirically" which rather suggests that the values were arrived at by trial and error rather then an understanding of the mathematics! One has to wonder why these values are not defined in terms of INT_UMAX.

There is a proposed "fix" described here, but it will not work at least because it applies the integer abs() function to the double parameter number, which will only work if the integer part is less than the even more restrictive MAX_INT. The author has posted a link to a zip file containing a fix that looks more likely to work (there is evidence at least of testing!).

Clifford
  • 88,407
  • 13
  • 85
  • 165