Author Topic: [SOLVED] ESP8266 - Arduino IDE - dtostrf() conversion function problems!  (Read 11483 times)

0 Members and 1 Guest are viewing this topic.

Offline TJ232Topic starter

  • Frequent Contributor
  • **
  • Posts: 331
  • Country: 00
  • www.esp8266-projects.org
    • ESP8266 Projects
While playing around with ESP8266 CBDBv2 Evo DevBoard and Arduino IDE 1.6.4 found that  it's returning wrong values for any float with more than 1 "0" after "." aka small values like 0.0256.

Can you please try and check also with a Arduino board for the result with the simple code below for 0.256, 0.0256, 0.00256 values:

Code: [Select]

void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
}

// the loop routine runs over and over again forever:
void loop() {

 char charVal[10];          //temporarily holds data from vals
 String stringVal = "";     //data on buff is copied to this string
 
 float fVal = 0.0256;
 Serial.print("Value :");
 Serial.println((float)fVal);
 
 dtostrf(fVal, 8, 4, charVal);  //4 is mininum width, 3 is precision; float value is copied onto buff

 stringVal = charVal;
 int strl = stringVal.length()-1;

 Serial.print("Conv val :"); Serial.println(charVal);
 Serial.print("Length: ");Serial.println(strl); //display string
 Serial.print("Conv val :"); Serial.println(stringVal);
 Serial.println("\n");
  delay(3000);        // delay in between reads for stability
}



For reference: MAX7219 Arduino IDE Driver - ESP8266
« Last Edit: June 16, 2015, 06:39:28 am by TJ232 »
ESP8266 Projects - www.esp8266-projects.org
MPDMv4 Dimmer Board available on Tindie: https://www.tindie.com/stores/next_evo1/
 

Offline amyk

  • Super Contributor
  • ***
  • Posts: 8275
Re: Arduino IDE - dtostrf() conversion function problems?
« Reply #1 on: June 15, 2015, 01:10:58 pm »
What are the incorrect values?

This could be an obvious bug, but converting strings to and from floating-point, and preserving precision, is actually not so easy: see https://lists.nongnu.org/archive/html/gcl-devel/2012-10/pdfkieTlklRzN.pdf for a good article about it.
 

Offline TJ232Topic starter

  • Frequent Contributor
  • **
  • Posts: 331
  • Country: 00
  • www.esp8266-projects.org
    • ESP8266 Projects
Re: Arduino IDE - dtostrf() conversion function problems?
« Reply #2 on: June 15, 2015, 01:31:26 pm »
What are the incorrect values?

This could be an obvious bug, but converting strings to and from floating-point, and preserving precision, is actually not so easy: see https://lists.nongnu.org/archive/html/gcl-devel/2012-10/pdfkieTlklRzN.pdf for a good article about it.


Let's try the code below, much easier to see what's going on:

Code: [Select]
void setup() {
 // initialize serial communication at 9600 bits per second:
 Serial.begin(9600);
}

void print_float(int no, float fVal, String sVal )
{
char charVal[12];          //temporarily holds data from vals
String stringVal = "";     //data on buff is copied to this string

dtostrf(fVal, 8, 4, charVal);  //4 is mininum width, 3 is precision; float value is copied onto buff

stringVal = charVal;
int strl = stringVal.length()-1;

Serial.print(no);  //just a order number
Serial.print(". - Expected value :"); Serial.print(sVal);  //the number represented as string for reference
Serial.print(" - String Length: ");Serial.print(strl); //display lenght of the obtained string after conversion
Serial.print(" - Conversion value in stringVal :"); Serial.println(stringVal); //display the value as stored in stringVal
}

void loop() {
   print_float(1,1.256,"1.2560");   //No 1
   print_float(2,1.0256,"1.0256");  //No 2
   print_float(3,1.00256,"1.0026"); //No 3
   Serial.println(); 
   delay(5000);        // delay in between reads for stability
}



The result:

Code: [Select]
1. - Expected value :1.2560 - String Length: 5 - Conversion value in stringVal :1.2560
2. - Expected value :1.0256 - String Length: 4 - Conversion value in stringVal :1.256
3. - Expected value :1.0026 - String Length: 3 - Conversion value in stringVal :1.26

Smells like a bug for me.
ESP8266 Projects - www.esp8266-projects.org
MPDMv4 Dimmer Board available on Tindie: https://www.tindie.com/stores/next_evo1/
 

Offline rs20

  • Super Contributor
  • ***
  • Posts: 2318
  • Country: au
Re: Arduino IDE - dtostrf() conversion function problems?
« Reply #3 on: June 15, 2015, 01:39:00 pm »
I'm sure you already know this, but just to be sure -- this bug (and it does look like a bug to me) is a bug in libraries/compiler, not in your hardware.
 

Offline TJ232Topic starter

  • Frequent Contributor
  • **
  • Posts: 331
  • Country: 00
  • www.esp8266-projects.org
    • ESP8266 Projects
