diff --git a/docs/算法/采集与算法层设计说明.md b/docs/算法/采集与算法层设计说明.md index 1ed621c1..1e41d09e 100644 --- a/docs/算法/采集与算法层设计说明.md +++ b/docs/算法/采集与算法层设计说明.md @@ -205,15 +205,18 @@ flowchart TD 代码里写成 `(s_head + SAMPLE_RING_DEPTH - n) % SAMPLE_RING_DEPTH` 而不是 `(s_head - n) % DEPTH`, 是因为后者有两个独立的坑: -- **16 位无符号下溢后再取模不等价**:`s_head < n` 时减法先回绕成 `65536-(n-s_head)`, - 而 65536 不是 40 的倍数,`(x mod 65536) mod 40 ≠ x mod 40`。反例 `s_head = 3`、`n = 20`: - 正确窗首是 23,回绕后得 65519,`65519 % 40 = 39` → 整窗错位。 -- **有符号负取模**:两个 `uint16_t` 先提升成 `int`,`3 - 20 = -17`;C99 的 `%` 向零截断, - `(-17) % 40 == -17`(不是 23),再转回无符号就是一次**越界读**——不报错、不 HardFault。 +- **16 位无符号下溢后再取模不等价**:`s_head < n` 时减法先回绕成 `65536-(n-s_head)` = 65521, + 而 65536 不是 40 的倍数,`(x mod 65536) mod 40 ≠ x mod 40`。同一个例子:正确窗首是 25, + 回绕后 `65521 % 40 = 1` → 整窗错位,读到的是环尾附近。 +- **有符号负取模**:两个 `uint16_t` 先提升成 `int`,`5 - 20 = -15`;C99 的 `%` 向零截断, + `(-15) % 40 == -15`(不是 25),再转回无符号就是一次**越界读**——不报错、不 HardFault。 **先加一个 DEPTH** 同时解决两件事:`DEPTH ≡ 0 (mod DEPTH)`,加它不改变同余类、数学值不变; 而 `s_head + DEPTH - n ∈ [0, 2·DEPTH - 2]`,恒非负、远小于 65535,两种整数提升规则下都不下溢。 -逐条反例与边界自检(`n == DEPTH` 时 `start == s_head`)见 `App/algo/sample_ring.c` 同名函数的注释。 + +边界自检:`n == DEPTH` 时 `start == s_head`——环满时「下一拍要覆盖的那格」就是最老点; +未写满时 `s_head == s_filled`,故 `start >= 0`,窗一定不跨环尾。 +`App/algo/sample_ring.c` 里只留结论与指向本节的指针,推导以本节为准。 ### 5.4 API 契约