【C】原码和补码以及环形坐标取模算法

一切数字在计算机底层都是以补码的形式存储和计算,补码天然是无符号的。但为了人们方便数学计算,利用计算机数据溢出绕尾的特性,提出了有符号数,也就是原码。补码层面的计算也是符合数学逻辑,比如unsigned int 和 int计算,都先转成unsigned int计算,结果是unsigned int类型,和你都当成有符号类型去计算,结果是一样的。属于是数学统一下的一体两面。

以有符号单字节为例,无符号原码补码相同:

原码 5(0000 0101)的补码就是 5(0000 0101)

原码-5(1000 0101)的补码就是251(1111 1011)

正数的补码和原码相同

负数符号位不变,其余取反加1,就是补码。补码符号位不变,其余取反加1又变成原码。

负数的补码也可以通过"0加"获得,0等于256,0+(-5) = 256 - 5 = 251,模型如下图:

在C语言的公式计算中,可以先不考虑有符号无符号,单纯以数学逻辑去计算,最后看结果,中间只要注意算出的数会不会因为整型提升丢失符号位即可。https://kdocs.cn/l/cgXXFjtyTtfa

补充:

0-(-5) = 256 - 251 = 5,可以通过"0减"的方式算一个负数的绝对值。

模运算补充:

数学语境中的除运算(/)和模运算(%)是除法带余数和取整,规则上和Python中的运算是一样的,但是Python有(//)用于取整除。C语言中只有除运算(/)和模运算(%)是取整除和求余数。

被除数 = 商 × 除数 + 余数(记为:a = q × b + r),a / b = q 余 r。

商的符号由a和b决定,同号为正,异号为负。

Python算法上余数符号和除数(M)一致。C语言算法上余数符号和被除数(N)一致。

两者运算规则上的核心差异:python的商向下取整,C语言的商向0取整。

例子:

Python:-10 / 3 = -4 余 2,-10 = 3 * -4 + 2,因为-10 / 3等于-3.几,向下取整到-4。

C:-10 / 3 = -3 余 -1,-10 = 3 * -3 + -1,商向0取整到-3。

Python:10 / -3 = -4 余 -2,10 = -3 * -4 + -2

C:10 / -3 = -3 余 1,10 = -3 * -3 + 1

Python:-10 / -3 = 3 余 -1,-10 = -3 * 3 + -1,因为-10 / -3等于3.几,向下取整到3。

C:-10 / -3 = 3 余 -1,-10 = -3 * 3 + -1,因为-10 / -3等于3.几,向0取整到3。

Python:10 / 3 = 3 余 1,10 = 3 * 3 + 1

C:10 / 3 = 3 余 1,10 = 3 * 3 + 1

Python:-3 / 1000 = -1 余 997,-3 = 1000 * -1 + 997,因为-3 / 1000等于-0.几,向下取整到-1。

C:-3 / 1000 = 0 余 -3,-3 = 1000 * 0 + -3,商向0取整到0。

Python中商为正数时和C语言中是一样的,但是商小于等于0就不一样,故在C语言中当M是正值,N是负值的时候一定要用公式(N % M + M) % M,此时的结果和Python是一致的。模运算的本质就是把N拉到[-M+1, M-1]的范围内。且余数符号和除数一致,当M为正数,则余数范围[0, M-1]。

补充:

数据在[0, M-1]的范围变化,总共有M个数据。从S点写LEN个数据到E点,E点是干净未处理的。

  • 有两个点S和E,从S加LEN到E,计算E,本质算法是E = (S + LEN) >= M ? ((S + LEN) - M) : (S + LEN);

对应取模算法:E = (S + LEN) % M,(S + LEN)是正值,直接%就行。

  • 有两个点S和E,从S减LEN到E,计算E,本质算法是E = (S - LEN) < 0 ? ((S - LEN) + M) : (S - LEN);

对应取模算法:E = (S - LEN + M) % M,(S - LEN + M)是正值,直接%就行。

  • 有两个点S和E,从S加LEN到E,计算LEN,本质算法是LEN = (E - S) >= 0 ? (E - S) : ((E - S) + M);

对应取模算法:LEN = ((E - S) % M + M) % M,(E - S)可能是负值,直接%的商也是负值,所以套用公式。

上述是数组类,LEN = 3是包含索引0在内。

如果是定时器节拍类,举例:实时时间R,之前时间C,超时时间D。LEN = 3是包含索引3在内,如下图。但两者本质上是一样的,只不过物理内容所在一个偏左一个偏右。

补充:上述"数据在[0, M-1]"的例子中,M是正数,"S - LEN"或"E - S"的绝对值不大于M:

  • "E = (S + LEN) % M"简化成"E = (S + LEN) % M";
  • "E = (S - LEN + M) % M"简化成"E = (S - LEN + M) % M",算"上N条"用法;
  • "LEN = ((E - S) % M + M) % M"简化成"LEN = (E - S + M) % M";
  • https://www.kdocs.cn/l/cp1DT0sq6ltW,见20240709,如果M是特殊的2的幂次数(整型变量的最大值+1),计算时则无需求余数,变量具有1个天然的模或者回绕点。
相关推荐
qiqsevenqiqiqiqi2 小时前
前缀和差分
算法·图论
代码旅人ing2 小时前
链表算法刷题指南
数据结构·算法·链表
2401_827499992 小时前
python项目实战09-AI智能伴侣(ai_partner_5-6)
开发语言·python
PD我是你的真爱粉2 小时前
MCP 协议详解:从架构、工作流到 Python 技术栈落地
开发语言·python·架构
Yungoal2 小时前
常见 时间复杂度计算
c++·算法
星晨雪海3 小时前
基于 @Resource 的支付 Service 多实现类完整示例
java·开发语言
yashuk3 小时前
C语言实现PAT练习及算法学习笔记,还有SQLite介绍
c语言·sqlite·开源项目·算法学习·pat练习
ACP广源盛139246256733 小时前
破局 Type‑C 切换器痛点@ACP#GSV6155+LH3828/GSV2221+LH3828 黄金方案
c语言·开发语言·网络·人工智能·嵌入式硬件·计算机外设·电脑
不爱吃炸鸡柳3 小时前
单链表专题(完整代码版)
数据结构·算法·链表