[docs] Julia 与 MATLAB 的显著差异

给现有文档增加了一堆例子:与其他语言的显著差异 · Julia中文文档


其他的 Matlab vs julia


Note:

  • 相对于文档,这里简单分了下类
  • 有些条目较长,对条目进行了拆分与合并
  • 输出放在注释里
  • matlab:2014b x64
  • julia:1.4.2 x64

julia 与 Matlab 的差异

线性代数

构造与拼接向量、多维数组

  • 在 Julia 中 [x, y, z]始终构造一个包含 xyz 的 3 元数组。
    即:julia 不会自动展开数组
    matlab

    [1, 2, 3]
    %      1     2     3
    
    [1, [0 0], 3]
    %      1     0     0     3
    

    julia

    [1, 2, 3]
    # 3-element Array{Int64,1}:
    #  1
    #  2
    #  3
    [1 2 3]
    # 1×3 Array{Int64,2}:
    #  1  2  3
    
    [1, [0 0], 3]
    # 3-element Array{Any,1}:
    #  1
    #   [0 0]
    #  3
    [1 [0 0] 3]
    # 1×4 Array{Int64,2}:
    #  1  0  0  3
    
    【相似之处】数组的构造 与 数组的拼接
    • 要在第一个维度「垂直列」中连接元素,请使用 vcat(x, y, z) 或用分号分隔 [x; y; z]
      matlab

      [1; 2; 3]
      %      1
      %      2
      %      3
      
      a = [1 2];
      [a; a; a]
      %      1     2
      %      1     2
      %      1     2
      

      julia

      [1; 2; 3]
      # 3-element Array{Int64,1}:
      #  1
      #  2
      #  3
      
      a = [1 2];
      vcat(a, a, a)
      # 3×2 Array{Int64,2}:
      #  1  2
      #  1  2
      #  1  2
      
      [a; a; a]
      # 3×2 Array{Int64,2}:
      #  1  2
      #  1  2
      #  1  2
      
    • 要在第二个维度「水平行」中连接元素,请使用 hcat(x, y, z) 或用空格分隔 [x y z]
      matlab

      [1 2 3]
      %      1     2     3
      
      a = [1 2];
      [a a a]
      %      1     2     1     2     1     2
      

      julia

      [1 2 3]
      # 1×3 Array{Int64,2}:
      #  1  2  3
      
      a = [1 2];
      hcat(a, a, a)
      # 1×6 Array{Int64,2}:
      #  1  2  1  2  1  2
      
      [a a a]
      # 1×6 Array{Int64,2}:
      #  1  2  1  2  1  2
      
    • 要在前两个维度中连接元素构造分块矩阵,请使用 hvcat 或组合使用空格和分号 [a b; c d]
      matlab

      [1 2; 3 4]
      %      1     2
      %      3     4
      
      a = [1 2];
      b = [3 4];
      [a a; b b]
      %      1     2     1     2
      %      3     4     3     4
      

      julia

      [1 2; 3 4]
      # 2×2 Array{Int64,2}:
      #  1  2
      #  3  4
      
      a = [1 2];
      b = [3 4];
      [a a; b b]
      # 2×4 Array{Int64,2}:
      #  1  2  1  2
      #  3  4  3  4
      
      hvcat((4,4), a..., a..., b..., b...)
      # 2×4 Array{Int64,2}:
      #  1  2  1  2
      #  3  4  3  4
      
  • Julia 拥有真正的一维数组 N-element Array{Float64,1},列向量的大小为 N,而不是 Nx1。
    例如:rand(N) 创建一个一维数组。
    matlab

    rand(3)
    %     0.8147    0.9134    0.2785
    %     0.9058    0.6324    0.5469
    %     0.1270    0.0975    0.9575
    
    rand(3, 1)
    %     0.4218
    %     0.9157
    %     0.7922
    

    julia

    rand(3)
    # 3-element Array{Float64,1}:
    #  0.4672600683116248
    #  0.09169094140222867
    #  0.4042011717217615
    
    rand(3, 1)
    # 3×1 Array{Float64,2}:
    #  0.06339164760309646
    #  0.9777149900468021
    #  0.6649767538620179
    
    rand(3, 3)
    # 3×3 Array{Float64,2}:
    #  0.587354  0.422352  0.439107
    #  0.528044  0.872661  0.374443
    #  0.207286  0.356782  0.861222
    

数组索引

  • Julia 数组使用方括号 A[i, j] 进行索引
    matlab

    a = [1 2 3; 4 5 6]
    %      1     2     3
    %      4     5     6
    a(1, 1)
    %      1
    

    julia

    a = [1 2 3; 4 5 6]
    # 2×3 Array{Int64,2}:
    #  1  2  3
    #  4  5  6
    a[1, 1]
    # 1
    

