计算机杂学笔记

名词解释

程序原子性

即程序无法中断,要么全部执行,要么全部不执行。

宏(Macro)

一种批量处理的称谓。计算机科学里的宏是一种抽象(Abstraction),它根据一系列预定义的规则替换一定的文本模式。解释器或编译器在遇到宏时会自动进行这一模式替换。

以上是网上的解释,按我的理解,宏的作用是用来提高效率的,宏指的是在程序或文本中用一些字符来替代另一些字符或一系列指令,例如C语言中的:

#define PI 3.1415926

就是用PI来代替3.1415926,编译器在预处理预编译的时候,就会把代码中的出现的全部“PI”替换成3.1415926,这个过程叫作“宏展开”,当然以上为一个最简单的宏定义,C语言中还有各种带参数的宏定义,水平有限就不展开了。

在硬件上,也有“宏”这个概念,例如游戏鼠标常有的“鼠标宏”功能,就是通过事先的编程,使得鼠标上的某个按键按下后,会自动执行一系列的操作,比如“起身(空格)—开火(左键)—下蹲(Ctrl)”这种……按我的理解,这也是一种替换,按键相当于“PI”,而执行的一系列动作相当于“3.1415926”。而如果把握住宏“为提高效率进行的指令替换”这一点,可以将宏的概念拓展到更为广泛的领域之中,如百度百科所说的“宏”更为通用的概念:将小命令或动作转化为一系列指令。


同余式与取模运算

对于整数a、b、m,若a%m==b%m(即a与b都mod m后有相同的余数),则记:a≡b(mod m),或记为a≡b(m)。

取模运算基本规则

(a + b) % p = (a % p + b % p) % p

(a - b) % p = (a % p - b % p) % p

(a * b) % p = (a % p * b % p) % p

a ^ b % p = ((a % p)^b) % p

结合律

((a+b) % p + c) % p = (a + (b+c) % p) % p

((ab) % p * c) % p = (a * (bc) % p) % p

分配律

(a+b) % p = ( a % p + b % p ) % p (9)

((a +b)% p * c) % p = ((a * c) % p + (b * c) % p) % p


求两数平均值的细节

为了防止溢出,应避免使用前面这种算法:

int mid = (left+right)/2;           //避免使用
int mid = left + (right-left)/2;    //推荐使用,两者效果完全一样



不使用大括号实现二维数组的打印

for (int i=0; i<n; i++)
    for (int j=0; j<m; j++)
        printf("%d%c", a[i][j], " \n"[j == m-1]);  //C版本
        //cout << a[i][j] << " \n"[j == m-1];      //C++版本



高精度处理的细节

不能从高位向低位进行处理。(若上一位是9,当前位满10,向上一位进1就无法返回去处理上一位使其归零。)

高精度乘法可以用FFT(快速傅里叶变换)优化。


​浮点型数据存储方法

单精度(single)及双精度(double)

单精度(也称为float)占用32bit,1位符号,8位指数,23位尾数。

下面存储方式以C++的float类型为例:

浮点数的存储以2为底数的科学计数法表示,即 a × 2^k 这种形式,且a、2、k均以二进制形式存储。a为尾数,k为指数。

  • 符号位:0代表正数,1代表负数。

  • 指数:指数存储的值减去127,才是实际的指数值。举个例子,‭01011011‬转换成十进制为133,其对应的实际指数值就是133-127=6。此外,指数11111111用于表示特殊情况,指数全为1,尾数全为0,用于表示无穷,指数全为1,尾数不为0,用于表示NaN。因此,指数表示范围为-127到127。对应十进制,就是10^(-38) 到 10^38的范围。

  • 尾数:实际上,23位的长度可以表示24位尾数,这是因为写成科学计数法后,a的第一位永远是1,例如1. 010011…因此尾数的第一位就被省略掉了。

因此,float所能表示的最大的数(除了符号位全为1)转换为十进制是(小数点后23个1):

1.11111111111111111111111 × 2 127 1.11111111111111111111111 \times 2^{127} 1.11111111111111111111111×2127

