信息的表示

注意點

  1. 計算機一般使用8位的塊或者字節作爲最小的可尋址的單位。而不是直接對位進行編碼。
  2. 虛擬存儲器 :一個字節數組
  3. 虛擬地址空間:所有可能的地址
  4. 一個指針的值都是 存儲塊的第一個字節的虛擬地址。指針的類型是由編譯器來維護的,具體的機器代碼卻沒有關於數據類型的信息。
  5. C語言裏面 0x|0X aA
  6. 字長,虛擬空間是以一個字來編碼的,所以字的大小決定了虛擬空間的大小。
  7. 多字節對象存儲爲連續的,地址爲字節中最小的地址。
  8. 小端就是 最低位先放,大端就是 最高位先放
  9. 十進制數x的ASCII碼就是0x3x
  10. ASCII具有更加好的平臺獨立性,字節順序無關大小端。
  11. 無符號數字截斷到k位就是等價於x mod 2^k,補碼的話還要加上2^n.
  12. 負數計算,如果是無符號數的話: x + y := 0 mod 2^m也就是-0 = 0,x = 2^m - x。如果是補碼的話,-INT_MIN=INT_MIN,其他一樣。1
  13. 浮點數從 0 000 0000 不斷遞增, 直到0 111 0000停止都是比較正常的數字後面都是NaN. 對於 0 000 * 系列數字 階碼等於下一組數的階碼也就是1(2k11)=22k1 數的值就是數的值。 從下一組開始就是階碼不爲0開始,階碼等於x-bias=x-(2^{k-1}-1),數的值等於1+數的值。
  14. 向偶數舍入,如果是0.5那麼就是向偶數前進,其他就取最近的了。

練習題

2.1

A. 0x39A7F8 = 0011 1001 1010 0111 1111 1000
B. 1100 1001 0111 1011 = 0xC98B ->0xC97B

C. 0xD5E4C = 1100 0101 1110 0100 1010 -> 1101 0101 1110 0100 1100
D. 10 0110 1110 0111 1011 0101 = 0x26E7C5 -> 0x26E7B5

2.2

210=1024 ,2n=2k4+b=2b000(k0)
220=10241024=1000000+48000+576=1048576

n 2n 10進制 2n 16進制
9 512 0x200
19 524288 0x80000
14 16384 0x4000
16 65535 0x10000|
17 131072 0x10000->0x20000
5 32 0x10->0x20
7 128 0x80

2.3

167 = 16 * 10 + 7

十進制 二進制 十六進制
0 0000 0000 0x00
167 1010 0111 0xA7
62 0011 1100-> 0011 1110 0x3D->0x3E
188 1011 1100 0xCD->0xBC
55 0011 0111 0x37
136 1000 1000 0x88
243 1111 0011 0xF3
82 0101 0010 0x52
172 1010 1100 0xAC
231 1110 0111 0xE7

2.4

A. 0x503c + 0x8 = 0x5044
B. 0x503c - 0x40 = 0x4ffc
C. 0x503c + 64 = 0x503c +0x40 = 0x507c
D. 0x50ea-0x503c = 0xad->0xae

2.5

* 小端 大端
A 21 87
B 21 43 87 65
C 21 43 65 87 65 43

2.6

  1. 0x00 35 91 41 = 0000 0000 0011 0101 1001 0001 0100 0001
  2. 0x4A 56 45 04 = 0100 1010 0101 0110 0100 0101 0000 0100

2.7

#include <stdio.h>
#include <cstring>
typedef unsigned char* byte_pointer;
void show_bytes(byte_pointer start,int len) {
    for (int i = 0;i < len;i ++) {
        printf(" %.2x",start[i]);
    }
    puts("");
}
void show_int(int x) {
    show_bytes((byte_pointer)&x,sizeof(int));
}

void show_float(float x) {
    show_bytes((byte_pointer)&x,sizeof(float));
}

void show_pointer(void *x) {
    show_bytes((byte_pointer)&x,sizeof(void *));
}
int main() {
    const char *s = "abcdef";
    show_bytes((byte_pointer)s,strlen(s)); 
}

2.8

