I would like to convert a float or double to a decimal fixed point integer in C language. I am searching the most appropriate (robust) solution for this problem, considering C language's specification.
我想将一个float或double转换为C语言中的十进制定点整数。考虑到C语言的规范,我正在为这个问题寻找最合适(强大)的解决方案。
The problem for example is along the lines of this:
例如,问题在于:
double d = 15.6;
int i;
...
i = (int)(d * 10.0); /* I am excepting getting 156 in 'i' */
Relevant elements of the standard (using a C99 one, ISO/IEC 9899:TC3, see this question for download) as far as I see:
据我所知,标准的相关要素(使用C99,ISO / IEC 9899:TC3,请参阅此问题进行下载):
- 6.3.1.4 / 1: When a finite value of real floating type is converted to an integer type other than
_Bool
, the fractional part is discarded (i.e., the value is truncated towards zero). (...) - 6.3.1.4 / 1:当实数浮动类型的有限值转换为除_Bool之外的整数类型时,小数部分被丢弃(即,该值被截断为零)。 (......)
- 6.4.4.2 / 3: (...) For decimal floating constants, (...) the result is either the nearest representable value, or the larger or smaller representable value immediately adjacent to the nearest representable value, chosen in an implementation-defined manner. (...)
- 6.4.4.2 / 3 :( ...)对于十进制浮点常数,(...)结果是最接近的可表示值,或者与实现中选择的最接近的可表示值紧邻的较大或较小的可表示值 - 定义的方式。 (......)
The 15.6
in the example has not got an exact representation in IEEE double, so I would except d
to get something slightly above, or slightly below. The problem is with the "slightly below" part, then i
in the example wouldn't get the excepted result (would get 155
instead).
示例中的15.6在IEEE double中没有得到精确的表示,所以除了d之外我会得到略高于或稍低的东西。问题是“略低于”部分,然后我在示例中不会获得例外结果(将获得155)。
My obvious take would be something like this (considering zero or positive values only):
我明显的看法是这样的(仅考虑零值或正值):
i = (int)(d * 10.0 + 0.5);
At least if I interpreted the C standard correctly. I ask because due to the "implementation-defined" behavior, one may experience a consistent result while in the reality some other implementation may break the program, so trial and error is not an adequate method for finding an appropriate solution.
至少如果我正确地解释了C标准。我问,因为由于“实现定义”行为,人们可能会遇到一致的结果,而在现实中,其他一些实现可能会破坏程序,因此试错不是找到合适解决方案的适当方法。
In particular the following question relates this problem, which I believe has an incorrect accepted answer.
特别是以下问题涉及这个问题,我认为这个问题的答案是错误的。
1 个解决方案
#1
2
C99 specifies a round function for exactly this purpose. Use that, then cast to int.
C99为此目的指定了一个圆函数。使用它,然后转换为int。
UPDATE: for C89, you could try
更新:对于C89,你可以试试
double y = floor(x);
double z = x == y ? x : floor(2.0*x-y);
This should give the same as C99 round
, except that negative numbers with fractional parts equal to 0.5 will be rounded upwards (like Java), and zeros may be signed incorrectly (this is based on a similar trick due to Arch Robinson).
这应该与C99圆相同,除了小数部分等于0.5的负数将向上舍入(如Java),并且零可能被错误地签名(这是基于Arch Robinson的类似技巧)。
#1
2
C99 specifies a round function for exactly this purpose. Use that, then cast to int.
C99为此目的指定了一个圆函数。使用它,然后转换为int。
UPDATE: for C89, you could try
更新:对于C89,你可以试试
double y = floor(x);
double z = x == y ? x : floor(2.0*x-y);
This should give the same as C99 round
, except that negative numbers with fractional parts equal to 0.5 will be rounded upwards (like Java), and zeros may be signed incorrectly (this is based on a similar trick due to Arch Robinson).
这应该与C99圆相同,除了小数部分等于0.5的负数将向上舍入(如Java),并且零可能被错误地签名(这是基于Arch Robinson的类似技巧)。