展开数组

  • 类似于提取(或「解引用」)元胞数组的所有元素的操作。例如 MATLAB 中的 horzcat(A{:})
    在 Julia 中是使用 splat 运算符(...)编写的:hcat(A...)
    matlab

    c = {1 2 3; 4 5 6}
    %     [1]    [2]    [3]
    %     [4]    [5]    [6]
    horzcat(c{:})
    %     1     4     2     5     3     6
    

    julia

    a = [1 2 3; 4 5 6]
    # 2×3 Array{Int64,2}:
    #  1  2  3
    #  4  5  6
    
    hcat(a...)
    # 1×6 Array{Int64,2}:
    #  1  4  2  5  3  6
    

范围

  • 在 Julia 中用 a:ba:b:c 来构造 AbstractRange 对象。
    matlab

    1:5
    %     1     2     3     4     5
    
    1:2:10
    %     1     3     5     7     9
    

    julia

    collect(1:5)
    # 5-element Array{Int64,1}:
    #  1
    #  2
    #  3
    #  4
    #  5
    
    1:2:10
    # 1:2:9
    
    collect(1:2:10)
    # 5-element Array{Int64,1}:
    #  1
    #  3
    #  5
    #  7
    #  9
    

数组的运算

  • 在 Julia 中,像 sumprodmax 等函数,以单参数调用时,即使数组 A 是多维数组,规约操作也会逐元素进行。
    matlab

    a = [1 2 3; 4 5 6]
    %      1     2     3
    %      4     5     6
    
    sum(a)
    %      5     7     9
    
    prod(a)
    %      4    10    18
    
    max(a)
    %      4     5     6
    

    julia

    a = [1 2 3; 4 5 6]
    # 2×3 Array{Int64,2}:
    #  1  2  3
    #  4  5  6
    
    sum(a)
    # 21
    sum(a; dims=1)
    # 1×3 Array{Int64,2}:
    #  5  7  9
    
    prod(a)
    # 720
    prod(a; dims=1)
    # 1×3 Array{Int64,2}:
    #  4  10  18
    
    max(a...)
    # 6
    maximum(a; dims=1)
    # 1×3 Array{Int64,2}:
    #  4  5  6
    
  • 在 Julia 中,如果 A 和 B 是数组,像 A == B 这样的逻辑比较运算符不会返回布尔值数组。
    相反地,请使用 A .== B。对于其他的像 <> 这样的的比较运算符同理。
    matlab

    a = [1 2 3];
    b = [4 5 6];
    
    a == b
    %     0     0     0
    
    all(a == b)
    %     0
    

    julia

    a = [1 2 3];
    b = [4 5 6];
    
    a == b
    # false
    
    a .== b
    # 1×3 BitArray{2}:
    #  0  0  0
    all(a .== b)
    # false
    
  • 在 Julia 中,运算符 &|(xor)进行按位操作,分别与 MATLAB 中的 andorxor 等价,并且优先级与 Python 的按位运算符相似(不像 C)。
    他们可以对标量运算或者数组中逐元素运算,可以用来合并逻辑数组。
    matlab

    a = [true true false false]
    %      1     1     0     0
    b = [true false true false]
    %      1     0     1     0
    
    a & b   % and(a, b)
    %      1     0     0     0
    a | b   % or(a, b)
    %      1     1     1     0
    xor(a, a)
    %      0     0     0     0
    

    julia

    a = [true true false false]
    # 1×4 Array{Bool,2}:
    #  1  1  0  0
    b = [true false true false]
    # 1×4 Array{Bool,2}:
    #  1  0  1  0
    
    a .& b
    # 1×4 BitArray{2}:
    #  1  0  0  0
    a .| b
    # 1×4 BitArray{2}:
    #  1  1  1  0
    a .⊻ a  # xor.(a, a)
    # 1×4 BitArray{2}:
    #  0  0  0  0
    
  • 注意运算顺序的区别:括号可能是必要的。
    例如:选择 A 中等于 1 或 2 的元素可使用 (A .== 1) .| (A .== 2)
    matlab

    A = [1 2 3 4];
    (A == 1) | (A == 2)
    %      1     1     0     0
    
    A( (A == 1) | (A == 2) )
    %      1     2
    

    julia

    A = [1 2 3 4];
    (A .== 1) .| (A .== 2)
    # 1×4 BitArray{2}:
    #  1  1  0  0
    
    A[ (A .== 1) .| (A .== 2) ]
    # 2-element Array{Int64,1}:
    #  1
    #  2
    filter(y -> y==1 || y==2, A)
    # 2-element Array{Int64,1}:
    #  1
    #  2
    

