年轻吧 > 热点 > 正文

​如何花式计算20的阶乘?

时间:2024-11-21 01:48

来源:年轻吧

点击:

如何花式计算20的阶乘?

今天刷知乎看到个挺有意思的问题:

我想这有啥难的,还能写出花来不成?结果看到高赞回答,感觉自己的智商有点不够用了。

随便来看一个高赞回答是怎么写的:

这个其实还算比较简单的,没啥难度,还有更晦涩的:

这个乍一看根本看不懂在写啥,当然平时也很少会写这种晦涩的代码。

CUDA花式整活!

今天我就教大家用CUDA来计算一下20的阶乘,就当作是CUDA的一个入门例子。

先来看看我的回答:

如何优雅地利用c++编程从1乘到20?13 赞同 · 2 评论回答

我提供了两种CUDA的实现方法。

方法1

#includetypedef unsigned long long int ull;
const int N = 20;
__device__ ull atomicMul(ull* address, ull val) {
ull *address_as_ull = (ull *)address;
ull old = *address_as_ull, assumed;
do {
assumed = old;
old = atomicCAS(address_as_ull, assumed, val * assumed);
} while (assumed != old);
return old;
}
__global__ void mul(ull *x) {
ull i = threadIdx.x + 1;
atomicMul(x, i);
}
int main() {
ull *x;
cudaMallocManaged(&x, sizeof(ull));
x[0] = 1;
mul<<>>(x);
cudaDeviceSynchronize();
std::cout << x[0] << std::endl;
cudaFree(x);
return 0;
}

这个方法使用原子操作,一共20个线程,每个线程负责一个乘数,然后一起乘到x[0]上。

但是由于并行执行,线程之间没有先后顺序,会导致同时乘的时候产生冲突,所以需要使用原子操作。在某一个线程将它的乘数乘到x[0]上时,不会被其他线程打断。也就是会加锁,同一时刻只会有一个线程在进行乘法操作。

但是由于CUDA只提供了加法和减法的原子操作(atomicAdd和atomicSub),所以得自己实现乘法的原子操作atomMul,利用的是atomicCAS操作,也就是compare and swap ,如果目标地址元素和待比较的元素相同,就进行元素的交换,否则不进行任何操作。

可以看出,在atomicMul函数的do while循环中,先用old变量保存x[0]处的当前值,这时候如果有其他线程在x[0]处写入了新的值,那么接下来该线程的atomicCAS操作就会判断元素不相同,不进行任何操作,重新执行下一轮循环。

方法2

#includetypedef unsigned long long int ull;
const int N = 20;
const int WARP_SIZE = 32;
__global__ void mul(ull *x) {
int i = threadIdx.x;
ull val = x[i];
for (int mask = WARP_SIZE / 2; mask > 0; mask >>= 1)
val *= __shfl_xor_sync(WARP_SIZE - 1, val, mask, WARP_SIZE);
x[i] = val;
}
int main() {
ull *x;
cudaMallocManaged(&x, WARP_SIZE * sizeof(ull));
for (int i = 0; i < WARP_SIZE; ++i)
x[i] = i < N ? i + 1 : 1;
mul<<>>(x);
cudaDeviceSynchronize();
std::cout << x[0] << std::endl;
cudaFree(x);
return 0;
}

这种方法使用线程束原语__shfl_xor_sync,只要线程在同一个线程束中(32个线程),就可以获取其他线程的值,异或运算后写入指定地址。详细原理这里就不解释了,可以简单理解为:

一共进行5轮操作。第一轮操作之后,下标为0-15的位置分别保存着下标0+1、2+3、一直到30+31的结果。第二轮操作之后,下标为0-7的位置分别保存着下标0+1+2+3、4+5+6+7、一直到28+29+30+31的结果。最后一轮之后,下标为0的位置保存着所有32个元素之和。

所以只需要在开始时,分配一个大小为32的数组,前20个元素分别保存1-20,后面12个元素是为了满足线程束大小32的条件,赋值为1就行了。

方法2改进

方法2需要额外开辟大小为32的数组,空间存在浪费,并且数组赋值也需要时间。

感谢@NekoDaemon老哥提供的优化建议,只需要在计算的时候根据线程号计算对应乘积元素就行,但是线程数仍然需要分配32个。

