难得一见的好文。赞,文章来自:Tim[后端技术]
全文点击查看。
┏┓ ┏┓
┏┛┻━━━┛┻┓
┃ ┃
┃ ━ ┃
┃ ┳┛ ┗┳ ┃
┃ ┃
┃ ┻ ┃
┃ ┃
┗━┓ ┏━┛
┃ ┃
┃ ┃
┃ ┗━━━┓
┃ ┣┓
┃ ┏┛
┗┓┓┏━┳┓┏┛
一个基础的问题,常常会源于几点限制而上升到艰难解答的猜想,
比如:大数问题,经典的高精度算数。
大量问题,OI时代常常遇到的大量数据,算法不当常常导致超时.
内存限制问题,在很多极限内存限制的时候,算法截然不同,这个等下会提到.
时间限制问题,O(n^2)与O(nlogn)算法之间的区别,在于n为100万时,这两种算法的运行时间分别为3小时和1秒。
首先来个很简单的例子。实现单位字节(8 bits)内部循环左移。
要求:循环左移x位
基础:基本位操作
int leftmove(int x, unsigned char B)
{
B = (B << x) | (B >> (8-x));
}
大部分时候我们会左移大得多的东西,例如字符串。
关于循环左移字符串,这里记录两个算法
要求:循环左移字符串
A:
基础:迭代思想
旋转向量x其实就是交换ab的两段,得到向量ba。
假设a比b短,将b分成bl与br, 使 length(br) = length(a),
交换 br与a, 得 br bl a 向量,则新任务是交换br与bl,与之前思想想通。
B:
基础:逆序思想(准确的说,近世代数)
一开始就分别对ab求逆序,ab-> ar b-> ar br
然后对a‘b’整体求逆 (ar br)r->ba
例如对于”abcdefg“
i = 3;
reverse(0, i-1); /* cbadefgh */
reverse(i, n-1); /* cbahgfed */
reverse(0, n-1); /* defghabc */
浮点数
一直以来我们对浮点都比较郁闷,他们在C里长期存在,但是大多数时候都被认为没意思和深奥难懂。
甚至C标准也未要求机器使用IEEE浮点,乃至 Intel IA32处理器对于浮点的特殊寄存器常常会打乱程序员思路。
这些都是这一次小结讲述说的内容。
现在大多数计算机都使用被称为IEEE浮点(IEEE floating point)的标准。 PS:IEEE读作 “I-Triple-E” .
V = (-1)^s * M * 2^E
s:符号位 1位
M:2进制小数 n位
E:2的幂,对浮点数加权 k位
对于单精度float, snk分别为1位,k=8位和n=23位。
对于双精度double,snk分别为1位,k=11位和n=52位。
根据E(exp)的值,浮点编码分为三种情况
1. 规格化值
exp非全0(数0),也非全1(数255或2047)时,指数的值被偏置(Biased),
指数域 E = e – Bias = e – 2^(k-1) + 1 e为指数域的无符号值
小数域 M = f + 1 其中 0<= f <1, 被认为是隐含的以1开头的数(implied leading 1)
2. 非规格化值
exp全0
指数域 E = 1 – Bias
小数域 M = f
非规格化数常常来表示 +0和-0 ,除了表示0值,也用于逐渐下溢出(gradual underflow)
3. 特殊数值
指数域exp E 全1
小数域 M 全0
符号位 s = 1 表示 负无穷 s = 0 表示正无穷
此时如果 小数域不全为零,这表示这个是 NaN,不是一个数(Not a Number).
CS:APP浮点部分写了一半,比较纠结。
去大波那里看了下,发现他在Qzone留言一个C题目,并且大言不惭的问谁会,于是果断解决了 🙂
试解释(*(void(*)())0)(); 是什么意思?
很简单的代码,却很有意思,谁会?
记得之前在书上看过,记得不太清楚了,自己又重新试了一下,不知道准不准确。
(*(void(*)())0) | (); 分离第一步,确定是一个函数,调用"(void(*)())0" 的函数指针使其运行。
(void(*)()) | 0 分离第二步,确定是一个强制类型转换,使用"void(*)()" 强制类型转换。
void(*) | () 分离第三布,确定是一个函数。
所以他总体的意思是: 运行在内存0位置的函数。
最早的出处在《C语言陷阱与缺陷》。
美丽心灵(A Beautiful Mind)。
i will watch you in the darkness ,show you love will see you through。
———- 《all love can be》
如果有一天早上起来,发现要开始相信昨天做的一切都成为虚假,近乎是人生中遇到的最恐惧事情。
最难忘的回忆,最要好的朋友,一切没有活着,没有死去,而是应该消失。
Nash: Thank you.
I’ve always believed in numbers ,in the equations and logics that lead to reason.
But after a lifetime of such pursuits, I ask, "What truly is logic? Who decides reason?"
My quest has taken me through the physical, the metaphysical, the delusional — and back.
那究竟是怎样的困境,现实与虚幻交错时,不再是现实,也不再是现实之上。
当纳什最后站在领奖台上,似乎证明了这样的希望,证明了这样的力量。
超越逻辑和理性,剩下的心灵,和身边最重要人的守护。支持着你走过这一切。
And I have made the most important discovery of my career,
the most important discovery of my life:
It is only in the mysterious equations of love that any logic or reasons can be found.
I’m only here tonight because of you (my wife, Alicia). You are the reason I am. You are all my reasons.
Thank you.
看到你的心灵,那埋藏在灵魂深处,给予你最初的力量,给予一切空间的力量。
不再是积累的习惯,不再是跳跃的思维,不再是严格的逻辑,心灵一直在,却很少被你看到。
用心灵的力量改变生活,远远大于用心力的努力,我想,也是纳什所表达的,艾丽西娅在绝望中寻找心灵的力量,
和最后证明爱的力量。
Nash: I don’t, I just believe it.
Alicia: It’s the same with love, I guess.
作者:梦幻流星 | 来自:丁洋,内蒙古
本部分仅作保存。
大学究竟原本是什么样的?
德国二百年前的教育宣言曾经如此说道:教育的目的,不是培养人们适应传统的世界,不是着眼于实用性的知识和技能,而要去唤醒学生的力量,培养他们自我学习的主动性,抽象的归纳力和理解力,以便使他们在目前无法预料的种种未来局势中,自我做出有意义的选择。教育是以人为最高的目的,接受教育是人的最高价值的体现。
宋朝一代大儒张载曾如此说过:为天地立心,为生民立命,为往圣继绝学,为万世开太平!
五年多以前,我进入了全国重点名牌大学:武汉大学读书。我抱着最理想的热情,以为从此走上了一条报效祖国,报效父母的人生坦途,以为我的人生即将要大展宏图!
三年以前,抱着对“我的大学”最大的疑惑和不解,我辞去了分团委副书记的职务,开始认真地大量阅读和思考我的人生,我的大学,我的未来。试图找到对周围一切我无法理解问题的解决方案。这一次的决定,也意味着我放弃了原来一直抱有的,通过“从政”来为国家民族做贡献的“远大理想”。
一年半以前,我自以为已经看清了中国大学的本质,不愿意再继续自欺欺人地“学”下去,主动放弃了学校保研的名额,退出了用青春和热血换取一纸毫无真实内容和分量文凭的游戏,退出了中国虚伪可笑的“精英学历社会”。决心进入企业,踏踏实实地从事“实业”,站到中国经济第一线,为国家和社会以及自己作真实的努力和贡献。因为我不想用镀金的“文凭”和“文化”来糊弄我自己,也糊弄其他人。
今天,在毕业工作一年多后,在我的工作和能力已经得到老板和同事的肯定,马上就要派我出国任职的时候,我却辞职了。我不想违心地接受这个光荣,我决心到远在大山中的一所规模很小的,志在探索中国新教育模式的私立学堂,试图通过投身中国最缺乏,
最需要的教育,来实现我人生最大的价值:为我热爱的中国,为中国的孩子和未来,也为我自己,做一点真正有意义的事情,而不是日复一日地在无望的等待中浪费掉自己的生命。
因为,中国真正缺的不是钱,我缺的也不是钱。中国缺文化,缺教育。我也一样!
周围的人都认为我疯了,鬼迷心窍阿了。放弃了中国人从小就灌输的,从小就追求的“最正宗”、“最正确”、“最理所当然”的道路的确令人不解。我也在认真地思考我这样做的理由。在这里,把自己对家人和朋友质疑的回答写出来。你们也可以自己评析:到底是我疯了,还是这个社会疯了?
C基础文件操作常常遇到,例如 fopen,fputc 等,在其之上可以自己重新定义文件操作,写大作业的过程中需要重写文件输入输出。(大一做的调用linux函数,在win下还是不方便)
于是重写了文件封装。
主要实现的功能:获取文件大小(字节单位),实现无视空格回车等特殊符号的文件流读入(文件结束符EOF除外)
ctqmumu@ctqmumu-laptop:~/桌面/Code/sms$ ./smsfile Filetest/md5.c
0000000000000000000000000000000000000000
0000000000000000000000000000000000000000
0:./smsfile
1:Filetest/md5.c
(nil):0x9819008
file_size:8850(Bytes)
len is 0
copy[30]:
2F2A0D0A202A205468697320636F646520696D706C656D656E7473207468
代码点击查看。
继续阅读
下次的第二章小结会以浮点数结束。
这几天重新看CS:APP,一直在想一个问题,那就是究竟什么才算 “优秀的程序员”?
下午突然有所感想,那时正在看《编程珠玑》(Programming Pearls),第一章习题中的答案似乎不太准确(P196页 C下使用位向量的举例):
#defien BITSPERWORD 32
#defien SHIFT 5
#define MASK 0x1F
#define N 10000000
int a[ 1 + N/BITSPERWORD];
void set(int i) { a[i>>SHIFT] |= (1<<(i & MASK));}
void clr(int i) { a[i>>SHIFT] &= ~(1<<(i & MASK));}
int test(int i) { return a[i>>SHIFT] & (1<<(i & MASK));}
当出现负数时会如何?随后我又否定了自己的观点,因为题意中标注只会有正整数。可是如果是负数呢?
那么很可惜算数位移并不会对他造成太大的偏差,因为填充的最高位被新的次高位抵消一半,而整体权值下降一半。
却需要重新定义数组了。
想到这个问题确实是因为重新看了第二章的缘故。
另外这里还有一点小彩蛋。
有么有真正想过CPU对于你的代码的时间消费呢?
CS:APP里面提到:
加法,减法,位级运算,位移 只需要1个时钟周期
乘法需要至少 12个时钟周期
除法需要至少 30个时钟周期
所以GCC编译器很喜欢尽可能的将乘除换成左右位移 🙂
例如
result = X*M + Y/N;
return return;
>>GCC to >>
int t X;
X << 4;
X -= t;
if (Y < 0) Y += 3;
Y >>= 2;
return X+Y;
猜猜M,N是多少? (提示:对于二进制补码左移,如果X < 0 需要在位移前偏置(biasing), 即加上2^k-1)