Re: Arduino IDE - dtostrf() conversion function problems?
« Reply #4 on: June 15, 2015, 01:45:18 pm »
I'm sure you already know this, but just to be sure -- this bug (and it does look like a bug to me) is a bug in libraries/compiler, not in your hardware.

Yes, I know, I am just asking if anybody else noticed this strange behavior.
Will be great if somebody with a Arduino board can run the code and give the result.
I don't have any around now to see if is only ESP8266 STDLIB or general Arduino problem.
ESP8266 Projects - www.esp8266-projects.org
MPDMv4 Dimmer Board available on Tindie: https://www.tindie.com/stores/next_evo1/
 

Offline amyk

  • Super Contributor
  • ***
  • Posts: 8275
 

Offline TJ232Topic starter

  • Frequent Contributor
  • **
  • Posts: 331
  • Country: 00
  • www.esp8266-projects.org
    • ESP8266 Projects
Re: Arduino IDE - dtostrf() conversion function problems?
« Reply #6 on: June 15, 2015, 04:06:35 pm »
Bug is probably in here somewhere:
http://minimosd-extra.googlecode.com/svn/trunk/libraries/FastSerial/ftoa_engine.S

Don't know for native Arduino, but for ESP8266 extension the "dtostrf()" monkey hides in
"core_esp8266_noniso.c" and is called by "#include<stdlib_noniso.h>"

If anybody want to have fun, a copy below:
Code: [Select]
char * dtostrf(double number, signed char width, unsigned char prec, char *s) {

    if(isnan(number)) {
        strcpy(s, "nan");
        return s;
    }
    if(isinf(number)) {
        strcpy(s, "inf");
        return s;
    }

    if(number > 4294967040.0 || number < -4294967040.0) {
        strcpy(s, "ovf");
        return s;
    }
    char* out = s;
    // Handle negative numbers
    if(number < 0.0) {
        *out = '-';
        ++out;
        number = -number;
    }

    // Round correctly so that print(1.999, 2) prints as "2.00"
    double rounding = 0.5;
    for(uint8_t i = 0; i < prec; ++i)
        rounding /= 10.0;

    number += rounding;

    // Extract the integer part of the number and print it
    unsigned long int_part = (unsigned long) number;
    double remainder = number - (double) int_part;
    out += sprintf(out, "%d", int_part);

    // Print the decimal point, but only if there are digits beyond
    if(prec > 0) {
        *out = '.';
        ++out;
    }

    while(prec-- > 0) {
        remainder *= 10.0;
    }
    sprintf(out, "%d", (int) remainder);

    return s;
}

For my specific application, the MAX7219 8 Digit Display driver workaround is in the code here:
https://www.eevblog.com/forum/microcontrollers/max7219-8-bit-led-display-module-esp8266/

ESP8266 Projects - www.esp8266-projects.org
MPDMv4 Dimmer Board available on Tindie: https://www.tindie.com/stores/next_evo1/
 

Offline TJ232Topic starter

  • Frequent Contributor
  • **
  • Posts: 331
  • Country: 00
  • www.esp8266-projects.org
    • ESP8266 Projects
Re: Arduino IDE - dtostrf() conversion function problems?
« Reply #7 on: June 15, 2015, 07:24:03 pm »
MISTERY SOLVED: it is a bug in the ESP8266 dtostrf() function implementation -> "core_esp8266_noniso.c".

It was affecting ESP8266 code only. Confirmed and fixed with the guys from Arduino Forum.

Correct dtostrf() function code below:

Code: [Select]
char * dtostrf(double number, signed char width, unsigned char prec, char *s) {

    if(isnan(number)) {
        strcpy(s, "nan");
        return s;
    }
    if(isinf(number)) {
        strcpy(s, "inf");
        return s;
    }

    if(number > 4294967040.0 || number < -4294967040.0) {
        strcpy(s, "ovf");
        return s;
    }
    char* out = s;
    // Handle negative numbers
    if(number < 0.0) {
        *out = '-';
        ++out;
        number = -number;
    }

    // Round correctly so that print(1.999, 2) prints as "2.00"
    double rounding = 0.5;
    for(uint8_t i = 0; i < prec; ++i)
        rounding /= 10.0;

    number += rounding;

    // Extract the integer part of the number and print it
    unsigned long int_part = (unsigned long) number;
    double remainder = number - (double) int_part;
    out += sprintf(out, "%d", int_part);

    // Print the decimal point, but only if there are digits beyond
    if(prec > 0) {
        *out = '.';
        ++out;
    }

    while(prec-- > 0) {
        remainder *= 10.0;
        if((int)remainder == 0){
                *out = '0';
                 ++out;
        }
    }
    sprintf(out, "%d", (int) remainder);

    return s;
}
ESP8266 Projects - www.esp8266-projects.org
MPDMv4 Dimmer Board available on Tindie: https://www.tindie.com/stores/next_evo1/
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf