Pelles C forum
C language => Beginner questions => Topic started by: Grincheux on November 14, 2020, 12:29:58 pm

The function atof rouds my results!
I have strings with 15 numbers after the decimal point and I can't get correct double or float numer.
Is there a solution (without writing my own).

I had a best result using strtold
*(_lpszDatas + 17) = '\0' ;
// _dJulianDate = atof(_lpszDatas) ;
_dJulianDate = (double) strtold(_lpszDatas,NULL) ;

I suppose that Pelle make the same thing:
/* Copyright (C) 19912019 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
#include <stdlib.h>
#undef atof
/* Convert a string to a double. */
double
atof (const char *nptr)
{
return strtod (nptr, (char **) NULL);
}

Hi Grincheux,
Not that I'm qualified to speak to this but I am aware that there was a bug report on using more than 11 or 12 digits after the decimal. I think the suggestion was to use the advance math lib for now.
John Z

Maybe there is a problem somewhere, I havn't really hunted for anything yet, but there could also be the common case of having to high expectations about the binary floatingpoint format in general. There are only so many decimals you can expect to be correct.
If you have trouble sleeping, this may (or may not) help:
"What Every Computer Scientist Should Know About FloatingPoint Arithmetic"
https://docs.oracle.com/cd/E1995701/8063568/ncg_goldberg.html (https://docs.oracle.com/cd/E1995701/8063568/ncg_goldberg.html)
Also, like Microsoft, there is no (at least shouldn't be any) difference between double and long double type.

If you have trouble sleeping, this may (or may not) help:
"What Every Computer Scientist Should Know About FloatingPoint Arithmetic"
https://docs.oracle.com/cd/E1995701/8063568/ncg_goldberg.html (https://docs.oracle.com/cd/E1995701/8063568/ncg_goldberg.html)
I found the following equations, under the PROOF section, to be particularly effective at helping me to fall asleep.
To get the general formula for Sk and Ck, expand the definitions of sk and ck, ignoring all terms involving xi with i > 1 to get
sk = (sk  1 + yk)(1 + k)
= [sk  1 + (xk  ck  1) (1 + k)](1 + k)
= [(sk  1  ck  1)  kck  1](1+k)
ck = [{sk  sk  1}(1 + k)  yk](1 + k)
= [{((sk  1  ck  1)  kck  1)(1 + k)  sk  1}(1 + k) + ck  1(1 + k)](1 + k)
= [{(sk  1  ck  1)k  kck1(1 + k)  ck  1}(1 + k) + ck  1(1 + k)](1 + k)
= [(sk  1  ck  1)k(1 + k)  ck  1(k + k(k + k + kk))](1 + k),
sk  ck = ((sk  1  ck  1)  kck  1) (1 + k)
 [(sk  1  ck  1)k(1 + k)  ck  1(k + k(k + k + kk)](1 + k)
= (sk 1  ck  1)((1 + k)  k(1 + k)(1 + k))
+ ck  1(k(1 + k) + (k + k(k + k + kk)) (1 + k))
= (s 1  ck  1) (1  k(k + k + kk))
+ ck  1  [k + k + k(k + kk) + (k + k(k + k + kk))k]

In fact I have trouble for sleeping, only two or three hours a night!
This formula will give me a headache that's all, nothing for sleeping.
I have looked at many post (stackoverflow...) many people have the problem.
I download ephemeris from the nasa (https://ssd.jpl.nasa.gov/horizons.cgi (https://ssd.jpl.nasa.gov/horizons.cgi)) their programs are written using FORTRAN.
I have solved the problem in an other way.
I thank every one for the help.
This could help someone : http://arrayfire.org/docs/index.htm (http://arrayfire.org/docs/index.htm) and https://gmplib.org/ (https://gmplib.org/)
It seems too hard for me.
Merci

In fact I have trouble for sleeping, only two or three hours a night!
This formula will give me a headache that's all, nothing for sleeping.
Me too, sometimes. My point was that this isn't "easy reading", if fact it requires a lot of time and thinking, but some of this information has proven useful to some people in the past, so I thought I share the link again.
Apart from that, if you still have problems, maybe a more complete example with the actual input to atof() (or whatever) may produce better help/answers.

Yes but I don't where is the problem because when using strtold, atof, or sqlite3_snprintf.
It seems there is the problem in all the functions.
I have solved it in modifying the %f argument.
I need 15 numbers after the decimal point :
sqlite3_snprintf(sizeof(_szTmp),_szTmp,"%.15f",_dDistanceLaPlusProche) ;
so I format with 16 numbers
sqlite3_snprintf(sizeof(_szTmp),_szTmp,"%.16f",_dDistanceLaPlusProche) ;
With the other functions I have not any solution.
I have not tried with snprintf (don't want MS functions).
I have not tried by replacing %f by %g
My avatar is what I am actually doing.
Thank You for your help
Your compiler is the BEST

The point is that the number of significant digits that we can express with a double float is approximately 16 decimal (decimal intended as base 10 not as after decimal point) digits (53 bits => log10(2) ≈ 15.955), and really means all significant decimal digits before and after the decimal point.
So you can't expect to have 15 significant decimal for numbers bigger or equal to 1.
If you need such precision you should use a math library with extended precision.

Thank You Frankie I expected an other solution, but with your post it is clear I must change something. Perhaps I could multiply by 100 so there will be only five numbers after the decimal point.
With the help every one gave me, I can say the post is closed.

I still waits what those numbers are.
Give us series of those numbers to check.

Here are examples
2466285.687500000, A.D. 2040May11 04:30:00.0000, 1.556590248345051E+09, 2.709382709369094E+08, 8.836233844876927E+07, 7.653652678628662E+00, 3.833227168750318E+01, 4.593642982153394E01, 5.278527865450719E+03, 1.582462843404964E+09, 9.398838110390882E01,
2466285.708333333, A.D. 2040May11 05:00:00.0000, 1.556576462563047E+09, 2.710072669242373E+08, 8.836316353478888E+07, 7.663882752316741E+00, 3.832993585150521E+01, 4.573979376624084E01, 5.278522195719391E+03, 1.582461143662273E+09, 9.487191675119203E01,
2466285.729166667, A.D. 2040May11 05:30:00.0000, 1.556562658367611E+09, 2.710762587037903E+08, 8.836398508131553E+07, 7.674112045828995E+00, 3.832759637718574E+01, 4.554315282629915E01, 5.278516472939437E+03, 1.582459428016004E+09, 9.575544522874865E01,
2466285.750000000, A.D. 2040May11 06:00:00.0000, 1.556548835760150E+09, 2.711452462690158E+08, 8.836480308826166E+07, 7.684340557115283E+00, 3.832525326549152E+01, 4.534650705151737E01, 5.278510697111295E+03, 1.582457696466289E+09, 9.663896636982247E01,
2466285.770833333, A.D. 2040May11 06:30:00.0000, 1.556534994742076E+09, 2.712142296133627E+08, 8.836561755554067E+07, 7.694568284329571E+00, 3.832290651737497E+01, 4.514985649057817E01, 5.278504868235410E+03, 1.582455949013259E+09, 9.752248002768448E01,
2466285.791666667, A.D. 2040May11 07:00:00.0000, 1.556521135314799E+09, 2.712832087302955E+08, 8.836642848306687E+07, 7.704795225828729E+00, 3.832055613379973E+01, 4.495320119136608E01, 5.278498986312236E+03, 1.582454185657053E+09, 9.840598607536791E01,
2466285.812500000, A.D. 2040May11 07:30:00.0000, 1.556507257479735E+09, 2.713521836132668E+08, 8.836723587075542E+07, 7.715021380166704E+00, 3.831820211575668E+01, 4.475654120184007E01, 5.278493051342231E+03, 1.582452406397807E+09, 9.928948440483559E01,
2466285.833333333, A.D. 2040May11 08:00:00.0000, 1.556493361238303E+09, 2.714211542557307E+08, 8.836803971852225E+07, 7.725246746101247E+00, 3.831584446427977E+01, 4.455987657079348E01, 5.278487063325862E+03, 1.582450611235662E+09, 1.001729749272952E+00,
2466285.854166667, A.D. 2040May11 08:30:00.0000, 1.556479446591923E+09, 2.714901206511572E+08, 8.836884002628440E+07, 7.735471322605457E+00, 3.831348318045865E+01, 4.436320734841406E01, 5.278481022263600E+03, 1.582448800170757E+09, 1.010564575740471E+00,
2466285.875000000, A.D. 2040May11 09:00:00.0000, 1.556465513542015E+09, 2.715590827930046E+08, 8.836963679395960E+07, 7.745695108875569E+00, 3.831111826544660E+01, 4.416653358663005E01, 5.278474928155919E+03, 1.582446973203236E+09, 1.019399322971638E+00,
2466285.895833333, A.D. 2040May11 09:30:00.0000, 1.556451562090006E+09, 2.716280406747333E+08, 8.837043002146657E+07, 7.755918104349613E+00, 3.830874972045784E+01, 4.396985533885100E01, 5.278468781003298E+03, 1.582445130333242E+09, 1.028233990713471E+00,
2466285.916666667, A.D. 2040May11 10:00:00.0000, 1.556437592237315E+09, 2.716969942898195E+08, 8.837121970872520E+07, 7.766140308727367E+00, 3.830637754675538E+01, 4.377317265922063E01, 5.278462580806210E+03, 1.582443271560917E+09, 1.037068578961048E+00,
2466285.937500000, A.D. 2040May11 10:30:00.0000, 1.556423603985368E+09, 2.717659436317282E+08, 8.837200585565612E+07, 7.776361721981864E+00, 3.830400174563097E+01, 4.357648560154441E01, 5.278456327565135E+03, 1.582441396886405E+09, 1.045903087973520E+00,
2466285.958333333, A.D. 2040May11 11:00:00.0000, 1.556409597335591E+09, 2.718348886939266E+08, 8.837278846218090E+07, 7.786582344376431E+00, 3.830162231837438E+01, 4.337979421764349E01, 5.278450021280551E+03, 1.582439506309848E+09, 1.054737518296720E+00,

Thank You Frankie I expected an other solution, but with your post it is clear I must change something. Perhaps I could multiply by 100 so there will be only five numbers after the decimal point.
I don't think it will solve your problem.
Multiplying by 100 moves the decimal point, but don't change the total number of digit figures of the number, ergo the whole digits that make up your number still can't be enclosed in the 54 bits (53 real plus an implicit bit), and can't be represented without approximations.
When approximations comes in all the issues, explained in the paper reported by Pelle, start to play.
In very plain words: if you need high precision calculations without any tricky approximation, be sure that all your numbers, removing the decimal point, are less than 2^541.
In your case you can find convenient to work with quadruple precision float, standard "IEEE 754 2008 binary128", that use 128bits.
Many free libraries are available, among them you can try QPFloat (https://github.com/coder0xff/QPFloat) (C++) this in C (https://www.codeproject.com/Articles/1206126/Quadrupleprecisionfloatingpointcalculationsin).

I have read something about what you told.
I have read too that a programmer gave numbers in the form of a string.
What about transforming in two 64 bits numbers.
Than You Frankie for your help.

I have read too that a programmer gave numbers in the form of a string.
I have ugly code that I wrote in 1992 that creates 3 functions  fpAdd, fpSub, and fpMul.
Each takes 2 string arguments. The BASIC code was written for MSDOS but compiles with Pelles
when converted using my BCX translator.
Examples:
PRINT fpAdd$ ("999.123456789","100")
PRINT fpSub$ ("500.987654321","100")
PRINT fpMul$ ("999999999999999999.123456789","999999999999999999.123456789")
OUTPUT
1099.123456789
400.987654321
999999999999999998246913578000000000.768328000750190521
Impressively, the fpMul result matches the result obtained here:
https://keisan.casio.com/calculator

A good thing and impressive calculator!
I also have found LibBF and GNU MPFR but there is no Windows Version!
It is possible using MinGW but too complicated for me.

Check
https://forum.pellesc.de/index.php?topic=7184.msg27264#msg27264
EDIT:
https://www.davidhbailey.com/dhbsoftware/

What about transforming in two 64 bits numbers.
Than You Frankie for your help.
I would avoid to to reinvent the wheel and write your own math library.
You can use the QD library ported by Timovjl.
I also found another quad precision float library that seems interesting: the HPALIB (https://www.nongnu.org/hpalib/) (High Precision Arithmetic library).
The IEEE 754 2008 binary128 uses 1 bit for sign, 15bits for exponent and 113bits for mantissa. 113bits means 33 significant digits. This means that you can work i.e. with numbers of 16 digits before decimal dot and 16 digits after without precision loss.

There are too many numbers after the decimal point!
Thank You Frankie & Timo I will use the library

QDC library should follow lisence:
https://www.davidhbailey.com/dhbsoftware/LBNLBSDLicense.docx
PS.
David H Bailey accept that QDC project.