Pages: [1]   Go Down
Author Topic: printing double-precision floating point  (Read 1498 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Jr. Member
**
Karma: 1
Posts: 58
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

In case it is useful, here is an updated version of an older Arduino sketch to convert floating point numbers to a string in scientific notation for printing.
This one shows up to 16 decimal digits, so you can see the full accuracy of your double-precision float types. (Note, I have only tested it on a Teensy 3, not a Due.)
This fits into the category of "quick hack", it is not in any way optimized.

Sample output string:  3.1415926535897926 E+146

Try running this sketch on an older ATmega type Arduino, and you will see quite a difference in the range and precision of floating point values (because the original Arduinos set type double == type float).

Code:
//
// Test of function that builds a C-style "string" for a floating point
// number in scientific notation.
//
// original by davekw7x December, 2010  
// http://arduino.cc/forum/index.php/topic,46931.0.html
// modified to use "double" and to run to smaller / larger values  March 12 2013 JPB
//

#define STEPS 330

void setup()
{
    double f, fa;
    int d;
    char str[26];  // formated number as string
    
    Serial.begin(115200);
    delay(3000);
    Serial.println("double precision floating point test");

    f = 0.0;
    // No "digits" argument means 2 digits
    Serial.print("0.0 = ");Serial.println(double2s(f));Serial.println();
    
    // Rounding with leading zeros in the fractional part
    f = 10.3456;
    Serial.print(f,4);Serial.print(" = ");Serial.println(double2s(f, 4));Serial.println();
    
    /*
       For loops 1 and 2, note that floating point
       overflows result values of"INF"
    */
    f = PI;

    
    Serial.println("Loop 1");
    for (int i=1; i< STEPS; i++)
    {
        Serial.println(double2s(f, 16));
        if (isinf(f)) break;        
        f *=1E1;
    }
    Serial.println();

    f = -PI;
    Serial.println("Loop 2");
    for (int i=1; i< STEPS; i++)
    {
        Serial.println(double2s(f, 16));
        if (isinf(f)) break;        
        f *=1E1;
    }  
    Serial.println();

    /*
       For loops 3 and 4 note that floating point
       underflows result in values that go to zero.
    */
    f = PI;
    Serial.println("Loop 3");
    for (int i=1; i< STEPS; i++)
    {
        Serial.println(double2s(f, 16));        
        if (f == 0.0) break;
        f /= 1E1;
    }
    Serial.println();

    f = -PI;
    Serial.println("Loop 4");
    for (int i=1; i< STEPS; i++)
    {
        Serial.println(double2s(f, 16));
        if (f == 0.0) break;
        f /= 1E1;
    }
    Serial.println();

    /*
       Loop 5 shows rounding as follows:
        6: 1.999518 E+20
        5: 1.99952 E+20
        4: 1.9995 E+20
        3: 2.000 E+20
        2: 2.00 E+20
        1: 2.0 E+20
        0: 2 E+20
    */

    f = 1.999518e20;
    Serial.println("Loop 5");
    for (int i = 16; i >= 0; i--) {
        Serial.print(i);Serial.print(": ");Serial.println(double2s(f, i));
    }
    Serial.println();
    
    /*
       Loop 6 shows rounding as follows:
        6: 1.999496 E+20
        5: 1.99950 E+20
        4: 1.9995 E+20
        3: 1.999 E+20
        2: 2.00 E+20
        1: 2.0 E+20
        0: 2 E+2
    */
    
    f = 1.999496e20;
    Serial.println("Loop 6");
    for (int i = 16; i >= 0; i--) {
        Serial.print(i);Serial.print(": ");Serial.println(double2s(f, i));
    }    
    Serial.println();
    
    Serial.println("NaN tests");
    f = sqrt(-1);
    Serial.print("sqrt(-1) = ");Serial.println(double2s(f, 3));

    f = 0.0/0.0;
    Serial.print("0.0/0.0 = ");Serial.println(double2s(f, 4));

    f = INFINITY * 0;
    Serial.print("INFINITY*0 = ");Serial.println(double2s(f, 5));Serial.println();

    
    Serial.println("INFINITY tests");
    f = 1.0/0;
    Serial.print("1.0/0 = ");Serial.println(double2s(f, 1));
    //printBytes(f);

    f = -1.0/0;
    Serial.print("1.0/-0 = ");Serial.println(double2s(f, 1));
    //printBytes(f);

    f = -1.0/0L;
    Serial.print("1.0/0L = ");Serial.println(double2s(f, 2));
    
    f = 1.0/0UL;
    Serial.print("1.0/0UL = ");Serial.println(double2s(f, 3));
    
    Serial.println();
    
    // Note that tan(pi/2) may not result in INF due
    // to limited precision.
    //
    f = tan(HALF_PI);
    Serial.print("tan(");Serial.print(HALF_PI, 6);Serial.print(") = ");  
    Serial.println(double2s(f, 6));
}

void loop()
{
}


// ====== double2s(): print out up to 16 digits of input double-precision value
// This version enables double-precision for Teensy 3, etc.
// by J.Beale March 2013
// modified from original float2s() posted by davekw7x on December, 2010
// http://arduino.cc/forum/index.php/topic,46931.0.html

char * double2s(double f)
{
  return double2s(f, 2);
}

char * double2s(double f, unsigned int digits) {    
int d;
static char s[26];  // formated number as string
int index=0;

  // handle sign
  if (f < 0.0)
  {
    s[index++] = '-';
    f = -f;
  }
  // handle infinite values
  if (isinf(f))
  {
    strcpy(&s[index], "INF");
    return s;
  }
  // handle Not a Number
  if (isnan(f))
  {
    strcpy(&s[index], "NaN");
    return s;
  }

  // max digits
  if (digits > 16) digits = 16;
  int exponent = int(log10(f));
  double g = f / pow(10, exponent);
  if ((g < 1.0) && (g != 0.0))      
  {
    g *= 10;
    exponent--;
  }
  if (exponent < -330) {  // lower limit of double-precision on Teensy 3
    g = 0;
    exponent = 0;
  }
  if (digits < 16) {  // display number rounded at last digit
    g += 0.5 / pow(10,digits);
  }
  
  d = g;  
  sprintf(&s[index++],"%d",d);  
  if (digits > 0) sprintf(&s[index++],".");
  for (int i=0;i<digits;i++) {
      g = (g - d) * 10.0;  // shift one decimal place to the left
      d = int(g);
      sprintf(&s[index++],"%d",d);
  }
  sprintf(&s[index], " E%+d", exponent);
  return s;    
} // ===== end double2s()

« Last Edit: March 13, 2013, 02:51:51 pm by John Beale » Logged

Pages: [1]   Go Up
Jump to: