你可以说我对C比较陌生,但我需要澄清一个问题。 我有一个代表数字的char []。如果此char []长于LONG_MAX,我想告诉用户它太长了。问题是,当我将其值与浮点数进行比较时,它会被截断。这就是我的意思。
int main(int argc, char ** argv) {
char str[] = argv[1]; /* I set it to 9223372036854775809, only +1 higher than LONG_MAX */
double l = atof(str);
double j = LONG_MAX;
printf("%lf\n", l); /* This prints 9223372036854775808.000000, which is LONG_MAX ??? WHY?? */
printf("%lf\n", j); /* This prints same as above, 9223372036854775808.000000 */
printf("%s\n", l > j ? "true" : "false"); /* false */
return 0; /* what am I doing wrong? */
}
更新:
我尝试了你的iret解决方案,但我仍遇到了同样的问题
j = LONG_MAX;
int iret = sscanf (str, "%lf", &l);
if (iret != 1)
return 0; /* conversion was bad */
else {
if (l > j || l < -(j))
return 0; /* too small or too large */
}
printf("%lf\n", l);
printf("%lf\n", j);
printf("%s\n", l > j ? "true" : "false");
答案 0 :(得分:1)
您可以使用strtol
轻松检查溢出,但需要一些额外的工作。
const char *str = ...;
char *e;
long x;
errno = 0;
x = strtol(str, &e, 0);
if (!*str || *e) {
fprintf(stderr, "invalid number: %s\n", str);
exit(1);
}
if ((x == LONG_MAX || x == LONG_MIN) && errno == ERANGE) {
fprintf(stderr, "number too large: %s\n", str);
exit(1);
}
现在,我们来谈谈strtod
(或atof
的问题,这只是strtod
的破解版本。)
如果您将9223372036854775809
转换为double
,则9223372036854775808
正确。 double
具有53位精度,而64位long
具有64位精度。一旦开始使用浮点数,就需要为舍入做好准备。
例如,以下代码中存在舍入错误。你能发现它吗?
double x = 0.1;
脚注:我假设这里有64位long
和IEEE双精度double
。
答案 1 :(得分:0)
根据atof的“man”页面:
http://linux.die.net/man/3/atof
atof()函数转换指向的字符串的初始部分 由nptr加倍。 ... atof()不会检测错误。
这就是为什么我更喜欢使用“sscanf”:
int iret = sscanf (SOME_TEXT, "%lf", &SOME_DOUBLE);
如果“iret!= 1”,那么我知道发生了错误,可以采取相应的措施。
... IMHO
PS:
你为什么不宣布“l”和“j”。调皮顽皮!您应该始终声明您的变量,即使在FORTRAN和Basic中也是如此;)
为什么不将它们声明为float(“%f”)或double(“%lf”)?
答案 2 :(得分:0)
我相信你输入两个值的原因是“9223372036854775808.000000”是由于浮点近似的精度限制。
顺便说一下,该值不是LONG_MAX
,而是LONG_MAX + 1 -> 2^63
。
根据定义,LONG_MAX
的表示完全(作为整数)需要63位精度。但是,在像double
这样的64位浮点表示中,只有53位精度,因为其他位需要存储符号和指数。这就是为什么LONG_MAX
和LONG_MAX + 2
最终都被舍入到9223372036854775808 <=> 2^63
。
要正确处理这种情况,或许请查看strtol
,当输入超出范围时,会设置错误代码。
答案 3 :(得分:0)
你的长期似乎是63位。浮点数有23个有效位(或24个有前导1)。你的长点在高24位中完全相同。所以他们变得一样。 浮点数基本上是尾数* 2 ^指数。指数确保幅度仍然匹配。但是你只有23位的尾数。所以它变成top23bitsoflong * 2 ^(numberofremainingbits)。 这有点简化,忽略了前导和指数偏差。