前言
- 最近在看channel源码时,看到一个函数MulUintptr,功能很简单,就是把两个数相乘,看是否越界,在golang很多地方都有使用,用于判断内存申请
- 如果越界就返回false,否则返回true
,代码如下
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package math
import "runtime/internal/sys"
const MaxUintptr = ^uintptr(0)
// MulUintptr returns a * b and whether the multiplication overflowed.
// On supported platforms this is an intrinsic lowered by the compiler.
func MulUintptr(a, b uintptr) (uintptr, bool) {
if a|b < 1<<(4*sys.PtrSize) || a == 0 {
return a * b, false
}
overflow := b > MaxUintptr/a
return a * b, overflow
}
说明
- 没搞明白的点在于a|b < 1<<(4*sys.PtrSize) || a== 0,看了半天没看懂
- 在网上查了一下,只发现了用法,也没找到为什么这么写
- 最后晚上下班在车上才终于想明白
分析
-
首先a==0,没什么可说的,如果a=0,那么肯定不会越界
-
重点落在了**a|b < 1<<(4*sys.PtrSize) **
-
sys.PtrSize在64位机器中为8,所以上面的代码等价于a|b < 1<<32
-
我们知道64位计算中最大的无符号数是2^64-1
-
看到232和264,再联想到函数的作用是乘法,一下子就明白了
-
有两个条件要达成共识
- 相乘的两个数很少会特别大,很少会大于等于2^32
- 当a|b<232时,则a<232, b<2^32
- 位运算,这个应该大家都了解
-
由此得出,如果要判断两个相乘是否大于等于264,只要这两个数都小于232就可以了
-
这种情况可覆盖99.9%的情况
-
剩下的情况用verflow := b > MaxUintptr/a就能兜底了
翻译一下代码如下
func MulUintptr(a, b uintptr) (uintptr, bool) {
if a和b都小于2^32 或者 a 等于 0 时{
return a * b, 越界
}
// a*b如果越界了,得到的数一定比2^64-1小
overflow := b > MaxUintptr/a
return a * b, overflow
}
字节跳动长期招聘,欢迎投递
字节跳动内推链接:https://job.bytedance.com/referral/pc/autumn-referral?category=&location=&token=MzsxNjAzOTUzMDMxMzY3OzY4MjAwNjY4ODc4ODg1MzcxMDI7MA
欢迎投递加入~