龙空技术网

《仅用 10 行 Python 代码实现多种数学运算》

编程小小将 10

前言:

此时看官们对“python的math函数库求和”大约比较着重,咱们都想要知道一些“python的math函数库求和”的相关文章。那么小编在网络上搜集了一些有关“python的math函数库求和””的相关知识,希望我们能喜欢,小伙伴们快快来了解一下吧!

在当下 AI 迅猛发展的时期,Python 凭借其简洁易读的语法以及强大的表现力,深受程序员与科学家的青睐。本文旨在展示 Python 仅用 10 行代码便能完成复杂数学运算的强大能力,涵盖向量加法、点积、矩阵乘法、矩阵转置以及线性系统求解器等诸多方面。

回想最初使用 Python 时,NumPy 或 SymPy 尚未出现。那时,研究常借助 MatLab,快速原型设计依赖 Delphi……甚至还会在 Prolog 中进行符号计算。那时的 Python 类似优化版的 Perl,但并非研究人员的首选。

不过,用它编写程序颇具趣味,我因而选择以 Python 来实现论文中的部分实验,其中涉及一些线性代数的内容。起初,我采用类似 Pascal 风格的嵌套循环程序,感觉较为枯燥,然而随着对 Python 研究的深入,有趣的一面逐渐展现。

某一时刻,我察觉到这门语言绝非仅能编写嵌套循环,于是开始更深入地探索,而非局限于论文所需——这或许是我所做的最佳“错误”决定。

Python 以其友好的学习曲线著称,但这也可能带来问题。您可以用 Python 编写类似 Pascal、C++ 或 Lisp 的程序,但只有以 Python 特有的方式编写,方能充分发挥其优势。

好在,即便仅掌握 Python 的基础知识,可能会错失精彩部分,但用户体验依然良好。

为阐释这一点,我选取了线性代数领域。按理说,Python 有众多出色的库可处理线性代数,因此无需重新实现文中提及的内容。而我选择线性代数,旨在证明 Python 中以少量代码表达丰富含义的语法是完全可行的(免责声明:为保证可读性,部分代码示例未严格限制在一行内,示例中的所有缩进纯粹是为了提升阅读体验)。

列表解析

列表解析是 Python 单行代码的精髓所在,它是一种用于描述列表转换的特殊语法。例如,若要将一个向量乘以一个标量,在类似 Pascal 的 Python 代码中,可能会这样书写:

def scaled(A, x):    B = list()    for i in range(len(A)):        B.append( A[i] * x )    return B

这种写法虽无过错,也有其优点,例如总能找到一行设置断点,但确实显得有些“冗长”。在 Python 中,您可以简洁地写成:

def scaled(A, x): return [ai*x for ai in A]

然后其运行效果如下:

