补码一位乘法

在补码一位乘法(Booth 算法)中,y 的初始值是乘数 y 的最低位。也就是说,如果你的乘数 y 的最低位是 0,那么 yn的初始值就是 0;如果乘数 y 的最低位是 1,那么 yn的初始值就是 1。而 yn+1的初始值总是 0。这两位(yn和 yn+1)用于判断下一步的操作。

算数移位和逻辑移位

算术移位和逻辑移位

逻辑移位: 无符号数的移位。逻辑右移,左边补 0;逻辑左移,右边补 0.

算术移位: 对于正数、和负数的原码来说,移位后添补的代码和“逻辑移位”相同;

  • 对于负数补码来说,左移时右侧添 0,右移时左侧添 1
  • 对于负数反码来说,左移、右移都添 1

一个很有用的结论是:对于 负数补码 来说,左移不丢 0,右移不丢 1,就可以满足上面的 2 倍
和 1/2 倍关系。

IEEE754浮点数规格化总结

IEEE754 标准下的浮点数,规格化和偏移量 (bias)/ 移码使得规格化数不需要显示表示数值位上的最高位 1,(在每个规格化数中,最高位总是 1,换句话说,把一个数变成规格化数需要把最高位通过左右移变为 1)因为这个 1 被隐藏了,即最高位是隐藏位 (hidden bit),只需在计算的时候带上它。 而非规格化数不隐藏最高位的 1,使得表示的精度更高,能更好地表示接近于 0 的数。 规格化的好处是能节省 1 位的存储空间 (因为能够做到隐藏) 让程序更高效。

海明校验码k和r

海明码构建

在海明码的构建中,我们有以下符号:

  • k:信息位的数量
  • r:校验位的数量,也就是分成了 k

校验位的位置(如 p1p2p4p8)是根据二进制表示中的位置关系确定的。具体来说,p1的位置是二进制表示中从右到左第 1 位为 1 的位置,p2的位置是第 2 位为 1 的位置,以此类推。

首先明确,P 是校验位,D 是数据位。我们将数据位和校验位分成若干个组,记为 g

  • P1 检验 g1 组:组内成员是二进制数从右往左第一位的值为 1,如 1 3 5 7 9 11等。
  • P2 检验 g2 组:组内成员是二进制数从右往左第二位的值为 1,如 2 3 6 7 10 11等。
  • P4 检验 g3 组:组内成员是二进制数从右往左第三位的值为 1,如 4 5 6 7等。
  • P8 检验 g4 组:组内成员是二进制数从右往左第四位的值为 1,如 8 9 10 11等。

浮点数判断规格化

要区分一个数是否是规格化的浮点数,可以通过观察其指数部分和尾数部分来进行判断。

在 IEEE 754 标准中,对于一个给定的浮点数,可以按照以下步骤进行判断:

  1. 提取出指数部分和尾数部分。(单精度 23 位尾数位,双精度 52 位尾数)
  2. 判断指数部分是否全为 0 或全为 1。如果是,则这个数不是规格化的浮点数。
  3. 判断尾数部分的最高位是否为 1。如果最高位不是 1,则这个数也不是规格化的浮点数。

通过这些步骤,可以判断一个给定的浮点数是否是规格化的。

线程异步执行

线程异步执行

在多线程编程中,”线程异步执行”指的是多个线程可以同时执行,彼此之间不受阻塞,而且它们的执行顺序是不确定的。异步执行使得不同的线程能够独立运行,提高程序的性能和响应性。

特点和优势

  1. 并行执行: 异步执行允许多个线程同时运行,特别是在多核处理器上,可以实现真正的并行执行,充分利用硬件资源。

  2. 提高响应性: 当一个线程被阻塞等待某些资源时,其他线程仍然可以继续执行,从而保持系统的响应性。这对于需要快速响应用户输入的应用程序非常重要。

  3. 提高性能: 异步执行有助于充分利用计算资源,通过同时执行多个任务,可以更有效地完成工作。

示例

考虑以下简单的 Java 程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class AsyncExample {
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
System.out.println("Thread 1: " + i);
}
});

Thread thread2 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
System.out.println("Thread 2: " + i);
}
});

thread1.start();
thread2.start();
}
}

在这个例子中,thread1thread2 是两个独立的线程,它们可以同时执行,输出的顺序是不确定的。

注意事项

虽然异步执行提供了许多优势,但在多线程编程中也需要注意以下问题:

  • 竞态条件: 多个线程访问共享资源可能导致竞态条件,需要使用同步机制来确保线程安全。

  • 死锁: 当多个线程相互等待对方释放资源时,可能发生死锁情况,需要小心设计和管理资源的使用。

  • 线程安全: 确保在多线程环境中正确处理共享数据,防止数据不一致的问题。

