Арифметика произвольной точности в Джулии

Это как бы спрашивали, но не таким образом. У меня есть небольшая программа на Python, которая находит непрерывные дроби для квадратных корней из n (1 ‹= n ‹= 10000).

Я пытался сделать это в Джулии, и я не понимаю, как это сделать. В основном потому, что он имеет дело с иррациональными числами (sqrt(x) иррационален, если x не является полным квадратом, например, sqrt(2) = 1,414213...). Поэтому я не думаю, что могу использовать рациональный класс.

Здесь написано https://docs.julialang.org/en/latest/manual/integers-and-floating-point-numbers/#Arbitrary-Precision-Arithmetic-1, что Джулия может выполнять арифметические операции с произвольной точностью с помощью BigFloats. Но они кажутся недостаточно точными.

Я также пытался использовать PyCall и пакет Decimals в Python (от Джулии), но получаю странные ошибки (я могу опубликовать их, если они будут полезны).

Вот моя программа Python, которая работает. И мой вопрос, как это сделать в Джулии, пожалуйста?

def continuedFractionSquareRoots():
''' 
  For each number up to 100, get the length of the continued fraction 
  of the square root for it.
'''

decimal.getcontext().prec = 210 # Need lots of precision for this problem.

continuedFractionLengths = []
for i in range(1, 101):

    # For perfect squares, the period is 0
    irrationalNumber = decimal.Decimal(i).sqrt()
    if irrationalNumber == int(irrationalNumber):
        continue        

    continuedFractionLength = 0
    while True:

        intPart = irrationalNumber.to_integral_exact(rounding=decimal.ROUND_FLOOR)
        if continuedFractionLength == 0:
            firstContinuedFractionTimes2 = int(intPart*2)

        continuedFractionLength += 1
        if intPart == firstContinuedFractionTimes2:
            # Have reached the 'period' end for this fraction
            break

        fractionalPart = irrationalNumber - intPart
        irrationalNumber = 1 / fractionalPart

continuedFractionLengths.append(continuedFractionLength)
return continuedFractionLengths

Итак, как видите, мне нужен способ вычисления точного квадратного корня, а также способ получения целой части числа. И это все на самом деле, если не считать много-много точности!

Ребята, я не стал выкладывать свой код Юлии, потому что не хотел иметь маленькую рукопись для ответа! Но вот это работает. Как я сказал в комментариях ниже, я использовал функцию setprecision, чтобы установить высокое значение точности, и это работает. Я получил значение 711 опытным путем.

setprecision(711)

function continuedFractionSquareRoots()
#=
  For each number up to 100, get the length of the continued fraction 
  of the square root for it.
=#

continuedFractionLengths = Int[]
for i=1:100

    # For perfect squares, the period is 0
    irrationalNumber = BigFloat(sqrt(BigFloat(i)))
    if irrationalNumber == floor(irrationalNumber)
        continue
    end

    continuedFractionLength = 0
    while true

        intPart = floor(irrationalNumber)
        if continuedFractionLength == 0
            firstContinuedFractionTimes2 = intPart*2
        end

        continuedFractionLength += 1
        if intPart == firstContinuedFractionTimes2
            # Have reached the 'period' end for this fraction
            break
        end

        fractionalPart = irrationalNumber - intPart
        irrationalNumber = BigFloat(1) / fractionalPart

    end

    push!(continuedFractionLengths, continuedFractionLength)

end


return continuedFractionLengths
end

Так или иначе, пользователь 2357112 решил это, большое спасибо.


person davo36    schedule 20.08.2017    source источник
comment
Вы не забыли настроить точность для BigFloats?   -  person user2357112 supports Monica    schedule 20.08.2017
comment
@user2357112 user2357112 Нет, как мне это сделать, пожалуйста?   -  person davo36    schedule 20.08.2017
comment
О, я вижу, с set_bigfloat_precision.   -  person davo36    schedule 20.08.2017
comment
На самом деле, это с setprecision. Изменение функций Джулии...   -  person davo36    schedule 20.08.2017
comment
@user2357112 user2357112 Чувак, я просто сделал точность до 1000, и это исправлено! Большое спасибо.   -  person davo36    schedule 20.08.2017
comment
@ user2357112 Я думаю, что это полезный вопрос, который, вероятно, будет найден в Google в будущем, и он заслуживает правильного ответа, несмотря на его простоту. Пожалуйста, рассмотрите возможность преобразования вашего комментария в хороший ответ :)   -  person Tasos Papastylianou    schedule 20.08.2017
comment
@ davo36 (и, очевидно, рассмотрите возможность принятия его после публикации, поскольку он фактически рассмотрел и решил вашу настоящую проблему)   -  person Tasos Papastylianou    schedule 20.08.2017


Ответы (2)


Как и в случае с decimal.Decimal Python, вы можете настроить точность BigFloat Джулии:

setprecision(however_many_bits)

Обратите внимание, что это в битах, в отличие от decimal.Decimal, потому что BigFloat не использует десятичное число.

person user2357112 supports Monica    schedule 20.08.2017

Ответ пользователя 2357112 лежит в основе проблемы и является правильным ответом на этот вопрос.

Однако, для завершения, «буквальный» вопрос «как мне заставить этот скрипт Python работать в julia» сам по себе интересный вопрос, поскольку он не так прост, как может показаться на первый взгляд из-за эту проблему, поэтому я также покажу, как это сделать.

Предполагая, что у вас есть скрипт python с именем «testo.py» в вашем текущем каталоге (и с правильными операторами import decimal и т. д.), то вот как импортировать его как модуль python и запустить соответствующую функцию:

using PyCall
unshift!(PyVector(pyimport("sys")["path"]), ""); # as per https://github.com/JuliaPy/PyCall.jl#troubleshooting
testo = pyimport("testo");
testo[:oddPeriodSquareRoots]()  # will output '1322'
person Tasos Papastylianou    schedule 20.08.2017
comment
Спасибо друг. На самом деле я написал этот код по-другому, прежде чем использовать этот способ. С помощью SymPy. И это вроде сработало, но я получил ошибку рекурсии. Я напишу об этом в новом вопросе. Спасибо за вашу помощь. - person davo36; 21.08.2017