Julia on Float 与 Octave on Float

Julia on Float versus Octave on Float

版本:v"0.5.0-dev+1259"

上下文:目标是针对VC维度dvc计算给定数据点n上的Rademacher惩罚边界]和delta

表示的概率

请考虑 Julia 代码:

#Growth function on any n points with respect to VC-dimmension 
function mh(n, dvc) 
    if n <= dvc 
        2^n #A
    else 
        n^dvc #B
    end
end

#Rademacher penalty bound
function rademacher_penalty_bound(n::Int, dvc::Int, delta::Float64)
    sqrt((2.0*log(2.0*n*mh(n,dvc)))/n) + sqrt((2.0/n)*log(1.0/delta)) + 1.0/n   
end

和Octave/Matlab中的等效代码:

%Growth function on n points for a give VC dimmension (dvc)
function md = mh(n, dvc)
  if n <= dvc
    md= 2^n;
  else
    md = n^dvc;
  end
end

%Rademacher penalty bound
function epsilon = rademacher_penalty_bound (n, dvc, delta)
  epsilon = sqrt ((2*log(2*n*mh(n,dvc)))/n) + sqrt((2/n)*log(1/delta)) + 1/n;
end

问题: 当我开始测试它时,我收到以下结果:

首先是朱莉娅:

julia> rademacher_penalty_bound(50, 50, 0.05) #50 points
1.619360057204432

julia> rademacher_penalty_bound(500, 50, 0.05) #500 points
ERROR: DomainError:
 [inlined code] from math.jl:137
 in rademacher_penalty_bound at none:2
 in eval at ./boot.jl:264

现在八度:

octave:17> rademacher_penalty_bound(50, 50, 0.05)
ans =  1.6194
octave:18> rademacher_penalty_bound(500, 50, 0.05)
ans =  1.2387

问题:根据Noteworthy differences from MATLAB我认为我遵循了经验法则("literal numbers without a decimal point (such as 42) create integers instead of floating point numbers...")。当点数超过 51 时,代码会崩溃(mh 中的 #B 行)。能不能有经验的人看看代码说说我该怎么做improve/change?

因为默认情况下 Julia Int 是一个 "machine-size" 整数,一个用于通用 x86-64 平台的 64 位整数,而 Octave 使用浮点数。所以在 Julia 中 mh(500,50) 溢出了。您可以通过如下替换 mh() 来修复它:


function mh(n, dvc)
    n2 = BigInt(n) # Or n2 = Float64(n)
    if n <= dvc 
        2^n2 #A
    else 
        n2^dvc #B
    end
end

我不知道得到 BigFloat 的结果是否可以接受,但无论如何在 julia 部分你可以使用 BigInt

#Growth function on any n points with respect to VC-dimmension 
function mh(n, dvc) 
    if n <= dvc 
        (BigInt(2))^n #A
    else 
        n^dvc #B
    end
end

#Rademacher penalty bound
function rademacher_penalty_bound(n::BigInt, dvc::BigInt, delta::Float64)
    sqrt((2.0*log(2.0*n*mh(n,dvc)))/n) + sqrt((2.0/n)*log(1.0/delta)) + 1.0/n   
end

rademacher_penalty_bound(BigInt(500), BigInt(500), 0.05)
# => 1.30055251010957621105182244420.....

尽管 BigIntBigFloat 在必要时是极好的工具,但通常应避免使用它们,因为它们太过分而且速度慢。

在这种情况下,问题确实是 Octave 和 Julia 之间的区别,Octave 将所有内容都视为浮点数,而 Julia 将例如2 作为整数。

所以要做的第一件事就是在 Julia 中也使用浮点数:

function mh(n, dvc) 
    if n <= dvc 
        2.0 ^ n 
    else 
        Float64(n) ^ dvc 
    end
end

这已经有所帮助,例如mh(50, 50) 有效。

但是,这个问题的正确解法是仔细看代码,发现函数mh只出现在[=18=里面]:

log(2.0*n*mh(n,dvc))

我们可以用对数定律改写为

log(2.0*n) + log_mh(n, dvc)

其中log_mh是一个新函数,returns是mh结果的对数。当然,这不应该直接写成log(mh(n, dvc)),而是一个新函数:

function log_mh(n, dvc) 
    if n <= dvc 
        n * log(2.0)
    else 
        dvc * log(n) 
    end
end

这样,你就可以使用大数而不会溢出。

虽然 BigIntBigFloat 可以在这里工作,但它们严重矫枉过正。真正的问题是您在 Julia 中进行整数求幂,在 Octave/Matlab 中进行浮点求幂。所以你只需要更改 mh 以使用浮点数而不是整数作为指数:

mh(n, dvc) = n <= dvc ? 2^float(n) : n^float(dvc)

rademacher_penalty_bound(n, dvc, δ) =
    √((2log(2n*mh(n,dvc)))/n) + √(2log(1/δ)/n) + 1/n

使用这些定义,您会得到与 Octave/Matlab:

相同的结果
julia> rademacher_penalty_bound(50, 50, 0.05)
1.619360057204432

julia> rademacher_penalty_bound(500, 50, 0.05)
1.2386545010981596

在 Octave/Matlab 中,即使您输入的文字没有小数点,您仍然会得到一个浮点数 – 您必须显式转换为 int 类型。此外,Octave/Matlab 中的求幂总是首先转换为浮点数。在 Julia 中,x^2 等同于 x*x,后者禁止转换为浮点数。