#includetypedef unsigned long long int ull;
const int N = 20;
const int WARP_SIZE = 32;
__global__ void mul(ull *x) {
int i = threadIdx.x;
ull val = i < N ? i + 1 : 1;
for (int mask = WARP_SIZE / 2; mask > 0; mask >>= 1)
val *= __shfl_xor_sync(WARP_SIZE - 1, val, mask, WARP_SIZE);
if (!i) x[i] = val;
}
int main() {
ull *x;
cudaMallocManaged(&x, sizeof(ull));
mul<<>>(x);
cudaDeviceSynchronize();
std::cout << x[0] << std::endl;
cudaFree(x);
return 0;
}

执行结果

代码保存为run.cu,然后执行nvcc run.cu -o run,最后执行./run,就会出来结果2432902008176640000。

今天没有讲解CUDA编程的基础概念,适合有一定基础的同学阅读,如果有对CUDA感兴趣的同学,可以在评论区留言,下次专门写一个CUDA入门系列教程。关注我的公众号【算法码上来】,每天跟进最新文章。

相关标签:

相关推荐

​美人鱼究竟长什么样?(当然希望不是图中这样)

​美人鱼究竟长什么样?(当然希望不是图中这样)

美人鱼究竟长什么样?(当然希望不是图中这样) 安徒生童话里那个眼睛像星星一样、歌声美丽动人的小美人鱼大概是我们所有人对美人鱼最初的印象,纯洁、美丽、心地善良。人类历...

2024-11-21 01:45:56

​河北省迁安市概况

​河北省迁安市概况

河北省迁安市概况 迁安市隶属河北省,位于河北省东北部,燕山南麓,滦河岸边,地理坐标为东经118°37′~118°55′,北纬39°51′~40°15′之间,西距北京市195公里,天津市160公里,东...

2024-11-21 01:43:43

​7部人生必看校园韩剧!

​7部人生必看校园韩剧!

7部人生必看校园韩剧! 不论是想要找回青春爱恋、同学友谊、考试压力,还是校园霸凌等社会议题与回忆,都可以在校园剧找到共鸣和代入感! 南柱赫、金泰梨《二十五,二十一》...

2024-11-21 01:41:30

​《层层密室》第11、12、13、14、15关攻略

​《层层密室》第11、12、13、14、15关攻略

《层层密室》第11、12、13、14、15关攻略 第十一关:点击标志1,得到一把引线,点击蓝色柜子,按照里面的记忆点击,得到一捆绳索,和一个C4炸药, 点击标志5 ,得到一个钉环, 点击...

2024-11-21 01:39:17

​十月初十将至,你知道是什么日子吗?老祖宗的谚语怎么说

​十月初十将至,你知道是什么日子吗?老祖宗的谚语怎么说

十月初十将至,你知道是什么日子吗?老祖宗的谚语怎么说 #头条创作挑战赛# 导读:农历十月初十将至,你知道是什么日子吗?老祖宗留下的谚语怎么说? 俗话说: “八月冷,九月温...

2024-11-21 01:37:04

​忍者神龟第2集:boss露面,史莱德打劫动物园,牛头猪面诞生

​忍者神龟第2集:boss露面,史莱德打劫动物园,牛头猪面诞生

忍者神龟第2集:boss露面,史莱德打劫动物园,牛头猪面诞生 萌叔侃动漫,每天找一点时间,跟大家边看边侃童年经典动画片,好久不侃1987版《忍者神龟》了,眼下就找来第2集闲侃吧...

2024-11-21 01:34:51

​都是套路!购买葡萄酒,千万不可迷信扫码价

​都是套路!购买葡萄酒,千万不可迷信扫码价

都是套路!购买葡萄酒,千万不可迷信扫码价 葡萄酒营销套路多,小心面子碎一地 N年前的中秋前夕,陪好友W去选购礼物。 在当时,过节送红酒还是挺有面儿的。 来到了一个酒庄,门...

2024-11-21 01:32:38

​星座密语:你的星座揭示的生命密码

​星座密语:你的星座揭示的生命密码

星座密语:你的星座揭示的生命密码 无论是追寻人生目标还是寻找内心平静,每一个人都希望在生活中找到自己的独特密码。而这个密码,或许就隐藏在你的星座之中。让我们深入探索...

2024-11-21 01:30:26

​苏联杰出艺术家伊万诺维奇油画

​苏联杰出艺术家伊万诺维奇油画

苏联杰出艺术家伊万诺维奇油画 维塔利·伊万诺维奇(1937 - 1998)1937年2月28日出生在列宁格勒。1962年,他从的工作室毕业。我和彼得·法明,梅尔尼科夫一起学习。1932 - 1997年艺术家是俄罗...

2024-11-21 01:28:13

​肉香剧情佳 - 长着翅膀的大灰狼

​肉香剧情佳 - 长着翅膀的大灰狼