= ( 1 + 1 / 2 + 1 / 4 + . . . + 1 / 2 23 ) =(1+1/2+1/4+...+1/2^{23}) =(1+1/2+1/4+...+1/223)

= ( 2 23 + 2 22 + 2 21 + . . . + 2 0 ) × 2 − 23 × 2 127 =(2^{23}+2^{22}+2^{21}+...+2^0) \times 2^{-23} \times 2^{127} =(223+222+221+...+20)×223×2127

= ( 2 24 − 1 ) × 2 127 − 23 =(2^{24}-1) \times 2^{127-23} =(2241)×212723

≈ 3.4028 × 1 0 38 \approx 3.4028 \times 10^{38} 3.4028×1038

双精度(double)为1位符号,11位指数,52位尾数。

有效位数

对于float,十进制下有效数字有7位,举个例子:

float a = 3.000001;
float b = 3;
cout<<a-b;
a = 3.0000001;
cout<<a-b;

前者输出9.53674e-007,后者输出0,这是由于float 的精度只能达到小数点后6位(也就是7位有效数字),因此有效数字的第八位会被四舍五入掉(区别:如果将小数赋值给整型,小数部分会被直接舍掉,而不是四舍五入)

double则可以达到15位有效数字的精度。

举个例子

8.25转为二进制为1000.01,科学计数法为1.00001×(10×10×10),即11个10相乘,指数为11,指数位为10000010。

尾数为1.00001,由于尾数第一位永远为1,被省略,所以8.25的尾数部分为00001000000000000000000。


整型数据存储方法

我们以byte类型(8位,数据范围-128~127)的变量a为例:

众所周知,非负数的原码、反码、补码相同,在此不做讨论,这里讲讲我对负数反码、补码的理解以及其实际用处。

假如a=-13,其原码为10001101,反码为11110010。实际上,反码的求法可以这样理解:

负数的原码、反码、补码符号位均为1,现在忽略符号位(即假设原码、补码、反码仅有7位,转为对应的十进制数均为正数,若无特殊说明以下码值均作此处理),设负数的绝对值的原码为a,发现:反码=1111111-a。

也就是说,如果我们把反码除符号位看成了原码,并换成十进制,发现-13的反码为127-13=114。

同理,忽略符号位,补码=1111111+1-原码,即补码=128-13=115,也就是说,绝对值越大的负数,其补码看起来越小。

这样一来,补码的其中一个作用得以体现:把-128容纳进数据范围,其补码为128-128=0,考虑符号位,也就是10000000。

补码的另一个作用体现在运算上,先阐述三个特性:

(1)计算机存储和运算都是通过补码来完成。

(2)变量的值若超过范围,并不会报错,而是如同时钟一样,越过终点又回到起点。

例如给a赋值为128时,其值会自动变成-128,赋值为129时会变成-127,对于超过范围的负数同样适用,赋值为-129时,a自动变为127。

(3)实际运算中,变量只进行加法运算,例如7-6,会变为7+(-6)再进行运算。

结合这两个特性,我们来看补码的加法运算:

(1)两个正数相加。没有什么特殊的,只提一点:因为符号位都是0,若两数a、b的和超过127,则补码符号位会变为1,和为127+超出部分,即1111111+超出部分,和从-128开始随超出部分增大而增大,符合特性(1)。

(2)两个负数相加。设这两数原码为a、b,则它们的和c的补码等于1111111+1-a+1111111+1-b=10000000-(a+b)+10000000,原来两数符号位均为1,加完后为0,多加的一个10000000补到符号位上,也就是说,c的补码可以看作10000000-(a+b),符号位为1。若a+b未超出范围,即1<a+b<=10000000,则c的补码>=0,符号为1,结果满足加法运算法则。若a+b超出范围,则c<0,低位不足,高位退位,符号位又变回0,符合特性(1)。

(3)一正一负相加。忽略符号位,设正数原码为a,负数原码为b,补码相加等于10000000-b+a,符号位为0+1=1。若a>=b,补码>=10000000,符号位从1又变为0。若a<b,补码<10000000,加上符号位的1,为负数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值