運算 結果
a [0110 1001]
b [0101 0101]
~a [1001 0110]
~b [1010 1010]
a & b [0100 0001]
a [0111 1101]
a ^ b [0011 1100]

2.9

A.

- -
111 011
110 010
101 001
100 000

B.
1. 001 | 010 = 011 藍綠色
2. 110 & 011 = 010 綠色
3. 100 ^ 101 = 001 藍色

2.10

#include <stdio.h>
#include <cstring>
#include <iostream>
using namespace std;
void inplace_swap(int *x,int *y) {
    *y = *x ^ *y;
    *x = *y ^ *x;
    *y = *y ^ *x;
}
int main() {
    int a = 1;
    int b = 2;
    inplace_swap(&a,&b);
    cout <<a << " " << b << endl; 
}

2.11

#include <stdio.h>
#include <cstring>
#include <iostream>
using namespace std;
void inplace_swap(int *x,int *y) {
    *y = *x ^ *y;
    *x = *y ^ *x;
    *y = *y ^ *x;
}

void reverse_array(int a[],int cnt) {
    int first, last;
    for (first = 0,last = cnt-1;first **<=** last;first ++,last --) {
        inplace_swap(&a[first],&a[last]);
    }
    for (int i = 0;i < cnt;i ++) {
        cout << a[i] << " " ;
    }
    cout << endl;
}


int main() {
    int a[5] = {1,2,3,4,5};
    reverse_array(a,5);
}

2.12

A. x & 0xff
B. x ^ (~0xff)
C. x | 0xff

2.13

or: bis(x,y)
xor: LEARNED: bis(bic(x,y),bic(y,x))
因爲bic(x,m) = x & ~m
x^y = (x & ~y) | (y & ~x)

2.14

x = 0x66,y = 0x39
x = 0110 0110
y = 0011 1001

表達式
x & y 0010 0000
x | y 0111 1111
~x | ~y 1101 1111
x & !y 0100 0110 -> 0000 0000
x && y 0x1
x || y 0x1
!x || !y 0x0
x && ~y 0x0

2.15

x & ~y == 0 -> !(x ^ y)

2.16

十六進制 二進制 二進制 x<<3 十六進制x<<3 二進制x>>2 十六進制x>>2 二進制x>>2 十六進制x>>2
0xC3 1100 0011 0001 1000 0x18 0011 0000 0x30 1111 0000 0xf0
0x75 0111 0101 1010 1000 0xA8 0001 1101 0x1D 0001 1101 0x1D
0x87 1000 0111 0011 1000 0x38 0010 0001 0x21 1110 0001 0xE1
0x66 0110 0110 0011 0000 0x30 0001 1001 0x19 0001 1001 0x19

2.17

十六進制 二進制 無符號數 補碼
0xE 1110 14 -2
0x0 0000 0 0
0x5 0101 5 5
0x8 1000 8 -8
0xD 1101 13 -3
0xF 1111 15 -1

2.18

十六進制 二進制
0x1b8 440
0x14 20
0xffff fe58 0x258 = -424
0xffff fe74 0x1e74 = 0x274 = 4 + 16*7-2*256 = 116-512 = -396
0x44 68
0xffff fec8 0x2c8 = 8 + 12*16 - 2 * 256=200 - 512 = -312
0x10 16
0xc 12
0xffff feec 0x2ec = 12 + 16*14 - 2 * 256 = -500 + 224 = -276
0x20 32

2.19

x T2U4(x)
-8 8
-3 13
-2 14
-1 15
0 0
5 5

2.20

2.21

表達式 類型 求值
-2147483647-1==2147483648U 無符號 1
-2147483647-1 < 2147483647 有符號 1
-2147483647-1U <2147483647 無符號 0
-2147483647-1<-2147483647 有符號 1
-2147483647-1U <-2147483647 無符號 1

2.22

2.23

w fun1(w) fun2(w)
0x00000076 0x00000076 0x00000076
0x87654321 0x00000021 0x00000021
0x000000C9 0x000000C9 0xFFFFFFC9
0xEDCBA987 0x00000087 0xFFFFFF87

2.24

