golang-math实用小技巧
返回a/b向上舍入最接近的整数
func divRoundUp(n, a uintptr) uintptr {return (n + a - 1) / a
}
这个方法用过的人应该不少,最典型的就是分页计算。
判断x是否为2的n次幂
func isPowerOfTwo(x uintptr) bool {return x&(x-1) == 0
}
这个也挺容易理解的,唯一需要注意的是x需要大于0,因为该等式0也是成立的。
向上/下将x舍入为a的倍数,且a必须是2的n次幂
// 向上将x舍入为a的倍数,例如:x=6,a=4则返回值为8
func alignUp(x, a uintptr) uintptr {return (x + a - 1) &^ (a - 1)
}// 向上将x舍入为a的倍数,例如:x=6,a=4则返回值为4
func alignDown(x, a uintptr) uintptr {return x &^ (a - 1)
}
在这里老许再次明确一个概念,2的n次幂即为1左移n位
。然后上述代码中^
为单目运算法按位取反,则^ (a - 1)
的运算结果是除了最低n位为0其余位全为1。剩余的部分则是一个简单的加减运算以及按位与。
上述代码分开来看每一部分都认识,合在一起就一脸懵逼了。幸运的是,经过老许的不懈努力终于找到了一种能够理解的方式。
以x=10,a=4
为例。a
为2的2次幂即1左移2位。x
可看作两部分之和,第一部分x1为0b1000
,第二部分x2为0b0011
。x
的拆分方式是1左移n
位可得到a
来决定的,即x的最低n位为x2,x1则为x-x2。因此x1相当于0b10左移2位得到,即x1已经是a的整数倍,此时x2只要大于0则x2+a-1一定会向前进1,x1+1
或x1
不就是x向上舍入的a的整数倍嘛,最后和^ (a - 1)
进行与运算将最低2位清零得到最终的返回结果。
有一说一,我肯定是写不出这样的逻辑,这也令我不得不感叹大佬们对计算机的理解简直出神入化。这样的函数牛逼归牛逼,但是在实际开发中还是尽量少用。一是有使用场景的限制(a必须为2的n次幂),二是不易理解,当然炫技和装逼除外(性能要求极高也除外)。
布尔转整形
// bool2int returns 0 if x is false or 1 if x is true.
func bool2int(x bool) int {return int(uint8(*(*uint8)(unsafe.Pointer(&x))))
}
如果让我来写这个函数,一个稀松平常的switch
就完事儿,现在我又多了一种装逼的套路。老许在这里特别友情提示,字节切片和字符串也可使用上述方式进行相互转换。
计算不同类型最低位0的位数
var ntz8tab = [256]uint8{0x08, ..., 0x00,
}
// Ctz8 returns the number of trailing zero bits in x; the result is 8 for x == 0.
func Ctz8(x uint8) int {return int(ntz8tab[x])
}const deBruijn32ctz = 0x04653adfvar deBruijnIdx32ctz = [32]byte{0, 1, 2, 6, 3, 11, 7, 16,4, 14, 12, 21, 8, 23, 17, 26,31, 5, 10, 15, 13, 20, 22, 25,30, 9, 19, 24, 29, 18, 28, 27,
}// Ctz32 counts trailing (low-order) zeroes,
// and if all are zero, then 32.
func Ctz32(x uint32) int {x &= -x // isolate low-order bity := x * deBruijn32ctz >> 27 // extract part of deBruijn sequencei := int(deBruijnIdx32ctz[y]) // convert to bit indexz := int((x - 1) >> 26 & 32) // adjustment if zeroreturn i + z
}const deBruijn64ctz = 0x0218a392cd3d5dbfvar deBruijnIdx64ctz = [64]byte{0, 1, 2, 7, 3, 13, 8, 19,4, 25, 14, 28, 9, 34, 20, 40,5, 17, 26, 38, 15, 46, 29, 48,10, 31, 35, 54, 21, 50, 41, 57,63, 6, 12, 18, 24, 27, 33, 39,16, 37, 45, 47, 30, 53, 49, 56,62, 11, 23, 32, 36, 44, 52, 55,61, 22, 43, 51, 60, 42, 59, 58,
}// Ctz64 counts trailing (low-order) zeroes,
// and if all are zero, then 64.
func Ctz64(x uint64) int {x &= -x // isolate low-order bity := x * deBruijn64ctz >> 58 // extract part of deBruijn sequencei := int(deBruijnIdx64ctz[y]) // convert to bit indexz := int((x - 1) >> 57 & 64) // adjustment if zeroreturn i + z
}
Ctz8
、Ctz32
和Ctz64
分别计算无符号8、32、64位数最低位为0的个数,即某个数左移的位数。
函数的作用通过翻译倒是能理解,我也能深刻的明白这是典型的空间换时间,然而要问一句为什么我是万万答不上来的。不过老许已经替你们找好了答案,原因就藏在这篇Using de Bruijn Sequences to Index a 1 in a Computer Word论文中。欢迎巨佬们去挑战一下,而我只想坐享其成,那么在巨佬们分析完这篇论文之前就让这些函数安家在我的收藏栏里方便以后炫技。
这里特别说明,术业有专攻,我们不一定要所有东西都会,但要尽可能知道有这么一个东西存在。这即是老许为自己找的一个不去研究此论文的接口,也是写下此篇文章的意义之一(万一有人提到了Bruijn Sequences
关键词,我们也不至于显得过分无知)。
math/bits包中的部分函数
如果有人知道这个包,那请原谅我的无知直接跳过本部分即可。老许发现这个包是源于ntz8tab
变量所在文件runtime/internal/sys/intrinsics_common.go
中的一句注释。
// Copied from math/bits to avoid dependence.
作为一个资深的CV工程师, 看到这句的第一反应就是我终于可以挺直腰杆了。适当Copy代码不丢人!
math/bits
这个包函数较多,老许挑几个介绍即可,其余的还请各位读者自行挖掘。
LeadingZeros(x uint) int
: 返回x所有高位为0的个数。
TrailingZeros(x uint) int
: 返回x最低位为0的个数。
OnesCount(x uint) int
:返回x中bit位为1的个数。
Reverse(x uint) uint
: 将x按bit位倒序后再返回。
Len(x uint) int
: 返回表示x的有效bit位个数(高位中的0不计数)。
ReverseBytes(x uint) uint
: 将x按照每8位一组倒序后返回。
将x逃逸至堆
// Dummy annotation marking that the value x escapes,
// for use in cases where the reflect code is so clever that
// the compiler cannot follow.
func escapes(x interface{}) {if dummy.b {dummy.x = x}
}var dummy struct {b boolx interface{}
}
老许是在reflect.ValueOf
函数中发现此函数的调用,当时就觉着挺有意思。如今再次回顾也依旧佩服不已。读书是和作者的对话,阅读源码是和开发者的对话,看到此函数就仿佛看到Go语言开发者们和编译器斗智斗勇的场景。
让出当前Processor
// Gosched yields the processor, allowing other goroutines to run. It does not
// suspend the current goroutine, so execution resumes automatically.
func Gosched() {checkTimeouts()mcall(gosched_m)
}
让出当前的Processor,允许其他goroutine执行。在实际的开发当中老许还未遇到需要使用此函数的场景,但多了解总是有备无患。
最后,衷心希望本文能够对各位读者有一定的帮助。
golang-math实用小技巧相关推荐
- 送你16个matplotlib绘图实用小技巧(附代码)
来源:雪山飞猪 本文约2800字,建议阅读10分钟 本文为你分享16个matplotlib绘图实用小技巧. 标签:数据分析 1. 添加标题-title import numpy as npimport ...
- VC的若干实用小技巧
Visual C++6.0(5.0)开发工具功能非常强大,但是对于初学者来说,却有很多细节的问题需要注意.作者搜集整理了以下一些实用小技巧,希望对初学者有所帮助. 1:使用vc开发项目时,常会遇到这种 ...
- 实用小技巧(一):UIScrollView中上下左右滚动方向的判断
https://www.jianshu.com/p/93e8459b6dae 2017.06.01 01:13* 字数 674 阅读 1201评论 0喜欢 1 2017.06.01 01:13* 字数 ...
- VC的若干实用小技巧 (如何干净的删除一个类)
Visual C++6.0(5.0)开发工具功能非常强大,但是对于初学者来说,却有很多细节的问题需要注意.作者搜集整理了以下一些实用小技巧,希望对初学者有所帮助. 1:使用vc开发项目时,常会遇到这种 ...
- 总结MySQL建表、查询优化实用小技巧
MySQL建表阶段是非常重要的一个环节,表结构的好坏.优劣直接影响着后续的管理维护,赶在明天上班前分享总结个人MySQL建表.MySQL查询优化积累的一些实用小技巧. 技巧一.数据表冗余记录添加时间与 ...
- mysql建表测试_总结MySQL建表、查询优化实用小技巧
MySQL建表阶段是非常重要的一个环节,表结构的好坏.优劣直接影响着后续的管理维护,赶在明天上班前分享总结个人MySQL建表.MySQL查询优化积累的一些实用小技巧. 技巧一.数据表冗余记录添加时间与 ...
- 20个你应该知道的iPhone 7实用小技巧
听说iOS 11马上就要发布,再过几个月新版iPhone8也即将上线,你真的会用你的iPhone7了吗?下面我们来介绍几个iPhone7的实用小技巧. 1.输入消息时的光标移动: 有很多新用户在疑惑输 ...
- 苹果手机计算机怎样拉到桌面,20个你应该知道的iPhone 7实用小技巧
本文由那年那个饭桶整理,未经作者授权,请勿转载,感谢您的尊重. 听说iOS11马上就要发布,再过几个月新版iPhone8也即将上线,你真的会用你的iPhone7了吗?下面我们来介绍几个iPhone7的 ...
- phpstudy mysql建表_MySQL_总结MySQL建表、查询优化的一些实用小技巧,MySQL建表阶段是非常重要的一 - phpStudy...
总结MySQL建表.查询优化的一些实用小技巧 MySQL建表阶段是非常重要的一个环节,表结构的好坏.优劣直接影响着后续的管理维护,赶在明天上班前分享总结个人MySQL建表.MySQL查询优化积累的一些 ...
- 微信公众号运营都有哪些实用小技巧,你学会了吗
移动媒体的发展,一些新媒体平台也变得热门起来,其原因人流量随之增长起来,像公众号.自媒体.短视频等,这些平台都是流量非常多的,公众号在微信刚出来的时候,还不怎么热门,也是近几年才受到企业受宠,很多企业 ...
最新文章
- linux 调用栈打印
- 量子计算竞速时代,如何拨动时间的指针
- 6. Qt 信号与信号槽 (7)-QMetaObject:: activate
- 热电偶校验仪_热电偶校验方法_电厂系列之热控仪表装置校验讲解
- ubuntu16.04安装ROS
- SCPPO(十五):IIS配置文件节点加密
- Visual Studio Code下载安装教程
- 使用 R 构建复杂设计调查加权(Survey-Weighted) Cox 模型的列线图
- 英雄无敌3pc移植android版,今日手游:全盘移植《魔法门之英雄无敌3》
- mysql ndb 关闭,监控mysql、ndb进程重启
- xml分页php采集,海洋cms自动采集脚本可分页
- 【BLE】CC2541之Large OAD
- Android长图文截图的实现(支持截取第三方app)-(一)
- Java架构师成长直通车:LVS+Nginx实现高可用集群
- 吉首大学校赛B——干物妹小埋(线段树求最大递增子序列)
- 华为USG6000V 内网通过NAT地址池访问公网
- OpenGL 绘制音频波形
- 高等几何——射影平面3
- Raptor-素数判断/质数判断
- LeetCode按照怎样的顺序来刷题比较好?