Продолженные дроби и уравнение Пелла - численные вопросы - PullRequest
0 голосов
/ 12 марта 2020

Математическое обоснование

Непрерывные дроби представляют собой способ представления чисел (рациональных или нет) с базисом c формулой рекурсии чтобы рассчитать это. Для числа r мы определяем r[0]=r и имеем:

for n in range(0..N):
    a[n] = floor(r[n])
    if r[n] == [an]: break
    r[n+1] = 1 / (r[n]-a[n])

, где a - окончательное представление. Мы также можем определить ряд сходящихся по

h[-2,-1] = [0, 1]
k[-2, -1] = [1, 0]
h[n] = a[n]*h[n-1]+h[n-2]
k[n] = a[n]*k[n-1]+k[n-2]

, где h[n]/k[n] сходятся к r .

уравнение Пелла - это проблема вида x^2-D*y^2=1, где все числа являются целыми числами, а D не является идеальным квадратом в нашем случае. Решение для данного D, которое минимизирует x , дается непрерывными дробями . В принципе, для приведенного выше уравнения гарантируется, что это (фундаментальное) решение равно x=h[n] и y=k[n] для самого низкого найденного n, что решает уравнение в продолженном расширении дроби sqrt (D) .


Проблема

Мне не удается заставить этот простой алгоритм работать для D=61. Сначала я заметил, что оно не решает уравнение Пелла для 100 коэффициентов, поэтому я сравнил его с сходимостями Вольфрама Альфы и продолжение дробного представления и заметил, что 20-й элемент не работает - представление 3 по сравнению с 4, который я получаю, получая различные конвергенты - h[20]=335159612 на Вольфраме по сравнению с 425680601 для меня.

Я тестировал приведенный ниже код, два языка (хотя, если честно, Python - это C под капотом, я думаю), на двух системах и получаю одинаковый результат - разность на l oop 20. Замечу, что конвергенты все еще точны и сходятся! Почему я получаю другие результаты по сравнению с Wolfram Alpha, и можно ли это исправить?


Для тестирования вот программа Python для решения уравнения Пелла для D=61, печать первых 20 конвергентов и представление непрерывной дроби cf (и некоторый дополнительный ненужный пух):

from math import floor, sqrt  # Can use mpmath here as well.


def continued_fraction(D, count=100, thresh=1E-12, verbose=False):
    cf = []
    h = (0, 1)
    k = (1, 0)
    r = start = sqrt(D)
    initial_count = count
    x = (1+thresh+start)*start
    y = start
    while abs(x/y - start) > thresh and count:
        i = int(floor(r))
        cf.append(i)
        f = r - i
        x, y = i*h[-1] + h[-2], i*k[-1] + k[-2]
        if verbose is True or verbose == initial_count-count:
            print(f'{x}\u00B2-{D}x{y}\u00B2 = {x**2-D*y**2}')
        if x**2 - D*y**2 == 1:
            print(f'{x}\u00B2-{D}x{y}\u00B2 = {x**2-D*y**2}')
            print(cf)
            return
        count -= 1
        r = 1/f
        h = (h[1], x)
        k = (k[1], y)

    print(cf)
    raise OverflowError(f"Converged on {x} {y} with count {count} and diff {abs(start-x/y)}!")

continued_fraction(61, count=20, verbose=True, thresh=-1)  # We don't want to stop on account of thresh in this example

A c программа делает то же самое:

#include<stdio.h>
#include<math.h>
#include<stdlib.h>

int main() {
    long D = 61;
    double start = sqrt(D);
    long h[] = {0, 1};
    long k[] = {1, 0};
    int count = 20;
    float thresh = 1E-12;
    double r = start;
    long x = (1+thresh+start)*start;
    long y = start;
    while(abs(x/(double)y-start) > -1 && count) {
        long i = floor(r);
        double f = r - i;
        x = i * h[1] + h[0];
        y = i * k[1] + k[0];
        printf("%ld\u00B2-%ldx%ld\u00B2 = %lf\n", x, D, y, x*x-D*y*y);
        r = 1/f;
        --count;
        h[0] = h[1];
        h[1] = x;
        k[0] = k[1];
        k[1] = y;
    }
    return 0;
}

1 Ответ

2 голосов
/ 12 марта 2020

mpmath, python библиотека с множественной точностью может быть использована. Только будьте осторожны, чтобы все важные числа были в формате mp.

В приведенном ниже коде x, y and i являются стандартными целыми числами с высокой точностью. r и f - действительные числа с высокой точностью. Обратите внимание, что начальный счет установлен выше, чем 20.

from mpmath import mp, mpf

mp.dps = 50  # precision in number of decimal digits

def continued_fraction(D, count=22, thresh=mpf(1E-12), verbose=False):
    cf = []
    h = (0, 1)
    k = (1, 0)
    r = start = mp.sqrt(D)
    initial_count = count
    x = 0 # some dummy starting values, they will be overwritten early in the while loop
    y = 1
    while abs(x/y - start) > thresh and count > 0:
        i = int(mp.floor(r))
        cf.append(i)
        x, y = i*h[-1] + h[-2], i*k[-1] + k[-2]
        if verbose or initial_count == count:
            print(f'{x}\u00B2-{D}x{y}\u00B2 = {x**2-D*y**2}')
        if x**2 - D*y**2 == 1:
            print(f'{x}\u00B2-{D}x{y}\u00B2 = {x**2-D*y**2}')
            print(cf)
            return
        count -= 1
        f = r - i
        r = 1/f
        h = (h[1], x)
        k = (k[1], y)

    print(cf)
    raise OverflowError(f"Converged on {x} {y} with count {count} and diff {abs(start-x/y)}!")

continued_fraction(61, count=22, verbose=True, thresh=mpf(1e-100))

Вывод похож на Вольфрама:

...
335159612²-61x42912791² = 3
1431159437²-61x183241189² = -12
1766319049²-61x226153980² = 1
[7, 1, 4, 3, 1, 2, 2, 1, 3, 4, 1, 14, 1, 4, 3, 1, 2, 2, 1, 3, 4, 1]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...