AnsiString to Double C++

4.1k Views Asked by At

I am trying to convert an AnsiString to a double, but after running the programm, it says "20.60 is not a valid floating point".

AnsiString Temperatur

RE_Temperatur->Text = Temperatur;

Chart1->Series[0]->AddXY(DT_Uhrzeit->Time, RE_Temperatur->Text.ToDouble(), 
"", clRed);

The value for Temperatur comes from a SerialPort connection from my Arduino and delivers something like 20.60 and so on. When I cut the string to the first 2 digits it is working fine. Guess the . has something to do with the error but I dont know how to solve it.

EDIT // I now tried to just replace the "." with a "," with following code:

    RE_Temperatur->Text = StringReplace(RE_Temperatur->Text, ".", ",", 
    TReplaceFlags() << rfReplaceAll);

Now I get an Error Message "20,60 is not a valid floating point". Its so frustrating :/

3

There are 3 best solutions below

0
On BEST ANSWER

Try this simple piece of code in a new console program:

AnsiString Temperatur = "12.45"; // locale independent
AnsiString Temperatur2 = "12,45"; // correct in my German locale

double temp = StrToFloat(Temperatur, TFormatSettings::Invariant());
double temp2 = StrToFloat(Temperatur2); // In my case: German locale!

printf("%8.4f %8.4f\n", temp, temp2);

The output is:

 12.4500  12.4500

You can see that it works as expected. Note that on my system, the comma is the decimal separator for the locale, and yet this code works fine with the period as decimal separator, because of the invariant format settings.

So make your choice: use TFormatSettings::Invariant() if you need independence of the locale, but don't use it if you want it to use the decimal separator for the locale of the user.

4
On

You can use StrToFloat it has a second version that takes a TFormatSettings object which you can use to specify a specific DecimalSeperator. BTW it does not return a float as its name might suggest it returns an Extended aka long double.

4
On

My bet is that your problem is the decimal point. The character used for it is one of the Windows environment variables and can vary from computer to computer. There are winapi calls to receive it but I do not remember them ...

The problem with AnsiString("1.23").ToDouble() is that catch/try will not catch the exception (at least on my compiler BDS2006). There are workarounds. I am using atoi() instead which is not crashing but rather truncate to integer when invalid character present so it can be used to detect the correct decimal point character and conversion:

char _floating_point_char=' ';         // decimal point separator
AnsiString   strnum (AnsiString s,int sig=1,int pnt=1,int hex=0,char dot=_floating_point_char);
double       str2num(AnsiString s,int sig=1,int pnt=1,int hex=0,char dot=_floating_point_char);

AnsiString strnum(AnsiString s,int sig,int pnt,int hex,char dot)
    {
    if (dot==' ')
        {
        float x;
        x=atof("0.5"); if (x>=0.25) _floating_point_char='.';
        x=atof("0,5"); if (x>=0.25) _floating_point_char=',';
        dot=_floating_point_char;
        }

    int i,l,a,e,e0,exp=pnt;
    AnsiString q="";
    l=s.Length();
    if (hex) exp=0;     // exponent is e,E so it colide with hex e,E
    e0=0; for (i=1;i<=l;i++)
        {
        e=0;
        a=s[i];
        if ((a>='0')&&(a<='9'))       { e=1; q+=char(a  ); sig=0; }
        if ((a>='A')&&(a<='F'&&(hex))){ e=1; q+=char(a  ); sig=0; }
        if ((a>='a')&&(a<='f'&&(hex))){ e=1; q+=char(a  ); sig=0; }
        if ((a=='e')||(a=='E'))
         if (!hex)   { if (!exp) break; e=1; q+=char('e'); exp=0; sig=1; pnt=0; e0=0; }
        if (a=='+')  { if (!sig) break; e=1;               sig=0; }
        if (a=='-')  { if (!sig) break; e=1; q+=char(a  ); sig=0; }
        if (a=='.')  { if (!pnt) break; e=1; q+=char(dot); pnt=0; }
        if (a==',')  { if (!pnt) break; e=1; q+=char(dot); pnt=0; }
        if ((e0)&&(!e)) break;
        e0|=e;
        }
    if (q.Length()<=0) q="0";
    return q;
    }
double str2num(AnsiString s,int sig,int pnt,int hex,char dot)
    {
    return atof(strnum(s,sig,pnt,hex,dot).c_str());
    }

It simply detect if . or , is the right one and then replace it in string before conversion... Of coarse fetching the correct decimal point character from winapi is safer as the decimal point separator can be anything... You can ignore the hex part I am using this for any kind of numbers ...