Skip to content

Commit 1305a25

Browse files
committed
2 parents 7fd943e + f855f72 commit 1305a25

File tree

6 files changed

+26
-22
lines changed

6 files changed

+26
-22
lines changed

content/english/hpc/arithmetic/integer.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ This seems like an important architecture aspect, but in most cases, it doesn't
9393
- Little-endian has the advantage that you can cast a value to a smaller type (e.g., `long long` to `int`) by just loading fewer bytes, which in most cases means doing nothing — thanks to *register aliasing*, `eax` refers to the first 4 bytes of `rax`, so conversion is essentially free. It is also easier to read values in a variety of type sizes — while on big-endian architectures, loading an `int` from a `long long` array would require shifting the pointer by 2 bytes.
9494
- Big-endian has the advantage that higher bytes are loaded first, which in theory can make highest-to-lowest routines such as comparisons and printing faster. You can also perform certain checks such as finding out whether a number is negative by only loading its first byte.
9595

96-
Big-endian is also more "natural" — this is how we write binary numbers on paper — but the advantage of having faster type conversions outweigh it. For this reason, little-endian is used by default on most hardware, although some CPUs are "bi-endian" and can be configured to switch modes on demand.
96+
Big-endian is also more "natural" — this is how we write binary numbers on paper — but the advantage of having faster type conversions outweights it. For this reason, little-endian is used by default on most hardware, although some CPUs are "bi-endian" and can be configured to switch modes on demand.
9797

9898
### 128-bit Integers
9999

content/english/hpc/profiling/noise.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
---
22
title: Getting Accurate Results
33
weight: 10
4+
published: true
45
---
56

67
It is not an uncommon for there to be two library algorithm implementations, each maintaining its own benchmarking code, and each claiming to be faster than the other. This confuses everyone involved, especially the users, who have to somehow choose between the two.
@@ -111,7 +112,7 @@ for (int i = 0; i < N; i++)
111112
checksum ^= lower_bound(q[i]);
112113
```
113114

114-
It is also sometimes convenient to combine the warm-up run with answer validation, it if is more complicated than just computing some sort of checksum.
115+
It is also sometimes convenient to combine the warm-up run with answer validation, if it is more complicated than just computing some sort of checksum.
115116

116117
**Over-optimization.** Sometimes the benchmark is outright erroneous because the compiler just optimized the benchmarked code away. To prevent the compiler from cutting corners, you need to add checksums and either print them somewhere or add the `volatile` qualifier, which also prevents any sort of interleaving of loop iterations.
117118

@@ -127,10 +128,10 @@ https://github.com/sosy-lab/benchexec
127128

128129
The issues we've described produce *bias* in measurements: they consistently give advantage to one algorithm over the other. There are other types of possible problems with benchmarking that result in either unpredictable skews or just completely random noise, thus increasing *variance*.
129130

130-
These type of issues are caused by side effects and some sort of external noise, mostly due to noisy neighbors and CPU frequency scaling:
131+
These types of issues are caused by side effects and some sort of external noise, mostly due to noisy neighbors and CPU frequency scaling:
131132

132133
- If you benchmark a compute-bound algorithm, measure its performance in cycles using `perf stat`: this way it will be independent of clock frequency, fluctuations of which is usually the main source of noise.
133-
- Otherwise, set core frequency to the what you expect it to be and make sure nothing interferes with it. On Linux you can do it with `cpupower` (e.g., `sudo cpupower frequency-set -g powersave` to put it to minimum or `sudo cpupower frequency-set -g ondemand` to enable turbo boost). I use a [convenient GNOME shell extension](https://extensions.gnome.org/extension/1082/cpufreq/) that has a separate button to do it.
134+
- Otherwise, set core frequency to what you expect it to be and make sure nothing interferes with it. On Linux you can do it with `cpupower` (e.g., `sudo cpupower frequency-set -g powersave` to put it to minimum or `sudo cpupower frequency-set -g ondemand` to enable turbo boost). I use a [convenient GNOME shell extension](https://extensions.gnome.org/extension/1082/cpufreq/) that has a separate button to do it.
134135
- If applicable, turn hyper-threading off and attach jobs to specific cores. Make sure no other jobs are running on the system, turn off networking and try not to fiddle with the mouse.
135136

136137
You can't remove noises and biases completely. Even a program's name can affect its speed: the executable's name ends up in an environment variable, environment variables end up on the call stack, and so the length of the name affects stack alignment, which can result in data accesses slowing down due to crossing cache line or memory page boundaries.

content/russian/cs/decomposition/scanline.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
---
22
title: Сканирующая прямая
33
authors:
4-
- Сергей Слотин
4+
- Сергей Слотин
55
prerequisites:
6-
- /cs/range-queries
7-
- /cs/segment-tree
6+
- /cs/range-queries
7+
- /cs/segment-tree
88
weight: 1
9+
published: true
910
---
1011

1112
Метод сканирующей прямой (англ. *scanline*) заключается в сортировке точек на координатной прямой либо каких-то абстрактных «событий» по какому-то признаку и последующему проходу по ним.
@@ -22,7 +23,7 @@ weight: 1
2223

2324
Это решение можно улучшить. Отсортируем интересные точки по возрастанию координаты и пройдем по ним слева направо, поддерживая количество отрезков `cnt`, которые покрывают данную точку. Если в данной точке начинается отрезок, то надо увеличить `cnt` на единицу, а если заканчивается, то уменьшить. После этого пробуем обновить ответ на задачу текущим значением `cnt`.
2425

25-
Как такое писать: нужно представить интересные точки в виде структур с полями «координата» и «тип» (начало / конец) и отсортировать со своим компаратором. Удобно начало отрезка обозначать +1, а конец -1, чтобы просто прибавлять к `cnt` это значение и на разбирать случае.
26+
Как такое писать: нужно представить интересные точки в виде структур с полями «координата» и «тип» (начало / конец) и отсортировать со своим компаратором. Удобно начало отрезка обозначать +1, а конец -1, чтобы просто прибавлять к `cnt` это значение и не разбивать на случаи.
2627

2728
Единственный нюанс — если координаты двух точек совпали, чтобы получить правильный ответ, сначала надо рассмотреть все начала отрезков, а только потом концы (чтобы при обновлении ответа в этой координате учлись и правые, и левые граничные отрезки).
2829

content/russian/cs/persistent/persistent-array.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22
title: Структуры с откатами
33
weight: 1
44
authors:
5-
- Сергей Слотин
6-
date: 2021-09-12
5+
- Сергей Слотин
6+
date: {}
7+
published: true
78
---
89

910
Состояние любой структуры как-то лежит в памяти: в каких-то массивах, или в более общем случае, по каким-то определенным адресам в памяти. Для простоты, пусть у нас есть некоторый массив $a$ размера $n$, и нам нужно обрабатывать запросы присвоения и чтения, а также иногда откатывать изменения обратно.
@@ -20,7 +21,7 @@ int a[N];
2021
stack< pair<int, int> > s;
2122

2223
void change(int k, int x) {
23-
l.push({k, a[k]});
24+
s.push({k, a[k]});
2425
a[k] = x;
2526
}
2627

@@ -84,7 +85,7 @@ void rollback() {
8485

8586
```cpp
8687
int t = 0;
87-
vector<int> versions[N];
88+
vector< pair<int, int> > versions[N];
8889

