Skip to content

Commit 15eaa4f

Browse files
authored
Update cpp_tricks.md for ceildiv
1 parent 3867810 commit 15eaa4f

File tree

1 file changed

+60
-3
lines changed

1 file changed

+60
-3
lines changed

docs/cpp_tricks.md

+60-3
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ std::swap(a, b);
2727
2828
> {{ icon.tip }} 只需要 `#include <utility>` 就可以使用!
2929
30-
## RAII 地分配一段内存空间
30+
## 安全地分配一段内存空间
3131
32-
小彭老师:不要让我看到 new 和 delete。
32+
小彭老师:不要出现 new 和 delete,不安全
3333
3434
同学:我想要**分配一段内存空间**,你不让我 new,我还能怎么办呢?
3535
@@ -80,6 +80,63 @@ std::wstring utf8_to_wstring(std::string const &s) {
8080
}
8181
```
8282

83+
## 地板除与天花板除
84+
85+
众所周知,C语言中 `int` 相除 `/`,得到的结果也是 `int`,如果除法产生了余数,那么只会保留整数部分。
86+
87+
例如 `14 / 5`,本来应该得到 2.8。但是因为 C 语言的除法返回 `int`,结果会自动向下取整,导致得到 2。
88+
89+
```cpp
90+
int a, b;
91+
int c = a / b;
92+
```
93+
94+
等价于
95+
96+
```cpp
97+
int c = floor((float)a / b);
98+
```
99+
100+
如果 `a` 除以 `b` 除不尽,那么会找到比他大的第一个整数作为结果,这就是**地板除 (floor div)**
101+
102+
C 语言默认的就是地板除。
103+
104+
如果我想要的是向上取整,该怎么写?
105+
106+
最原始的写法是先转成浮点数来除,然后ceil函数向上取整:
107+
108+
```cpp
109+
int c = ceil((float)a / b);
110+
```
111+
112+
但是浮点数不仅低效,还有糟糕的浮点数精度误差!对于很大的整数(大于 $2^{23}$)会产生错误的结果。
113+
114+
更合理的写法是先把 `a` 加上 `b - 1`,然后再下取整地除以 `b`
115+
116+
```cpp
117+
int c = (a + b - 1) / b;
118+
```
119+
120+
这样就能产生一个向上取整的除法了。
121+
122+
如果 `a` 除以 `b` 除不尽,那么会找到比他大的第一个整数作为结果,这就是**天花板除 (ceil div)**
123+
124+
试试看:14 除以 5,应该得到 2.8;如果用地板除,会得到 2;如果用天花板除,会得到 3。
125+
126+
```cpp
127+
14 / 5 = 2
128+
(14 + 5 - 1) / 5 = (14 + 4) / 5 = 18 / 5 = 3
129+
```
130+
131+
试试看:10 除以 5,应该得到 2;那么无论是地板除还是天花板除,都应该得到 2。
132+
133+
```cpp
134+
10 / 5 = 2
135+
(10 + 5 - 1) / 5 = (10 + 4) / 5 = 14 / 5 = 2
136+
```
137+
138+
这就是 C 语言中实现天花板除的业界公认标准方式。
139+
83140
## 读取整个文件到字符串
84141

85142
```cpp
@@ -130,7 +187,7 @@ struct Student {
130187
Student stu{"小彭老师", 24, 123};
131188
```
132189
133-
这被称为**聚合初始化** (aggergate initialize)。只要你的类没有自定义构造函数,没有 private 成员,都可以用 `{}` 聚合初始化。
190+
这被称为**聚合初始化** (aggregate initialize)。只要你的类没有自定义构造函数,没有 private 成员,都可以用 `{}` 聚合初始化。
134191
135192
好消息:C++20 中,聚合初始化也支持 `()` 了,用起来就和传统的 C++98 构造函数一样!
136193

0 commit comments

Comments
 (0)