来谈谈64位乘法器和除法吧!
前言
在开始之前,我们必须要先谈谈我们的目标:
我们在这里并不是想完成一个大作业或者写出一个很好的乘法器,而是在你上完一天课后,在睡前的两小时内能完成的的一个作品。
所以,我并不会做出一个很好的乘法器,我们将会使用一些更简单的方式。
当然我知道,你肯定不会满足于此对吧?所以我们仍会谈一谈更快速乘法器的原理,并给出一点示例。
请一直记住这点吧:我们想要一个简单玩意,并尽可能的从中理解它的原理。
对了……你可能会发现,越往后面的内容其实越简单哦。所以实在不会的话,不要死磕哦w
那么w,让我们开始吧喵!
阵列乘法器
或许你已经学过计算机组成原理,并且脑子里已经充满了每次移位相加的东西(或者补码两位乘之类的)。
但是,还是让我们来看看吧。
我们不妨先从4位*4位的乘法开始:
对于以下的一个乘法:
$ 1011 * 0111 $
它是这么运算的:(希望格式是对的)
1234 1011 1+ 1011 1+ 1011 1+ 0000 0
(想一想10进制时,你是怎么做乘法的?)
它需要四个加法。我们可以这么做:(计组里为了节 ...
创建一个64位加法器!
前言
由于这个学期选了一节硬件设计的课程,所以开始写一些硬件的小东西w
所以不妨从一个最核心也比较简单的部件:加法器开始?
我默认你对二进制已经很熟悉惹。不熟悉的话,可以去看一些进制相关的内容?
全加器
如果你对这些内容已经很熟悉的话,跳转到相应的区域吧!
半加器
要想谈论更多位的加法器,我们不妨先来看看一位得到加法器是怎么构成的w
不妨设其输入的两个值为A和B,输出S和进位C(正如你10进制下单位的加法也会有进位一样!)
或许你会想到画一个真值表,但……我们不妨直接来想想吧。
什么时候S会为1呢?当A和B同时为1时?不是,因为此时进位了,S为0。A和B同时为0呢?也不行,0+0=0。也就是说,当且仅当A和B中只有一个为1时,S才为1。也就是如下表示:
1S=(A&!B)|(!A&B);
在这里,我们不妨约定下记号。和C语言中类似,&代表按位与,|代表按位或,!代表按位非,^代表按位异或。注意里面并没有同或,当我们必须用到时使用!(A^B)代替。
由于有公式:(A&!B)|(!A&B) == (A^B),上面的代码更好写为:
1S=A^B;
类似 ...
关于Whitebox GAN的一些碎碎念
什么是Whitebox GAN?
Whitebox GAN网络最初发表于CVPR2020的论文Learning to Cartoonize Using White-box Cartoon Representations。其是一个将现实风格的图片(视频)转换为动漫风格的网络。
该网络改进了生成图片中的高频纹理和细节,获得了更好的图片动漫风格化的结果。
其代码开源在GitHub,可以下载已经训练完成的代码进行尝试~
该网络同样在B站上有效果展示!
网络结构
该网络采用了Generater-Discriminator结构,通过一个Generator网络实现从现实图片到动漫图片的风格域转换;同时,采用了两个Discriminator来进行甄别和训练。
Generator
Generator网络采用了一个标准的结构:三层down sample layer(下采样层),四层residual block(残差网络)和三层up sample layer(上采样层)。其中,从down sample layer到对应的up sample layer之间有对应的skip connection(跳跃连接),以 ...
回龙观一游&变猫证*1
在场上叠放四张卡组以召唤变猫猫证!
在疫情防控肆虐的今天,终于抽到空跑了一趟回龙观,解决了一些“小”问题w
然后就有了这篇流水账w
挂号
咱是在【北京114预约挂号】上挂的周四上午两性心理科的号。似乎目前号源还算充足?在下午抢到了最后一个余号。
据说其他时段的两性心理科都可以就诊,但是并没有亲自确认w
交通
由于本人从海淀中心区出发,所以路程很长。地铁乘13号线+骑自行车的话大概需要一个半小时左右。需要注意的是回龙观站旁倒回龙观医院都没有什么商业区,最近的也在差不多两公里之外,记得带一些食物什么的。水的话院内倒是有自动售货机(还有没有货就不知道了w)
就诊过程
取号
如果是第一次去的话,需要去人工窗口领一张京医通的卡。速度什么的都还可以,去的当天也没有什么人所以很快就办理好了。另外如果是当地(北京)在读的话,会开成公费的 (然后邸奶奶就看着公费说到:既然是公费就把检查全做了吧x) 。所以,虽然没什么大区别,但是如果无法报销的话,还是挂自费吧。
另,在挂完号之后会立刻进入就诊队列, 请务必在之前解决完其它需求!
就诊
就诊流程较为常规,进入诊室后就是一般的流程。会问一些常规的问题,如: ...
堆
简介
有一棵树,其树上的每个节点有一个值,且每个节点的这个值都大于等于(小于等于)其父亲上的值。
那么,我们就把这颗特别的树叫做一个“堆”。
如果,节点值是大于等于其父亲的值,那么我们就叫做小根堆;反之节点值小于等于其父亲的值,那么我们就叫做大根堆。
这是一个小根堆
这也是堆(一个大根堆
对于一个基本的堆,它可以支持:插入一个元素,输出最大(小)值,删除最大(小)值。
如以上就是C++ STL中堆的操作。
堆有很多种类,如对顶堆、斐波那契堆……但在这篇博客中,让我们关注一个最基本的堆:二叉堆。
二叉堆
对于二叉堆而言,它是一颗二叉树。
但是二叉树并不够好。正如上面第二个堆,完全退化成了一条链。对此,我们还希望它是一个完全二叉树。
当然了,它同样需要具有堆的性质!
每个节点的这个值都大于等于(小于等于)其父亲上的值
而对于这颗二叉树而言,树根就是它最大(最小)的元素!
为了方便,接下来都会是一个大根堆
还记得吗?对于一个堆,它需要有一些基本的操作:插入一个元素,输出最大值,删除最大值。让我们来一个个的解决吧。
姆好吧……或许在这之前,我们先来看一看怎么存储一颗二叉树吧!
存储
...
关于符号链接的一些碎碎念
静态链接
在C中,编译一个程序的过程如下:
xx.c->(翻译器)->xx.o->(链接器)->xx
而在第二部将xx.o构造为一个可执行文件的过程被称为静态链接
为了完成静态链接这个目标,链接器需要做两件事:
知道每一个变量到底是什么,这样才能将变量的定义与引用相关联
这里的变量可以是一个全局变量,一个静态变量,一个函数……
而在之后,统一将这些变量的定义和引用称为符号
这一步被称为符号解析
知道每一个变量在哪,这样才能将符号和内存地址相关联,并将所有的符号修改为内存地址
这一步被称为重定位
而诸如extern、static、attribute(weak)这些关键字,则正是在符号解析中发挥作用的
可重定位目标文件
下表是一个典型的可重定位目标文件:
段
作用
.text
已编译的机器代码(此时符号未被替换)
.rodata
只读数据
.data
已初始化的全局和静态变量
.bss
未初始化的全局和静态变量
.symtab
符号表(也就是我们要关注的部分)
.rel.text
.text重定位信息
.rel.data
. ...
在C中面向对象:#0x2 让我们来实现一个迭代器!
非常建议先看0x1
说起来我才发现,因为我超喜欢用波浪线,一大堆东西被替换成了删除线QAQ
前言
我们先来解决上一节中遗留下来的几个问题吧
UNUSED
由于在上一节中,我们强行规定了函数该长什么样。但是,有些时候我们可能并用不到某些参数,这个时候编译器就会报warning或error(取决你有没有开Wall、Werror、Wextra)。
为了保证编译器既不会报错,又能符合固定的函数原型,在此我们需要定义UNUSED宏。
12345678#ifdef UNUSED#elif defined(__GNUC__) || defined(MSVC)#define UNUSED(x) UNUSED_##x __attribute__((unused))#elif defined(__LCLINT__)#define UNUSED(x) (void *)(x)#else#deifne UNUSED(x)(void *)(x)#endif
该宏的作用是:若编译器有__attribute__((unused))选项时,则给该变量添加上unused属性,并重命名为UNUSED_var。
其示例用法如 ...
在C中面向对象:#0x1 来"注册"一个对象吧~
非常建议先看#0x0 w~
目标
在这一节中,我们希望能够实现类似C++中一样,能一键new和delete一个对象。
同时,我们也希望能构造一个通用的“类”模板,以便规范我们的编写和调用。
对此,我们需要:
搞清楚一个类的原型需要些什么
实现在程序中“注册”一个“类”
成功new一个对象
实现一系列的函数,以便代替操作符进行一个统一的调用
那么,让我们开始吧~
一个类的原型
为了让所有的类看起来相似,同时也是为了更方便的注册一个类,我们需要首先规定一个类必须要存储哪些信息。
对此,我们不妨先来一个结构体存吧~
123typedef struct CLASS_T{} class;
首先,我们需要知道如果要新建一个对象的话,需要多少的空间。也就是说,我们需要存储一个类的大小。
于是我们加上const size_t type_size;
接下来,为了能统一所有类的构建,我们并不希望生成一个对象的时候,都要去调用这个类的构造函数(如你要一个cat对象,就要调用cat_constructor;一个dog对象就要dog_constructor)。
我们期望的是像C++那样, ...
在C中面向对象:#0x0 封装、继承与多态
前言:为什么要在C中面向对象
虽然c++由c语言发展而来,且其中(大部分)兼容了c的语法。它解决了c中开发繁杂(没有对象、抽象方法),不好阅读(为了实现多态,指针、强制类型转换满天飞),不易维护等痛点。
但不得不说,现在的c++更像一锅大杂烩,学习难度指数级上升。而c与其相比就变得很容易入门了(基础总共就那么点)。而且,很多的嵌入式项目并没有提供c++的工具链,导致仍然不得不使用c编程 (或者折腾一周环境之后,回到用c编程)
当然……以上其实并没有完全说明为什么要在c中面向对象。毕竟要实现的话,又繁琐又不方便……
但是它很有挑战不是喵!而且还可以学到一些新的技巧。
什么是面向对象编程
对于一个程序,可以分为两部分:
数据(你希望处理的东西)
算法(如何处理这些数据)
面向过程编程
C就是一个典型的面向过程的语言。它的数据和算法是分开的,你通过将数据一个一个放到函数里进行处理,获得想要的结果。
面向对象编程
面向对象就是将数据和算法包在一起,做成一个东西。接下来无论你想要做什么(无论是改变参数还是产生行为),你都直接告诉这个东西就好
想要让一个语言能够面向对象,一般需要实现三个特征: ...
套娃理解c语言指针
虽说是c语言指针,对于c++也是一样的
编程基于套娃
————沃·兹基硕得
前言
这篇文章的目的并非解释什么是指针,而是为了让人能更好的理解如这样的char **(*(*p[4][10])(int,void(*)(int)))(int)
(没错上面这坨东东是合法的!)
以及,这个方法在处理一个(返回类型为函数的指针)的函数的指针的时候还是会有点混乱……需要一些悟性puq
但是考虑到这句话拿嘴说估计都能绕晕一堆人……还算情有可原?QAQ
基本定义
抽象类型
首先,我们需要抽象一下类型。
1template<typename T>
也就是说,将所有的目前已知类型(不管是int、char、int*、long long[10],甚至一个函数),这里都视为一个最基本的已知类型T
于是,在整个过程中,我们便将类型简化到只剩两种:
T
T
也就是抽象出来的类型
T1 (*)(T2,T3,…)
T1 (*)(T2,T3,…)
指一个返回类型为T1,传入参数类型为(T2,T3,…)的函数指针
为什么?
这样,便可以不再纠结于具体的类型(毕竟你甚至可以通过typedef、class来得 ...