List comprehension    [1.0, 4.0, 3.0]* 2.0    [,...Step 1    [1.0, 4.0, 3.0]     * 2.0    [2.0,...Step 2    [1.0, 4.0, 3.0]          * 2.0    [2.0, 8.0,...Step 3    [1.0, 4.0, 3.0]               * 2.0    [2.0, 8.0, 6.0]

不过,列表解析并非 Python 所独有,Haskell 和 Clojure 也具备类似功能,甚至 C# 的 LINQ 也为范围提供了特殊语法。鲜为人知的是,Python 还支持字典解析和元组解析。

>>> [2*v for v in [1.0, 2.0, 3.0]][2.0, 4.0, 6.0]>>> {k:2*v for k, v in {0:1.0, 1:4.0, 2:3.0}.items()}{0: 2.0, 1: 8.0, 2: 6.0}>>> tuple(2*v for v in (1.0, 4.0, 3.0))(2.0, 8.0, 6.0)

列表压缩

列表压缩能够将多个可迭代对象作为一个整体进行迭代,并将所有对象转换为一个元组列表。尽管标题提及“列表”,但它同样适用于元组、字典、生成器等任何可迭代的对象。

>>> A = [1, 2, 3]>>> B = ('a', 'b', 'c')>>> C = {1:'a', 2:'b', 3:'c'}>>> D = xrange(123)>>> zip(A, B, C, D)[(1, 'a', 1, 0), (2, 'b', 2, 1), (3, 'c', 3, 2)]

同样,您可以用一行代码实现向量加法。

def sum_of(A, B): return [ai+bi for (ai, bi) in zip(A, B)]

对于两组列表,这能够如同拉链一般将数据压缩在一起。

List zipping    A = [1.0, 4.0, 3.0]    B = [7.0, 3.0, 1.0]zip(A, B) = [...Step 1         A = [1.0, 4.0, 3.0]         B = [7.0, 3.0, 1.0]zip(A, B) = [(1.0, 7.0),...Step 2                A = [1.0, 4.0, 3.0]                B = [7.0, 3.0, 1.0]zip(A, B) = [(1.0, 7.0), (4.0, 3.0),...Step 3                       A = [1.0, 4.0, 3.0]                       B = [7.0, 3.0, 1.0]zip(A, B) = [(1.0, 7.0), (4.0, 3.0), (3.0, 1.0)]

求和函数

求和函数能够进行简单的求和操作。您可以通过累积向量元素的乘积,用一行代码实现向量点积。

def dot_of(A, B): return sum([ai*bi for (ai, bi) in zip(A, B)])

然而,有时简单的求和并不足够。例如在处理浮点数时,可能会遭遇一些恼人的小误差。为了更加便利,Python 提供了另一个求和函数,能够对部分求和进行操作,从而获取更精确的输出。

>>> [0.1]*10[0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]>>> sum([0.1]*10)0.9999999999999999>>> import math>>> math.fsum([0.1]*10)1.0

条件表达式

条件表达式是 Python 中的三元运算符,是依赖于条件的表达式,通常也是简单纯粹的表达式。我们能够用条件表达式来构建一个单位矩阵。

def identity(n):    return [[1.0 if i==j else 0.0            for j in range(n)]        for i in range(n)]

这实际上是一个包含条件表达式的嵌套列表解析,结果如下:

Conditional expression: 0 == 0  j = 0[[1.0,...            i = 0Conditional expression: 1!= 0       j = 1[[1.0, 0.0,...       i = 0Conditional expression: 2!= 0            j = 2[[1.0, 0.0, 0.0],... i = 0Conditional expression: 0!= 1  j = 0[[1.0, 0.0, 0.0], [0.0,...            i = 1Conditional expression: 1 == 1       j = 1[[1.0, 0.0, 0.0], [0.0, 1.0,...       i = 1Conditional expression: 2!= 1            j = 2[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0],... i = 1Conditional expression: 0!= 2  j = 0[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0,...            i = 2Conditional expression: 1!= 2       j = 1[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0,...       i = 2Conditional expression: 2 == 2      j = 2[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]]     i = 2

条件表达式在简洁性和表达力方面表现出色,但由于它们是表达式,所以不易添加副作用。但并非完全不可能,只是需要一些技巧。在 Python 中,元组计算会从左到右依次计算每个元组元素,所以当您需要在表达式中添加更多内容时,只需使用元组即可。

def identity(n):    return [[1.0 if i==j else (0.0,                               sys.stdout.write("i!= j\n")                              )[0]            for j in range(n)]        for i in range(n)]

您也不能在表达式中使用 print,因为它们不应具有副作用,但可以使用 sys.stdout.write。

def identity(n):    return [[1.0 if i==j else (0.0,                               sys.stdout.write("i!= j\n")                              )[0]            for j in range(n)]        for i in range(n)]

同样的技巧也适用于 lambda 表达式,您可以通过元组让您的 lambda 表达式尽可能复杂。不过建议若非必要,请勿如此操作。

我猜测肯定会有人反驳说,“您的例子根本无需条件表达式!”的确如此。在 Python 中,您可以显式地将布尔类型变量转换为浮点数变量。

def identity(n):    return [[float(i==j) for j in range(n)] for i in range(n)]

这只是风格问题。就个人而言,我更倾向于将事实和数字分开,不这样做也完全可行。

将容器内容作为参数传递

假设在 Python 中我们有一个矩阵,以列表形式表示,其中每个嵌套列表是一行。若将这些行传递给前面提到的 zip,它会生成一个元组列表,其中每个元组代表矩阵的一列。如此一来,我们便得到了一个现成的矩阵转置。

不过,我们还需解决两个问题。一个较为简单:我们期望矩阵是一个列表,而非元组,所以需要通过一个简单的列表解析来解决。另一个问题则需使用特殊的 Python 语法,它能让我们将列表转变为函数参数的元组,此语法便是在矩阵前添加一个星号。

def transposed(A): return [list(aj) for aj in zip(*A)]

领取方式:私信回复666,免费领取资料软件~

标签: #python的math函数库求和