從N位變成M位,如果是無符號數直接x mod 2^M
如果是有符號數先把他看成無符號數然後再變回有符號數
那就是(x + 2^N) % (2 ^ M) = x % 2 ^M.
所以無論是有符號數還是無符號數都先mod 2 ^M然後如果是有符號數再進行處理下

原始值 無符號 補碼
0 0 0
2 2 2
9 1 1
11 3 3
15 7 -1
原始值 無符號 補碼
0 0 0
2 2 2
-7 9 1
-5 11 3
-1 15 -1

2.25

錯誤原因: unsigned int - 1其實等於最大值了,然後i <= 最大值恆爲真

float sum_elements(float a[],unsigned length) {
    int i;
    float result = 0;
    for (i = 0,`i <= length-1`;i ++) {
        result += a[i];
    }
    return result;
}

改成i < length
或者是int length

2.26

size_t strlen(const char* s);
int strlonger(char* s,char *t) {
    reutnr strlen(s) - strlen(t)  > 0;
}

改成strlen(s) > strlen(t)

2.27

2.28

十六進制 十進制 十進制 十六進制
0 0 15 F
5 5 10 A
8 8 7 7
D 13 2 2
F 15 0 0

2.29

x y x+y x+5y 情況
10100 -12 10001 -15 100101 -27 00101 5 3
11000 -8 11000 -8 110000 -16 10000 -16 2
10111 -9 01000 8 11111 -1 1111 -1 2
00010 2 00101 5 00111 7 0111 7 2
01100 12 00100 4 010000 16 10000 -16 1

2.30

int tadd_ok(int x,int y) {
    bool ok = true;
    if(x > 0 && y > 0 && x + y `< -> <=` 0) ok = false;
    if(x < 0 && y < 0 && x + y `> -> >=` 0) ok = false;
    if(ok) return 1;
}

2.31

如果是正溢出,那麼x+y = x +y -2^m
然後sum - x = x + y - 2^m -x = y - 2^m < 2^m-1
所以y-2^m = y-2^m+2^m=y
其他同理

2.32

當y時負數的時候,輸入x-y x<0認爲呢不會溢出,但是當y=INT_MIN的時候,-y=INT_MIN,所以返回溢出了。

int tadd_ok(int x,int y) {
    bool ok = true;
    if(x > 0 && y > 0 && x + y <= 0) ok = false;
    if(x < 0 && y < 0 && x + y >= 0) ok = false;
    if(ok) return 1;
    return 0;
}
int main() {
    int x = -2147483647 - 1;
    cout << tadd_ok(-100,x) << endl;
}

2.33

十六進制 十進制 十進制 十六進制
0 0 0 0
5 5 11 B
8 8 8 8
D 13 3 3
F 15 1 1

2.34

模式 x y x*y 截斷的x*y
無符號 100 101 4*5=20 0001 1000 4 100
有符號 100 101 -4*-3=12 0000 1100 -4 100
無符號 010 111 2*7=14 0000 1110 6 110
有符號 010 111 2*-1=-2 110 -2 110
無符號 110 110 6*6=36 0010 0100 4 100
有符號 110 110 -2*-2=4 -4 100

2.35 待完成

2.36

int tmult_ok(int x,int y) {
    long long pll = (long long)x * y;
    return pll == (int) pll;
}

2.37

malloc的傳參數的時候會進行類型轉換。

if(x != (unsigned)x)

2.38

2^k或者2^k+1

2.39

-(1<<m)

2.40

K 移位 加減法 表達式
6 2 1 (x<<2)|(x<<1)
31 1 1 32-1 (x<<5)-x
-6 2 1 -4-2 -(x<<2)-(x<<1)
55 2 2 64-8-1 (x<<6)-(x<<3)-x

2.41

第一個有n-m+1個
第二個有2個
所以如果n-m+1 < 2用第一個
如果n-m+1=2隨便
其他用第二個

2.42

int div16(int x) {
    int flag = `(x >> 31)` & 0xF; //這裏產生一個字
    return (x + flag) >> 4;
}

2.43

M=31,N=8

2.44