肉香剧情佳 - 长着翅膀的大灰狼 更多免费小说资源请关注微信公众号:晋江书迷,还有更多好文推荐给大家。 写在前面: 前段时间听说长着翅膀的大灰狼被抓了,然后还登上了热搜。...

2024-11-21 01:26:00

​大唐荣耀:慕容林致李倓结局意难平

​大唐荣耀:慕容林致李倓结局意难平

大唐荣耀:慕容林致李倓结局意难平 #演技实力派# 这是2016年的剧了,这部剧让任嘉伦一下子走进了观众的心里,他饰演的广平王李俶温柔、专情,对沈珍珠不离不弃,他们的感情多坎...

2024-11-21 01:23:47

​爱因斯坦,手机和你

​爱因斯坦,手机和你

爱因斯坦,手机和你 作者:Robert Cahn 翻译:胡岚翔 审校:loulou 爱因斯坦之所以得诺贝尔奖,靠的不是他的相对论。他得这个奖,是因为他向整个科学界阐明了为何我们毋需担忧手机辐...

2024-11-21 01:21:34

​1920年海原8.5级大地震—28万人死亡,4座县城夷为平地

​1920年海原8.5级大地震—28万人死亡,4座县城夷为平地

1920年海原8.5级大地震—28万人死亡,4座县城夷为平地 1920年12月26日20点06分,甘肃固原县跟海原县一带发生了8.5级超级大地震,震中位于海原县县城西郊外的哨马营跟大沟门的中间位置...

2024-11-21 01:19:21

​中科院院士陆大道:贪大求快是一些新城新区失败的主要原因

中科院院士陆大道:贪大求快是一些新城新区失败的主要原因 《财经》记者 张倩/文 朱弢/编辑 近年来,新城新区遍地开花,不少地方意在借此推动地方产业升级转型,并拉动增长。但...

2024-11-21 01:17:09

​全面禁售苹果?库克听了心都要碎了,外媒:这一切都将尘埃落定!

​全面禁售苹果?库克听了心都要碎了,外媒:这一切都将尘埃落定!

全面禁售苹果?库克听了心都要碎了,外媒:这一切都将尘埃落定! 近日,有关全面禁售苹果手机的消息在网络上引起了广泛关注和热议。据外媒报道,这一事件已经进入尘埃落定的阶...

2024-11-21 01:14:56

​伟大女性雷洁琼:74岁任北京副市长,81岁官至副国级,享年106岁

​伟大女性雷洁琼:74岁任北京副市长,81岁官至副国级,享年106岁

伟大女性雷洁琼:74岁任北京副市长,81岁官至副国级,享年106岁 二十世纪初,随着清政府的轰然坍塌,中国结束了两千多年的帝制时代,步入了民国时期。这一时期,中国女性的地位...

2024-11-21 01:12:43

​为了复仇自毁容貌吞炭毁声,倚天的范遥原来是仿效战国的刺客豫让

​为了复仇自毁容貌吞炭毁声,倚天的范遥原来是仿效战国的刺客豫让

为了复仇自毁容貌吞炭毁声,倚天的范遥原来是仿效战国的刺客豫让 有看过《倚天屠龙记》的朋友应该都会记得那个为潜入汝阳王府做卧底而自毁容貌,吞炭毁声的明教光明右使范遥。...

2024-11-21 01:10:30

​铃木Ignis:小可爱级别的城市代步车

​铃木Ignis:小可爱级别的城市代步车

铃木Ignis:小可爱级别的城市代步车 铃木Ignis 铃木Ignis的设计走跨界休旅车风格,有很可爱的圆润方正造型,驾驶时给人“轻盈、机动”的感觉,起步轻快流畅,适合用于城市通勤,在...

2024-11-21 01:08:17

​食鲨记-三亚海鲜美食追寻

​食鲨记-三亚海鲜美食追寻

食鲨记-三亚海鲜美食追寻 鲨鱼翅在民间通常以鱼翅简称。作为中国传统的名贵食品之一,始见于《宋会要》。鱼翅为古代八珍之一,八珍虽有好几个版本,但鱼翅总能占据一席,可见...

2024-11-21 01:06:04

​4AM孤存事件再反转,SY、niko接力蹭热度,龙神决终于亮出实锤

​4AM孤存事件再反转,SY、niko接力蹭热度,龙神决终于亮出实锤

4AM孤存事件再反转,SY、niko接力蹭热度,龙神决终于亮出实锤 最近绝地求生圈子里最热门的事件全都是关于4AM的,一方面以全新阵容出战斗鱼黄金大奖赛的4AM高歌猛进,提前打卡下班晋...

2024-11-21 01:03:52