总体而言,了解异步执行的概念并谨慎处理多线程编程可以帮助提高程序的性能和可维护性。

抽象类、抽象方法、接口

Java 中的抽象类、抽象方法和接口关系

抽象类(Abstract Class)

抽象类是一种不能被实例化的类,它通常用于作为其他类的基类。抽象类可以包含抽象方法和非抽象方法。

特点:

  • 不能被实例化。
  • 可以包含构造方法。
  • 可以包含抽象方法和非抽象方法。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public abstract class Animal {
int age;

public Animal(int age) {
this.age = age;
}

// 抽象方法
public abstract void makeSound();

// 非抽象方法
public void sleep() {
System.out.println("Animal is sleeping");
}
}

抽象方法(Abstract Method)

抽象方法是在抽象类中声明但没有实现的方法,需要在具体的子类中实现。

特点:

  • 只有声明,没有实现。
  • 必须在抽象类中。

示例:

1
2
3
4
public abstract class Animal {
// 抽象方法
public abstract void makeSound();
}

接口(Interface)

接口是一种完全抽象的类,它定义了一组抽象方法,而不包含任何实现。类可以通过实现接口来获得接口定义的功能。

特点:

  • 完全抽象,不包含任何实现。
  • 类可以实现多个接口。
  • 接口中的方法默认为public abstract

示例:

1
2
3
4
5
6
7
8
9
10
11
public interface Drawable {
// 抽象方法
void draw();
}

public class Circle implements Drawable {
// 实现接口方法
public void draw() {
System.out.println("Drawing a circle");
}
}

抽象类和接口的关系

  • 一个类可以同时继承抽象类并实现多个接口。
  • 抽象类可以包含实例变量,而接口只能包含常量。
  • 抽象类的方法可以有各种访问修饰符,而接口的方法默认为public
1

日语笔记

五十音

五十音

浊音 4个

  • K-G ga gi gu ge go
    • が ぎ ぐ げ ご
  • S-Z za ji zu ze zo
    • ざ じ ず ぜ ぞ

     

  • T-D da ji zu de do
    • だ ぢ づ で ど
  • H-B ba bi bu be bo
    • ば び ぶ べ ぼ

半浊音 1个

  • H-P pa pi pu pe po
    • ぱ ぴ ぷ ぺ ぽ

长音

  • a i u e o段加 a i u e o
  • e o段还可以加 i u

促音

  • っ需要停一拍
  • 打字后面的音双写

拗音

  • きゃ きゅ きょ 
  • kya kyu kyo

主存-cache映射方式

Cache中包含:

  • 有效位(Valid)
  • 标记(Tag)
  • 数据块(Data Block)
  • 替换策略信息(如LRU信息)
  • 其他控制信息(如脏位Dirty)

主存中包含:

  • 区地址(Tag)
  • 行索引(Index)
  • 块内偏移(Offset)
  • 数据信息

直接相联映射

主存分区
按照cache的大小把主存分成若干个相同大小的块,每个块通过模运算映射cache中的一行,每个块有一个标记位,用于存放主存块的地址。

全相联映射

主存不分区
主存中的每个块都可以映射到cache中的任意一行,每个块有一个标记位,用于存放主存块的地址。

组相联映射

主存分区
第一个版本的解释:把cache分成n个组,主存的若干个区中每个区有n个块(行)。比如每个区中第一行是第一组的第一块,第二行是第二组的第一块…… 也就是说主存的每个区中有多少块,cache就有多少组。

第二个版本的解释主存的块通过模运算映射到Cache的某一组,然后在该组内的任意行存放。

找到组之后,主存中的块是可以在这个组中的任意行存放的。即在组内是全相联映射。

Q&A Section

Q: Cache中块的数据块(data block)和主存中的数据信息是同种东西吗

A: 是的,Cache中的数据块(Data Block)和主存中的数据信息是同种东西。Cache的主要目的就是存储主存中的数据块,以便CPU可以更快地访问这些数据。

Q: 当主存块映射cache块时,主存中的区地址,行索引,块内偏移放到cache块中的什么位置?

A: 在主存块映射到Cache块时,主存中的区地址、行索引、块内偏移并不会直接放到Cache块中的某个位置。实际上,主存中的这些信息是用来确定主存块应该映射到Cache的哪个位置。

Q: 块内偏移是什么?

A: 块内偏移用来确定访问块内的哪个字或字节。

Q: 在直接相联映射中,主存块是区地址+行索引+块内偏移,在组相联映射中却是标记+组索引+块内偏移。这样的名称变化只是名称变化吗?为什么有这种变化?