表達式 特例
(x > 0) || (x - 1) < 0 INT_MIN
(x & 7) != 7 || (x << 29 < 0) TRUE
(x * x) >= 0 (1<<15 | 1<<14)
x < 0 || -x <= 0 TRUE
x > 0 || -x >= 0 INT_MIN
x + y == ux + uy TRUE
x * ~y +uy*ux == -x TRUE

x(y1)+uyux=xyx+uyux=x

2.45

小數值 二進制表示 十進制表示
18 0.001 0.125
34 0.11 0.75
2516 1.1001 1.5625
4316 10.1011 2.6875
98 1.001 1.125
478 101.111 5.875
5116 11.0011 1.1875

2.46

0.2 = 1/5 = 3/16 + 3/16^2+… =(3/16-0)/(1-1/16) = 1/5
A. 0…..1100 1100
B. 2^-20 * 1/10 = 9.54*10-8
C. 9.54*10-8*100*60*60*10 = 0.343
D. 0.343*2000 = 687

2.47

e E 2E f M 2EM V 十進制
0 00 00 0 0 1 0 0 0 0 0
0 00 01 0 0 1 14 14 14 18 0.125
0 00 10 0 0 1 24 24 24 24 0.25
0 00 11 0 0 1 34 34 34 34 0.75
0 01 00 1 0 1 0 1 1 1 1
0 01 01 1 0 1 14 114 114 114 1.25
0 01 10 1 0 1 24 124 124 124 1.5
0 01 11 1 0 1 34 134 134 134 1.75
0 10 00 2 1 2 04 1 2 2 2
0 10 01 2 1 2 14 114 104 52 2.5
0 10 10 2 1 2 24 124 124 3 3
0 10 11 2 1 2 34 134 144 72 3.5
0 11 00 inf
0 11 01 不合法
0 11 10 不合法
0 11 11 不合法

2.48

3510493 = 11 0101 1001 0001 0100 0001 = 1.1 0101 1001 0001 0100 0001 * 2^21
21+127 = 128 + 20 = 1001 0100
0 1001 0100 1 0101 1001 0001 0100 0001 00
0100 1010 0101 0110 0100 0101 0000 0100
4A564504

2.49待完成

2.50

A. 10.010 10.0
B. 10.011 10.1
C. 10.110 11.0
D. 11.001 11.0

2.51

0.0 0011 0011 0011 0011 0011 01

#### 2.52
bias = 2^2-1=3
3-3=0
4*(1+1-1/16)=8 - 1/4
1/2*(1+1/2+1/16) = 1/2 * 25/16
1/2*(1+1/2) = 3/4
8*(2-1/16) = 16-1/2=15.5
1.1111 = 10.000
1/4*1
0001 0010

011 0000 1 0011 000 1
101 1110 7.75 101 111 7.75
010 1001 0.78125 010 100 0.75
110 1111 15.5 111 000 16
000 0001 1/4 000?

2.53

表達式
x == (int)(double)x True
x==(int)(float)x INT_MAX
d==(double)(float)d INT_MAX
f==(float)(double)f True
f==-(-f) True
1.0/2==1/2.0 True
d*d >= 0.0 True
(f+d)-f==d 溢出

總結

  1. 對B,C,D,E的二進制不熟悉 就記住AC吧 1010 1100
  2. 4*k + b裏面如果b=0 則爲1 反之也如此
  3. xor: LEARNED: bis(bic(x,y),bic(y,x))
  4. !x的結果要不是0要不是1。
  5. -(1<<m)
    6.有限範圍內的數的運算是模的運算,無符號數和補碼在位級運算是一樣的。 unsigned很容易出bug。

代碼

#include <stdio.h>
typedef unsigned char* byte_pointer;

void show_bytes(byte_pointer start,int len) {
    for (int i = 0;i < len;i ++) {
        printf(" %.2x",start[i]);
    }
    puts("");
}
void show_int(int x) {
    show_bytes((byte_pointer)&x,sizeof(int));
}

void show_float(float x) {
    show_bytes((byte_pointer)&x,sizeof(float));
}

void show_pointer(void *x) {
    show_bytes((byte_pointer)&x,sizeof(void *));
}
int main() {
    show_int(16);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章