printf icon indicating copy to clipboard operation
printf copied to clipboard

double with 15digits precision?

Open igor-m opened this issue 4 years ago • 8 comments

Hi, what is the reason to limit the precision to 9 digits only?

  // limit precision to 9, cause a prec >= 10 can lead to overflow errors
  while ((len < PRINTF_FTOA_BUFFER_SIZE) && (prec > 9U)) {

I would be happy to have double float printed with full 15digits precision - is that 9 digits limit an issue with some algorithms used? Thanks for your work!

igor-m avatar Mar 17 '21 10:03 igor-m

uint32_t is used for printing, so e9 is limit

ledvinap avatar Mar 18 '21 09:03 ledvinap

You work with double (64bits) already - line 487 - thus the "exponent" is in exp2 (11bits) and "mantissa" (1+52bits) could be stored in an uint64_t M, for example (and then M should be "converted" to int64_t by the code as is, and printed out) :

  union {
    uint64_t U;
    double   F;
  } conv;

  conv.F = value;
  uint64_t M = (conv.U & 0x800F_FFFF_FFFF_FFFF) ;                  <<<<<<<<<< Mantissa for example
  int exp2 = (int)((conv.U >> 52U) & 0x07FFU) - 1023;           // effectively log2

I think everything is there already, some tweaking, perhaps..

igor-m avatar Mar 18 '21 10:03 igor-m

here is fractional part printing: https://github.com/mpaland/printf/blob/master/printf.c#L413

ledvinap avatar Mar 19 '21 10:03 ledvinap

I added to the pow[] array the powers of up to 10^15 and changed the precision to 15, but still I get wrong results, usually the first 5-6 decimal places are zero, ie. like

PI= 3.000000466742562e+00
A=  -1.000002554368448e+08
1 xyz = 8.000001902844712e-01
2 xyz = 1.000000317619429e+00
3 xyz = 2.000001240909688e+00
4 xyz = 3.000002166359860e+00
5 xyz = 4.000003089594626e+00
6 xyz = 5.000004013904494e+00
7 xyz = 6.000000643134767e+00
8 xyz = 7.000001567591462e+00
9 xyz = 8.000002491627471e+00

igor-m avatar Mar 19 '21 10:03 igor-m

ok, this looks better:

PI= 3.141592653589793e+00         // 3.141592653589793
A=  -1.234567891233759e+08       // -123456789.12345678
9 degree Calculator test started.. wait...      // asin(acos(atan(tan(cos(sin(degree))))))) in DEG mode
1 degree = 1.000000001957684e+00 hex= 0x3ff00000008687f3
2 degree = 1.999999999819259e+00 hex= 0x3ffffffffff3945f
3 degree = 2.999999998867262e+00 hex= 0x4007ffffffd91454
4 degree = 4.000000000341832e+00 hex= 0x401000000005df65
5 degree = 4.999999999327491e+00 hex= 0x4013fffffff47246
6 degree = 5.999999999520980e+00 hex= 0x4017fffffff7c53f
7 degree = 6.999999999588305e+00 hex= 0x401bfffffff8ed59
8 degree = 7.999999999946748e+00 hex= 0x401fffffffff15cb
9 degree = 8.999999999832568e+00 hex= 0x4021fffffffe8fd0

With uint64_t instead of unsigned long

  int whole = (int)value;
  double tmp = (value - whole) * pow10[prec];
  uint64_t frac = (uint64_t)tmp;
  diff = tmp - frac;

igor-m avatar Mar 19 '21 10:03 igor-m

@ledvinap : Is there any good reason to limit this to uint32_t and 1e9? I mean, uint64_t's are used elsewhere in printf.c after all.

eyalroz avatar Jul 14 '21 21:07 eyalroz

@eyalroz, @ledvinap Thanks so much for this massive amount of input from you guys! Right now I'm just too busy with another project, I'll get back to printf in August. Promised.

mpaland avatar Jul 14 '21 22:07 mpaland

@mpaland : If you do, please email me and let's chat, as my fork currently integrates most other people's contributions...

eyalroz avatar Jul 14 '21 22:07 eyalroz