【发布时间】:2015-02-08 19:07:06
【问题描述】:
我想用 C 语言将浮点数或双精度数转换为十进制定点整数。考虑到 C 语言的规范,我正在为这个问题寻找最合适(稳健)的解决方案。
例如,问题是这样的:
double d = 15.6;
int i;
...
i = (int)(d * 10.0); /* I am excepting getting 156 in 'i' */
据我所知,标准的相关元素(使用 C99 标准,ISO/IEC 9899:TC3,参见this question 下载):
- 6.3.1.4 / 1:当实浮点类型的有限值转换为
_Bool以外的整数类型时,小数部分被丢弃(即,该值被截断为零)。 (...) - 6.4.4.2 / 3:(...) 对于十进制浮点常量,(...) 结果是最接近的可表示值,或者是紧邻最近的可表示值的较大或较小的可表示值,在一种实现定义的方式。 (...)
示例中的 15.6 在 IEEE double 中没有得到精确的表示,所以除了 d 之外,我会得到略高于或略低于的东西。问题在于“略低于”部分,然后示例中的i 不会得到例外结果(而是会得到155)。
我的明显看法是这样的(仅考虑零或正值):
i = (int)(d * 10.0 + 0.5);
至少如果我正确解释了 C 标准。我问是因为由于“实现定义的”行为,人们可能会遇到一致的结果,而实际上其他一些实现可能会破坏程序,因此反复试验并不是找到合适解决方案的充分方法。
特别是the following question 涉及到这个问题,我认为这个问题的答案不正确。
【问题讨论】:
-
C 标准不强制使用 IEEE 浮点。从理论上讲,
d可能被表示为像15.65这样的疯狂数字。随着d变大,这变得更有可能。我想说d已经错了,你应该从一开始就使用任意精度库。 -
@Kevin:我刚才提到了 IEEE,因为即使在 IEEE 中,这个例子也说明了问题。如果按照 C 标准的措辞加上严格的“重型火炮”,当然你很快就会有一个大洞。任意精度库可能并不总是可行的,例如考虑嵌入式目标。
-
好吧,那么你必须决定你更看重哪一个:性能还是正确性?
-
我怀疑
(void) fesetround(FE_DOWNWARD);后面跟着i = (int) nearbyint(d);,但我几乎不是浮点专家,所以我不敢将这个作为答案发布。 -
@Kevin:C 语言的浮点数和双精度数不应该是那么糟糕!还是他们? (因此在最坏情况下使用标准 C 无法解决此问题)
标签: c floating-point