导语
“向上取整”是编程中最常用的小操作之一,但 C 标准库并没有给整数版本开箱即用的接口。本文总结几种零依赖、可嵌入的写法,并指出浮点场景的正确打开方式。
一、需求场景
- 分页计算:总记录数 n,每页 m 条,需要多少页?
- 内存对齐:申请 n 字节,按 m 字节对齐,至少分配多少?
- 任务打包:n 个任务,每批处理 m 个,需要多少批?
以上问题本质都是「n ÷ m 向上取整」。
二、整数向上取整:一句代码就够
int ceildiv(int n, int m)
{
return (n + m - 1) / m; /* m > 0 时成立 */
}
原理:先把余数“补满”到 m-1,再整除 m,相当于进一位。
复杂度:O(1),无分支,不调用任何库。
三、宏版:编译期内联
#define CEILDIV(n, m) (((n) + (m) - 1) / (m))
注意:m 为负数时需先取绝对值或另行处理。
四、浮点场景:用标准库 ceil
#include <math.h>
double x = 10.0 / 3.0;
double y = ceil(x); /* y == 4.0 */
返回类型仍是浮点,如需整数再强转:(int)ceil(x)。
五、完整示例
#include <stdio.h>
#include <math.h>
#define CEILDIV(n, m) (((n) + (m) - 1) / (m))
int main(void)
{
int n = 10, m = 3;
printf("integer ceildiv: %d\n", CEILDIV(n, m)); /* 4 */
double x = (double)n / m;
printf("float ceil: %.0f\n", ceil(x)); /* 4 */
return 0;
}
六、常见疑问
- 为什么标准库没有整数 ceil?
历史原因:早期 C 主要面向系统/底层,整数除法已够用,且「(a+b-1)/b」足够简单。 - 会溢出吗?
当m > 0且a + m - 1不超过对应类型最大值时安全;若担心,可用更大宽度类型或判断分支。 - 负数怎么办?
若 m 为负,先取绝对值;若 a 为负,需先定义“向上”语义(向零还是向负无穷)。