无法从 MSVCRT strtod/sscanf/atof 函数获取 NaN
有没有办法将 Windows CRT string
中的 NaN
转换为 float
函数?
原因:我正在用 C 编写一个 IEEE float
到 string
转换器,不会丢失信息(strtod
,< (code>sscanf 或 atof
返回原始 float
),前提是舍入模式不改变。
我使用的是 MinGW 或 Visual C++,因此这些调用会转到 MSVC++ 运行时。问题是我无法让它解析任何特殊值(例如 "Inf"
或 "NaN"
)。 Inf
没问题(它在解析不适合 float
的值后返回,例如 "1e999"
)。
/* Return the shortest string representation of a float with a successful scanf round-trip.
* Guaranteed to fit in 13 chars (including the final '\0').
*/
char* ftoa(char* res, float f) {
float r = 0;
int i, j, len, e = floor(log10(f)) + 1;
char fmt[8];
union { float f; int32_t i; } u = { f } ;
if (f > FLT_MAX) { sprintf(res, "1e999"); return res; }
if (f < -FLT_MAX) { sprintf(res, "-1e999"); return res; }
if ((u.i & 0x7F800000) == 0x7F800000) { // NaN
sprintf(res, u.i == 0x7FC00000 ? "%sNaN" : "%sNaN%d", u.i<0 ? "-" : "", u.i & 0x7FFFFF);
return res;
}
// compute the shortest string without exponent ("123000", "0.15")
if (!f || e>-4 && e<10) {
for (i=0; i<=10; i++) {
sprintf(fmt, "%%.%df", i);
sprintf(res, fmt, f);
sscanf(res, "%f", &r); if (r==f) break;
}
}
if (r==f) len = strlen(res);
else len = 1e9;
if (!f) return res; // handle 0 and -0
// compute the shortest string with exponent ("123e3", "15e-2")
for (i=0; i<9; i++) {
sprintf(res, "%.0fe%d", f * pow(10,-e), e); sscanf(res, "%f", &r); if (r==f) break;
j = strlen(res); if (j >= lenF) break;
while (res[j] != 'e') j--;
res[j-1]--; sscanf(res, "%f", &r); if (r==f) break; // try +-1
res[j-1]+=2; sscanf(res, "%f", &r); if (r==f) break;
e--;
}
if (len <= strlen(res)) sprintf(res, fmt, f);
return res;
}
Is there any way to get NaN
s from the Windows CRT string
to float
functions?
Why: I'm writing an IEEE float
to string
converter in C with no information loss (strtod
, sscanf
or atof
return the original float
) provided the rounding mode doesn't change.
I'm under MinGW or Visual C++, so these calls go to the MSVC++ runtime. The problem is that I can't get it to parse any special values (like "Inf"
or "NaN"
). Inf
is OK (it's returned after parsing a value that doesn't fit in a float
, such as "1e999"
).
/* Return the shortest string representation of a float with a successful scanf round-trip.
* Guaranteed to fit in 13 chars (including the final '\0').
*/
char* ftoa(char* res, float f) {
float r = 0;
int i, j, len, e = floor(log10(f)) + 1;
char fmt[8];
union { float f; int32_t i; } u = { f } ;
if (f > FLT_MAX) { sprintf(res, "1e999"); return res; }
if (f < -FLT_MAX) { sprintf(res, "-1e999"); return res; }
if ((u.i & 0x7F800000) == 0x7F800000) { // NaN
sprintf(res, u.i == 0x7FC00000 ? "%sNaN" : "%sNaN%d", u.i<0 ? "-" : "", u.i & 0x7FFFFF);
return res;
}
// compute the shortest string without exponent ("123000", "0.15")
if (!f || e>-4 && e<10) {
for (i=0; i<=10; i++) {
sprintf(fmt, "%%.%df", i);
sprintf(res, fmt, f);
sscanf(res, "%f", &r); if (r==f) break;
}
}
if (r==f) len = strlen(res);
else len = 1e9;
if (!f) return res; // handle 0 and -0
// compute the shortest string with exponent ("123e3", "15e-2")
for (i=0; i<9; i++) {
sprintf(res, "%.0fe%d", f * pow(10,-e), e); sscanf(res, "%f", &r); if (r==f) break;
j = strlen(res); if (j >= lenF) break;
while (res[j] != 'e') j--;
res[j-1]--; sscanf(res, "%f", &r); if (r==f) break; // try +-1
res[j-1]+=2; sscanf(res, "%f", &r); if (r==f) break;
e--;
}
if (len <= strlen(res)) sprintf(res, fmt, f);
return res;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
不会。如果发生溢出,它们会返回 HUGE_VAL;如果输入无法解析或发生下溢,它们会返回 0。
No. They return HUGE_VAL if overflow would occur and 0 if the input can't be parsed or underflow occurs.