Problem 66 "Diophantine equation"

Consider quadratic Diophantine equations of the form:

x2 – Dy2 = 1

For example, when D=13, the minimal solution in x is 6492 – 13×1802 = 1.

It can be assumed that there are no solutions in positive integers when D is square.

By finding minimal solutions in x for D = {2, 3, 5, 6, 7}, we obtain the following:

32 – 2×22 = 1
22 – 3×12 = 1
92 – 5×42 = 1
52 – 6×22 = 1
82 – 7×32 = 1

Hence, by considering minimal solutions in x for D ≤ 7, the largest x is obtained when D=5.

Find the value of D ≤ 1000 in minimal solutions of x for which the largest value of x is obtained.

問 66 「ディオファントス方程式」

次の形式の, 2次のディオファントス方程式を考えよう:

x2 – Dy2 = 1

たとえば D=13 のとき, xを最小にする解は x is 6492 – 13×1802 = 1.である.

D が平方数(square)のとき, 正整数のなかに解は存在しないと考えられる.

D = {2, 3, 5, 6, 7} に対して x を最小にする解は次のようになる:

32 – 2×22 = 1
22 – 3×12 = 1
92 – 5×42 = 1
52 – 6×22 = 1
82 – 7×32 = 1

したがって, D ≤ 7 に対して x を最小にする解を考えると, D=5 のとき x は最大である.

D ≤ 1000 に対する x を最小にする解で, x が最大になるような D の値を見つけよ.


Non primitive Pythagorean triples and parabolas

Continued fractions and their periods

x^2 - Dy^2 = 1 ⬄ √D ≈ x/y

mod fraction {
    trait MixedFraction {
        fn integer_part(&self) -> u32;
    }

    pub struct QuadraticIrrational {
        rational_part: u32,
        irrational_part: u32,
        downscaling_ratio: u32,
        pub integer_part: u32,
        pub iteration: u32,
        integers: Vec<u32>,
    }

    impl MixedFraction for QuadraticIrrational {
        fn integer_part(&self) -> u32 {
            let mixed_fraction 
                = self.rational_part as f64 
                + (self.irrational_part as f64).sqrt();
            (mixed_fraction / self.downscaling_ratio as f64) as u32
        }
    }

    impl QuadraticIrrational {
        pub fn new(square_free_integer: u32) -> Self {
            assert!(
                ((square_free_integer as f64).sqrt() as u32).pow(2)
                != square_free_integer
            );
            let mut q = Self {
                rational_part: 0,
                irrational_part: square_free_integer,
                downscaling_ratio: 1,
                integer_part: u32::MAX,
                iteration: 0,
                integers: vec![],
            };
            q.integer_part = q.integer_part();
            q.integers.push(q.integer_part);
            q
        }
        pub fn next_iteration(&mut self) {
            self.iteration += 1;
            self.rational_part
                = self.downscaling_ratio 
                * self.integer_part 
                - self.rational_part;
            self.downscaling_ratio
                = (self.irrational_part - self.rational_part.pow(2))
                / self.downscaling_ratio;
            self.integer_part = self.integer_part();
            self.integers.push(self.integer_part);
        }
        pub fn last_numerator_approx(&self) -> f64 {
            let mut result = self.integers[0] as f64;
            let mut term_before_last = 1f64;
            for a in (&self.integers[1..self.integers.len() - 1])
                .iter()
                .map(|&a| a as f64)
            {
                let t = result.clone();
                result *= a;
                result += term_before_last;
                term_before_last = t;
            }
            result
        }
        pub fn last_denominator_approx(&self) -> f64 {
            let mut result = 1f64;
            let mut term_before_last = 0f64;
            for a in (&self.integers[1..self.integers.len() - 1])
                .iter()
                .map(|&a| a as f64)
            {
                let t = result.clone();
                result *= a;
                result += term_before_last;
                term_before_last = t;
            }
            result
        }
    }
}

fn main() {
    let mut max_numerator_aprox = 0f64;
    let mut max_d = 0u32;
    for n in 2..=1000 {
        if ((n as f64).sqrt() as u32).pow(2) == n {
            continue;
        }
        let mut surd = fraction::QuadraticIrrational::new(n);
        let integer_part_orig = surd.integer_part;
        while {
            surd.next_iteration();
            surd.integer_part != integer_part_orig * 2 || surd.iteration % 2 != 0
        } {}
        let last_numerator_approx = surd.last_numerator_approx();
        if last_numerator_approx > max_numerator_aprox {
            max_numerator_aprox = last_numerator_approx;
            max_d = n;
        }
    }

    println!("{}", max_d);
    assert_eq!(max_d, 661);
}