32位的无符号数表示形式如下图所示:
32位有符号数以补码形式表示,表示形式如下图所示:
由于取反是关于 -1 和 0 对称,因此负数转补码需要将数字位取反后加一。
浮点数的表示遵循 IEEE754 标准。
一个浮点数为:
S
⋅
2
E
⋅
M
(
S
∈
{
−
1
,
1
}
,
0
≤
M
<
2
)
S\cdot2^{E}\cdot M\ (S\in \{-1,1\},0\le M<2)
S⋅2E⋅M (S∈{−1,1},0≤M<2)
其中阶码需要在补码的基础上加上 2 e − 1 − 1 2^{e-1}-1 2e−1−1,这里 e e e 为阶码 E 的位数。
通过拆分浮点数进行验证:
#include
int main() {
float x = 1;
auto b = std::bitset<32>(*(unsigned int *) &x);
std::cout << b[31] << " ";
for (int i = 30; i >= 23; i--) {
std::cout << b[i];
}
std::cout << " ";
for (int i = 22; i >= 0; i--) {
std::cout << b[i];
}
std::cout << std::endl;
return 0;
}
如果运算结果的最高位产生了一个进位或借位,那么,其值为1,否则其值为0。(无符号数溢出)
以下两类指令在运算时需要将 CF 标志位加上:
奇偶标志PF用于反映运算结果中最低字节中“1”的个数的奇偶性。
如果“1”的个数为偶数,则PF的值为1,否则其值为0。
在发生下列情况时,辅助进位标志AF的值被置为1,否则其值为0
如果运算结果为0,则其值为1,否则其值为0。在判断运算结果是否为0时,可使用此标志位。
符号标志SF用来反映运算结果的符号位,它与运算结果的最高位相同。
溢出标志OF用于反映有符号数加减运算所得结果是否溢出。(有符号数溢出)
当追踪标志TF被置为1时,CPU进入单步执行方式,即每执行一条指令,产生一个单步中断请求。这种方式主要用于程序的调试。
中断允许标志IF是用来决定CPU是否响应CPU外部的可屏蔽中断发出的中断请求。但不管该标志为何值,CPU都必须响应CPU外部的不可屏蔽中断所发出的中断请求,以及CPU内部产生的中断请求。具体规定如下:
当IF=1时,CPU可以响应CPU外部的可屏蔽中断发出的中断请求;
当IF=0时,CPU不响应CPU外部的可屏蔽中断发出的中断请求。
CPU的指令系统中也有专门的指令来改变标志位IF的值。
方向标志DF用来决定在串操作指令执行时有关指针寄存器发生调整的方向。
当条件分支较少时与 if-else 结构类似。
分支较多且条件比较连续时会通过查表的方式找到要执行的分支语句。
此时会再生成一个以字节为单位的小表来减少存储过多 default 分支地址造成的空间浪费。
此时会形成类似二叉树的 if-else 分支嵌套,还会在其中嵌套查表的方法,较为复杂。
因此假设一个结构体中有
n
n
n 个元素,每个元素大小为
a
i
(
1
≤
i
≤
n
)
a_i(1\le i\le n)
ai(1≤i≤n) 并且按照
k
k
k 字节对齐,则结构体大小计算方式如下:
#include
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n, k;
std::cin >> n >> k;
assert(__builtin_popcount(k) == 1);
std::vector<int> a(n);
for (int i = 0; i < n; i++) {
std::cin >> a[i];
assert(__builtin_popcount(a[i]) == 1);
}
k = std::min(k, *std::max_element(a.begin(), a.end()));
int ans = 0;
for (int i = 0; i < n; i++) {
if ((ans + a[i] - 1) / a[i] * a[i] + a[i] <= (ans + k - 1) / k * k) {
ans = (ans + a[i] - 1) / a[i] * a[i] + a[i];
} else {
ans = (ans + k - 1) / k * k + a[i];
}
}
ans = (ans + k - 1) / k * k;
std::cout << ans << std::endl;
return 0;
}