A: 在不同的Cache映射策略中,我们使用不同的术语来描述主存地址的不同部分。这些术语的变化反映了不同映射策略的特性。

  • 直接相联映射中,主存地址被划分为“区地址”、“行索引”和“块内偏移”。这是因为在直接相联映射中,主存中的每个块都直接映射到Cache的一个特定行,这个行就由行索引来确定。

  • 组相联映射中,主存地址被划分为“标记”、“组索引”和“块内偏移”。这是因为在组相联映射中,主存中的每个块可以映射到Cache的一个特定组,这个组就由组索引来确定。而标记则用于在这个组中找到正确的块。

  • 全相联映射中,主存地址被划分为“标记”和“块内偏移”。这是因为在全相联映射中,主存中的每个块可以映射到Cache的任何位置,所以我们不需要索引。我们只需要标记来确定主存块是否已经在Cache中,以及块内偏移来访问块内的数据。

这些名称的变化并不只是为了改变名称,而是为了反映不同映射策略中主存地址的不同划分方式。

cpu-cache-主存

cache-主存:

直接映射 将主存按照cache的大小分成若干个块进行映射,在这种情况下主存中的块可以变成——【区地址tag | 行索引index】 而这个整体叫做“主存块地址”

什么叫做 cache 的块?cache 中存放主存数据副本的区域。

内存地址:

  1. 行索引(index):位数决定了主存一个区中块的数量。比如上面这个例子中行索引有 3 位,则
    主存一个区中的块就有 8 块。
  2. 区地址((tag):主存中区的编号,上图的例子中便是 2 位,表示了 00、01、10、11 共 4 个主
    存区。

cache地址:

  1. 行号(index):cache 的行编号,有时也叫做槽号,或者索引。
  2. 标记(tag):缓存中的 标记(tag)——表示了主存的块和 cache 的块的对应关系,如果一个主存的块被调入到 cache 中,那么,我们就把主存的块号写入这个 标记 里。

    比如:CPU 给出一个内存地址,CPU 希望能在 cache 中访问到这个地址的话,那么 CPU 首先要确定这个地址所在的块是否已经被送到了 cache 之中,于是,CPU 就拿主存的块号和 标记 进行比较,如果和某一个标记正好相等,并且这个 cache 块是有效的,这就说明,cache 里就保存了 CPU 准备在内存中要访问的信息,于是,CPU 便直接从 cache 中获取这些信息,这样 CPU 取得数据的速度就得到了很大的提高。

  3. 有效位:标识一个行是否含有有效地址。(没有设置,或者设置为 0)。
  4. 数据:通常对 cache 的容量计算只考虑数据的大小,而不会考虑以上①②③所占用的大小。

命中(hit)和数据缺失(miss)

cpu访问主存时,如果要访问的块已经在cache中,称为“**数据命中(hit)”,命中时数据的访问时间称为 “命中访问时间(tc)”,这个时间包括 查找时间 和 cache访问时间 。如果块没在cache中,cpu就需要去主存里获取数据、指令,称为 “数据缺失(miss)**”

如果命中 就建立映射关系,如果数据缺失 就不建立

值得注意的是,cpu在找数据的时候,先从cache找(命中的),再从主存找(没命中的)。但是实际上这两个操作是并行进行的,也就是说时间是 【①在cache中找命中的时间+②在主存中找未命中的时间】,而不是【①在cache中找hit的时间+②在cache中找miss的时间+③在主存中找miss的时间】

cache地址映射变化机构:

负责 1.主存中的块映射到cache中哪个块 2.把主存(块)地址转换为cache(块)地址

cache替换机构:

检测cache中是否还有位置装入主存的块。如果没有位置了,就从cache中退回部分块到主存中,或者直接废弃。再把目标主存块装入cache

cpu-cache-主存流程图

写操作的一致性问题:

读操作不对数据进行修改,但是在写操作时,由于cache中数据其实是主存中某块数据的副本,所以我们应该保持cache块和主存块的一致性。这里有两种方法。

  1. 写直达法(Write-through):在写操作时,同时修改cache块和主存块。写操作时间是访问主存的时间,因为是并行操作,所以写操作时间是访问主存的时间。写直达法的性能主要取决于访问主存的时间。
  2. 写回法(Write-back):允许在一段时间内,cache和主存写入数据不一致。CPU对某个内存单元进行写操作时,如果这个内存单元所在的块已经被取入到内存中,这时只写入cache不写入主存,直到这个cache块退出cache,再对主存进行写操作。 所以这种方法无法保证实时性。但是写回法的性能主要取决于访问cache的时间。因为只有最后一次才会对主存进行操作。
  • Copyrights © 2015-2024 buynonsense
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信