数组的正确初始化姿势?

不可名状的 bug 的发现过程 "今日平安无事"

先说我要干嘛:想学一学 performance-tips 里面的姿势。需要初始化一个复数数组,能初始化为 0 最好。

v0.6.4 的文档是这样教的
我是这样做的:

arr_S = Array{Complex128}(3,3) * 0
Wz    = Array{Complex128}(41,41) * 0
WNM   = Vector{Complex128}(630) * 0

输出看了下 3x3 的矩阵,效果拔群,就没看后面的。

然后我就拿这个数组存结果,有的是直接赋值,有的是再上面初始化为 0 的基础上累加
然后累加就炸了。

我想把放结果的矩阵每个元素都缩放到 [0, 1],就先取模再求最大值

colors = abs.(Wz)
facecolors=get_cmap("jet").o(colors/maximum(colors))

最后画图一看结果怎么都是一个颜色,不对。然后打印了最大值发现是 NaN,就坑了。

我自己试了下 0.6.4/0.7/1.0 都是

julia>  maximum([0, NaN, 1])
NaN

查来查去发现这个初始化就有问题,三个数组中按一定概率出 NaN


简单地说:用类似 Array{Complex128}(3,3) 生成的数组里可能有 NaN 从而导致一些意料之外的错误。
复现代码。

NaN_bug_test.jl @0.6.4/0.7


function bug_test!(bug_number, i)
    res3x       = any(isnan, Array{Complex128}(3,3))
    res41x      = any(isnan, Array{Complex128}(41,41))
    res41x0     = any(isnan, Array{Complex128}(41,41) * 0)
    res41x0im   = any(isnan, Array{Complex128}(41,41) * 0im)
    if (res3x | res41x | res41x0 | res41x0im)
        bug_number += 1
        print("i=",i," anyNaN? 3x3: ", res3x,   " 41x41: ", res41x,
                         " 41x41x0: ", res41x0, " 41x41x0im: ", res41x0im, "\n")
    end
end

function bug_test_loop()
    bug_number = 0
    for i in 0:1_000
        bug_test!(bug_number, i)
    end
    return bug_number
end

function main()
    bug_number = bug_test_loop()
    if bug_number == 0
        print("今日平安无事\n")
    else
        print("今天又出了 ", bug_number, " 个 bug\n")
    end
end

main()

PS: 上面用 arr .* 0 效果是一样的

VSC@0.6.4 命令行逐行运行结果:

i=86 anyNaN? 3x3: false 41x41: false 41x41x0: false 41x41x0im: true
i=88 anyNaN? 3x3: false 41x41: false 41x41x0: false 41x41x0im: true
i=90 anyNaN? 3x3: false 41x41: true 41x41x0: false 41x41x0im: false
i=258 anyNaN? 3x3: false 41x41: true 41x41x0: true 41x41x0im: false
i=260 anyNaN? 3x3: false 41x41: true 41x41x0: false 41x41x0im: false
i=261 anyNaN? 3x3: false 41x41: false 41x41x0: true 41x41x0im: false
i=442 anyNaN? 3x3: false 41x41: false 41x41x0: false 41x41x0im: true
i=443 anyNaN? 3x3: false 41x41: true 41x41x0: false 41x41x0im: false
i=446 anyNaN? 3x3: false 41x41: true 41x41x0: true 41x41x0im: false
i=606 anyNaN? 3x3: false 41x41: false 41x41x0: false 41x41x0im: true
i=771 anyNaN? 3x3: false 41x41: true 41x41x0: false 41x41x0im: false
今天又出了 11 个 bug
i=0 anyNaN? 3x3: false 41x41: true 41x41x0: false 41x41x0im: false
i=93 anyNaN? 3x3: false 41x41: false 41x41x0: true 41x41x0im: false
今天又出了 2 个 bug
i=649 anyNaN? 3x3: false 41x41: false 41x41x0: false 41x41x0im: true
i=804 anyNaN? 3x3: false 41x41: true 41x41x0: false 41x41x0im: false
i=987 anyNaN? 3x3: false 41x41: true 41x41x0: false 41x41x0im: false
今天又出了 3 个 bug
i=59 anyNaN? 3x3: false 41x41: true 41x41x0: false 41x41x0im: false
今天又出了 1 个 bug
今日平安无事
今日平安无事

目前的解决办法

fill(0im, 41,41)

for i in 1_000_000
    resFill41x  = any(isnan, fill(0im, 41,41))
    if resFill41x
        print("i=",i," anyNaN? 41x41: ", resFill41x, "\n")
    end
end

当然是没有输出啦。

不知道还有没有其它的姿势。

1.0 里用 any(isnan, Array{ComplexF64}(undef, 41, 41))any(isnan, Array{ComplexF64}(undef, 41, 41)*0) 还是会有以上的问题,不知道 undef 是干嘛用的

初始化为0的话可以直接用zeros(Complex, 32, 32),直接构造是那块内存的原有值,所以有概率是NaN,undef是未初始化的,访问未初始化的值undef会触发 undef error.

2 个赞

QQ%E5%9B%BE%E7%89%8720180821172618
然而我可以引用,只是没有意义,但是也不报错

julia> x = Array{Complex}(undef, 3, 3)
3×3 Array{Complex,2}:
 #undef  #undef  #undef
 #undef  #undef  #undef
 #undef  #undef  #undef

julia> x[1]
ERROR: UndefRefError: access to undefined reference
Stacktrace:
 [1] getindex(::Array{Complex,2}, ::Int64) at ./array.jl:731
 [2] top-level scope at none:0

你测的是primitive type 行为比较特殊

1 个赞