zoukankan      html  css  js  c++  java
  • 6.Python3标准库--数学运算

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    '''
    作为一种通用的变成语言,Python经常用来解决数学问题。它包含一些用于管理整数和浮点数的内置类型,这很适合完成一般应用中可能出现的基本数学运算。
    而标准库中包含一些用于满足更高级需求的模块。
    Python的内置浮点数在底层C语言中是double类型,对于大多数数学运算需求的程序来说,这已经足够精确。
    但是如果需要非整数值更为精确的表示,那么decimal和fractions模块会很有用。小数和分数值的算术运算可以保证精度,但是不如原生float的运算速度快
     
    random模块则包含了一个均匀分布的伪随机数生成器,还提供了一些函数用于模拟很多常用的非均匀分布
     
    math模块则包含一些高级数学函数的快速实现,如对数、三角函数。这个模块对原生平台C库中常见的IEEE函数提供了全面的补充
    '''

      

    (一)decimal:定点数和浮点数的数学运算

    1.Decimal

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    import decimal
    '''
    小数值被表示为Decimal类的实例。
    构造函数取一个整数或字符串作为参数。
    在使用浮点数创建Decimal之前,可以先将浮点数转换为一个字符串,以使调用者能够显示地处理值的位数,因为如果使用硬件浮点数表示则可能无法准确的描述。
    或者,类方法from_float可以把一个浮点数转换为精确的小数表示
    '''
    print(f"{'input':<25} {'output':<25}")
    print("-"*25"-"*25)
     
    # integer
    print(f"{5:<25} {decimal.Decimal(5):<25}")
    # string
    print(f"{'3.14':<25} {decimal.Decimal('3.14'):<25}")
    # float
     
    print(f"{3.14:<25} {decimal.Decimal.from_float(3.14)}")
    '''
    input                     output                  
    ------------------------- -------------------------
    5                         5                       
    3.14                      3.14                    
    3.14                      3.140000000000000124344978758017532527446746826171875
    '''
     
     
    # Decimal还可以使用元组创建,但是不太方面,这里不推荐了。

      

    2.格式化

    1
    2
    3
    4
    5
    6
    7
    8
    import decimal
    '''
    Decimal对应Python的字符串格式化协议,使用与其他数值类型一样的语法和选项
    '''
    = decimal.Decimal(1.1)
    print(f"{d:.1f}")  # 1.1
    print(f"{d:.2f}")  # 1.10
    print(f"{d:.10f}")  # 1.1000000000

      

    3.算术运算

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    import decimal
    '''
    Decimal重载了简单的算术操作符,所以可以采用与内置数值类型相同的方法来处理Decimal实例
    '''
    = decimal.Decimal("5.1")
    = decimal.Decimal("3.14")
    = 4
    = 3.14
    print(repr(a))  # Decimal('5.1')
    print(repr(b))  # Decimal('3.14')
    print(repr(c))  # 4
    print(repr(d))  # 3.14
     
    print(f"a+b = {a+b}")  # a+b = 8.24
    print(f"a-b = {a-b}")  # a-b = 1.96
    print(f"a*b = {a*b}")  # a*b = 16.014
    print(f"a/b = {a/b}")  # a/b = 1.624203821656050955414012739
    # 对Decimal实例进行运算,得到的仍是一个Decimal对象
    print(type(a*b))  # <class 'decimal.Decimal'>
     
     
    try:
        + d
    except TypeError as e:
        print(e)  # unsupported operand type(s) for +: 'decimal.Decimal' and 'float'

      

    4.特殊值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    import decimal
    '''
    除了期望的特殊值,Decimal还可以表示很多特殊值,包括正负无穷大值、不是一个数(NAN)和0
    '''
    for value in ["Infinity""NAN""0"]:
        print(decimal.Decimal(value), decimal.Decimal("-"+value))
        '''
        Infinity -Infinity
        NaN -NaN
        0 -0
        '''
     
     
    print("Infinity+1:", decimal.Decimal("Infinity")+1)  # Infinity+1: Infinity
    print("-Infinity+1:", decimal.Decimal("-Infinity")+1)  # -Infinity+1: -Infinity
     
    print(decimal.Decimal("NAN"== decimal.Decimal("Infinity"))  # False
    print(decimal.Decimal("NAN") != decimal.Decimal("Infinity"))  # True
    '''
    与无穷大值相加减总会返回无穷大值,与NAN比较相等性总会返回False,比较不等性则返回True。
    与NAN比较大小来确定排序是未定义的,这回导致一个错误
    '''
     
     
    # 除此之外math和numpy当中也有这种功能
    import math, numpy as np
    print(math.inf, math.nan)  # inf nan
    print(np.inf, np.nan)  # inf nan
     
    print(math.inf == math.inf, math.inf is math.inf)  # True True
    # 可以看到nan有点特殊,即便是同一个对象is成立,但是==不成立。
    print(math.nan == math.nan, math.nan is math.nan)  # False True

      

    (二)fractions:有理数

    1
    2
    3
    '''
    Fraction类基于numbers模块中Rational定义的API来实现有理数的数值运算
    '''

      

    1.创建Fraction实例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    import fractions
    '''
    与decimal模块类似,可以采用多种方式创建新值。一种简便的方式是由单独的分子和分母值来创建
    '''
    for n, d in [(12), (24), (36)]:
        = fractions.Fraction(n, d)
        print(f"{n} / {d} = {f}")
        '''
        1 / 2 = 1/2
        2 / 4 = 1/2
        3 / 6 = 1/2
        '''
     
    # 还可以使用字符串方式来创建
    # 会自动解析这个字符串,找出分子和分母值
    for in ["1/2""2/4""3/6"]:
        = fractions.Fraction(s)
        print(f"{s} = {f}")
        '''
        1/2 = 1/2
        2/4 = 1/2
        3/6 = 1/2
        '''
     
    # 字符串还可以使用更常用的小数或浮点数记法,即用一个小数点分隔的一系列数字。能够由float()解析而且不表示NAN或者无穷大值的所有字符串都支持
    for in ["0.5""1.5""2.0""5e-3"]:
        = fractions.Fraction(s)
        print(f"{s} = {f}")
        '''
        0.5 = 1/2
        1.5 = 3/2
        2.0 = 2
        5e-3 = 1/200
        '''
     
     
    # 此外还可以使用Decimal类创建
    import decimal
    values = [
        decimal.Decimal("0.1"),
        decimal.Decimal("0.5"),
        decimal.Decimal("1.5"),
        decimal.Decimal("2.0")
    ]
    for in values:
        print(f"{v} {fractions.Fraction(v)}")
        '''
        0.1 1/10
        0.5 1/2
        1.5 3/2
        2.0 2
        '''
     
    # 此外得到的都是Fraction对象
    print(type(fractions.Fraction("0.5")))  # <class 'fractions.Fraction'>

      

    2.算术运算

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    import fractions
    '''
    一旦分数被实例化,就可以在数学表达式中使用了
    '''
    f1 = fractions.Fraction("1/2")
    f2 = fractions.Fraction(34)
    print(f"{f1} + {f2} = {f1 + f2}")  # 1/2 + 3/4 = 5/4
    print(f"{f1} - {f2} = {f1 - f2}")  # 1/2 - 3/4 = -1/4
    print(f"{f1} * {f2} = {f1 * f2}")  # 1/2 * 3/4 = 3/8
    print(f"{f1} / {f2} = {f1 / f2}")  # 1/2 / 3/4 = 2/3

      

    3.近似值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    import fractions
    import math
    '''
    Fraction有一个很有用的特性,即能够将一个浮点数转换为一个近似的有理数值
    '''
     
     
    f_pi = fractions.Fraction(str(math.pi))
    print(f_pi)  # 3141592653589793/1000000000000000
    for in [1611607090100]:
        limited = f_pi.limit_denominator(i)
        print(f"{i} {limited}")
        '''
        1 3
        6 19/6
        11 22/7
        60 179/57
        70 201/64
        90 267/85
        100 311/99
        '''

      

    (三)random:伪随机数生成器

    1
    2
    3
    4
    '''
    random模块基于Mersenne Twister算法提供了一个快速伪随机数生成器。
    原先开发这个生成器是为了向蒙特卡洛模拟生成输入,Mersenne Twister算法会生成大周期近均匀分布的数,因此适用于大量不同类型的应用
    '''

      

    1.生成随机数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    import random
     
    '''
    random返回一个0到1之间的随机浮点数
    '''
    print(random.random())  # 0.254811057329168
    print(random.random())  # 0.7395548455074491
    print(random.random())  # 0.505764048975116
    print(random.random())  # 0.4639293410664217
     
     
    # random的范围是0到1,如果我想指定范围呢?可以使用uniform,说到uniform,我就想起了uniform temptation。就想起了孙悟空那豹纹小短裙,想起了今年下半年文体两开花
    # 生成的规则是 2+(4-2)*random(), min + (max - min)*random()
    print(random.uniform(24))  # 3.4563486365870606

      

    2.指定种子

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    import random
     
    '''
    每次重复执行的时候,生成的结果都不一样。
    因此可以指定种子,只要种子一样,那么每次生成的结果都是一样的
    '''
    print(random.random())
    print(random.random())
    '''
    $ python 3.random.py
    0.6968598797532435
    0.5403043133943518
     
    $ python 3.random.py
    0.7498812800384731
    0.08841963718934376
    '''
     
    # 当我指定种子之后
    random.seed(666)
    print(random.random())
    print(random.random())
    '''
    $ python 3.random.py
    0.45611964897696833
    0.9033231539802643
     
    $ python 3.random.py
    0.45611964897696833
    0.9033231539802643
    '''
    # 可以看到当我重新指定种子的时候,不管执行多少次结果都是一样的

    3.保存状态

    1
    2
    3
    4
    5
    import random
     
    '''
    几乎不用
    '''

      

    4.随机整数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    import random
     
    '''
    random生成浮点数,可以再转化为整数,不过直接使用randint生成整数会更方便
    '''
    print(random.randint(13))  # 1
    print(random.randint(13))  # 2
    print(random.randint(13))  # 3
     
    print(random.randint(-5-3))  # -4
    print(random.randint(-5-3))  # -5
    print(random.randint(-5-3))  # -4
    # 可以看到randint接收的值为两个,分别是闭区间的两端。可以是正数也可以是负数,但是左边要小于右边。
     
    # 还有一个randrange方法,前两个参数和randint一样,但是randrange还可以接收第三个参数,表示步长
    # 从1到8里面随机选择,但是步长为2,也就是说,只可能选到1 4(1+3) 7(1+3+3)这三个值
    # 注意,如果不指定第三个参数,那么步长默认为1,并且是不包含右短点的。也就是说,即便步长为1,也是不可能随机到8这个数的
    print(random.randrange(183))  # 4
    print(random.randrange(183))  # 7
    print(random.randrange(183))  # 1

      

    5.选择随机元素

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    import random
     
    '''
    随机数生成器有一种常见用法,即从一个枚举值序列中选择元素,即使这些值并不是数字。
    random模块包含一个choice函数,可以从一个序列中随机选择。
    '''
    girls = ["mashiro""satori"]
    print(random.choice(girls))  # mashiro
     
     
    # 此外我们还可以验证大数定理
    '''
    大数定理:用个人的大白话解释,就是我们知道一个事物出现的概率是固定的,比如说等于A,但是由于次数较少,可能会出现不同的结果。但是随着实验次数的增加,比例越来越趋近A
     
    就拿抛硬币来说,出现正面的概率是0.5,这是肯定的。但是由于我们只抛了3次,恰好都是正面或者都是反面,所以概率就变成1或者0了。
    但是随着次数的增加,比如我抛个十万次,那么最终出现正面和出现反面的次数都是接近5万次的,也就是说出现的几率应该越来越趋近于0.5
    '''
    outcomes = {"正面"0"反面"0}
    sides = list(outcomes.keys())
     
    for in range(1201):
        outcomes[random.choice(sides)] += 1
        if % 10 == 0:
            print(f"抛了{i}次之后--》")
            print(f"出现正面的次数:{outcomes['正面']},对应比率:{outcomes['正面'] / (outcomes['正面'] + outcomes['反面'])}")
            print(f"出现反面的次数:{outcomes['反面']},对应比率:{outcomes['反面'] / (outcomes['正面'] + outcomes['反面'])}")
            print("-"*20)
    '''
    抛了10次之后--》
    出现正面的次数:6,对应比率:0.6
    出现反面的次数:4,对应比率:0.4
    --------------------
    抛了20次之后--》
    出现正面的次数:12,对应比率:0.6
    出现反面的次数:8,对应比率:0.4
    --------------------
    抛了30次之后--》
    出现正面的次数:15,对应比率:0.5
    出现反面的次数:15,对应比率:0.5
    --------------------
    抛了40次之后--》
    出现正面的次数:22,对应比率:0.55
    出现反面的次数:18,对应比率:0.45
    --------------------
    抛了50次之后--》
    出现正面的次数:27,对应比率:0.54
    出现反面的次数:23,对应比率:0.46
    --------------------
    抛了60次之后--》
    出现正面的次数:31,对应比率:0.5166666666666667
    出现反面的次数:29,对应比率:0.48333333333333334
    --------------------
    抛了70次之后--》
    出现正面的次数:36,对应比率:0.5142857142857142
    出现反面的次数:34,对应比率:0.4857142857142857
    --------------------
    抛了80次之后--》
    出现正面的次数:39,对应比率:0.4875
    出现反面的次数:41,对应比率:0.5125
    --------------------
    抛了90次之后--》
    出现正面的次数:48,对应比率:0.5333333333333333
    出现反面的次数:42,对应比率:0.4666666666666667
    --------------------
    抛了100次之后--》
    出现正面的次数:52,对应比率:0.52
    出现反面的次数:48,对应比率:0.48
    --------------------
    抛了110次之后--》
    出现正面的次数:59,对应比率:0.5363636363636364
    出现反面的次数:51,对应比率:0.4636363636363636
    --------------------
    抛了120次之后--》
    出现正面的次数:63,对应比率:0.525
    出现反面的次数:57,对应比率:0.475
    --------------------
    抛了130次之后--》
    出现正面的次数:66,对应比率:0.5076923076923077
    出现反面的次数:64,对应比率:0.49230769230769234
    --------------------
    抛了140次之后--》
    出现正面的次数:69,对应比率:0.4928571428571429
    出现反面的次数:71,对应比率:0.5071428571428571
    --------------------
    抛了150次之后--》
    出现正面的次数:75,对应比率:0.5
    出现反面的次数:75,对应比率:0.5
    --------------------
    抛了160次之后--》
    出现正面的次数:79,对应比率:0.49375
    出现反面的次数:81,对应比率:0.50625
    --------------------
    抛了170次之后--》
    出现正面的次数:85,对应比率:0.5
    出现反面的次数:85,对应比率:0.5
    --------------------
    抛了180次之后--》
    出现正面的次数:88,对应比率:0.4888888888888889
    出现反面的次数:92,对应比率:0.5111111111111111
    --------------------
    抛了190次之后--》
    出现正面的次数:94,对应比率:0.49473684210526314
    出现反面的次数:96,对应比率:0.5052631578947369
    --------------------
    抛了200次之后--》
    出现正面的次数:100,对应比率:0.5
    出现反面的次数:100,对应比率:0.5
    --------------------
    '''
    # 可以看到正反面出现了次数越来越接近,最后一次居然整好一边一半,真给面子

      

    6.排列

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    import random
     
    '''
    shuffle,英文有洗牌的意思,顾名思义,就是讲一个序列进行打乱操作。
    '''
    = list(range(20))
    random.shuffle(l)
    # 这个函数是没有返回值的,实在序列本身上进行操作的
    print(l)  # [17, 11, 8, 13, 6, 7, 19, 1, 15, 9, 12, 4, 3, 0, 18, 2, 10, 5, 16, 14]
     
    try:
        = (12345)
        print(random.shuffle(t))
    except TypeError as e:
        print(e)  # 'tuple' object does not support item assignment
    # 可以看到由于元组是不可修改的,但shuffle又是在对象本身上进行操作,因此结果是会报错的

      

    7.采样

    1
    2
    3
    4
    5
    6
    7
    8
    9
    import random
     
    '''
    很多模拟需要从大量输入值中得到随机样本,sample函数可以生成无重复值得同样本,并且不会修改原来的序列。
    '''
    = list(range(100))
    # 接收两个参数,第一个是序列,第二个是选择的样本个数。
    # 样本的个数不可以超过序列里面元素的个数
    print(random.sample(l, 10))  # [13, 98, 18, 62, 75, 43, 32, 15, 10, 83]

      

    8.多个并发生成器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    import random
     
    '''
    除了模块级函数,rnadom还包括一个Random类以管理多个随机数生成器的内部状态。
    之前介绍的所有函数都可以作为Random实例的方法得到,并且每个实例都可以被单独初始化和使用,而不会干扰到其他实例返回的值
    '''
    r1 = random.Random()
    r2 = random.Random()
    for in range(3):
        print(f"{r1.random():.3f} {r2.random():.3f}")
    '''
    0.201 0.076
    0.954 0.065
    0.742 0.544
    '''
     
    r3 = random.Random(100)
    r4 = random.Random(100)
    for in range(3):
        print(f"{r3.random():.3f} {r4.random():.3f}")
    '''
    0.146 0.146
    0.455 0.455
    0.771 0.771
    '''

      

    9.SystemRandom

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    import random
     
    '''
    有些操作系统提供了一个随机数生成器,可以访问更多能引入生成器的信息源。
    random通过SystemRandom类提供了这个特性,该类与Random的API相同,只不过是使用os.urandom()生成值,该值会构成所有其他算法的基础
    '''
     
    r1 = random.SystemRandom()
    r2 = random.SystemRandom()
    for in range(3):
        print(f"{r1.random():.3f} {r2.random():.3f}")
    '''
    0.497 0.360
    0.304 0.208
    0.158 0.568
    '''
     
     
    r3 = random.SystemRandom(1000)
    r4 = random.SystemRandom(1000)
    for in range(3):
        print(f"{r3.random():.3f} {r4.random():.3f}")
    '''
    0.725 0.532
    0.030 0.489
    0.457 0.165
    '''
     
    # 可以看到即便设置了随机种子,也是不管用的,因为其随机性来自系统,而不是来自软件状态。
     
     
    # 顺便看看os.urandom()是个什么东西
    import os
    # 传入一个整数,返回包含相应整数个数的bytes对象
    print(os.urandom(20))  # b"xb4xe8xc9xe0'x1cxe8hxfagx19xc8xb8xb4xc3KXJ!x14"

      

    (四)math:数学函数

    1
    2
    3
    4
    5
    import math
     
    '''
    math模块实现了正常情况下原生平台C库中才有的很多专用IEEE函数,可以使用浮点值完成复杂的数学运算,包括对数和三角函数运算
    '''

      

    1.特殊常量

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    import math
     
    '''
    很多数学运算依赖于一些特殊的常量。math包含有pi、e、nan(不是一个数)和infinity(无穷大)的值
    '''
    print(math.pi)  # 3.141592653589793
    print(math.e)  # 2.718281828459045
    print(math.nan)  # nan
    print(math.inf)  # inf
    # pi和e的精度仅受平台的浮点数C库限制

      

    2.测试异常值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    import math
     
    '''
    浮点数计算可能会导致两种类型的异常值。第一种是inf(无穷大),当用double存储一个浮点值,而该值会从一个具有很大绝对值的值上溢出时,就会出现这个异常值
    '''
    print(f"{'e':^3} {'x':^6} {'x**2':^6} {'isinf':^6}")
    print(f"{'':-^3} {'':-^6} {'':-^6} {'':-^6}")
    for in range(020120):
        = 10.0 ** e
        = * x
        print(f"{e:>3} {x:<6g} {y:<6g} {bool(math.isinf(y))}")
    '''
     e    x     x**2  isinf
    --- ------ ------ ------
      0 1      1      False
     20 1e+20  1e+40  False
     40 1e+40  1e+80  False
     60 1e+60  1e+120 False
     80 1e+80  1e+160 False
    100 1e+100 1e+200 False
    120 1e+120 1e+240 False
    140 1e+140 1e+280 False
    160 1e+160 inf    True
    180 1e+180 inf    True
    200 1e+200 inf    True
    '''
    # 当这个例子中的指数变得足够大时,x的平方无法再存放于一个double中,这个就会被记录为无穷大
    # 不过,并不是所有浮点数都会导致inf值。具体地,用浮点值计算一个指数时,会生成OverFlowError而不是保留inf结果
    try:
        10.0 ** 400
    except OverflowError as e:
        print(e)  # (34, 'Result too large')
    # 这种差异是由C和Python所用库中的实现差别造成的。
     
    # 无穷大值得除法运算未定义。将一个数除以无穷大值的结果是nan(不是一个数)
    = 10.0**200 * 10.0**200
    = / x
    print("x =", x)  # x = inf
    print("isnan(x) =", math.isnan(x))  # isnan(x) = False
    print("y =", y)  # y = nan
    print("isnan(y) =", math.isnan(y))  # isnan(y) = True
    '''
    x是无穷大,由于无穷大的除法未定义,那么即使是x/x,得到的也并不是1,而是nan
    注意:nan不等于任何值,甚至也不等于它自身,所以要检查nan,要使用isnan()
    '''
    print(y == math.nan)  # False
    print(y is math.nan)  # False
    print(math.nan == math.nan)  # False
    print(math.nan is math.nan)  # True
    print(y == y)  # False
    print(y is y)  # True
    '''
    因此nan还是比较特殊的,即使同一个nan也不相等,但使用is会打印True,表示是同一个对象。
    但是y和math.nan虽然都是nan,但是是不同的nan,因此==和is都返回True
    '''
    # 因此最好使用math.isnan
    print(math.isnan(y))  # True
    # 再来看看numpy和pandas
    import numpy as np
    import pandas as pd
    # 可以看到依旧返回True
    print(math.isnan(np.nan))  # True
    print(np.isnan(math.nan))  # True
    print(np.isnan(y))  # True
    print(pd.isna(np.nan))  # True
    print(pd.isna(math.nan))  # True
    # 因此使用isnan函数来对nan判断最为合适
     
     
    # 此外还有一个isfinite函数检查是普通的值还是inf或者nan
    # infinity表示无穷,那么finite表示有穷。isfinite表示是否有穷,是不是一个有限的数字
    # inf肯定不是了,至于nan,它根本就不是一个数字,当然更不是了。
    # 所以isfinite(inf)和isfinite(nan)返回False,其它的返回True
    print(math.isfinite(x))  # False
    print(np.isfinite(x))  # False
    print(math.isfinite(100))  # True
    print(np.isfinite(100))  # True

      

    3.比较

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    import math
     
    '''
    浮点数的比较容易出错,每一个计算都可能由于数值表示而引入误差。
    isclose函数使用一种稳定的算法来尽可能的减少这种误差,同时完成绝对比较和相对比较
    '''
    = 1.1
    = 1.21
    # 首先isclose函数的前两个参数是要比较的两个数字,后面的两个参数一个是rel_tol,一个是abs_tol
    # 先来看看abs_tol,tol表示tolerate容忍,表示能容忍的最大极限。举个栗子
    print(math.isclose(a, b, abs_tol=0.2))  # True
    print(math.isclose(a, b, abs_tol=0.1))  # False
    '''
    asb_tol=0.2:表示我最多能容忍a和b之前差0.2,小于等于0.2,我认为是True,也就是两个数是相等的。超过0.2,不忍了,返回False
    而我们的a和b之前差0.11,所以0.2的时候返回True,0.1的时候返回False,因为0.11小于没有超过容忍极限0.2,但超过了容忍极限0.1
    '''
    # 了解abs_tol那么rel_tol也就好理解了,这个是与a、b的值有关系的
    # abs(a - b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)
    # 如果不传入abs_tol,那么表示a、b差的绝对值要小于等于a、b之间较大的那个数再乘以rel_tol。
    # 如果传入abs_tol,那么再和abs_tol比较,选出较大的做为容差,判断abs(a-b)是否小于等于这个容差
    # 因此rel_tol也叫相对容差,abs_tol也叫绝对容差
     
    # 如果只传入a、b的话,那么rel_tol默认为1e-9,即只要abs(a-b)小于等于a、b之间绝对值较大的那个数的绝对值再乘上rel_tol,那么结果就认为是True

      

    4.将浮点值转换为整数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    import math
     
    '''
    math模块中有三个函数用于将浮点值转换为整数。这三个函数分别采用不同的方法,适用于不同的场合
    最简单的是trunc,其会截断小数点之后的数字,只留下整数部分,说白了和int的作用是一样的。
    floor向下取整,2.5--》2
    ceil向上取整,2.5--》3
    '''
    val = 2.85
    print(math.trunc(val), type(math.trunc(val)))  # 2 <class 'int'>
    print(math.floor(val), type(math.floor(val)))  # 2 <class 'int'>
    print(math.ceil(val), type(math.ceil(val)))  # 3 <class 'int'>
    # 最后得到的结果都是int类型

      

    5.浮点值的其他表示

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    import math
     
    '''
    modf取一个浮点值,并返回一个元组,其中包含这个输入值得小数和整数部分。
    注意是小数和整数,不是整数和小数。这与我们平常的思维比较相反,因为我们做除法一般是先得到商,也就是整数部分,然后才得到余数也就是小数部分
    '''
    # 可以看到,即便传入整数,也会自动地将其转化为浮点数
    print(math.modf(10))  # (0.0, 10.0)
     
    print(math.modf(2.888431))  # (0.8884310000000002, 2.0)
    '''
    结果可能不太一样,但这是没办法的事情,不光是Python,所有语言都会存在这个问题。
    比如golang,我们用golang的math库,计算直角三角形的边长。两个直角边是3和4,那么求斜边
    手动计算,很容易知道是5,但是机器计算的话,那么在golang中有时会得到4.999999,那么取整之后就变成了4。
    因此浮点数会有误差,这是无法避免的
    '''
     
    # frexp返回一个浮点数的位数和指数
    '''
    什么意思呢?我先拿整数为例子,比如20
    先找一个数e,使得2**e > 20并且2**(e-1) < 20, 显然这里e=5,因为2**5=32>20, 2**4=16<20
    然后找一个数m,使得m * 2**e=20,这里m=20/ 2** 5 = 20 / 32 = 5/8 = 0.625
    返回m和e。
    综上所述:frexp(20)-->(0.625, 5)
    '''
    print(math.frexp(20))  # (0.625, 5)
    # ldexp和frexp是一对,返回一个浮点数
    # 2**5 * 0.625 = 20.0
    print(math.ldexp(0.6255))  # 20.0
     
    '''
    个人不知道,这几个函数会有什么用,反正我是觉得没有什么卵用
    '''

      

    6.正号和负号

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    import math
     
    '''
    一个数的绝对值就是不带正负号的本值。使用fabs函数可以计算一个浮点数的绝对值
    '''
    print(math.fabs(-1.1), abs(-1.1))
    print(math.fabs(-0.0), abs(-0.0))
    print(math.fabs(1.0), abs(1.0))
    print(math.fabs(1.1), abs(1.1))
    '''
    1.1 1.1
    0.0 0.0
    1.0 1.0
    1.1 1.1
    '''
    # 感觉和abs没有太大区别
     
    # copysign表示拷贝符号,copysign(a, b), 将b的符号拷贝到a中
    # 注意与a的符号无关,如果b为正,结果相当于abs(a) * 1, 结果b为负,结果相当于abs(a) * -1
    print(math.copysign(-1.15))  # 1.1
    print(math.copysign(-1.1-5))  # -1.1

      

    7.常用计算

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    import math
     
    '''
    在二进制浮点数内存中表示精确值很有难度。有些值无法准确地表示,而且如果通过反复计算来处理一个值,那么计算越频繁就越容易引入表示误差。
    math包含一个函数来计算一系列浮点数的和,它使用一种高效的算法来尽量减少这种误差。
    '''
    values = [0.1* 10
    = 0.0
    for in values:
        += v
    print("for-loop:", s)  # for-loop: 0.9999999999999999
    print("sum:"sum(values))  # for-loop: 0.9999999999999999
    print("fsum:", math.fsum(values))  # fsum: 1.0
    # 由于0.1不能精确表示为一个浮点数,因此在计算总和的时候会引入误差,但是可以使用fum来避免这种情况
     
     
    # factorial用于计算阶乘
    print(math.factorial(5))  # 120
     
    # gamma、lgamma不再介绍,感觉没啥用
     
    # fmod,之前好像介绍一个modf
    print(math.modf(2.2))  # (0.20000000000000018, 2.0)
    # 相当于取余,%
    print(math.fmod(83))  # 2.0
    print(int.__mod__(83))  # 2
     
     
    # gca函数,可以用来查找两个数的最大公约数
    print(math.gcd(2015))  # 5

      

    8.指数和对数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    import math
     
    '''
    指数生长曲线在经济学、物理学和其他科学中经常出现。Python有一个内置的**幂运算符。
    不过,如果需要将一个可调用函数作为另一个函数的参数,那么可能需要用到pow
    '''
    print(2**5, math.pow(25))  # 32 32.0
    print(3**4, math.pow(34))  # 81 81.0
     
    # 1的任何次幂都返回1.0,任何值得指数为0也返回1.0
    # 对于nan,大多数运算返回nan,如果值小于1,那么pow会计算一个根
    # 如果指数是1/2,就变成了求平方根,这也有一个专门的函数叫sqrt,因为平方根用的很频繁
    print(math.pow(91/2))  # 3.0
    print(math.sqrt(9))  # 3.0
    # 如果是求负数的平方根,那么会报错,因为涉及到复数,可以使用cmath模块,c:complex
    try:
        print(math.sqrt(-9))
    except ValueError as e:
        print(e)  # math domain error
    import cmath
    # cmath和math模块的api基本上是一只的,只不过cmath是用来处理复数的,如果我传入实数呢,比如33,那么会解释器自动在结尾加上0j,变成33+0j,注意在Python中,复数的虚部用j表示,不是i
    print(cmath.sqrt(-9))  # 3j
    # 那我想手动创建复数怎么办?直接创建就好啦
    = 3 + 4j
    print(f"实部:{c.real},虚部:{c.imag},复数本身:{c},共轭复数:{c.conjugate()}")  # 实部:3.0,虚部:4.0,复数本身:(3+4j),共轭复数:(3-4j)
    print(f"模:{abs(c)}")  # 模:5.0
     
     
    # 对数,log里面接收两个参数,第一个参数传计算的值,表示要计算谁的对数。第二个参数表示底数,以谁为底,如果不传,默认为e
    print(math.log(math.e))  # 1.0
    print(math.log(93))  # 2.0
    print(math.log(0.52))  # -1.0
     
    # 对数还有两个常用变形,功能类似,但是会更精确
    # log10(x) <===> log(x, 10)
    # log2(x) <===> log(x, 2)
    print(math.log10(100))  # 2.0
    print(math.log2(32))  # 5.0
     
     
    # exp,用于计算指数函数,exp(x) <==> e**x
    print(math.e ** 2)  # 7.3890560989306495
    print(math.pow(math.e, 2))  # 7.3890560989306495
    print(math.exp(2))  # 7.38905609893065

      

    9.角

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    import math
     
    '''
    尽管我们每天讨论角是更常用的是度,但弧度才是科学和数学领域中度量角度的标准单位。
    弧度是在圆心相交的两条线所构成的角,其终点落在圆的圆周上,终点之间相距一个弧度。
    圆周长计算为2πr,所以弧度与π之间存在一个关系,要把度转化为弧度,可以使用函数radians
    要把弧度转化为度,使用函数degrees
    '''
    # 在半径为1的情况下,周长是2π,整个圆是360度,所以degree/360 * 2π便是弧度
    print(math.radians(180))  # 3.141592653589793
    print(math.degrees(math.pi))  # 180.0

      

    10.三角函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    import math
     
    '''
    概念不介绍了,上过高中应该都会的。
    '''
    # 注意的是要传入弧度,比如我传入30,那么这里的30是弧度,不是角度,所以结果不是二分之一
    print(math.sin(30))  # -0.9880316240928618
    print(math.sin(math.pi / 6))  # 0.49999999999999994
     
    print(math.cos(0))  # 1.0
    print(math.tan(0))  # 0.0
    # 可以看做是无穷大
    print(math.tan(math.pi / 2))  # 1.633123935319537e+16
     
     
    # 已知点(x, y),那么点[(0, 0), (x, 0), (0, y)]会构成一个直角三角形,求斜边长度,可以使用函数hypot来计算
    print(math.hypot(34))  # 5.0
    # 这不就是(x**2 + y **2)**(1/2)吗
     
    # 除此之外还有反三角函数
    print(math.asin(0.5))  # 0.5235987755982989
    # 大致结果为π/2
    print(math.atan(math.inf))  # 1.5707963267948966

      

    11.双曲函数

    12.特殊函数

    1
    2
    3
    4
    5
    6
    import math
     
    '''
    不做介绍,没啥乱用。
    真要用的话,可以使用numpy,更牛逼的方法可以使用scipy
    '''

      

    (五)statistics:统计计算

    1
    2
    3
    ''''
    statistics模块实现了很多常用的统计公式,允许使用Python的各种数值类型(int, float, Decimal,Fraction)来完成高级计算
    '''

      

    1.平均值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    import statistics
    '''
    共支持3种形式的平均值:均值(mean),中值或中位数(median),以及众数(mode)
    '''
    # 可以使用mean计算算术平均值
    data = [12344456]
    print(statistics.mean(data))  # 3.625
    # 对于整数和浮点数,返回的总是浮点数,对于Decimal和Fraction,返回的类型和输入的类型相同
     
    # 可以使用mode计算一个数据集中的最常见的数据点,也就是众数
    print(statistics.mode(data))  # 4
    # 由于mode是把输入处理为一个离散值集合,然后统计出现次数,所以对于mode函数来说,输入并不一定非要是数字
    print(statistics.mode(["a""xx""xx"]))  # xx
     
    # 可以使用median计算中位数
    '''
    如果是序列的个数是奇数,很好办,就是中间的那一个。
    但如果个数是偶数,那么中间值会有两个,median会取两者的平均值
    除了median还有median_high,median_low,显然这是针对个数是偶数的。median_high会取两者中的较大值,median_low会取两者中的较小值
    '''
    data = [1234]
    print(statistics.median(data))  # 2.5
    print(statistics.median_high(data))  # 3
    print(statistics.median_low(data))  # 2

      

    2.方差

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    import statistics
    '''
    统计使用两个值来描述一个集合相对于均值的离散程度。
    方差:各个值与平均值之差的平方的平均。
    标准差:方差的平方根。
    如果方差大:说明数据集不稳定,离散程度高。
    如果方差小:说明数据集稳定,离散程度低
    显然:[1, 10]的方差要大于[2, 9]大于[5, 6]
    '''
     
    data = [45334256]
    print(statistics.variance(data))  # 1.7142857142857142
    print(statistics.stdev(data))  # 1.3093073414159542

      

  • 相关阅读:
    【Services】【Web】【tomcat】配置tomcat支持https传输
    【Services】【Web】【apr】安装apr
    【Services】【Web】【Nginx】静态下载页面的安装与配置
    【Linux】【Problems】在fedora 9上解决依赖问题
    【Java】【设计模式】单例设计模式
    【Linux】【Shell】【text】awk
    【Linux】【Shell】【Basic】字符串操作
    【Linux】【Shell】【Basic】数组
    Linux上常用插件的一些命令(十)
    常见HTTP状态码
  • 原文地址:https://www.cnblogs.com/valorchang/p/11395728.html
Copyright © 2011-2022 走看看