最新要闻
- 当前热点-灵感来自微信:微软计划开发一站式“超级应用”
- 环球即时看!惊险!SUV被货车顶上铁轨 火车驶来瞬间逃离
- 玩家们都嫌太贵!曝英伟达考虑将RTX 4080降价
- 世界讯息:AI生成裸照谁之过?真相恐怕和你想的不一样
- 3小时超值!《阿凡达2》电影票价普遍低于50元 IMAX版80元
- “抽烟哥”红到国外 田协紧急倡议应积极正向:全马冲进3个半小时是狠人
- 世界百事通!RTX 4080全球销售疲软:太贵了我再等等
- 《阿凡达2》伦敦首映式
- 惊险一幕!后车记录仪拍下特斯拉失控瞬间 网友分析司机被特斯拉辅助“救”两次
- 今日大雪:仲冬时节正式开始 全国大部气温回升雨雪稀少
- 每日观察!《原神》3.3版本今日上线:风元素新角色来了 还有原石可领
- 葡萄牙6-1大胜瑞士 C罗31场首发终结:加练千个西班牙点球大战仍出局 连续三届无缘8强
- 看齐QQ音乐?Apple Music新功能来了:支持iPhone、iPad唱卡拉OK
- 安兔兔11月iOS设备好评榜出炉:iPhone 14全系未上榜
- 世界今亮点!不止是中药 连花清瘟新专利来了 可用于制作口罩、内衣、防护服等
- 时讯:200元耳机降噪效果比肩2000元!贝壳王子MO3 2代上手:同价位天花板
手机
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
票房这么火爆,如何请视障人士“看”一场电影?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
- 票房这么火爆,如何请视障人士“看”一场电影?
家电
看完微软大神写的求平均值代码 我意识到自己还是too young了
取整求个无符号整数的平均值,居然也能整出花儿来?
这不,微软大神Raymond Chen最近的一篇长文直接引爆外网技术平台,引发无数讨论:
无数人点进去时无比自信:不就是一个简单的相加后除二的小学生编程题吗?
unsigned average(unsigned a, unsigned b) { return (a + b) / 2; }但跟着大神的一路深挖,却逐渐目瞪狗呆……
没那么简单的求平均值
先从开头提到的小学生都会的方法看起,这个简单的方法有个致命的缺陷:
如果无符号整数的长度为32位,那么如果两个相加的值都为最大长度的一半,那么仅在第一步相加时,就会发生内存溢出。
也就是average(0x80000000U, 0x80000000U)=0。
不过解决方法也不少,大多数有经验的开发者首先能想到的,就是预先限制相加的数字长度,避免溢出。
具体有两种方法:
1、当知道相加的两个无符号整数中的较大值时,减去较小值再除二,以提前减少长度:
unsigned average(unsigned low, unsigned high) { return low + (high - low) / 2; }2、对两个无符号整数预先进行除法,同时通过按位与修正低位数字,保证在两个整数都为奇数时,结果仍然正确。
(顺带一提,这是一个被申请了专利的方法,2016年过期)
unsigned average(unsigned a, unsigned b) { return (a / 2) + (b / 2) + (a & b & 1); }这两个都是较为常见的思路,不少网友也表示,自己最快想到的就是2016年专利方法。
同样能被广大网友快速想到的方法还有SWAR(SIMD within a register):
unsigned average(unsigned a, unsigned b) { return (a & b) + (a ^ b) / 2;// 变体 (a ^ b) + (a & b) * 2以及C++ 20版本中的std: : midpoint函数。
接下来,作者提出了第二种思路:
如果无符号整数是32位而本机寄存器大小是64位,或者编译器支持多字运算,就可以将相加值强制转化为长整型数据。
unsigned average(unsigned a, unsigned b) { // Suppose "unsigned" is a 32-bit type and // "unsigned long long" is a 64-bit type. return ((unsigned long long)a + b) / 2; }不过,这里有一个需要特别注意的点:
必须要保证64位寄存器的前32位都为0,才不会影响剩余的32位值。
像是x86-64和aarch64这些架构会自动将32位值零扩展为64位值:
// x86-64: Assume ecx = a, edx = b, upper 32 bits unknown mov eax, ecx ; rax = ecx zero-extended to 64-bit value mov edx, edx ; rdx = edx zero-extended to 64-bit value add rax, rdx ; 64-bit addition: rax = rax + rdx shr rax, 1 ; 64-bit shift: rax = rax >> 1 ; result is zero-extended ; Answer in eax // AArch64 (ARM 64-bit): Assume w0 = a, w1 = b, upper 32 bits unknown uxtw x0, w0 ; x0 = w0 zero-extended to 64-bit value uxtw x1, w1 ; x1 = w1 zero-extended to 64-bit value add x0, x1 ; 64-bit addition: x0 = x0 + x1 ubfx x0, x0, 1, 32 ; Extract bits 1 through 32 from result ; (shift + zero-extend in one instruction) ; Answer in x0而Alpha AXP、mips64等架构则会将32位值符号扩展为64位值。
这种时候,就需要额外增加归零的指令,比如通过向左进位两字的删除指令rldicl:
// Alpha AXP: Assume a0 = a, a1 = b, both in canonical form insll a0, #0, a0 ; a0 = a0 zero-extended to 64-bit value insll a1, #0, a1 ; a1 = a1 zero-extended to 64-bit value addq a0, a1, v0 ; 64-bit addition: v0 = a0 + a1 srl v0, #1, v0 ; 64-bit shift: v0 = v0 >> 1 addl zero, v0, v0 ; Force canonical form ; Answer in v0 // MIPS64: Assume a0 = a, a1 = b, sign-extended dext a0, a0, 0, 32 ; Zero-extend a0 to 64-bit value dext a1, a1, 0, 32 ; Zero-extend a1 to 64-bit value daddu v0, a0, a1 ; 64-bit addition: v0 = a0 + a1 dsrl v0, v0, #1 ; 64-bit shift: v0 = v0 >> 1 sll v0, #0, v0 ; Sign-extend result ; Answer in v0 // Power64: Assume r3 = a, r4 = b, zero-extended add r3, r3, r4 ; 64-bit addition: r3 = r3 + r4 rldicl r3, r3, 63, 32 ; Extract bits 63 through 32 from result ; (shift + zero-extend in one instruction) ; result in r3或者直接访问比本机寄存器更大的SIMD寄存器,当然,从通用寄存器跨越到SIMD寄存器肯定也会增加内存消耗。
如果电脑的处理器支持进位加法,那么还可以采用第三种思路。
这时,如果寄存器大小为n位,那么两个n位的无符号整数的和就可以理解为n+1位,通过RCR(带进位循环右移)指令,就可以得到正确的平均值,且不损失溢出的位。
带进位循环右移
// x86-32 mov eax, a add eax, b ; Add, overflow goes into carry bit rcr eax, 1 ; Rotate right one place through carry // x86-64 mov rax, a add rax, b ; Add, overflow goes into carry bit rcr rax, 1 ; Rotate right one place through carry // 32-bit ARM (A32) mov r0, a adds r0, b ; Add, overflow goes into carry bit rrx r0 ; Rotate right one place through carry // SH-3 clrt ; Clear T flag mov a, r0 addc b, r0 ; r0 = r0 + b + T, overflow goes into T bit rotcr r0 ; Rotate right one place through carry那如果处理器不支持带进位循环右移操作呢?
也可以使用内循环(rotation intrinsic):
unsigned average(unsigned a, unsigned b) { #if defined(_MSC_VER) unsigned sum; auto carry = _addcarry_u32(0, a, b, &sum); sum = (sum & ~1) | carry; return _rotr(sum, 1); #elif defined(__clang__) unsigned carry; sum = (sum & ~1) | carry; auto sum = __builtin_addc(a, b, 0, &carry); return __builtin_rotateright32(sum, 1); #else #error Unsupported compiler. #endif }结果是,x86架构下的代码生成没有发生什么变化,MSCver架构下的代码生成变得更糟,而arm-thumb2的clang 的代码生成更好了。
// _MSC_VER mov ecx, a add ecx, b ; Add, overflow goes into carry bit setc al ; al = 1 if carry set and ecx, -2 ; Clear bottom bit movzx ecx, al ; Zero-extend byte to 32-bit value or eax, ecx ; Combine ror ear, 1 ; Rotate right one position ; Result in eax // __clang__ mov ecx, a add ecx, b ; Add, overflow goes into carry bit setc al ; al = 1 if carry set shld eax, ecx, 31 ; Shift left 64-bit value // __clang__ with ARM-Thumb2 movs r2, #0 ; Prepare to receive carry adds r0, r0, r1 ; Calculate sum with flags adcs r2, r2 ; r2 holds carry lsrs r0, r0, #1 ; Shift sum right one position lsls r1, r2, #31 ; Move carry to bit 31 adds r0, r1, r0 ; Combine微软大神的思考们Raymond Chen1992年加入微软,迄今为止已任职25年,做UEX-Shell,也参与Windows开发,Windows系统的很多最初UI架构就是他搞起来的。
他在MSDN 上建立的blogThe Old New Thing也是业内非常出名的纯技术向产出网站。
这篇博客的评论区们也是微软的各路大神出没,继续深入探讨。
有人提出了新方法,在MIPS ASM共有36个循环:
unsigned avg(unsigned a, unsigned b { return (a & b) + (a ^ b) / 2; } // lw $3,8($fp) # 5 // lw $2,12($fp) # 5 // and $3,$3,$2 # 4 // lw $4,8($fp) # 5 // lw $2,12($fp) # 5 // xor $2,$4,$2 # 4 // srl $2,$2,1 # 4 // addu $2,$3,$2 # 4有人针对2016年专利法表示,与其用(a / 2) + (b / 2) + (a & b & 1)的方法,为啥不直接把 (a & 1) & ( b & 1 ) ) 作为进位放入加法器中计算呢?
还有人在评论区推荐了TopSpeed编译器,能够通过指定合适的代码字节和调用约定来定义一个内联函数,以解决“乘除结果是16位,中间计算值却不是”的情况。
只能说,学无止境啊。
原文:https://devblogs.microsoft.com/oldnewthing/20220207-00/?p=106223
参考链接:https://news.ycombinator.com/item?id=30252263
关键词: 看完微软大神写的求平均值代码 我意识到自己还
-
【世界报资讯】大数据-数据仓库-实时数仓架构分析
数仓分层|分层|全称|译名|说明|压缩|列式存储|分区||-|-|-|-|-|-|-||ODS|OperationDataStore|原始层|原...
来源: 全球时讯:文盘Rust -- r2d2 实现redis连接池
前端精准测试实践
世界速递!JavaScript中 FileReader 对象详解
【世界报资讯】大数据-数据仓库-实时数仓架构分析
热头条丨JAVA8 函数式编程(1)- Lambda表达式
易基因|m6A去甲基化酶ALKBH5通过降低PHF20 mRNA甲基化抑制结直肠癌进展 | 肿瘤研究
焦点日报:火山引擎 DataTester:如何用 A/B 测试做产品增长?
WTM+InfluxDB时序数据库数据查询并放到DataTable中
中科慧政 & JNPF :全面开启智慧政务,灵活满足政务办公需求
【焦点热闻】南墙WAF-最好的免费Web应用防火墙
天天关注:高光时刻 | 方正璞华联合开发的「人力资源法律服务共享平台」在创新创业大赛中获奖
全球新消息丨95年属猪的2019年运势
【环球热闻】绳责的意思(绳责)
天天动态:水滴筹标题范文(水滴筹标题怎么写)
今头条!应用昆虫学(应用昆虫学报)
环球头条:工厂找哪个网站?
焦点信息:促排卵期间注意哪些事项(促排卵期间注意事项)
天天资讯:越南旅游签证办理流程及费用(越南旅游签证办理流程)
全球快报:空鼻症是什么样(空鼻症是什么病)
【天天新视野】电脑桌面怎么恢复到原来的样子(电脑桌面怎么恢复到原来的样子)
每日信息:闲鱼卖二手
微资讯!西藏万隆虫草鹿鞭王
环球观焦点:77电玩城(77dizhi)
热头条丨低温性能革命性进步!宁德时代:钠电池有望装车500公里续航车型
当前播报:非典是哪一年一共死多少人(非典是哪一年)
天天热讯:空调显示屏上显示df是什么意思(空调运行中显示屏出现字母df是什么意思)
全球报道:我国现存新能源汽车相关企业56.8万家,仅2021年新增17万家
全球要闻:日本电子巨头罗姆将量产下一代半导体:提高用电效率、增加电动车续航里程
环球今日报丨传感器和处理器如何打造更智能、更自主的机器人?
世界即时:如何实现工业自动化?传感器对于工业自动化有什么样的意义
天天新动态:工业自动化如何实现?
当前焦点!使用cpolar(内网穿透)最低成本搭建网站
如何在Windows AD域中驻留ACL后门
当前热点-灵感来自微信:微软计划开发一站式“超级应用”
环球即时看!惊险!SUV被货车顶上铁轨 火车驶来瞬间逃离
玩家们都嫌太贵!曝英伟达考虑将RTX 4080降价
世界讯息:AI生成裸照谁之过?真相恐怕和你想的不一样
3小时超值!《阿凡达2》电影票价普遍低于50元 IMAX版80元
Redis 的 keys 命令你知道有多慢吗?
“抽烟哥”红到国外 田协紧急倡议应积极正向:全马冲进3个半小时是狠人
世界百事通!RTX 4080全球销售疲软:太贵了我再等等
《阿凡达2》伦敦首映式
惊险一幕!后车记录仪拍下特斯拉失控瞬间 网友分析司机被特斯拉辅助“救”两次
今日大雪:仲冬时节正式开始 全国大部气温回升雨雪稀少
每日观察!《原神》3.3版本今日上线:风元素新角色来了 还有原石可领
葡萄牙6-1大胜瑞士 C罗31场首发终结:加练千个西班牙点球大战仍出局 连续三届无缘8强
看齐QQ音乐?Apple Music新功能来了:支持iPhone、iPad唱卡拉OK
安兔兔11月iOS设备好评榜出炉:iPhone 14全系未上榜
SpringBoot构建RESTful风格应用
环球速讯:Kubernetes单机创建MySQL+Tomcat演示程序:《Kubernetes权威指南》第一章demo报错踩坑
全球最新:npm或者yarn安装sharp太慢、失败等问题
世界今亮点!不止是中药 连花清瘟新专利来了 可用于制作口罩、内衣、防护服等
时讯:200元耳机降噪效果比肩2000元!贝壳王子MO3 2代上手:同价位天花板
全国单日票房一度超4000万元:《阿凡达2》万众期待
热门:快升级5G!明年4G网速体验更糟糕:原因很无解
54年了!波音747飞机正式停产 一记录保持37年
焦点播报:MAUI新生3.4-深入理解XAML:数据模板DataTemplate
环球观热点:生成器函数
当前视点!Kubernetes configmap 笔记
画家要失业了?PS母公司Adobe开卖AI图片:侵权赔偿也自己扛
为什么海底火山不会被海水浇灭?
Javascript-极速入门指南-2-BOM与DOM操作-jQuery简介
54个CSS重难点整理,12-24篇,进阶高薪必需要掌握的知识点
国产CPU与国产OS联合 阿里平头哥加入openKylin社区
男子iPhone 13 Pro不到三个月自燃 法院:商品不符合质量要求 可以换新
全球热点!java创建线程的唯一方式
第一百一十篇:内存泄漏和垃圾回收(JS)
新资讯:《阿凡达2》获知名制作人小岛秀夫好评点赞:能够让人焕发激情
当前滚动:进军PC配件!一加将推出旗下首款机械键盘
《巫师3》次时代版“史诗升级”:官方Mod工具终于来了
AMD RX 7900又一非公卡亮相:档次上去了
每日热文:女子被绑浇墨汁?官方:自导自演 直播网红为赚流量博人眼球将严惩
left jon连接查询踩坑记
全球观热点:AMD RX 7900首批供货非常紧张!某品牌明年才能有
环球讯息:约4.1万人民币 法国一公司推出氢能电动自行车:像是助力车
环球焦点!一加11渲染图被网友恶搞:辨识度拉满
中国超越德国成全球第二大出口国!比亚迪自建船队引关注
世界快看点丨福建一景区回应多人推山顶“风动石”:重几十吨 风能吹动人推不动它
天天微头条丨没开发人员,接到开发物联网系统的活儿,干不干?
当前快讯:大笔加码越南!三星电子和LG将追加投资数十亿美元建厂
世界观点:惊了!研究发现蚂蚁竟也产奶 难道它也是哺乳动物?
1.7米长 从头裹到脚:洁丽雅加厚加大浴巾29元抄底
天天快播:“售后、周转、维护” 电动自行车换电池“三不要”
环球微动态丨移动端硬件实时光追落地!第二代骁龙8让游戏画面更逼真
快讯:全同态加密是否完美?
力扣刷题03
热门看点:MySQ 8.0 推出直方图,性能大大提升!
记录--uniapp自定义相机 自定义界面拍照录像闪光灯切换摄像头
世界视点!浙里办单点登陆、令牌获取用户信息
【全球热闻】iOS开发证书发布证书,推送证书,描述文件的生成总集(一)
世界今热点:AirPods Pro 2立大功!苹果占据31%真无线耳机市场
天天热议:网友吐槽买瓶饮料都要下载APP 网友:是我我扭头就走
全球热点!Chrome更新置顶横幅通知:明确不再支持Win7/8.1平台
环球速看:价格屠夫 小米4K双99%色域专业显示器2399元(首发3499)
天天快播:日本队更衣室留千纸鹤表感谢!国际足联再感谢日本球迷清理看台引热议 高素质
世界快讯:日产回应车机更新显示文案待定:车联网激活才可正常使用
手机端光追将至:Basemark推出首个移动设备光追基准测试
奇瑞汽车站起来了!连续6月销量超10万 破百万辆大关
小太阳取暖忘断电7分钟烧掉整间屋!官方科普冬季电器使用指南
世界焦点!买到运损保时捷女子要求退一赔三!判了:退车4S店再赔20万