有没有办法在C中舍入数字?
我不想使用ceil和floor。还有其他选择吗?
当我用Google搜索答案时,我遇到了这段代码:
(int)(num < 0 ? (num - 0.5) : (num + 0.5))
即使浮点数= 4.9,上面的行总是将值打印为4。
答案 0 :(得分:9)
4.9 + 0.5是5.4,除非你的编译器被严重破坏,否则它不可能舍入到4。
我刚刚确认Google搜索代码为4.9提供了正确答案。
marcelo@macbookpro-1:~$ cat round.c
#include <stdio.h>
int main() {
float num = 4.9;
int n = (int)(num < 0 ? (num - 0.5) : (num + 0.5));
printf("%d\n", n);
}
marcelo@macbookpro-1:~$ make round && ./round
cc round.c -o round
5
marcelo@macbookpro-1:~$
答案 1 :(得分:3)
一般解决方案是使用rint()并根据需要设置FLT_ROUNDS舍入模式。
答案 2 :(得分:3)
我不确定这是个好主意。该代码依赖于强制转换,我很确定精确的截断是未定义的。
float result = (num - floor(num) > 0.5) ? ceil(num) : floor(num);
我会说这是一个更好的方式(这基本上是Shiroko发布的),因为它不依赖于任何演员阵容。
答案 3 :(得分:3)
要在C中舍入float
,有3个<math.h>
函数可以满足需要。建议rintf()
。
float nearbyintf(float x);
nearbyint
函数将它们的参数围绕浮点格式的整数值,使用当前的舍入方向并且不引发“不精确的”浮点异常。 C11dr§7.12.9.32
或强>
float rintf(float x);
rint
函数与nearbyint
函数(7.12.9.3)的不同之处仅在于,如果结果不同,rint
函数可能会引发''不精确''浮点异常来自论证的价值。 C11dr§7.12.9.42
或强>
float roundf(float x);
round
函数将它们的参数四舍五入为浮点格式的最接近的整数值,无论当前的舍入方向如何,都将中间情况四舍五入。 C11dr§7.12.9.62
实施例
#include <fenv.h>
#include <math.h>
#include <stdio.h>
void rtest(const char *fname, double (*f)(double x), double x) {
printf("Clear inexact flag :%s\n", feclearexcept(FE_INEXACT) ? "Fail" : "Success");
printf("Set round to nearest mode:%s\n", fesetround(FE_TONEAREST) ? "Fail" : "Success");
double y = (*f)(x);
printf("%s(%f) --> %f\n", fname,x,y);
printf("Inexact flag :%s\n", fetestexcept(FE_INEXACT) ? "Inexact" : "Exact");
puts("");
}
int main(void) {
double x = 8.5;
rtest("nearbyint", nearbyint, x);
rtest("rint", rint, x);
rtest("round", round, x);
return 0;
}
输出
Clear inexact flag :Success
Set round to nearest mode:Success
nearbyint(8.500000) --> 8.000000
Inexact flag :Exact
Clear inexact flag :Success
Set round to nearest mode:Success
rint(8.500000) --> 8.000000
Inexact flag :Inexact
Clear inexact flag :Success
Set round to nearest mode:Success
round(8.500000) --> 9.000000
Inexact flag :Exact
OP的代码有什么弱点?
(int)(num < 0 ? (num - 0.5) : (num + 0.5))
如果num
的值不在int
范围内,则广告(int)
会导致未定义的行为。
num +/- 0.5
导致答案不准确时。这不太可能,因为0.5
是double
,导致添加的精度高于float
。当num
和0.5
具有相同的精度时,将0.5
添加到数字可能会导致数字舍入答案。 (这不是OP职位的整数舍入。)示例:小于0.5的数字应该按照每个OP的目标舍入为0,但是num + 0.5
会导致1.0和最小double
之间的确切答案不到1.0。由于确切的答案是不可表示的,因此总和通常为1.0,导致答案不正确。大量的情况也会发生类似的情况。
OP的困境“即使float num =4.9
,上述行总是将值打印为4。”如上所述,无法解释。需要额外的代码/信息。我怀疑OP可能使用过int num = 4.9;
。
// avoid all library calls
// Relies on UINTMAX_MAX >= FLT_MAX_CONTINUOUS_INTEGER - 1
float my_roundf(float x) {
// Test for large values of x
// All of the x values are whole numbers and need no rounding
#define FLT_MAX_CONTINUOUS_INTEGER (FLT_RADIX/FLT_EPSILON)
if (x >= FLT_MAX_CONTINUOUS_INTEGER) return x;
// Positive numbers
// Important: _no_ precision lost in the subtraction
// This is the key improvement over OP's method
if (x > 0) {
float floor_x = (float)(uintmax_t) x;
if (x - floor_x >= 0.5) floor_x += 1.0f;
return floor_x;
}
if (x < 0) return -my_roundf(-x);
return x; // x is 0.0, -0.0 or NaN
}
经过测试 - 稍后我会有时间这样做。
答案 4 :(得分:1)
我认为你在寻找的是:
int n = (d - floor(d) > 0.5) ? ceil(d) : floor(d);
答案 5 :(得分:1)
Google搜索代码正常运行。它背后的想法是,当小数小于0.5时向下舍入,否则向上舍入。 (int)
将float转换为一个只删除小数的int类型。如果将.5添加到正数,则会转到下一个int。如果你从负数中减去.5就会做同样的事情。
答案 6 :(得分:0)
您可以在fesetround()
中使用fenv.h
(在C99中引入)。可能的参数是宏FE_DOWNWARD
,FE_TONEAREST
,FE_TOWARDZERO
和FE_UPWARD
,但请注意,并非所有宏都必须定义 - 只有平台/实现支持的那些是。然后,您可以使用round
(也是C99)中的各种rint
,nearbyint
和math.h
函数。这样,您可以设置一次所需的舍入行为,并调用相同的函数,无论该值是正还是负。
(例如lround
你通常不需要设置正常使用的舍入方向来获得你想要的东西。)
答案 7 :(得分:0)
int round(double x)
{
return x >= 0.0 ? int(x + 0.5) : int(x - int(x-1) + 0.5) + int(x-1);
}
它会比使用ceil和floor的版本更快。
答案 8 :(得分:0)
舍入值x到精度p,其中0 < p&lt;无穷。 (f.ex.0.25,0.5,1,2,......)
float RoundTo(float x, float p)
{
float y = 1/p;
return int((x+(1/(y+y)))*y)/y;
}
float RoundUp(float x, float p)
{
float y = 1/p;
return int((x+(1/y))*y)/y;
}
float RoundDown(float x, float p)
{
float y = 1/p;
return int(x*y)/y;
}
答案 9 :(得分:0)
只需在数字上加上0.5并键入。 并通过将其类型转换为整数进行打印。 否则,您可以使用round(),在其中只需将参数作为相应的数字传递。
答案 10 :(得分:-4)
尝试移动上方解决方案中的括号,使其显示为:
(int)(num < 0) ? (num - 0.5) : (num + 0.5)
使用num作为4.9,它在我的机器上舍入为5。