String GCC和MSVC下的strtod()和sprintf()不一致
我正在为Windows和Mac OS X开发一个跨平台应用程序,我有两个标准C库函数的问题:String GCC和MSVC下的strtod()和sprintf()不一致,string,gcc,double,visual-c++,String,Gcc,Double,Visual C++,我正在为Windows和Mac OS X开发一个跨平台应用程序,我有两个标准C库函数的问题: strtod()-字符串到双精度转换 sprintf()-用于输出双精度浮点数时) 他们的GCC和MSVC版本返回不同的结果,以尾数的一些数字表示。但如果指数值较大,则起关键作用。例如: MSVC: 9,999999999999999500000000000000e+032 GCC: 9,999999999999999455752309870428e+32 MSVC: 9,999999999999
-字符串到双精度转换strtod()
-用于输出双精度浮点数时)sprintf()
MSVC: 9,999999999999999500000000000000e+032
GCC: 9,999999999999999455752309870428e+32
MSVC: 9,999999999999999500000000000000e+033
GCC: 9,999999999999999455752309870428e+33
MSVC: 9,999999999999999700000000000000e+034
GCC: 9,999999999999999686336610791798e+34
在MSVC和GCC下,输入测试编号具有相同的二进制表示形式
我正在寻找这些函数的一个经过良好测试的跨平台开源实现,或者仅仅是一对能够正确、一致地将double转换为string并返回的函数
我已经尝试过clib GCC实现,但是代码太长,太依赖于其他源文件,所以我认为修改会很困难
您建议使用什么样的字符串到双精度和双精度到字符串函数?在浮点数和字符串之间进行转换很难-非常困难。关于这一主题的论文很多,包括:
举例说明
double通常存储16位(有些人可能认为是17位)有效十进制数字。MSVC正在处理17位数字。除此之外的就是噪音。GCC按照您的要求执行,但是双精度中没有足够的位来保证您请求的额外14位。如果您有16字节的“
长双精度”
”值(SPARC、PPC、Intel x86_64 for Mac),那么您可能需要32位有效数字。然而,你所展示的差异是QoI;我甚至可能会说MS在这方面比GCC/glibc做得更好(我不常这么说!)。我所知道的以十进制打印浮点数精确值的唯一算法如下:
dtoa
返回一个字符串,该字符串将无损地转换回相同的double
如果您将aisd
重写为测试所有string
-to-float
实现,您将在它们之间拥有可移植的输出
// Return whether a string represents the given double.
int aisd(double f, char* s) {
double r;
sscanf(s, "%lf", &r);
return r == f;
}
// Return the shortest lossless string representation of an IEEE double.
// Guaranteed to fit in 23 characters (including the final '\0').
char* dtoa(char* res, double f) {
int i, j, lenF = 1e9;
char fmt[8];
int e = floor(log10(f)) + 1;
if (f > DBL_MAX) { sprintf(res, "1e999"); return res; } // converts to Inf
if (f < -DBL_MAX) { sprintf(res, "-1e999"); return res; } // converts to -Inf
if (isnan(f)) { sprintf(res, "NaN"); return res; } // NaNs don't work under MSVCRT
// compute the shortest representation without exponent ("123000", "0.15")
if (!f || e>-4 && e<21) {
for (i=0; i<=20; i++) {
sprintf(fmt, "%%.%dlf", i);
sprintf(res, fmt, f);
if (aisd(f, res)) { lenF = strlen(res); break; }
}
}
if (!f) return res;
// compute the shortest representation with exponent ("123e3", "15e-2")
for (i=0; i<19; i++) {
sprintf(res, "%.0lfe%d", f * pow(10,-e), e); if (aisd(f, res)) break;
j = strlen(res); if (j >= lenF) break;
while (res[j] != 'e') j--;
res[j-1]--; if (aisd(f, res)) break; // try mantissa -1
res[j-1]+=2; if (aisd(f, res)) break; // try mantissa +1
e--;
}
if (lenF <= strlen(res)) sprintf(res, fmt, f);
return res;
}
//返回字符串是否表示给定的双精度。
内部aisd(双f,字符*s){
双r;
sscanf(s、%lf、&r);
返回r==f;
}
//返回IEEE double的最短无损字符串表示形式。
//保证可容纳23个字符(包括最后的“\0”)。
char*dtoa(char*res,双f){
int i,j,lenF=1e9;
char-fmt[8];
内部e=楼层(log10(f))+1;
如果(f>DBL_MAX){sprintf(res,“1e999”);返回res;}//转换为Inf
如果(f<-DBL_MAX){sprintf(res,“-1e999”);返回res;}//转换为-Inf
if(isnan(f)){sprintf(res,“NaN”);return res;}//NaN不在MSVCRT下工作
//计算不带指数的最短表示法(“123000”、“0.15”)
如果(!f | | e>-4&&e)当你说“不同的结果”,您的意思是您得到的结果不正确,还是仅仅在第n个小数位上有一点差异?它们在尾数的某些数字上有差异。但如果指数值较大,则它起着关键作用。例如:MSVC:999999999999999500000000000000e+032
GCC:999999999999999999999455752309870428e+32
MSVC:99999999999999999999950000000000000E+033 GCC:999999999999999999455752309870428E+33 MSVC:999999999999999700000000000E+034 GCC:999999999999999686336610791798e+34输入测试数在MSVC和GCC下有一个相同的二进制重新表述。这不是一个关键角色;这是一个微不足道的区别。您无法理解浮点。即使浮点运算的结果是不精确的,每个浮点值都对应一个特定的精确的二元有理数。打印浮点值的好算法将能够打印这个精确的数字。令人满意的(根据标准)算法将打印足够的有效数字,以唯一地确定原始浮点值是什么。我支持Jonathan。一个令人满意的(符合标准的)算法将打印足够的有效数字,以唯一地确定原始值(GCC和MSVC都管理这个)。一个好的算法也会将十进制结果四舍五入到与二进制表示法中最低有效位近似相同的精度,以避免暗示结果比二进制表示法允许的精度更高。这似乎无法回答问题