Julia 学习笔记——5. 变量作用域与类型系统
Julia 具有强烈的学院派风格,类型系统设计的非常复杂,并且比 C++ 充满历史包袱的类型系统和模板机制精巧很多。 变量作用域 Julia 有相对复杂的作用域机制,包括全局作用域,局部作用域,对于局部作用域又分为软作用域和硬作用域。 大部分语句都会产生作用域,但是有两个例外:begin 语句和 if 语句。 Julia 使用词法作用域,也就是说一个函数的作用域不继承自调用了函数的调用者作用域,而继承自该函数定义处作用域。 容器 元组和具名元组 Julia 支持和 Python 几乎一样的元组,元组中的元素可以是不同类型,例如 1234(1, 2)1, 2(1, "2", 3.0) 这里的括号在不存在歧义时可以省略,只含一个元素的元组和空元组有固定的写法,例如 12(1,)() 元组中的元素可以使用索引访问(索引从1开始),例如 123a = (1,'a');a[1] # 1a[2] # 'a' 和 Python 一样,Julia 的元组赋值可以自动解包,因此可以用来同时定义多个变量,例如 123(x,y,z) = (1...
Julia 学习笔记——4. 函数基础
Julia 中的函数与 Python 很类似,都是作为语言的一等公民,包括直接把函数视作变量,可以用函数赋值和作为参数传递等都是一样的,两者最大的区别可能就是关键字从 Python 的 def 换成 Julia 的 function,除此以外都是一些细节差异。 函数基础 简单例子 最基本的例子如下 12345function f(x,y) x + yendf(1,2) # 3 和 Python 一样,Julia 的函数不需要额外的类似函数句柄的机制,函数对象可以和普通的值一样被传递。 12345function f(x,y) x + y;endg = f; g(1,2) # 3 函数的赋值形式 Julia 支持以单行的赋值形式定义简单的函数 1f(x, y) = x + y; 此时的函数体只能是一个单行表达式,这个表达式的结果自然就是函数的返回值。由于函数分派机制的存在,这种简单函数在 Julia 中实际上很常见。 return 语句 Julia 可以使用 return 语句返回值,但是和 Python 不同的是,Julia 在不使用 return 语句时,自动将最后...
Julia 学习笔记——3. 流程控制
简单过一遍 Julia 中的流程控制。 条件语句 if 条件语句和其它语言一样,注意其中的条件表达式不需要括号 123456789101112x = 3;y = 2;if x < y println("x is less than y")elseif x > y println("x is greater than y")else println("x is equal to y")end# x is greater than y C/C++ 使用 else if;Python 使用 elif;MATLAB 使用 elseif,Julia 也使用 elseif。 Julia 严格要求 if 和 elseif 所接受的条件必须是 Bool 值,不接受隐式转换,例如下面的语句会报错 123if 1 # error println("1 is true")end if 语句整体在运行时会将对应分支的执行结果作为返回值,这相比于其他语言有点奇怪。 123456ju...
Julia 学习笔记——2. 基本数据类型与运算符
整数与浮点数 整数 Julia 支持固定长度的整数类型,包括有符号和无符号的版本,例如 Int8,Int32,UInt32 等。对于十进制整数字面量,在64位系统中默认使用 Int64 类型整数。可以使用 typeof() 查看字面量的类型(Python 对应的函数为 type()) 1typeof(1) # Int64 类型也是可以作为参数进行运算的,例如使用 typemin() 和 typemax() 直接查看类型的最大最小值 123typemin(Int32) # -2147483648typemin(Int64) # -9223372036854775808typemax(Int64) # 9223372036854775807 注: Julia 支持使用 _ 作为数字的分隔符,可以提高可读性,例如10_000。 由于整数的位数是固定的,在运算中自然也存在溢出问题,与其它语言中的处理类似,不再赘述。 Python 的整数是无限精度的,Julia 也提供了 BigInt 类型以支持无限精度。 对于非十进制的整数字面量,Julia 采用了不同的处理:默认将其视作无类型整数...
Julia 学习笔记——1. 概述
尝试学一下 Julia,但是这份笔记的时间跨度可能很长,有空就写一点吧。 需要说明的是,这个系列不是零基础的 Julia 笔记,而是直接从 Python 和 MATLAB 到 Julia 的迁移学习,并且笔记是围绕主题进行的,不是逐渐展开的。 介绍 Julia是一门新兴的科学计算语言,它的设计目标非常宏大:希望 Julia 可以同时拥有 Python/MATLAB 一样的易用性和 C/C++/Fortran 一样的运算效率。 Julia有很多与众不同的特点: 从设计定位来说,Julia 具有后发优势,是为 JIT 编译而量身定制的语言,目的是解决现在泾渭分明的动态语言和静态语言之间,优劣不能兼顾,因而必须组合使用的问题。 从计算效率的角度,虽然和Python在使用时很相似,但是Julia的计算效率却比Python高很多。Python的科学计算模块Numpy等必须依赖于C/C++编写的底层库,但是Julia自身就可以提供足够的科学计算能力(主要是通过预编译实现的)。 从语法设计的角度,Python并没有关注于科学计算编程中的便利性,Julia和MATLAB、Fortran、R语言...
Numpy 学习笔记——3. 数组的线性代数运算
NumPy 提供了比较丰富的线性代数运算功能,主要集中在 numpy.linalg 模块中,下面罗列一些基础的操作,主要针对一维和二维数组,对于其它高维数组的语义可能不太符合直觉。 重要函数 点积 np.dot np.dot() 函数可以计算两个向量的点积,最基本的用法例如 1234a = np.array([1, 2, 3], dtype=np.float64)b = np.array([4, 5, 6], dtype=np.float64)np.dot(a, b) # np.float64(32.0)# 1*4 + 2*5 + 3*6 = 32 np.dot(a, b)的完整语义需要根据两个数组的维度来区分: 第一类情况: 如果其中一个是标量,那么就是进行(逐元素的)乘法,等效于 np.multiply(a, b) 或 a * b。 第二类情况: 如果 a 是 \(N\) 维数组,b 是一维数组,那么会沿着两者的最后一个轴求和,得到 \(N-1\) 维数组。 (特例,标准情况)如果两者都是尺寸为 (m,) 的一维数组,那么就是标准的向量内积,结果是一个标量。 (特例...
Numpy 学习笔记——2. 数组的变换和基本运算
数组的拷贝 Python 本身有深拷贝和浅拷贝等复杂的概念,对于多层列表等数据结构,对应的行为差异非常明显。 但是 Numpy 的 ndarray 数组无论形状如何,在内存中始终是连续存储的,高维数组并不是数组的数组, 因此并没有深拷贝和浅拷贝的明显差异。 和其它 Python 数据一样,在函数传参过程中对 ndarray 数组的传递并不会触发任何的拷贝行为。 为了获取一个 ndarray 数组的完整拷贝,可以使用 ndarray.copy() 方法,例如 12345a = np.array([1, 2, 3])b = a.copy()b[0] = 100a # array([1, 2, 3]) 上述测试代码表明,拷贝得到的是完全独立的数组,修改不会相互影响。 也可以使用numpy.copy()函数,例如 12a = np.array([1, 2, 3])b = np.copy(a) ndarray.copy() 方法和 numpy.copy() 函数的行为是基本一致的,都是获取原数组的拷贝,但是两者关于内存排布参数的默认值有细微差异,可以参考具体文档。 数组的视图 为了优化计...
Numpy 学习笔记——1. 数组的创建和索引
Numpy 是一个用于科学计算的 Python 扩展库,虽然不是 Python 标准库,但是已经是 Python 在科学计算、机器学习等领域毋庸置疑的基础库,很多主流的 Python 库都依赖 Numpy。 1import numpy as np 一个循序渐进的入门笔记的内容组织比较麻烦,我也并不打算这么做,这个笔记的内容会围绕一些关键点展开, 主要参考 Numpy 的官方资料。 ndarray 基本概念 np.ndarray (别名 np.array)是 Numpy 的核心数据类型,可以用于存储 n 维数组,并提供了大量相关操作方法。 它与 Python 的 list 类型类似,但是存在更多限制:只能存储同类型数据,并且尺寸是固定且规则的,即不允许各个元素长短不一的数组。 这些限制使得 ndarray 的运算非常高效(直接调用底层的 C/C++ 实现)。 但是有一点不足的是:Numpy 没有提供稀疏矩阵的数据结构,需要时可以使用其它包提供的稀疏矩阵。 我们主要关注一维数组和二维数组,例如 123array([1, 2, 3]) # shape=(3,)array([[1, ...
MATLAB 高性能编程笔记
记录一些常用的 MATLAB 编程技巧/规范,目标是写出高性能的 MATLAB 代码。主要参考官方文档中的提升性能的方法。 基础 关于代码结构 MATLAB 提供了很多方式来执行代码:命令行 vs 脚本 vs 函数,绝大多数代码在不同方式中执行都是等效的,但是考虑优化就不是一回事了,通常的运行效率关系为:命令行 < 脚本 < 函数,也就是说函数的执行速度通常是最快的。 基于模块化编程的思维,避免使用过大的单一文件,考虑将其中重复使用的功能拆分为简洁的函数文件,这种做法可以降低首次运行的成本。 优先使用局部函数而非嵌套函数,嵌套函数可以直接访问外层函数的变量(按照引用捕获),这会影响效率,更好的做法是将所有需要的变量以函数参数的形式显式传递。 交互式地在命令行中调用某些内置函数,相比于从脚本文件中调用,可能会有不一样的结果。 关于内置函数 避免重载内置函数,尤其不要对标准 MATLAB 数据类重载内置函数。 在可选的情况下,优先考虑使用 MATLAB 的内置函数来实现数组的常用运算,因为内置函数可能是直接使用底层语言实现的,至少也经过了大量的优化,比我们直接实现的效...
MATLAB 踩坑记录
记录一下 MATLAB 踩过的小坑,MATLAB的各种内置函数的用法实在是太奇怪了,一个小细节就可以搞出各种问题。 矩阵偏移 函数 circshift 可以用于向量或矩阵的循环偏移,不会修改原始数据。 向量偏移 123456A = [1, 2, 3, 4, 5];circshift(A, 1)% [5, 1, 2, 3, 4]circshift(A, -1)% [2, 3, 4, 5, 1] 矩阵的偏移就比较复杂了,按照前面的做法会以行为整体进行偏移!!! 1234567A = [1 2 3; 4 5 6; 7 8 9];circshift(A, 1);% 7 8 9% 1 2 3% 4 5 6 如果希望以列进行偏移,有两种方式,第一种方式是额外指定维数(传递两个标量) 1234567A = [1 2 3; 4 5 6; 7 8 9];circshift(A, 1, 2)% 3 1 2% 6 4 5% 9 7 8 ...
