有没有办法让Julia在使用BigFloats时停止使用科学(指数)表示法?

4
好的,我有一个看起来表面上很简单的问题。我想要获取一个无理数的小数部分,直到指定的位数,并将其视为整数。例如,如果我的无理数是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: https://dev59.com/D1oU5IYBdhLWcg3w35gM#37031535 - Felipe Lema
1
我说“不使用字符串”,你却给我一个字符串?是的,我可以用return parse(BigInt, @sprintf("%.0f", dp))(并将函数类型从BigFloat更改为BigInt)替换上面代码中的return dp,但它实际上会使我的自己的字符串方法的运行时间翻倍。 - Mark Birtwistle
1个回答

3

在不使用字符串的情况下,实现此目标的一种方法是在进行减法(并将函数类型从BigFloat更改为BigInt)之前将结果及其整数部分转换为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评论)是仅截断结果(以摆脱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,以消除答案的指数格式。 - Bill
这两种方法都很有帮助,谢谢。关于第二种方法,我没有意识到将函数类型更改为BigInt会导致BigFloat的自动转换,我只是认为它会触发错误消息。所以你每天都能学到一些新东西... - Mark Birtwistle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接