C_and_CPP 板


LINE

最近有个热门的讨论话题 就是计算费氏数列的复杂度到底是 O(1) 还是 O(n) 刚好我前几天在看 wiki 尝试 compiler 的一些东西的时候 https://zh.wikipedia.org/wiki/%E5%B0%BE%E8%B0%83%E7%94%A8 也遇到一些有趣的 O(1) 还是 O(n) 的问题 觉得很有趣所以就分享上来 我也有把问题丢在 stackoverflow 上面问 没想到上面的反应也蛮热烈的 https://stackoverflow.com/questions/54686395 让我不小心赚到了一些 reputation,大概比我回答十个问题还多 --- 不管复杂度是 O(1) 或是 O(n),也不管 lookup table 到底要不要存在月球上 费氏数列递回的形式都是这条:F(x) = F(x-1) + F(x-2), F(1) = F(2) = 1 不过今天要讨论的是一个更简单的问题 F(x) = F(x-1)+1, F(0) = 0 学过中学以上归纳法的人类都能知道 F(x) = x 而学过 C++ 的人都可以把这个式子转换变成程式码 int Identity(int i) { if (i == 1) return 1; else return Identity(i-1)+1; } 上面的 wiki 说明了这个并不是有效的 tail recursion 形式 理论上应该不会变成 for loop 会产生 O(n) memory, O(n) runtime 的程式 (PS: 如果是 for loop,应该是 O(1), memory O(n) runtime) 为了验证,我用了 gcc 8.2.1 编译看看,结果大出意外 % g++ a.cpp -c -O2 && objdump -d a.o Disassembly of section .text: 0000000000000000 <_Z8Identityi>: 0: 89 f8 mov %edi,%eax 2: c3 ret Linux 下 x64 的第一个整数是 %edi,回传值放在 %eax 等等,所以我以为 O(n) 的问题,真的可以在 O(1) 解出来吗(误) 难道 compiler 做了一些数学计算,推出 F(x) = x 了吗 该不会在这个大 AI 时代,compiler 也要内建高中生等级的 super AI 了吧 该不会我下次升级到 gcc 9 的时候,我的 compiler 就会跑去当 Youtuber 了吧?! --- Sorry 扯远了,回归正题 我一开始的想法是 1. gcc 知道了 negative i 会撞到 UB,因此可以随便回传任何值 (PS: negative i 不会变成 infinite loop 的 UB,而是 overflow) 2. positive i 的情形 gcc 经过了某些数学推导算出 F(x) = x 但是怎麽看都觉得太神奇,感觉不会有人实做这种东西 总之经过 stackoverflow 一番讨论之後 看起来的结论如下 首先,当代的 gcc 不只可以化简基本的 tail recursion 就连上面那个形式都可以(可以去看 stackoverflow 的一些讨论) 虽然详细上原理我不太明白,但是应该、大约、好像会变成这样子 int Identity(int i) { int ans = 0; for (; i != 0; i--, ans++); return ans; } 接着我猜测这个形式对 compiler 来说应该比较好化简了 因为这种 for loop 非常常见,应该有机会做某种化简得到 F(x) = x 顺带一题,直接写这个程式的话,gcc 是可以化简 O(n) -> O(1) 的 如果 i != 0 改成 i >= 0 的话,gcc 会变成 return i > 0 ? i : 0; 真的很厉害 --- 另外 stackoverflow 里面有人直接挖出 gcc code 来解释 但是其实我不是 compiler 专家 所以我这篇主要还是单纯分享一些我的观察啦 如果这个版有人能做出更浅显易懂,又更完整的解释的话就太好了 谢谢大家~ -- Time waits for no one. ↑ (。A。)ハァ --



