how to print a long double ... to 33 decimals

Status
Not open for further replies.

ninja2

Well-known member
how can I output a long double to many digits. For example my sketch below uses dtostrf, but the output is only accurate to about 10 digits, like this:

------ ------- -------
D2R:
_input: 0.017453292519943295769236907684886L
dtostrf: 0.017453292384743690490722656250000
------ end setup -------

heres the sketch:
Code:
const char CJ_ID[] = "t3D2Rtest.a";

#define LED LED_BUILTIN
#include <Streaming.h>

//nst double D2R = DEG_TO_RAD;                             // can't use - missing "L" in wiring.h
const long double D2R = 0.017453292519943295769236907684886L;// degrees to radians, to 33 places
char valBuffer[50] = {0}; 

void setup() {
  Serial.begin(115200);
  while (!Serial && (millis() <= 4000)){                   // wait for Serial to open, but only for 4 secs
    digitalWriteFast(LED,!digitalReadFast(LED));           // toggle LED
    delay(50);}                                            // rapidly!
  digitalWrite(LED, LOW);                                  // then off
  Serial << "### ##### " << CJ_ID << "########\n"; 
  Serial << F(" * Serial open, millis: ") << millis() << '\n';
  Serial << "\n------ ------- -------\n";
  Serial << "D2R:" << '\n'; // degrees to radians
  Serial << "  input:\t 0.017453292519943295769236907684886L" << '\n'; // degrees to radians
  dtostrf(D2R, 35, 33, valBuffer); // long double in, width, precision, buffer
  Serial << "dtostrf:\t"; Serial.println(valBuffer);
  Serial << "------ end setup -------" << '\n';
  }

void loop() {}
 
Last edited:
Try this.

Code:
void setup() {
  while (!Serial) ;
  double x = 0.017453292519943295769236907684886L;
  char buf[64];
  snprintf(buf, sizeof(buf), "%.30lf", x);
  Serial.println(buf);
}

void loop() {
}

Make sure Tools > Optimize is not set to smallest code (the default for Teensy LC).
 
Also consider that dtostrf(), despite its name and definition, takes a 32 bit floating point number to give the same results as AVR (where double is the same 32 bits as float). It does not actually use 64 bit double precision.
 
long double x;
x = 0.017453292519943295769236907684886L;
Serial.printf("size %d %.28Lf\n",sizeof(x),x);

with T3.2 (TD1.36 gcc 5.4.1) you get
size 8 0.0174532925199432954743716806


on my linux with gcc 5.4, size 16 0.0174532925199432957691391462

so Teensy is only using 8-byte double. With BigNumber.h
BigNumber::begin (50);
BigNumber e;
e= "0.017453292519943295769236907684886";
e += 1;
Serial.println (e);

you get 1.01745329251994329576923690768488600000000000000000
 
Last edited:
Try this.

Code:
void setup() {
  while (!Serial) ;
  double x = 0.017453292519943295769236907684886L;
  char buf[64];
  snprintf(buf, sizeof(buf), "%.30lf", x);
  Serial.println(buf);
}

void loop() {
}

Make sure Tools > Optimize is not set to smallest code (the default for Teensy LC).
That's a problematic choice for Teensy LC, you use up a ton of scarce memory (Optimize fast):
Sketch uses 35804 bytes (56%) of program storage space. Maximum is 63488 bytes.
Global variables use 4696 bytes (57%) of dynamic memory, leaving 3496 bytes for local variables. Maximum is 8192 bytes.


You can simply add "asm (".global _printf_float");" to the beginning of setup() to get floating point support for printf. With 'Optimize: Smallest code':
Sketch uses 24204 bytes (38%) of program storage space. Maximum is 63488 bytes.
Global variables use 2628 bytes (32%) of dynamic memory, leaving 5564 bytes for local variables. Maximum is 8192 bytes.


I would avoid sprintf / snprintf. All the classes inheriting from Print (e.g. USB Serial and the hardware serial classes) have a printf function that doesn't rely on a fixed buffer (no danger of a buffer overflow or string truncation).
 
how can I output a long double to many digits.

Note, long double on ARM platforms is the same as double. IEEE double has 53 binary bits in the mantissa (52 real bits plus one implied bit), which gives you roughly 15-17 decimal digits. There is an IEEE 128-bit floating point format, but the ARM GCC compiler does not support it.

FWIW, the normal long double on x86 is normal an 80 bit format.

Currently on the PowerPC, long double is a pair of double variables. This give you more bits of precision, but it does not give you more precision. In theory, I hope by the time GCC 8 is released, we will have an option to switch to the IEEE 128-bit format.

On the AVR platforms, both long double and double are mapped to float.
 
Status
Not open for further replies.
Back
Top