in-place 修改

  • 在 MATLAB 中,删除不需要的值的惯用方法是使用逻辑索引
    如表达式 x(x>3) 或语句 x(x>3) = [] 来 in-place 修改 x
    Julia 提供了更高阶的函数 filterfilter!
    允许用户编写 filter(z->z>3, x)filter!(z->z>3, x) 来代替相应直译 x[x.>3]x = x[x.>3]
    使用 filter! 可以减少临时数组的使用
    matlab

    A = [1 2 3 4];
    A(A>3)
    %      4
    A(A>3) = []
    % A =     1     2     3
    

    julia

    A = [1, 2, 3, 4]
    # 4-element Array{Int64,1}:
    #  1
    #  2
    #  3
    #  4
    
    filter(y -> y > 3, A)
    # 1-element Array{Int64,1}:
    #  4
    A
    # 4-element Array{Int64,1}:
    #  1
    #  2
    #  3
    #  4
    
    filter!(y -> y > 3, A)
    # 1-element Array{Int64,1}:
    #  4
    A
    # 1-element Array{Int64,1}:
    #  4
    

变量赋值

  • Julia 的数组在赋值给另一个变量时不发生复制。
    执行 A = B 后,改变 B 中元素也会修改 A。

  • Julia 的值在向函数传递时不发生复制。
    如果某个函数修改了数组,这一修改对调用者是可见的。
    matlab

    a = [1 2 3]
    % a =     1     2     3
    b = a
    % b =     1     2     3
    
    b(2) = 0
    % b =     1     0     3
    a
    % a =     1     2     3
    

    julia

    a = [1 2 3]
    # 1×3 Array{Int64,2}:
    #  1  2  3
    b = a
    # 1×3 Array{Int64,2}:
    #  1  2  3
    
    b[2] = 0
    # 0
    a
    # 1×3 Array{Int64,2}:
    #  1  0  3
    
    c = copy(a)
    # 1×3 Array{Int64,2}:
    #  1  0  3
    c[2] = -1
    # -1
    c
    # 1×3 Array{Int64,2}:
    #  1  -1  3
    a
    # 1×3 Array{Int64,2}:
    #  1  0  3
    
  • Julia 不会在赋值语句中自动增长数组。
    而在 MATLAB 中 a(4) = 3.2 可以创建数组 a = [0 0 0 3.2]
    a(5) = 7 可以将它增长为 a = [0 0 0 3.2 7]
    在 julia 中,如果 a 的长度小于 5 或者是第一次使用标识符 a,则相应的语句 a[5] = 7 会抛出错误
    Julia 使用 push!append! 来增长 Vector,它们比 MATLAB 的 a(end+1) = val 更高效
    matlab

    a = [];
    a(4) = 3.2
    % a =         0         0         0    3.2000
    a(5) = 7
    % a =     0     0     0     0     7
    a(end+1) = 10
    % a =     0     0     0     0     7    10
    

    julia

    a = [];
    a[4]
    # ERROR: BoundsError: attempt to access 0-element Array{Any,1} at index [4]
    # Stacktrace...
    append!(a, [0 0 0])
    # 3-element Array{Any,1}:
    #  0
    #  0
    #  0
    
    push!(a, 3.2)
    # 4-element Array{Any,1}:
    #  0
    #  0
    #  0
    #  3.2
    
    push!(a, 7)
    # 5-element Array{Any,1}:
    #  0
    #  0
    #  0
    #  3.2
    #  7
    
    push!(a, 10)
    # 6-element Array{Any,1}:
    #   0
    #   0
    #   0
    #   3.2
    #   7
    #  10
    
    a
    # 6-element Array{Any,1}:
    #   0
    #   0
    #   0
    #   3.2
    #   7
    #  10
    

杂项

  • 虚数单位 \sqrt{-1} 在 Julia 中表示为 im,而不是在 MATLAB 中的 i 或 j
    matlab

    sqrt(-1)
    %    0.0000 + 1.0000i
    i
    %    0.0000 + 1.0000i
    j
    %    0.0000 + 1.0000i
    
    i * i
    %     -1
    i * j
    %     -1
    i * i == sqrt(-1)
    %      0
    

    julia

    sqrt(-1)
    # ERROR: DomainError with -1.0:
    # sqrt will only return a complex result if called with a complex argument. Try sqrt(Complex(x)).
    # Stacktrace...
    sqrt(Complex(-1))
    # 0.0 + 1.0im
    sqrt(-1 + 0im)
    # 0.0 + 1.0im
    im
    # im
    1im
    # 0 + 1im
    
    im * im
    # -1 + 0im
    im * im == Complex(-1)
    # true
    
  • 在 Julia 中,没有小数点的数字字面量(例如 42)会创建整数而不是浮点数
    Julia 也支持任意大整数字面量。
    因此,某些操作(如 2^-1)将抛出 domain error,因为结果不是整数
    更多解释请参阅常见问题中有关 domain errors 的条目
    【注:截止 2020/07/08,2^-1 == 0.5 有 bug

    julia

    42
    # 42
    typeof(42)
    # Int64
    
    42.0
    # 42.0
    typeof(42.0)
    # Float64
    
    big"42"
    # 42
    typeof(big"42")
    # BigInt
    
    # domain errors 见上一个示例
    

