Есть ли способ остановить Джулию, используя научную (экспоненциальную) нотацию с BigFloats?
Хорошо, у меня есть, на первый взгляд, простая проблема. Я хочу взять десятичную часть иррационального числа до указанного числа цифр и рассматривать это как целое число. Например, если мое иррациональное число составляет 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. Проблема в том, что Джулия использует научную / экспоненциальную нотацию, поэтому я не могу достичь того, чего хочу, используя только цифры. Следующий (частичный) код показывает проблему:
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
(есть несколько дополнительных цифр, которые были бы удалены на этапе округления).
Итак, мой вопрос, есть ли способ достичь моей цели, не прибегая к последовательности?
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) - просто усечь результат (чтобы избавиться от 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