string ldecimal(double x,double toler)
{
double x2;
int h,i,iexp,chexp;
size_t zpos;
char *dotpos,*epos,*pLcNumeric;
string ret,s,m,antissa,exponent,saveLcNumeric;
char buffer[32],fmt[8];
assert(toler>=0);
pLcNumeric=getenv("LC_NUMERIC");
if (pLcNumeric)
saveLcNumeric=pLcNumeric;
setenv("LC_NUMERIC","C",true);
if (toler>0 && x!=0)
{
iexp=floor(log10(fabs(x/toler))-1);
if (iexp<0)
iexp=0;
}
else
iexp=DBL_DIG-1;
h=-1;
i=iexp;
while (true)
{
sprintf(fmt,"%%.%de",i);
sprintf(buffer,fmt,x);
x2=atof(buffer);
if (h>0 && (fabs(x-x2)<=toler || i>=DBL_DIG+3))
break;
if (fabs(x-x2)>toler || i<=0)
h=1;
i+=h;
}
dotpos=strchr(buffer,'.');
epos=strchr(buffer,'e');
if (epos && !dotpos) // e.g. 2e+00 becomes 2.e+00
{
memmove(epos+1,epos,buffer+31-epos);
dotpos=epos++;
*dotpos=='.';
}
if (dotpos && epos)
{
m=string(buffer,dotpos-buffer);
antissa=string(dotpos+1,epos-dotpos-1);
exponent=string(epos+1);
if (m.length()>1)
{
s=m.substr(0,1);
m.erase(0,1);
}
iexp=atoi(exponent.c_str());
zpos=antissa.find_last_not_of('0');
antissa.erase(zpos+1);
iexp=stoi(exponent);
if (iexp<0 && iexp>-5)
{
antissa=m+antissa;
m="";
iexp++;
}
if (iexp>0)
{
chexp=iexp;
if (chexp>antissa.length())
chexp=antissa.length();
m+=antissa.substr(0,chexp);
antissa.erase(0,chexp);
iexp-=chexp;
}
while (iexp>-5 && iexp<0 && m.length()==0)
{
antissa="0"+antissa;
iexp++;
}
while (iexp<3 && iexp>0 && antissa.length()==0)
{
m+='0';
iexp--;
}
sprintf(buffer,"%d",iexp);
exponent=buffer;
ret=s+m;
if (antissa.length())
ret+='.'+antissa;
if (iexp)
ret+='e'+exponent;
}
else
ret=buffer;
setenv("LC_NUMERIC",saveLcNumeric.c_str(),true);
return ret;
}
string ldecimal(double x,double toler)
{
double x2;
int h,i,iexp,chexp;
size_t zpos;
char *dotpos,*epos,*pLcNumeric;
string ret,s,m,antissa,exponent,saveLcNumeric;
char buffer[32],fmt[8];
assert(toler>=0);
pLcNumeric=getenv("LC_NUMERIC");
if (pLcNumeric)
saveLcNumeric=pLcNumeric;
setenv("LC_NUMERIC","C",true);
if (toler>0 && x!=0)
{
iexp=floor(log10(fabs(x/toler))-1);
if (iexp<0)
iexp=0;
}
else
iexp=DBL_DIG-1;
h=-1;
i=iexp;
while (true)
{
sprintf(fmt,"%%.%de",i);
sprintf(buffer,fmt,x);
x2=atof(buffer);
if (h>0 && (fabs(x-x2)<=toler || i>=DBL_DIG+3))
break;
if (fabs(x-x2)>toler || i<=0)
h=1;
i+=h;
}
dotpos=strchr(buffer,'.');
epos=strchr(buffer,'e');
if (epos && !dotpos) // e.g. 2e+00 becomes 2.e+00
{
memmove(epos+1,epos,buffer+31-epos);
dotpos=epos++;
*dotpos=='.';
}
if (dotpos && epos)
{
m=string(buffer,dotpos-buffer);
antissa=string(dotpos+1,epos-dotpos-1);
exponent=string(epos+1);
if (m.length()>1)
{
s=m.substr(0,1);
m.erase(0,1);
}
iexp=atoi(exponent.c_str());
zpos=antissa.find_last_not_of('0');
antissa.erase(zpos+1);
iexp=stoi(exponent);
if (iexp<0 && iexp>-5)
{
antissa=m+antissa;
m="";
iexp++;
}
if (iexp>0)
{
chexp=iexp;
if (chexp>antissa.length())
chexp=antissa.length();
m+=antissa.substr(0,chexp);
antissa.erase(0,chexp);
iexp-=chexp;
}
while (iexp>-5 && iexp<0 && m.length()==0)
{
antissa="0"+antissa;
iexp++;
}
while (iexp<3 && iexp>0 && antissa.length()==0)
{
m+='0';
iexp--;
}
sprintf(buffer,"%d",iexp);
exponent=buffer;
ret=s+m;
if (antissa.length())
ret+='.'+antissa;
if (iexp)
ret+='e'+exponent;
}
else
ret=buffer;
setenv("LC_NUMERIC",saveLcNumeric.c_str(),true);
return ret;
}
To copy to clipboard, switch view to plain text mode
The function is used to format numbers when writing to files, so it has to use '.' for the decimal point regardless of locale. I added the saving and restoring LC_NUMERIC code to fix this bug. It didn't work.
LANG=en_DK.UTF-8
LANGUAGE=en_US:es
LC_CTYPE="en_DK.UTF-8"
LC_NUMERIC="en_DK.UTF-8"
LC_TIME="en_DK.UTF-8"
LC_COLLATE="en_DK.UTF-8"
LC_MONETARY="en_DK.UTF-8"
LC_MESSAGES="en_DK.UTF-8"
LC_PAPER="en_DK.UTF-8"
LC_NAME="en_DK.UTF-8"
LC_ADDRESS="en_DK.UTF-8"
LC_TELEPHONE="en_DK.UTF-8"
LC_MEASUREMENT="en_DK.UTF-8"
LC_IDENTIFICATION="en_DK.UTF-8"
LC_ALL=
LANG=en_DK.UTF-8
LANGUAGE=en_US:es
LC_CTYPE="en_DK.UTF-8"
LC_NUMERIC="en_DK.UTF-8"
LC_TIME="en_DK.UTF-8"
LC_COLLATE="en_DK.UTF-8"
LC_MONETARY="en_DK.UTF-8"
LC_MESSAGES="en_DK.UTF-8"
LC_PAPER="en_DK.UTF-8"
LC_NAME="en_DK.UTF-8"
LC_ADDRESS="en_DK.UTF-8"
LC_TELEPHONE="en_DK.UTF-8"
LC_MEASUREMENT="en_DK.UTF-8"
LC_IDENTIFICATION="en_DK.UTF-8"
LC_ALL=
To copy to clipboard, switch view to plain text mode
LC_NUMERIC is actually unset.
Bookmarks