这才是神之语言
  • 板块灌水区
  • 楼主CleanIce
  • 当前回复24
  • 已保存回复24
  • 发布时间2023/9/15 20:14
  • 上次更新2023/11/2 20:39:18
查看原帖
这才是神之语言
821660
CleanIce楼主2023/9/15 20:14

(仅个人观点)

最近了解到一种新兴语言—— Julia(不要问我为什么取这个名字,我也不知道)。这种语言主要用于科学计算和数学领域,也可用于程序开发。

下面是该语言的几个特点:

  1. 该语言速度飞快,在大部分情况下比 C++ O2 还要快。
  2. 该语言极其直观,就如下面即将讲到的计算表达式和函数声明一样
  3. 该语言语法简洁,可以说堪比 Python。

1. 计算表达式与特殊运算符

下面的代码所执行的操作是相同的。

C++ 代码Julia 代码
int a = 2 * b;a = 2b
int a = (3 + 1) * b;a = (3 + 1)b
int a = (3 + b) * c + 5 / d;a = (3 + b)c + 5 ÷ d
int a = (a + c * d) * arr[2];a = (a + c * d)arr[3](Julia 语言下标从 1 开始)
int a = b * b * b;a = b ^ 3(Julia 中 ^ 表示幂运算)
int a = ~(b & c);(与非运算)a = b ⊼ c(Julia 中 ⊼ 表示与非运算)
int a = b ^ c;(异或运算)a = b ⊻ c
bool a = b <= c;a = b ≤ c
bool a = b != c;a = b ≠ c
bool a = (b <= c) && (c <= d);a = b ≤ c ≤ d
bool a = find(vec.begin(), vec.end(), b) != vec.end();(查找值 b 在不在 vec 中)a = b ∈ vec(如果是查找是否不在其中,使用 ∉ 运算符)

2. 特殊的函数声明

在 C++ 中,声明只有一个返回语句的函数要这么写:

int myfunc(int a, int b, int c) {
  return (a + b) * c;
}

但在 Julia 中,其就像数学函数一样:

pow(a, b, c) = (a + b)c

3. 自定义符号

Julia 已经定义了很多特殊的 Unicode 数学符号作为运算符,但实际上,Julia 除了能像 C++ 一样重载运算符,还能自定义运算符。例如,如果自定义中缀运算符:

⊕(a, b) = (a - 1) * (b + 1)

就可以这样使用:

a = 2 ⊕ 4
# a 的值为 (2 - 1) * (4 + 1) = 1 * 5 = 5

4. 批量操作

如果想对 C++ 的一个数组 a 中的所有元素加上 2,并存储到另一个数组 b 中,得这么写:

// 假设数组长度为 10
for (int i = 0; i < 10; i++) {
  b[i] = a[i] + 2;
}

但 Julia 不需要写循环:

b = a .+ 2

加上点号,就是批量操作。

5. 简写嵌套循环

在 C++ 中,如果我们想要写三重嵌套循环,并且最内层退出时必须退出三层。我们得这么写:

for (int i = 1; i <= x; i++) {
  bool flag = false;
  for (int j = 1; j <= y; j++) {
    for (int k = 1; k <= z; k++) {
      if (i + j + k == n) {
        flag = true;
        break;
      }
    }
    if (flag) {
      break;
    }
  }
  if (flag) {
    break;
  }
}

或者使用不推荐的 goto:

for (int i = 1; i <= x; i++) {
  for (int j = 1; j <= y; j++) {
    for (int k = 1; k <= z; k++) {
      if (i + j + k == n) {
        goto out_loop;
      }
    }
  }
}
out_loop:
void;  // 占位符,因为标签后必须是一条语句

但是,在 Julia 中,可以直接这么写:

for i = 1:x, j = 1:y, k = 1:z  # 三重循环
  if i + j + k == n
    break  # 将直接跳出所有循环
  end
end

6. 程序实例

这是用 Julia 写的线段树,其中加上了类型标注。

struct SegmentTree
    sum::Vector{Int}
    add_tag::Vector{Int}
    SegmentTree(n::Int) = new(zeros(4n), zeros(4n))  # 构造函数
end

function build(st::SegmentTree, k::Int, l::Int, r::Int, init::Vector{Int})::Nothing
    if l == r
        st.sum[k] = init[l]
        return
    end
    mid::Int = (l + r) ÷ 2  # 整除,/ 是浮点除法
    build(st, 2k, l, mid, init)
    build(st, 2k + 1, mid + 1, r, init)
end

function modify(st::SegmentTree, k::Int, l::Int, r::Int, x::Int, y::Int, v::Int)::Nothing
    if x ≤ l && r ≤ y
        st.add_tag[k] += v
        return
    end
    st.sum[k] += (min(r, y) - max(l, x) + 1)v;
    mid::Int = (l + r) ÷ 2
    if x ≤ mid
        modify(st, 2k, l, mid, x, y, v)
    end
    if mid < y
        modify(st, 2k + 1, mid + 1, r, x, y, v)
    end
end

function query(st::SegmentTree, k::Int, l::Int, r::Int, x::Int, y::Int)::Int
    if x ≤ l && r ≤ y
        return st.sum[k] + (r - l + 1)st.add_tag[k]
    end
    mid::Int = (l + r) ÷ 2
    res::Int = (min(r, y) - max(l, x) + 1)st.add_tag[k]
    if x ≤ mid
        res += query(st, 2k, l, mid, x, y)
    end
    if mid < y
        res += query(st, 2k + 1, mid + 1, r, x, y)
    end
    return res
end

function main()::Nothing  # 主函数,实际上并不必要,Julia 像 Python 一样可以直接写代码
    n::Int, m::Int = parse.(Int, split(readline()))  # 分解读取。注意点号表示批量操作
    # println("n = $n, m = $m")
    init::Vector{Int} = parse.(Int, split(readline()))
    st::SegmentTree = SegmentTree(n)
    build(st, 1, 1, n, init)
    for i::Int = 1:m  # Julia 的循环
        input::Vector{Int} = parse.(Int, split(readline()))
        opt::Int, x::Int, y::Int = input[1:3]
        if opt == 1
            v::Int = input[4]
            modify(st, 1, 1, n, x, y, v)
        elseif opt == 2
            println(query(st, 1, 1, n, x, y))
        end
    end
end

main()  # 由于 Julia 是直接执行代码的,所以我们要手动执行封装号的主函数
2023/9/15 20:14
加载中...