负数的整除和余数
刚试了一下负数的整数除法和余数,发现有两种结果。
一种是令余数和被除数的符号一致,例如 C / C++ (网上说还有 java):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int main()
{
fprintf(stdout, "(%+d) / (%+d) = %+d; ", x, y, (x) / (y)); \
fprintf(stdout, "(%+d) %% (%+d) = %+d\n", x, y, (x) % (y));
CALC(+5, +2);
CALC(+5, -2);
CALC(-5, +2);
CALC(-5, -2);
return 0;
}
-->
(+5) / (+2) = +2; (+5) % (+2) = +1
(+5) / (-2) = -2; (+5) % (-2) = +1
(-5) / (+2) = -2; (-5) % (+2) = -1
(-5) / (-2) = +2; (-5) % (-2) = -1另一种是令余数和除数的符号一致,例如 python、matlab:
1
2
3
4
5
6
7
8
9
10
11
12def calc(x, y):
print("({:+d}) // ({:+d}) = {:+d}; ({:+d}) % ({:+d}) = {:+d}" \
.format(x, y, (x) // (y), x, y, (x) % (y)))
calc(+5, +2)
calc(+5, -2)
calc(-5, +2)
calc(-5, -2)
-->
(+5) // (+2) = +2; (+5) % (+2) = +1
(+5) // (-2) = -3; (+5) % (-2) = -1
(-5) // (+2) = -3; (-5) % (+2) = +1
(-5) // (-2) = +2; (-5) % (-2) = -1
好吧,知道即可,不纠结。
C++ 原生字符串
引发原生字符串标识提议的是这样一个“惊天地泣鬼神”的例子:
1 | "('(?:[^\\\\']|\\\\.)*'|\"(?:[^\\\\\"]|\\\\.)*\")|" |
C++ 整型变量的绝对值
今天在 CppTemplateTutorial 群里面问了一个问题,为什么 C++ 里面的整型绝对值函数 abs 返回有符号类型而不是无符号类型,如 int abs(int) 而不是 unsigned abs(int),因为这样会出现 abs(INT_MIN) 不对的情况。后来给出的两个说法比较容易接受:
1 | int b, a; |
不过后来讨论偏了,引来了一个讨论:函数 abs 中是否需要判断?结果还真有这种操作。看 abs 的反汇编,还有 MFC 里面的 abs 实现,都用了下面这种方式(以 int 为例):
1 | int abs(int x) |
第一行的 mask 全部由 x 的符号位组成,对应于正数和负数分别为全 0 (0x00000000) 和全 1 (0xffffffff);第二步中的 x ^ mask,对于正数,仍是 x,对于负数,结果是 ~x;第三步的 -mask,对于正数,因为 mask = 0 所以不变,对于负数,无符号数减去最大的无符号数等于 +1,即 x - 0xfffffffff = x + 1u,所以上述函数对于正数等价于 return x,对于负数等价于 ~(unsigned)(x) + 1u,在 x != INT_MIN 时正好等价于 (unsigned)(~x) + 1u,按预期返回。
下面是一个实例代码,用来看各种中间结果。简便起见,这里使用 char 而不是 int。
1 |
|
下面为当 x 分别取 25 和 -25 时的输出:
1 | x: 19, +025 ux: 19, 025 mask: 00, 000 dx: 19, 025 ddx: 19, 025 ax: 19, +025 |
最后,可以调侃一下。在 C++ 中,对于有符号整型变量 x,x == (-x) 有两个解:0 和 TYPE_MIN。