如何让运算优先级浪费你的时间

这个世界本没有优先级,运算符多了,也便有了优先级。

——我也不知道是谁说的

我已经浪费了不知多少时间和奇怪的运算符优先级作斗争。

然而我总是败在它们的脚下。

将我光荣的败绩记录于此,来让我和大家一次又一次地重蹈覆辙。


可爱的位运算们

——你看左移右移运算符那么大肯定优先级贼高嘛!
——我也觉得呢!

int query(int x, int l, int r) {
	int mid = (l + r) >> 1;
	int lch = x << 1;
	int rch = x << 1 + 1; //(x << 1) + 1
	// ...
}

——都是位运算,优先级肯定相同嘛!
——当然啦!

void fun() {
	int a = 5, b = 7, c = 9;
	int ret1 = 5 ^ 7 & 9, ret2 = (5 ^ 7) & 9; 
	assert(ret1 == ret2); // ret1 == 4, ret2 == 0
	// "&" > "^" > "|"
}

更可爱的逻辑运算符们

——编译器那么聪明肯定知道我想要什么嘛!
——就是就是,逻辑那么清晰的!

#define MODadd(a, b) if (a += b >= MOD) a -= MOD
// if ((a += b) >= MOD) a -= MOD

——你骗我,你上篇文章说的半加器根本没办法工作!

int add(int a, int b) {
	if (a & b == 0) return a ^ b; // if ((a & b) == 0)
	else return add(a ^ b, (a & b) << 1);
}

——明明可爱的感叹号打在哪里都无所谓嘛!
——对对对,感叹号和取反没什么区别嘛!

int query(int l, int r) {
	int ret = 0;
	for (l += s - 1, r += s + 1; l^r^1;) {
		if (!l&1) ret += t[l^1]; //(!(l&1)) or (~l&1)
		if (r&1) ret += t[r^1];
		l >>= 1, r >>= 1;
	}
	return ret;
}

史诗级可爱的大爷们

以下都是各种能让你毁掉一整天的错误。(不要为什么我跪着说出这句话)

void splay(Node *x, Node *fa = null) {
	while (x->fa != fa) {
		if (x->fa->fa == fa) rot(x);
		else x->dir() == x->fa->dir() ? rot(x->fa), rot(x) : rot(x), rot(x);
//                                     (                  ) (              )
	}
	x->upd();
}
bool check(int l1, int r1, int l2, int r2) {
	return get(l1, r1)->c[0]->ha == get(l2, r2)->c[0]->ha;
	// get() is executed before ->
}
/*
bool check(int l1, int r1, int l2, int r2) {
	Ha v1 = get(l1, r1)->c[0]->ha, v2 = get(l2, r2)->c[0]->ha;
	return v1 == v2;
}
*/
for (int i = st; i <= ed; i++) {
	int u = getf(e[i].u), v = getf(e[i].v);
	if (u == v) continue;
	u = vis[u] ? vis[u] : rec[++cnt] = u, vis[u] = cnt; 
	v = vis[v] ? vis[v] : rec[++cnt] = v, vis[v] = cnt;
//                       (                            )
	a[u][v]--, a[v][u]--, a[u][u]++, a[v][v]++;
}

暂时就这些了,想到了再写。

总结,如果要想在这些上面浪费时间的话一定要:

  1. 拒绝打括号,尽可能地减少代码长度;
  2. 相信编译器,相信它理解代码的方式一定和你完全一样;
  3. 从不查资料,包括下面这张运算符优先级表。

C++ Operator Precedence

From cppreference

Prec Operator Description Associativity
1 :: Scope resolution Left-to-right
2 a++   a– Suffix/postfix increment and decrement
type()   type{} Functional cast
a() Function call
a[] Subscript
.   -> Member access
3 ++a   –a Prefix increment and decrement Right-to-left
+a   -a Unary plus and minus
!   ~ Logical NOT and bitwise NOT
(type) C-style cast
*a Indirection (dereference)
&a Address-of
sizeof Size-of[note 1]
new   new[] Dynamic memory allocation
delete   delete[] Dynamic memory deallocation
4 .*   ->* Pointer-to-member Left-to-right
5 a*b   a/b   a%b Multiplication, division, and remainder
6 a+b   a-b Addition and subtraction
7 <<   >> Bitwise left shift and right shift
8 <   <= For relational operators < and ≤ respectively
>   >= For relational operators > and ≥ respectively
9 ==   != For relational operators = and ≠ respectively
10 a&b Bitwise AND
11 ^ Bitwise XOR (exclusive or)
12 | Bitwise OR (inclusive or)
13 && Logical AND
14 || Logical OR
15 a?b:c Ternary conditional[note 2] Right-to-left
throw throw operator
= Direct assignment (provided by default for C++ classes)
+=   -= Compound assignment by sum and difference
*=   /=   %= Compound assignment by product, quotient, and remainder
<<=   >>= Compound assignment by bitwise left shift and right shift
&=   ^=   |= Compound assignment by bitwise AND, XOR, and OR
16 , Comma Left-to-right
  1. The operand of sizeof can’t be a C-style type cast: the expression sizeof (int) * p is unambiguously interpreted as (sizeof(int)) * p, but not sizeof((int)*p).
  2. The expression in the middle of the conditional operator (between ? and :) is parsed as if parenthesized: its precedence relative to ?: is ignored.

发表评论

电子邮件地址不会被公开。 必填项已用*标注