在GCC和MSVC下,strtod()和sprintf()不一致 [英] strtod() and sprintf() inconsistency under GCC and MSVC

查看:145
本文介绍了在GCC和MSVC下,strtod()和sprintf()不一致的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为Windows和Mac OS X的跨平台应用程序工作,我有两个标准C库函数的问题:




  • strtod() - 字符串到双转换

  • sprintf() - 用于输出双精度浮点数)



他们的GCC和MSVC版本返回不同的结果,在一些尾数数字。但是,如果指数值较大,则起到关键的作用。一个例子:

  MSVC:9,99999999999999999500000000000000e + 032 
GCC:9,999999999999999455752309870428e + 32
MSVC :9,99999999999999999500000000000000e + 033
GCC:9,9999999999999455752309870428e + 33
MSVC:9,99999999999999999700000000000000e + 034
GCC:9,999999999999999686336610791798e + 34

输入测试号在MSVC和GCC下具有相同的二进制表示。



我是寻找一个经过良好测试的跨平台的开源实现这些功能,或只是一对功能,将正确和一致地将双重转换为字符串和回来。



我已经尝试过clib GCC实现,但代码太长,太依赖于其他源文件,所以我希望适应变得困难。



什么你会推荐使用字符串到双和双字符串函数的实现?

解决方案

以下函数 dtoa 返回一个无损转换回相同的 double 的字符串。



如果您重写 aisd 以测试所有字符串

  //返回一个字符串是否表示给定的double。 
int aisd(double f,char * s){
double r;
sscanf(s,%lf,& r);
return r == f;
}

//返回IEEE double的最短无损字符串表示形式。
//保证适合23个字符(包括最后的'\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);返回res } //转换为Inf
if(f <-DBL_MAX){sprintf(res,-1e999);返回res } //转换为-Inf
if(isnan(f)){sprintf(res,NaN);返回res } // NaNs不工作在MSVCRT

//计算没有指数的最短表示(123000,0.15)
如果(!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);打破; }
}
}

if(!f)return res;

//为(i = 0; i <19; i ++)计算带指数(123e3,15e-2)
的最短表示{
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; //尝试尾数-1
res [j-1] + = 2; if(aisd(f,res))break; //尝试尾数+1
e--;
}
if(lenF< = strlen(res))sprintf(res,fmt,f);
return res;
}

请参阅 MSVCRT NaN 问题无法从MSVCRT strtod / sscanf / atof函数获取NaN。如果您不需要识别 NaN ,则可以输出无限远(1e999) 。


I'm working on a cross-platform app for Windows and Mac OS X, and I have a problem with two standard C library functions:

  • strtod() - string-to-double conversion
  • sprintf() - when used for outputting double-precision floating point numbers)

Their GCC and MSVC versions return different results, in some digits of mantissa. But it plays a cruicial role if the exponent value is large. An example:

MSVC: 9,999999999999999500000000000000e+032
GCC:  9,999999999999999455752309870428e+32
MSVC: 9,999999999999999500000000000000e+033
GCC:  9,999999999999999455752309870428e+33
MSVC: 9,999999999999999700000000000000e+034
GCC:  9,999999999999999686336610791798e+34

The input test numbers have an identical binary representation under MSVC and GCC.

I'm looking for a well-tested cross-platform open-source implementation of those functions, or just for a pair of functions that would correctly and consistently convert double to string and back.

I've already tried the clib GCC implementation, but the code is too long and too dependent on other source files, so I expect the adaptation to be difficult.

What implementations of string-to-double and double-to-string functions would you recommend?

解决方案

The following function dtoa returns a string that losslessly converts back into the same double.

If you rewrite aisd to test all of your string-to-float implementations, you'll have portable output among them.

  // 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;
  }

See Can't get a NaN from the MSVCRT strtod/sscanf/atof functions for the MSVCRT NaN problem. If you don't need to recognize NaNs, you can output infinity ("1e999") when you get one.

这篇关于在GCC和MSVC下,strtod()和sprintf()不一致的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