程序员的数学基础课
黄申
LinkedIn资深数据科学家
立即订阅
23478 人已学习
课程目录
已完结 57 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 作为程序员,为什么你应该学好数学?
免费
导读 (1讲)
导读:程序员应该怎么学数学?
基础思想篇 (18讲)
01 | 二进制:不了解计算机的源头,你学什么编程
02 | 余数:原来取余操作本身就是个哈希函数
03 | 迭代法:不用编程语言的自带函数,你会如何计算平方根?
04 | 数学归纳法:如何用数学归纳提升代码的运行效率?
05 | 递归(上):泛化数学归纳,如何将复杂问题简单化?
06 | 递归(下):分而治之,从归并排序到MapReduce
07 | 排列:如何让计算机学会“田忌赛马”?
08 | 组合:如何让计算机安排世界杯的赛程?
09 | 动态规划(上):如何实现基于编辑距离的查询推荐?
10 | 动态规划(下):如何求得状态转移方程并进行编程实现?
11 | 树的深度优先搜索(上):如何才能高效率地查字典?
12 | 树的深度优先搜索(下):如何才能高效率地查字典?
13 | 树的广度优先搜索(上):人际关系的六度理论是真的吗?
14 | 树的广度优先搜索(下):为什么双向广度优先搜索的效率更高?
15 | 从树到图:如何让计算机学会看地图?
16 | 时间和空间复杂度(上):优化性能是否只是“纸上谈兵”?
17 | 时间和空间复杂度(下):如何使用六个法则进行复杂度分析?
18 | 总结课:数据结构、编程语句和基础算法体现了哪些数学思想?
概率统计篇 (14讲)
19 | 概率和统计:编程为什么需要概率和统计?
20 | 概率基础(上):一篇文章帮你理解随机变量、概率分布和期望值
21 | 概率基础(下):联合概率、条件概率和贝叶斯法则,这些概率公式究竟能做什么?
22 | 朴素贝叶斯:如何让计算机学会自动分类?
23 | 文本分类:如何区分特定类型的新闻?
24 | 语言模型:如何使用链式法则和马尔科夫假设简化概率模型?
25 | 马尔科夫模型:从PageRank到语音识别,背后是什么模型在支撑?
26 | 信息熵:如何通过几个问题,测出你对应的武侠人物?
27 | 决策树:信息增益、增益比率和基尼指数的运用
28 | 熵、信息增益和卡方:如何寻找关键特征?
29 | 归一化和标准化:各种特征如何综合才是最合理的?
30 | 统计意义(上):如何通过显著性检验,判断你的A/B测试结果是不是巧合?
31 | 统计意义(下):如何通过显著性检验,判断你的A/B测试结果是不是巧合?
32 | 概率统计篇答疑和总结:为什么会有欠拟合和过拟合?
线性代数篇 (13讲)
33 | 线性代数:线性代数到底都讲了些什么?
34 | 向量空间模型:如何让计算机理解现实事物之间的关系?
35 | 文本检索:如何让计算机处理自然语言?
36 | 文本聚类:如何过滤冗余的新闻?
37 | 矩阵(上):如何使用矩阵操作进行PageRank计算?
38 | 矩阵(下):如何使用矩阵操作进行协同过滤推荐?
39 | 线性回归(上):如何使用高斯消元求解线性方程组?
40 | 线性回归(中):如何使用最小二乘法进行直线拟合?
41 | 线性回归(下):如何使用最小二乘法进行效果验证?
42 | PCA主成分分析(上):如何利用协方差矩阵来降维?
43 | PCA主成分分析(下):为什么要计算协方差矩阵的特征值和特征向量?
44 | 奇异值分解:如何挖掘潜在的语义关系?
45 | 线性代数篇答疑和总结:矩阵乘法的几何意义是什么?
综合应用篇 (6讲)
46 | 缓存系统:如何通过哈希表和队列实现高效访问?
47 | 搜索引擎(上):如何通过倒排索引和向量空间模型,打造一个简单的搜索引擎?
48 | 搜索引擎(下):如何通过查询的分类,让电商平台的搜索结果更相关?
49 | 推荐系统(上):如何实现基于相似度的协同过滤?
50 | 推荐系统(下):如何通过SVD分析用户和物品的矩阵?
51 | 综合应用篇答疑和总结:如何进行个性化用户画像的设计?
加餐 (3讲)
数学专栏课外加餐(一) | 我们为什么需要反码和补码?
数学专栏课外加餐(二) | 位操作的三个应用实例
数学专栏课外加餐(三):程序员需要读哪些数学书?
结束语 (1讲)
结束语 | 从数学到编程,本身就是一个很长的链条
程序员的数学基础课
登录|注册