函数

函数的参数

  • 在 Julia 中,集合的元素可以使用 splat 运算符 ... 来作为参数传递给函数,如 xs=[1,2]; f(xs...)
    julia

    a = [1 2 3]
    # 1×3 Array{Int64,2}:
    #  1  2  3
    
    println(a)
    # [1 2 3]
    println(a...)
    # 123
    
  • 在 Julia 中不存在 MATLAB 的 nargout,它通常在 MATLAB 中用于根据返回值的数量执行可选工作。 取而代之的是,用户可以使用可选参数和关键字参数来实现类似的功能。
    matlab: subtract.m
    ref: Number of function output arguments - MATLAB nargout

    function [dif,absdif] = subtract(y,x)
        dif = y-x;
        if nargout > 1
            disp('Calculating absolute value')
            absdif = abs(dif);
        end
    end
    

    matlab

    subtract(5, 10)
    %      -5
    
    [diff, adiff] = subtract(10, 5)
    % Calculating absolute value
    % diff =     -5
    % adiff =     5
    

    julia

    function subtract(y, x; absdif = false)
        dif = y - x
        if absdif
            println("Calculating absolute value")
            dif, abs(dif)
        else
            dif
        end
    end
    # subtract (generic function with 1 method)
    
    subtract(5, 10)
    # -5
    subtract(5, 10; absdif=true)
    # Calculating absolute value
    # (-5, 5)
    

函数的返回值

  • 在 Julia 中,能返回多个值并将其赋值为元组,例如 (a, b) = (1, 2) 或 a, b = 1, 2
  • Julia 中的函数返回其最后一个表达式或 return 关键字的值而无需在函数定义中列出要返回的变量的名称(有关详细信息,请参阅 return 关键字
  • 在 Julia 中,调用无参数的函数时必须使用小括号,例如 rand()
    julia
    function f1()
        print("func 1: ")
        1, 2, 3
    end
    # f1 (generic function with 1 method)
    
    f1()
    # func 1: (1, 2, 3)
    ans
    # (1, 2, 3)
    

脚本、代码风格

  • Julia 脚本可以包含任意数量的函数,并且在加载文件时,所有定义都将在外部可见
    可以从当前工作目录之外的文件加载函数定义
  • Julia 不鼓励使用分号来结束语句
    语句的结果不会自动打印(除了在 REPL 中),并且代码的一行不必使用分号结尾
    println 或者 @printf 能用来打印特定输出
  • 在 Julia 中,... 不用于延续代码行。不同的是,Julia 中不完整的表达式会自动延续到下一行
  • 在 Julia 和 MATLAB 中,变量 ans 被设置为交互式会话中提交的最后一个表达式的值
    在 Julia 中与 MATLAB 不同的是,当 Julia 代码以非交互式模式运行时并不会设置 ans
  • 在 Julia 中,每个模块有自身的全局作用域/命名空间,而在 MATLAB 中只有一个全局作用域

内置函数、关键字

struct

  • Julia 的 struct 不支持在运行时动态地添加字段,这与 MATLAB 的 class 不同。如需支持,请使用 Dict

svd

  • Julia 的 svd 将奇异值作为向量而非密集对角矩阵返回
    matlab

    A = [2 0 2; 0 1 0; 0 0 0];
    [U,S,V] = svd(A);
    S
    %     2.8284         0         0
    %          0    1.0000         0
    %          0         0         0
    

    julia

    using LinearAlgebra
    A = [2 0 2; 0 1 0; 0 0 0];
    F = svd(A);
    
    F.S
    # 3-element Array{Float64,1}:
    #  2.8284271247461903
    #  1.0
    #  0.0
    Diagonal(F.S)
    # 3×3 Diagonal{Float64,Array{Float64,1}}:
    #  2.82843   ⋅    ⋅
    #   ⋅       1.0   ⋅
    #   ⋅        ⋅   0.0
    

adjoint

3 个赞

欢迎补充更多例子。例如:matlab 中某些写法、函数在 julia 中的替代。