有没有办法阻止 Julia 使用 BigFloats 的科学(指数)表示法?

Posted

技术标签:

【中文标题】有没有办法阻止 Julia 使用 BigFloats 的科学(指数)表示法?【英文标题】:Is there a way to stop Julia using scientific (exponential) notation with BigFloats? 【发布时间】:2018-06-20 16:13:10 【问题描述】:

好的,从表面上看,我遇到了一个简单的问题。我想将无理数的小数部分取到指定的位数并将其视为整数。例如,如果我的无理数是 2.657829...并且我想要五位数,我正在寻找 65782(尽管我实际上是在处理“大”数字)。

这很容易使用字符串来实现,例如,如果我想要根的小数部分 3 到 50 位:

function main_1(n::Int, m::Int)::BigInt
    setprecision(Int(trunc((m + 3) * log2(10))))
    sr = string(sqrt(big(n)))
    ff = findfirst(sr, '.')
    dp = parse(BigInt, sr[ff + 1:ff + m])
    return dp
end

@time main_1(3, 50)

输出是73205080756887729352744634150587236694280525381038

但是,当我只处理数字时,我讨厌使用字符串!我想要做的是从 BigFloat 开始,减去整数部分,将结果乘以适当的 10 因子,将结果四舍五入为零,然后将其转换为 BigInt。问题是 Julia 使用科学/指数表示法,所以我似乎无法仅使用数字来实现我想要的。以下(部分)代码显示了问题:

function main_2(n::Int, m::Int)::BigFloat
    setprecision(Int(trunc((m + 3) * log2(10))))
    sr = sqrt(big(n))
    tr = trunc(sr)
    dp = (sr - tr) * big(10.0) ^ 50
    return dp
end

@time main_2(3, 50)

本例中的输出为7.32050807568877293527446341505872366942805253810380625e+49(在舍入阶段会删除一些额外的数字)。

所以我的问题是,有没有什么方法可以在不借助字符串的情况下实现我的目标?

【问题讨论】:

使用@sprintf,如此处所述:***.com/a/37031535/3637404 我说“不诉诸字符串”,你给我一个字符串?是的,我可以用return parse(BigInt, @sprintf("%.0f", dp)) 替换上面代码中的return dp(并将函数类型从BigFloat 更改为BigInt),但它实际上使我自己的字符串方法的运行时间加倍。 【参考方案1】:

在不使用字符串的情况下实现这一点的一种方法是在进行减法之前将结果及其整数部分转换为 BigInt(并从 BigFloat 更改函数类型到BigInt):

function main_2(n::Int, m::Int)::BigInt
    setprecision(Int(trunc((m + 3) * log2(10))))

    # Calc the sqrt
    result = sqrt(big(n))

    # Convert the whole number to BigInt to the specified precision
    sr = convert(BigInt, trunc(result*big(10)^m))

    # Convert the integer part to BigInt
    tr = convert(BigInt, trunc(result)*big(10)^m)

    dp = sr - tr
    return dp
end

上面的实现与main_1函数相比,有一点改进:

julia> @time main_1(3, 50)
  0.000042 seconds (36 allocations: 5.254 KiB)
73205080756887729352744634150587236694280525381038

julia> @time main_2(3, 50)
  0.000028 seconds (51 allocations: 1.617 KiB)
73205080756887729352744634150587236694280525381038

编辑:

其他方式(由@Bill 评论)只是 trunc 结果(摆脱InexactError())并将函数类型更改为BigInt

function main_2(n::Int, m::Int)::BigInt
    setprecision(Int(trunc((m + 3) * log2(10))))
    sr = sqrt(big(n))
    tr = trunc(sr)
    dp = (sr - tr) * big(10.0) ^ 50
    return trunc(dp)
end

测试后:

julia> @time main_2(3,50)
  0.000026 seconds (28 allocations: 1.016 KiB)
73205080756887729352744634150587236694280525381038

【讨论】:

是的,返回 BigInt 而不是 BigFloat 以摆脱答案的指数格式。 这两种方法都有帮助,谢谢。关于第二种方法,我没有意识到将函数类型更改为BigInt会导致BigFloat的自动转换,我只是假设它会触发错误消息。所以你每天都会学到一些东西......

以上是关于有没有办法阻止 Julia 使用 BigFloats 的科学(指数)表示法?的主要内容,如果未能解决你的问题,请参考以下文章

如何将 Julia 升级到新版本?

如何在 Julia 中为可变结构设置默认参数?

在 Julia Lang 中将 float 转换为 int

有没有办法阻止 avplayer 发送范围 http 标头字段

假设我不使用任何重载函数,有没有办法可以阻止所有名称修改? [复制]

有没有办法阻止顺风覆盖降价默认间距?