01 | 二进制:不了解计算机的源头,你学什么编程

黄申 2018-12-10
我们都知道,计算机的起源是数学中的二进制计数法。可以说,没有二进制,就没有如今的计算机系统。那什么是二进制呢?为什么计算机要使用二进制,而不是我们日常生活中的十进制呢?如何在代码中操作二进制呢?专栏开始,我们就从计算机认知的起源——二进制出发,讲讲它在计算机中的“玄机”。

什么是二进制计数法?

为了让你更好地理解二进制计数法,我们先来简单地回顾一下人类计数的发展史。
原始时代,人类用路边的小石子,来统计放牧归来的羊只数量,这表明我们很早就产生了计数的意识。后来,罗马人用手指作为计数的工具,并在羊皮上画出Ⅰ、Ⅱ、Ⅲ来代替手指的数量。表示一只手时,就写成“Ⅴ”形,表示两只手时,就画成“ⅤⅤ”形等等。
公元 3 世纪左右,印度数学家(也有说法是阿拉伯人)发明了阿拉伯数字。阿拉伯数字由从 0 到 9 这样 10 个计数符号组成,并采取进位制法,高位在左,低位在右,从左往右书写。由于阿拉伯数字本身笔画简单,演算便利,因此它们逐渐在各国流行起来,成为世界通用的数字。
日常生活中,我们广泛使用的十进制计数法,也是基于阿拉伯数字的。这也是十进制计数法的基础。因此,相对其他计数方法,十进制最容易被我们所理解。
让我们来观察一个数字:2871。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《程序员的数学基础课》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(157)

  • 无双
    请问有没有方法,快速实现进制转换,比如二进制、十进制、八进制、十六进制互相转化,我考试有要求要转,就是笔算,谢谢。

    作者回复: 如果要快速在二进制、八进制和十六进制间转换,方法确实存在,可以上网查一些资料。如果很多人都感兴趣,我可以加入

    2018-12-10
    73
  • huang
    算术左移和逻辑左移一样,是因为对于有符号数来说,如果数据最高位(第二个bit)和符号位(第一个bit)不同,则左移之后必然溢出。
    举个例子,8个bit表示-128-127,如果数据最高位和符号位不同,则这个数的绝对值肯定大于64,左移一位肯定溢出。
    所以“有效”的左移不用担心数据最高位会改变符号位,也就不用区分逻辑左移和算术左移。

    作者回复: 很好的回答

    2019-01-15
    4
    39
  • 溯雪
    老师,为什么不需要区分逻辑左移和算术左移呢?
    比如十进制数-3,对应二进制1000...0011,那按照右移的思路,应该有两种移法,一种是符号位不动其它位置左移的1000...0110,一种是全部左移导致符号位被顶出去的0000....0110嘛

    作者回复: 右移存在一个问题是,在高位补0还是1。但是左移只需要考虑后面补0就可以了

    2018-12-10
    3
    30
  • maliming
    /**
    * @Title: decimalToBinary
    * @Description: 十进制转二进制,方法1:余数短除法除以二
    * @param decimalSource
    * @return: String
    */
    /*public static String decimalToBinary(int decimalSource) {
    StringBuilder sb = new StringBuilder();
    while (decimalSource != 0) {
    sb.append(decimalSource % 2);
    decimalSource = decimalSource >> 1;
    }
    return sb.reverse().toString();
    }*/

    /**
    * @Title: decimalToBinary
    * @Description: 十进制转二进制,方法2:降二次幂及减法混合运算
    * @param decimalSource
    * @return: String
    */
    /*public static String decimalToBinary(int decimalSource) {
    int length = (int) (Math.log(decimalSource) / Math.log(2));
    StringBuffer sb = new StringBuffer();
    do {
    decimalSource = (int) (decimalSource - Math.pow(2, length));
    int power = decimalSource <= 0 ? -1 : (int) (Math.log(decimalSource) / Math.log(2));
    for (int i = length; i > power; i--) {
    if (i == length) {
    sb.append("1");
    } else {
    sb.append("0");
    }
    }
    length = power;
    } while (decimalSource > 0);
    return sb.toString();
    }*/
    /**
    *
    * @Title: decimalToBinary
    * @Description: 十进制转二进制,方法3:位运算法
    * @param decimalSource
    * @return
    * @return: String
    */
    public static String decimalToBinary(int decimalSource) {
    StringBuffer sb = new StringBuffer();
    while (decimalSource != 0) {
    //此&运算,decimalSource & 1,目的是获取最低位的二进制数值
    sb.append(decimalSource & 1);
    //此>>运算,decimalSource >> 1,目的是将获取到的最低位二进制数值除去
    decimalSource = decimalSource >> 1;
    }
    return sb.reverse().toString();
    }
    负整数转换为二进制 要点:
    取反加一 解释:将该负整数对应的正整数先转换成二进制,然后对其“取补”,再对取补后的结果加1即可。
    例如要把-52换算成二进制:
    1.先取得52的二进制:00110100
    2.对所得到的二进制数取反:11001011
    3.将取反后的数值加一即可:11001100 即:(-52)10=(11001100)2

    作者回复: 很好的总结

    2019-01-12
    28
  • 南山
    逻辑或,与,异或一般有什么使用场景,平常写代码不怎么用

    作者回复: 在elasticsearch的filter查询中,用到的bitset就是位运算,比查询倒排索引效率更高

    2018-12-10
    27
  • somenzz
    #python实现

    #encoding=utf-8
    def int3binary(num):
    result=[]
    while num!=0:
    result.append(num & 1)
    num = num >> 1
    result.reverse()
    return result

    print(*int2binary(10))

    #输出 1010
    2018-12-10
    23
  • 指间砂的宿命
    数字与1做与操作,结果为1说明低位是1,否则为0,然后数字右移,重复以上操作,直到数字为0结束,倒序输出所有结果
    2018-12-10
    1
    19
  • Lugyedo
    为什么不区分逻辑左移和算术左移
    2018-12-10
    17
  • Libra
    import java.util.Scanner;

    public class Test1 {
        public static void main(String[] args) {
            Scanner scanner = new Scanner(System.in);

            int value = scanner.nextInt();
            boolean flag = false;

            for (int i = 31; i >= 0; i--) {
                int temp = value & (1 << i);
                if (temp > 0){
                    flag = true;
                }
                if (flag){
                    if (temp > 0){
                        System.out.print(1);
                    }else {
                        System.out.print(0);
                    }
                }
            }
        }
    }

    作者回复: 还可以考虑负数的情况

    2018-12-10
    15
  • sloth-yp
    最后的思考题, 是不是应该考虑负数,用补码表示?

        public static String decimal2Binary(int decimal) {
            // 负数的话,先换成正数然后取反再加1,再递归调用本函数
            if (decimal < 0) {
                int reverseNumber = ((decimal * -1) ^ Integer.MAX_VALUE) + 1;
                return decimal2Binary (reverseNumber);
            }
            StringBuilder sb = new StringBuilder();
            while (decimal > 0) {
                // 跟0x0001 按位与,求得最低位的值
                String lastNumber = String.valueOf(decimal & 1);
                // 插入到字符串的最前面(这样才是原始的顺序)
                sb.insert(0, lastNumber);
                // 算术右移
                decimal = decimal >> 1;
            }
            return sb.toString();
        }

    作者回复: 是的 需要考虑补码

    2018-12-18
    13
  • Li Shunduo
    请问文章里的图是用什么软件画的?
    2018-12-10
    11
  • panda
    异或 我想到一个算法题 判断很多数是不是有相等的

    作者回复: 是的 很经典的一道面试题

    2018-12-11
    10
  • somenzz
    2^3<10<2^4

    得到3,然后

    10>>3=1
    (10>>2)&1=0
    (10>>1)&1=1
    10&1=0

    得到1010

    作者回复: 👍 再考虑一下负数的情况

    2018-12-10
    10
  • 桃园悠然在
    被池大吓得赶紧买一个数学专栏,配合吴军老师的数学之美一起看。
    2018-12-11
    9
  • daydreamer
    我查了一下Python里面没有“逻辑右移”运算符吧,除非自己手动实现

    作者回复: 我又查了一下,确实需要自己实现

    2018-12-18
    8
  • 石佳佳_Gemtra
    1.不考虑溢出的话,二进制数左移 n 位,即乘以 2^n;同理,右移 n 位,即除以 2^n,且向下取整数,因为移除的 n 位不全为 0 的话,除的结果就会包含小数。
    2.不考虑溢出的话,有符号和无符号的左移运算结果相同,而右移的结果不同,所以会有逻辑右移和算术右移的区别。
    3.两个数按位「异或」结果为 0,是这两个数值相等的必要充分条件。
    4.思考题
    Java 不太了解,根据提示,判断 n 位是否为 1,可与 1 左移n位后的数进行「与」运算,为真则为 1,反之为 0,循环即可。
    2018-12-10
    8
  • Transient
    加密算法中也有许多用到二进制运算吧,而且二进制应该还有取反操作吧

    作者回复: 是的 还有取反操作

    2018-12-10
    7
  • 刘凯
    思考题
    - (void)decimal2Binary:(NSInteger)value{
        NSString *result = @"";
        if (value < 0) {
            value = ((value * -1)^(INTMAX_MAX)) + 1;
        }
        for (NSInteger i = 31 ;i >= 0; i--) {
            if (value & (1 << i)) {
                result = [result stringByAppendingString:@"1"];
            }else{
                result = [result stringByAppendingString:@"0"];
            }
        }
        NSLog(@"%@", result);

    }

    作者回复: 负数的处理很赞

    2019-01-04
    1
    6
  • Julian
    01 | 二进制:不了解计算机的源头,你学什么编程的学习总结;
    一:对于进制我现在的理解就是几进制就是以几为基数,然后按照左高右低规则进行基数幂运算然后在乘以数量然后在相加。例如:二进制110,首先基数是“2”;坐高右低原则就是“2 1 0”分别对应最左边的“1 1 0”;其实坐高右低就是从右边以0开始然后依次加一,这个是进行幂运算的多少次方的数字。所以这个二进制数转换成我们日常的十进制的计算规则就是:1*2^2 + 1*2^1 + 0*2^0;最终结果就是 4 + 2 + 1 = 7;

    二:二进制的位操作;
        1.二进制的移位操作;分为左移(<<)和右移;其中右移又分为算数右移(>>)和逻辑右移(>>>);
              二进制左移<<:110 其实就是一次把数字往左移动一位,最右边补0所以最终就是1100;左移规律是数字的值翻倍;
              二进制右移>>:同上就是把数字往右边移动一位,然后最左边数字看情况;如果是算术右移就要考虑正负数的问题;正负数在计算机里面java实现是看你操作系统位数,最后一位代表正负数的标识;0:代表正数;1:代表负数;所以算术右移我理解就是考虑计算,既然考虑计算也就是考虑正负数的问题;对于负数的算术右移左边是要上1的,对于正数的算数右移左边是上0的;但是对于逻辑右移,不管你是正数还是负数,左边都是上0的;

        2.二进制的逻辑操作;
         逻辑或 | : 就是2个二进制数,从右到左,对相同位置的数字进行或运算;或运算就是 全是0才表示0,其余全是1;或顾名思义,只要有真就代表真;
         逻辑与 & : 就是2个二进制数,从右到左,对相同位置的数字进行与运算;与运算就是参与运算数字全1才是1,其余的都是0;与顾明思议,相同的而且都是真才为真;
         逻辑异或 ^: 就是2个二进制数吗,从右到左,对相同位置的数字进行运算;异或运算就是参与运算的数字相同结果为0,其余全为1;异或顾明思议,不同的才为真;

    在计算机世界,1代表真,0代表假;
    2018-12-12
    5
  • 郑晨Cc
    思考题
    public class test {

    public static void main(String[] args){
    StringBuffer sb = null;
    int a = 53;

    String buffer = null;

    while(a>1){
    System.out.println("余数:" + a % 2);
    String b = String.valueOf(a % 2);
    if(null == sb){
    sb = new StringBuffer(b);
    }else{
    sb.insert(0, b);
    }
    a = a >>>1;
    System.out.println("商:"+a);

    }

    sb.insert(0, a);
    System.out.println(sb);
    }

    }

    作者回复: 还需要考虑负数的情况

    2018-12-10
    5
收起评论
99+
返回
顶部