※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 118.160.89.176
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/C_and_CPP/M.1550249453.A.382.html
1F:推 KanzakiHAria: 你应该没搞懂那个讨论 02/16 06:33
2F:→ KanzakiHAria: O(1)是说费式数列有一个公式解 02/16 06:33
3F:→ KanzakiHAria: 可是里面有开根号 所以实务上并不是O(1) 02/16 06:34
4F:→ KanzakiHAria: 开根号速度跟数字长度有关系 02/16 06:34
5F:→ KanzakiHAria: 那个作者非常智障的呛人time it 实际上就不是O(1) 02/16 06:35
6F:→ KanzakiHAria: 那个人履历蛮漂亮的 电机出身+待过微软开发过VS前期 02/16 06:36
7F:→ KanzakiHAria: 看他讲话好像连基本的计算机原理和演算法数学都不懂 02/16 06:36
8F:→ KanzakiHAria: 连我以前当助教的学生都可以电爆他了XD 02/16 06:37
9F:推 KanzakiHAria: 讲错了 不是开根号 是次方问题 02/16 06:41
10F:推 KanzakiHAria: 然後O(n)里的n 一种是编码长度 一种是input数量 02/16 06:47
11F:→ KanzakiHAria: 因为是编码长度问题 所以实际上是O(lgn) 02/16 06:49
12F:推 KanzakiHAria: 不过说不定原作者是想表达C++有编译时期运算技术 02/16 06:52
13F:→ KanzakiHAria: 所以不管n多大C++都会在编译时期算好 02/16 06:52
14F:→ KanzakiHAria: 所以run-time是O(1)wwwwwwwwww 02/16 06:52
15F:推 KanzakiHAria: https://i.imgur.com/N6tFX0a.png 02/16 07:02
16F:推 alan23273850: 神奇给推! 02/16 08:57
17F:→ KanzakiHAria: 已经跟地球月球时间无关 而是根本上错误 02/16 08:57
18F:推 steve8625: 真有趣~~ 02/16 11:55
19F:推 b98901056: Vtuber compiler XD 02/16 12:44
20F:推 firejox: 以编码长度来看,也不会是O(lg n) 02/16 20:02
21F:→ Sanvean: 我是不是错过了什麽新闻? 求费氏数列的讨论串 pAq 02/17 14:45
22F:推 Higana: https://i.imgur.com/nZmquHA.jpg 02/17 16:26
23F:→ Ommm5566: ㄟ 这是两件事 1. O(logN) 是因为乘法有快速乘法logN 02/17 17:14
24F:→ Ommm5566: 2. turing machine来看编码长度确实是logN 02/17 17:16
25F:→ Ommm5566: 然後巧合的是刚好这两件事可以挂勾在一起 02/17 17:17
26F:推 Ommm5566: 这个讨论串居很无聊,居然这麽多人关注。 02/17 17:20
27F:推 LPH66: 楼上的两个 logN 是不同 N 吧? 02/17 20:02
28F:→ LPH66: 你的"快速乘法"的 log N 的 N 是编码长度 02/17 20:02
29F:→ LPH66: turing machine 编码的 logN 的 N 是数值本身 02/17 20:03
30F:推 Ommm5566: Fabonacci(X) 这个是编码长度logX 所以放在tap上是logX 02/17 20:19
31F:→ Ommm5566: 然後公式解是一个const连乘X次 02/17 20:20
32F:→ Ommm5566: 因为有快速乘法所以时间是logX 02/17 20:21
33F:→ Ommm5566: 这题只是刚好快速乘法的行为跟二进为编码直接有相关 02/17 20:21
34F:推 Ommm5566: 1000 是四位数编码 100是三位数编码 10是两位数编码 02/17 20:24
35F:→ Ommm5566: 放在tap上长度本来就是logN 02/17 20:24
36F:推 KanzakiHAria: 所以正确来说编码长度N的费氏数列时间复杂度O(N) 02/17 21:32
37F:推 KanzakiHAria: 前面可能我表达不好 这个应该没争议了吧 02/17 22:36
38F:推 AstralBrain: O(N)次乘法, 但是乘法的时间不一定是O(1), 看你要怎 02/18 02:33
39F:→ AstralBrain: 麽算 02/18 02:33
40F:→ AstralBrain: 算出没误差的精确值至少是O(2^N), 因为答案本身就有 02/18 02:34
41F:→ AstralBrain: O(2^N)bit了 02/18 02:34
42F:推 AstralBrain: 啊..修正一下, 底不确定是不是2, 但总之是指数级成长 02/18 02:53
43F:→ gus2: 怎麽推文都在回讨论串?本文重心是编译器优化递回f(i)成i吧 02/18 03:13
44F:推 gus2: 有趣给推 02/18 03:15
45F:→ Caesar08: 请问Higana,这是在哪个社团,那麽有趣 XD 02/18 13:04
46F:推 asd456fgh778: 楼上 Python台湾 02/18 14:42
47F:推 Higana: 是的 但该篇他老早就删了 剩一些後续讨论这样 02/20 01:44







like.gif 您可能会有兴趣的文章
icon.png[问题/行为] 猫晚上进房间会不会有憋尿问题
icon.pngRe: [闲聊] 选了错误的女孩成为魔法少女 XDDDDDDDDDD
icon.png[正妹] 瑞典 一张
icon.png[心得] EMS高领长版毛衣.墨小楼MC1002
icon.png[分享] 丹龙隔热纸GE55+33+22
icon.png[问题] 清洗洗衣机
icon.png[寻物] 窗台下的空间
icon.png[闲聊] 双极の女神1 木魔爵
icon.png[售车] 新竹 1997 march 1297cc 白色 四门
icon.png[讨论] 能从照片感受到摄影者心情吗
icon.png[狂贺] 贺贺贺贺 贺!岛村卯月!总选举NO.1
icon.png[难过] 羡慕白皮肤的女生
icon.png阅读文章
icon.png[黑特]
icon.png[问题] SBK S1安装於安全帽位置
icon.png[分享] 旧woo100绝版开箱!!
icon.pngRe: [无言] 关於小包卫生纸
icon.png[开箱] E5-2683V3 RX480Strix 快睿C1 简单测试
icon.png[心得] 苍の海贼龙 地狱 执行者16PT
icon.png[售车] 1999年Virage iO 1.8EXi
icon.png[心得] 挑战33 LV10 狮子座pt solo
icon.png[闲聊] 手把手教你不被桶之新手主购教学
icon.png[分享] Civic Type R 量产版官方照无预警流出
icon.png[售车] Golf 4 2.0 银色 自排
icon.png[出售] Graco提篮汽座(有底座)2000元诚可议
icon.png[问题] 请问补牙材质掉了还能再补吗?(台中半年内
icon.png[问题] 44th 单曲 生写竟然都给重复的啊啊!
icon.png[心得] 华南红卡/icash 核卡
icon.png[问题] 拔牙矫正这样正常吗
icon.png[赠送] 老莫高业 初业 102年版
icon.png[情报] 三大行动支付 本季掀战火
icon.png[宝宝] 博客来Amos水蜡笔5/1特价五折
icon.pngRe: [心得] 新鲜人一些面试分享
icon.png[心得] 苍の海贼龙 地狱 麒麟25PT
icon.pngRe: [闲聊] (君の名は。雷慎入) 君名二创漫画翻译
icon.pngRe: [闲聊] OGN中场影片:失踪人口局 (英文字幕)
icon.png[问题] 台湾大哥大4G讯号差
icon.png[出售] [全国]全新千寻侘草LED灯, 水草

请输入看板名称,例如:Gossiping站内搜寻

TOP