Julia 学习笔记——3. 流程控制
Some content in this article was created with AI assistance. Please verify as needed.简单过一遍 Julia 中的流程控制,其实和 Python 以及 MATLAB 基本一致。 主要的区别包括: Julia 的条件表达式必须是显式 Bool,不像 Python 和 MATLAB 那样允许各种隐式真值判断; if、begin 这类结构本身都可以作为表达式使用; for 和 while 不只是“执行循环”,还会和局部作用域规则产生联系。 条件语句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...
Julia 学习笔记——2. 字面量、基本数据类型与运算符
Some content in this article was created with AI assistance. Please verify as needed.这一篇主要整理 Julia 中最常见的基本数据类型,以及与这些类型直接相关的运算符语义。 整数与浮点数整数Julia 支持固定长度的整数类型,包括有符号和无符号的版本,例如 Int8,Int32,UInt32 等。对于十进制整数字面量,在64位系统中默认使用 Int64 类型整数。可以使用 typeof() 查看字面量的类型(Python 对应的函数为 type()) 1typeof(1) # Int64 类型也是可以作为参数进行运算的,例如使用 typemin() 和 typemax() 直接查看类型的最大最小值 123typemin(Int32) # -2147483648typemin(Int64) # -9223372036854775808typemax(Int64) # 9223372036854775807 注意: Julia 支持使用 _ 作为数字的分隔符,可以提高可读性,例如10_000。...
Julia 学习笔记——1. 概述
Some content in this article was created with AI assistance. Please verify as needed.这套笔记主要记录从 Python 和 MATLAB 迁移到 Julia 时需要关注的内容。 需要说明的是,这个系列不是零基础入门教程,而是围绕具体主题展开的整理型笔记,因此不同篇之间会有交叉,不严格追求循序渐进。 除非特别说明,下文默认以 Julia 最新版本 1.12 为准。 概述Julia 对我而言更像是一种值得单独学习的科学计算语言,而不是 Python 或 MATLAB 的某个附属工具。 它最吸引人的地方很明确: 写法上尽量保留动态语言和科学计算语言的易用性; 执行上尽量逼近静态编译语言的性能; 语言本身直接把数组、线性代数、泛型函数和多重分派当作核心设计对象。 介绍Julia 是一门面向科学计算的新兴语言,它的设计目标非常明确:希望同时拥有 Python/MATLAB 的易用性,以及 C/C++/Fortran 一类语言的运算效率。 Julia有很多与众不同的特点: ...
Numpy 学习笔记——3. 数组的线性代数运算
NumPy 提供了比较丰富的线性代数运算功能,主要集中在 numpy.linalg 模块中,下面罗列一些基础的操作,主要针对一维和二维数组,对于其它高维数组的语义可能不太符合直觉。 重要函数点积 np.dotnp.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,) 的一维数组,那么就是标准的向量内积,结果是一个标量。 (特例)如果 a ...
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 函数,绝大多数代码在不同方式中执行都是等效的,但是考虑优化就不是一回事了。 在涉及 JIT 优化和作用域分析时,函数形式通常更有利于 MATLAB 对代码进行分析,尤其是作用域与类型推断,进而对代码运行进行优化,因此运行效率更高;命令行和脚本则更偏向交互式使用。 在命令行中交互式地调用某些内置函数,相比于从脚本文件中调用,可能会有不一样的结果。 基于模块化编程的思维,避免使用过大的单一文件,考虑将其中重复使用的功能拆分为简洁的函数文件,这种做法可以降低首次运行的成本。 优先使用局部函数而非嵌套函数,嵌套函数可以直接访问外层函数的变量(按照引用捕获),这可能限制 MATLAB 对其进行的优化,更好的做法是将所有需要的变量以函数参数的形式显式传递。 关于内置函数避免重载内置函数,尤其不要对标准 MATLAB 数据类重载内置函数。 在可选的情况下,优先考虑使用 MATL...
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 ...
Cpp 多态方案对比——回字的四种写法
虽然C++没有直接提供interface,但是却提供了虚函数、模板类型等各种语法,使得我们可以用各种方式实现多态,这里我们不区分动态多态和静态多态,而是从设计一个框架的角度,分别使用四种方案实现: 虚函数(最简单直接的方式) std::function CRTP(最晦涩的方式) deducing this(可以视作CRTP的简化,不再需要将派生类作为模板参数传递,要求C++23) 需求我们考虑这样一个需求: 基类A包括:(不可实例化) 主方法run:调用func1,func2和func3 实现方法func1 实现方法func2(多态,允许子类修改) 实现方法func3(多态,子类必须实现) 派生类B1:继承A 实现方法func3(多态,允许子类修改) 派生类B2:继承A 实现方法func3(多态,允许子类修改):调用func4 实现方法func4(多态,允许子类修改) 具体类C1:继承B2 实现方法func4 具体类C2:继承B2 实现方法func3 最终我们直接通过各种对象自身来调用run方法,达到如下效果: 12345678Running...
解读一份极其晦涩的 c++ 代码
事先声明,下面的各种语法技巧都是炫技式的,刻意降低代码的可读性,只是写着玩,在实际应用中是不会允许这么乱写的。 先来几个开胃菜。 开胃菜(1) 嵌入网址?下面这段代码看起来是在c++中直接嵌入了一个网址 1234567#include <iostream>int main(){ https://www.zhihu.com std::cout << "Hello World!" << std::endl; return 0;} 它确实是合法的c++代码,但是含义却并不是网址: 左半部分https: 是一个标签,可以通过goto跳转; 右半部分由于//的存在,就是一个注释,直接被忽略了。 下面的代码就更利于理解了 123456789#include <iostream>int main() {label: // 这是注释 std::cout << "Hello World!" << std::endl; g...
