【问题标题】:Get a number from an array of digits从数字数组中获取一个数字
【发布时间】:2019-04-04 21:12:54
【问题描述】:

要将数字拆分为给定基数的数字,Julia 有 digits() 函数:

julia> digits(36, base = 4)
3-element Array{Int64,1}:
 0
 1
 2

什么是反向操作?如果您有一个数字数组和基数,是否有一种 内置 方法可以将其转换为数字?我可以将数组打印为字符串并使用parse(),但这听起来效率低下,并且对于大于 10 的基数也不起作用。

【问题讨论】:

    标签: julia base digits


    【解决方案1】:

    前面的答案都是正确的,但也有效率的问题:

    sum([x[k]*base^(k-1) for k=1:length(x)])
    

    在求和之前将数字收集到一个数组中,这会导致不必要的分配。跳过括号以获得更好的性能:

    sum(x[k]*base^(k-1) for k in 1:length(x))
    

    这也在求和之前分配了一个数组:sum(d.*4 .^(0:(length(d)-1)))

    如果你真的想要好的性能,写一个循环并避免重复求幂:

    function undigit(d; base=10)
        s = zero(eltype(d))
        mult = one(eltype(d))
        for val in d
            s += val * mult
            mult *= base
        end
        return s
    end
    

    这有一个额外的不必要的乘法,您可以尝试找出一些跳过它的方法。但在我的测试中,性能比其他方法好 10-15 倍,并且分配为零。

    编辑:上面的类型处理实际上有一点风险。如果输入向量和base 具有不同的整数类型,则会得到类型不稳定性。这段代码应该表现得更好:

    function undigits(d; base=10)
        (s, b) = promote(zero(eltype(d)), base)
        mult = one(s)
        for val in d
            s += val * mult
            mult *= b
        end
        return s
    end
    

    【讨论】:

    • 这是正确的方法。较慢(仍然比直接求和更好),但我认为有趣的方法使用 Polynomials.jl。你可以在哪里写polyeval(Poly(d), base)
    • 我同意@BogumiłKamiński 你的方法比我的更好、更慢但更有效
    【解决方案2】:

    答案似乎直接写在digits的文档中:

    
    help?> digits
    search: digits digits! ndigits isdigit isxdigit disable_sigint
    
      digits([T<:Integer], n::Integer; base::T = 10, pad::Integer = 1)
    
      Return an array with element type T (default Int) of the digits of n in the given base,
      optionally padded with zeros to a specified size. More significant digits are at higher
      indices, such that n == sum([digits[k]*base^(k-1) for k=1:length(digits)]).
    

    因此,对于您的情况,这将起作用:

    julia> d = digits(36, base = 4);
    
    julia> sum([d[k]*4^(k-1) for k=1:length(d)])
    36
    

    上面的代码可以用点运算符缩短:

    julia> sum(d.*4 .^(0:(length(d)-1)))
    36
    

    【讨论】:

    • 谢谢!不完全是我希望的内置功能,但也许它已经做到了。我会把这个问题留得久一点。
    • 你甚至可以使用点积来进一步缩短它:d' * base.^(0:length(d)-1)
    【解决方案3】:

    使用foldrmuladd 以获得最大的简洁性和效率

    undigits(d; base = 10) = foldr((a, b) -> muladd(base, b, a), d, init=0)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-09-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-09
      • 2014-06-23
      • 2015-02-08
      相关资源
      最近更新 更多