8990
void change(int k, int x) {
9091
versions[k].push_back({t++, x});

content/russian/cs/range-queries/sqrt-structures.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
---
22
title: Корневые структуры
33
authors:
4-
- Сергей Слотин
5-
- Иван Сафонов
4+
- Сергей Слотин
5+
- Иван Сафонов
66
weight: 6
7-
date: 2021-09-13
7+
date: 2022-08-16
88
---
99

1010
Корневые оптимизации можно использовать много для чего, в частности в контексте структур данных.
@@ -23,16 +23,15 @@ date: 2021-09-13
2323
```c++
2424
// c это и количество блоков, и также их размер; оно должно быть чуть больше корня
2525
const int maxn = 1e5, c = 330;
26-
int a[maxn], b[c];
27-
int add[c];
26+
int a[maxn], b[c], add[c];
2827

2928
for (int i = 0; i < n; i++)
3029
b[i / c] += a[i];
3130
```
3231

33-
Заведем также массив `add` размера $\sqrt n$, который будем использовать для отложенной операции прибавления на блоке. Будем считать, что реальное значение $i$-го элемента равно `a[i] + add[i / c]`.
32+
Заведем также массив `add` размера $\sqrt n$, который будем использовать для отложенной операции прибавления на блоке: будем считать, что реальное значение $i$-го элемента равно `a[i] + add[i / c]`.
3433

35-
Теперь мы можем отвечать на запросы первого типа за $O(\sqrt n)$ на запрос:
34+
Теперь мы можем отвечать на запросы первого типа за $O(\sqrt n)$ операций на запрос:
3635

3736
1. Для всех блоков, лежащих целиком внутри запроса, просто возьмём уже посчитанные суммы и сложим.
3837
2. Для блоков, пересекающихся с запросом только частично (их максимум два — правый и левый), проитерируемся по нужным элементам и поштучно прибавим к ответу.
@@ -68,6 +67,7 @@ void upd(int l, int r, int x) {
6867
l += c;
6968
}
7069
else {
70+
b[l / c] += x;
7171
a[l] += x;
7272
l++;
7373
}
@@ -111,8 +111,8 @@ vector< vector<int> > blocks;
111111
// возвращает индекс блока и индекс элемента внутри блока
112112
pair<int, int> find_block(int pos) {
113113
int idx = 0;
114-
while (blocks[idx].size() >= pos)
115-
pos -= blocks[idx--].size();
114+
while (blocks[idx].size() <= pos)
115+
pos -= blocks[idx++].size();
116116
return {idx, pos};
117117
}
118118
```

content/russian/cs/sorting/selection.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
---
22
title: Сортировка выбором
33
weight: 2
4+
published: true
45
---
56

67
Похожим методом является **сортировка выбором** (минимума или максимума).
@@ -10,7 +11,7 @@ weight: 2
1011
```cpp
1112
void selection_sort(int *a, int n) {
1213
for (int k = 0; k < n - 1; k++)
13-
for (j = k + 1; j < n; j++)
14+
for (int j = k + 1; j < n; j++)
1415
if (a[k] > a[j])
1516
swap(a[j], a[k]);
1617
}

0 commit comments

Comments
 (0)