首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >GCC和MSVC下的strtod()和sprintf()不一致性

GCC和MSVC下的strtod()和sprintf()不一致性
EN

Stack Overflow用户
提问于 2010-03-23 11:10:43
回答 3查看 2.2K关注 0票数 2

我正在为Windows和Mac开发一个跨平台的应用程序,我遇到了两个标准C库函数的问题:

  • strtod() -字符串到双转换
  • sprintf() -当用于输出双精度浮点数时)

他们的GCC和MSVC版本返回不同的结果,以一些数字尾数。但当指数较大时,则起着关键作用。举个例子:

代码语言:javascript
运行
复制
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和back。

我已经尝试过clib GCC的实现,但是代码太长,太依赖其他源文件,所以我预计修改会很困难。

您会推荐什么样的字符串对双和双对字符串函数的实现?

EN

回答 3

Stack Overflow用户

发布于 2010-03-23 11:52:48

浮点数和字符串之间的转换很难--非常困难。有许多关于这一问题的论文,包括:

最后一个是关于浮点小数点算法的信息宝库。

glibc实现可能会尽可能好,但它不会很短,也不会很简单。

寻址实例

一双通常存储16位(有些人可能认为是17位)的重要十进制数。MSVC正在处理17位数字。除此之外的任何东西都是噪音。GCC按你的要求做了,但是没有足够的位数来保证你所要求的额外的14位数。如果您有16字节的“long double”值(SPARC、PPC、Intel x86_64 for Mac),那么您可能需要32位数字。然而,您所展示的差异是QoI;我甚至可能认为MS比GCC/glibc在这里做得更好(而且我不经常这么说!)

票数 2
EN

Stack Overflow用户

发布于 2010-07-09 17:27:57

我所知道的在十进制中打印浮点数的确切值的唯一算法如下:

  1. 将尾数转换为十进制整数。你可以直接拆开尾数来读取尾数,也可以写一个杂乱的浮点循环,先把这个值乘以2的幂,然后把它放到范围1<=x<10中,然后一次取一个数字,转换成整数、减法和乘以10。
  2. 通过重复乘以或除以2来应用指数。这是对您生成的十进制数字的字符串的操作。每三个乘法会在左边多加一个数字。每一个分块都会在右边增加一个额外的数字。

它又慢又丑,但很管用..。

票数 0
EN

Stack Overflow用户

发布于 2011-08-08 21:06:22

下面的函数dtoa返回一个字符串,该字符串将无损地转换回相同的double

如果重写aisd以测试所有的stringfloat实现,那么它们之间就会有可移植的输出。

代码语言:javascript
运行
复制
  // 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;
  }

有关MSVCRT的无法从MSVCRT /sscanf/atof函数获得NaN问题,请参见NaN。如果不需要识别NaNs,则可以在获得无穷大("1e999")时输出。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2499329

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档