MojoでProject Euler 64

https://projecteuler.net/problem=64

平方根の連分数の周期は、たぶん具体的に計算するしかないです。
まず、 n = r^2 + s (1 \le s \lt 2r+1)とすると少し見通しがよくなります。
 \sqrt{n} - rの逆数を取ると、 \frac{\sqrt{n} + r}{s}となります。なので、 s = 1の場合に限り、周期1になります。
この整数部分がfだとすると、整数を引いて0以上1未満にするのにfを引いて、 \frac{\sqrt{n} + r - fs}{s}となります。この逆数を取ると、 \frac{s(\sqrt{n} - r + fs)}{s + 2rfs - f^2s^2} = \frac{\sqrt{n} - r + fs}{1 + 2rf - f^2s}となります。このように一般に \sqrt{n}の係数は1になります。ここで、 r - fs = -rとすると分母が1になって、周期2だとわかります。つまりs(>1)が2rの約数の時に周期2になります。たとえば、 r = 6なら、 s = 2, 3, 4, 6, 12なら周期2で、けっこう多いです。このようにある程度は周期がわかる場合がありますが、基本的には順番に計算していくしかないです。

import sys

fn find_period(r: Int, s: Int) -> Int:
    # (sqrt(r^2+s) - a) / b
    var a = r
    var b = 1
    var period = 1
    while True:
        # 逆数を取る
        var b1 = (r*r + s - a*a) // b
        var a1 = -(a - (r + a) // b1 * b1)
        if b1 == 1:
            return period
        a = a1
        b = b1
        period += 1

fn f(N: Int) -> Int:
    var counter = 0
    var r = 1
    while True:
        for s in range(1, 2*r+1):
            var n = r*r + s
            if n > N:
                return counter
            var period = find_period(r, s)
            if period % 2 == 1:
                counter += 1
        r += 1

fn main() raises:
    var args = sys.argv()
    var N = atol(args[1])
    print(f(N))