Problem Summary

Choose \(X\) uniformly from the interval \([0,1]\), and for each positive integer \(N\) define

$$f_N(x)=\min_{1\le m\le N}\{mx\},\qquad F(N)=\int_0^1 f_N(x)\,dx,$$

where \(\{y\}=y-\lfloor y\rfloor\) is the fractional part. The problem asks for the expected smallest fractional part among the first \(N\) multiples of a random \(x\), with the target case \(N=10000\).

A brute-force viewpoint would be hopelessly inefficient: for each \(x\) one would have to compare \(N\) different fractional parts, and doing that over a dense mesh still would not give an exact answer. The implementations avoid sampling entirely and instead partition \([0,1]\) into Farey intervals on which \(f_N(x)\) becomes a simple linear function.

Mathematical Approach

The key observation is that \(\{mx\}=mx-\lfloor mx\rfloor\) measures how far \(mx\) lies above the nearest smaller integer. So minimizing \(\{mx\}\) over \(1\le m\le N\) is equivalent to finding the best rational approximation to \(x\) from below with denominator at most \(N\).

From an expectation to an integral

Because \(X\) is uniform on \([0,1]\), the expected value in the title is exactly the integral of \(f_N(x)\). There is no probability machinery beyond that: once we know the graph of \(f_N\), the answer is its area under the curve.

For a fixed denominator \(m\), the quantity \(\{mx\}\) can be written as

$$\{mx\}=mx-p \qquad\text{with}\qquad p=\lfloor mx\rfloor,$$

so every candidate minimum is attached to a rational number \(p/m\le x\). This turns the original question into a geometric one about rationals of bounded denominator.

Why consecutive Farey fractions control the minimum

Let

$$\frac{a}{b} \lt \frac{c}{d}$$

be consecutive terms of the Farey sequence of order \(N\), denoted \(\mathcal{F}_N\). If \(x\) lies in the interval

$$\frac{a}{b}\le x\le \frac{c}{d},$$

then there is no reduced fraction with denominator at most \(N\) strictly between those endpoints. In particular, the best rational from below with denominator at most \(N\) stays fixed throughout the whole interval and is exactly \(a/b\).

That means the minimum fractional part is attained by the denominator \(b\):

$$f_N(x)=bx-a \qquad \text{for } x\in\left[\frac{a}{b},\frac{c}{d}\right].$$

At the left endpoint this value is \(0\), and as \(x\) moves rightward it rises linearly until the next Farey boundary is reached. The graph of \(f_N\) is therefore a chain of line segments, one segment for each adjacent Farey pair.

Exact contribution of one Farey interval

Adjacent Farey fractions satisfy the unimodular relation

$$bc-ad=1.$$

Consequently, the interval width is

$$\frac{c}{d}-\frac{a}{b}=\frac{1}{bd},$$

and the value of the linear segment at the right endpoint is

$$f_N\!\left(\frac{c}{d}\right)=b\frac{c}{d}-a=\frac{bc-ad}{d}=\frac{1}{d}.$$

So each Farey interval contributes the area of a triangle with base \(1/(bd)\) and height \(1/d\):

$$\int_{a/b}^{c/d}(bx-a)\,dx=\frac{1}{2}\cdot\frac{1}{bd}\cdot\frac{1}{d}=\frac{1}{2bd^2}.$$

This is the exact closed form accumulated by the implementations.

The global summation formula

Summing over all consecutive pairs in \(\mathcal{F}_N\) gives

$$\boxed{F(N)=\sum_{\substack{a/b \lt c/d\\ \text{consecutive in }\mathcal{F}_N}} \frac{1}{2bd^2}.}$$

Nothing is approximated in the mathematics: the only numerical issue is how to add many small positive terms stably when \(N\) is large.

Worked Example: \(N=4\)

The Farey sequence of order \(4\) is

$$0,\ \frac14,\ \frac13,\ \frac12,\ \frac23,\ \frac34,\ 1.$$

Therefore \(f_4(x)\) is piecewise linear:

$$ f_4(x)= \begin{cases} x, & 0\le x\le \frac14,\\ 4x-1, & \frac14\le x\le \frac13,\\ 3x-1, & \frac13\le x\le \frac12,\\ 2x-1, & \frac12\le x\le \frac23,\\ 3x-2, & \frac23\le x\le \frac34,\\ 4x-3, & \frac34\le x\le 1. \end{cases} $$

The interval contributions are

$$\frac{1}{32},\ \frac{1}{72},\ \frac{1}{24},\ \frac{1}{36},\ \frac{1}{96},\ \frac{1}{8},$$

and they add up to

$$F(4)=\frac14.$$

This matches the checkpoint used by the implementations and shows exactly how the Farey partition turns the expectation into a finite sum of triangle areas.

How the Code Works

The C++, Python, and Java implementations all follow the same mathematical plan: enumerate the consecutive Farey fractions of order \(N\), convert each interval into the exact term \(1/(2bd^2)\), and accumulate those terms carefully.

Enumerating adjacent Farey fractions

The sweep starts from the first two neighbors, \(0/1\) and \(1/N\). If the current neighboring pair is \(a/b \lt c/d\), the next Farey term is generated by the standard recurrence

$$k=\left\lfloor\frac{N+b}{d}\right\rfloor,\qquad \frac{e}{f}=\frac{kc-a}{kd-b}.$$

After processing the interval \([a/b,c/d]\), the pair advances to \(c/d \lt e/f\). Repeating this step walks through the entire Farey sequence in increasing order without building a table of all fractions in advance.

Accumulating the exact interval areas

For each current interval, the implementation adds

$$\frac{1}{2bd^2}$$

to the running total. Since the terms become very small near the end of the sweep, all three versions use compensated summation to reduce the loss of low-order digits. The C++ version keeps the running total in extended precision, while the Python and Java versions use standard floating-point arithmetic with the same compensation idea.

Once the right endpoint reaches \(1/1\), the next Farey update jumps past the unit interval and the traversal stops. The final decimal output is just the numerical form of the exact Farey sum above.

Complexity Analysis

Each neighboring Farey interval is visited exactly once, and each visit performs only constant-time arithmetic. The total running time is therefore linear in the number of intervals in the Farey sequence of order \(N\), which is \(\Theta(N^2)\).

The memory usage is \(O(1)\): the implementation stores only the current neighboring fractions, the running sum, and the compensation term. No large arrays, sieves, or dynamic programming tables are needed.

Footnotes and References

  1. Project Euler problem page: https://projecteuler.net/problem=965
  2. Farey sequence: Wikipedia - Farey sequence
  3. Fractional part: Wikipedia - Fractional part
  4. Diophantine approximation: Wikipedia - Diophantine approximation
  5. Kahan summation algorithm: Wikipedia - Kahan summation algorithm

Problemzusammenfassung

Wähle \(X\) gleichverteilt aus dem Intervall \([0,1]\) und definiere für jedes positive \(N\)

$$f_N(x)=\min_{1\le m\le N}\{mx\},\qquad F(N)=\int_0^1 f_N(x)\,dx,$$

wobei \(\{y\}=y-\lfloor y\rfloor\) den Nachkommateil bezeichnet. Gesucht ist also der Erwartungswert des kleinsten Nachkommateils unter den ersten \(N\) Vielfachen eines zufälligen \(x\), im Zielproblem für \(N=10000\).

Eine direkte numerische Behandlung wäre unattraktiv: Für jedes \(x\) müsste man \(N\) verschiedene Werte \(\{mx\}\) vergleichen, und selbst ein dichtes Gitter würde die Struktur nicht exakt erfassen. Der entscheidende Schritt ist deshalb, \([0,1]\) in Farey-Intervalle zu zerlegen, auf denen \(f_N(x)\) jeweils linear ist.

Mathematischer Ansatz

Die Größe \(\{mx\}=mx-\lfloor mx\rfloor\) misst, um wie viel \(mx\) die nächstkleinere ganze Zahl übersteigt. Das Minimum über \(1\le m\le N\) ist daher äquivalent zur besten rationalen Approximation von \(x\) von unten mit Nenner höchstens \(N\).

Vom Erwartungswert zum Flächeninhalt

Weil \(X\) auf \([0,1]\) gleichverteilt ist, ist der gesuchte Erwartungswert genau das Integral von \(f_N\). Sobald die Gestalt des Graphen bekannt ist, reduziert sich das Problem auf eine Flächenberechnung.

Für einen festen Nenner \(m\) gilt

$$\{mx\}=mx-p \qquad\text{mit}\qquad p=\lfloor mx\rfloor,$$

also gehört jede mögliche Kandidatenfunktion zu einem Bruch \(p/m\le x\). Das verlagert die Aufgabe von einer punktweisen Suche zu einer geordneten Beschreibung aller relevanten rationalen Zahlen.

Warum Farey-Nachbarn das Minimum bestimmen

Seien

$$\frac{a}{b} \lt \frac{c}{d}$$

zwei aufeinanderfolgende Glieder der Farey-Folge \(\mathcal{F}_N\). Liegt \(x\) im Intervall

$$\frac{a}{b}\le x\le \frac{c}{d},$$

dann gibt es keinen vollständig gekürzten Bruch mit Nenner höchstens \(N\), der strikt zwischen diesen beiden Endpunkten liegt. Damit bleibt die beste Approximation von unten auf dem ganzen Intervall konstant und ist genau \(a/b\).

Folglich wird der kleinste Nachkommateil von dem Nenner \(b\) geliefert:

$$f_N(x)=bx-a \qquad \text{für } x\in\left[\frac{a}{b},\frac{c}{d}\right].$$

Am linken Rand ist dieser Wert \(0\); danach wächst er linear bis zum nächsten Farey-Rand. Der Graph von \(f_N\) ist also eine Kette linearer Abschnitte, je einer pro benachbartem Farey-Paar.

Exakter Beitrag eines einzelnen Intervalls

Benachbarte Farey-Brüche erfüllen die unimodulare Relation

$$bc-ad=1.$$

Daraus folgt die Intervallbreite

$$\frac{c}{d}-\frac{a}{b}=\frac{1}{bd},$$

und am rechten Rand hat die lineare Funktion den Wert

$$f_N\!\left(\frac{c}{d}\right)=b\frac{c}{d}-a=\frac{bc-ad}{d}=\frac{1}{d}.$$

Jeder Abschnitt liefert also die Fläche eines Dreiecks mit Grundseite \(1/(bd)\) und Höhe \(1/d\):

$$\int_{a/b}^{c/d}(bx-a)\,dx=\frac{1}{2}\cdot\frac{1}{bd}\cdot\frac{1}{d}=\frac{1}{2bd^2}.$$

Genau dieser geschlossene Ausdruck wird in den Implementierungen aufsummiert.

Die globale Summenformel

Über alle benachbarten Paare der Farey-Folge ergibt sich damit

$$\boxed{F(N)=\sum_{\substack{a/b \lt c/d\\ \text{benachbart in }\mathcal{F}_N}} \frac{1}{2bd^2}.}$$

Die Mathematik selbst ist exakt; numerisch heikel ist nur die stabile Addition vieler kleiner positiver Summanden für großes \(N\).

Durchgerechnetes Beispiel: \(N=4\)

Die Farey-Folge der Ordnung \(4\) lautet

$$0,\ \frac14,\ \frac13,\ \frac12,\ \frac23,\ \frac34,\ 1.$$

Daher ist \(f_4(x)\) stückweise linear:

$$ f_4(x)= \begin{cases} x, & 0\le x\le \frac14,\\ 4x-1, & \frac14\le x\le \frac13,\\ 3x-1, & \frac13\le x\le \frac12,\\ 2x-1, & \frac12\le x\le \frac23,\\ 3x-2, & \frac23\le x\le \frac34,\\ 4x-3, & \frac34\le x\le 1. \end{cases} $$

Die sechs Flächenbeiträge sind

$$\frac{1}{32},\ \frac{1}{72},\ \frac{1}{24},\ \frac{1}{36},\ \frac{1}{96},\ \frac{1}{8},$$

und ihre Summe ist

$$F(4)=\frac14.$$

Genau diese Zerlegung wird im großen Fall \(N=10000\) nicht durch Probieren, sondern systematisch über die Farey-Nachbarschaft ausgenutzt.

So Funktioniert Der Code

Die C++-, Python- und Java-Implementierungen setzen denselben mathematischen Plan um: Sie durchlaufen die benachbarten Farey-Brüche der Ordnung \(N\), wandeln jedes Intervall in den exakten Term \(1/(2bd^2)\) um und summieren diese Beiträge sorgfältig auf.

Benachbarte Farey-Brüche erzeugen

Der Durchlauf beginnt bei den ersten beiden Nachbarn \(0/1\) und \(1/N\). Für ein aktuelles Nachbarpaar \(a/b \lt c/d\) wird das nächste Farey-Glied durch die Standardrekurrenz erzeugt:

$$k=\left\lfloor\frac{N+b}{d}\right\rfloor,\qquad \frac{e}{f}=\frac{kc-a}{kd-b}.$$

Nach der Bearbeitung von \([a/b,c/d]\) rückt das Paar zu \(c/d \lt e/f\) weiter. So wird die gesamte Farey-Folge in aufsteigender Reihenfolge durchlaufen, ohne sie vorher vollständig zu speichern.

Die exakten Flächen stabil aufsummieren

Zu jedem aktuellen Intervall addiert die Implementierung den Beitrag

$$\frac{1}{2bd^2}$$

zur laufenden Summe. Weil die Summanden gegen Ende sehr klein werden, verwenden alle drei Versionen eine kompensierte Summation, um den Verlust niederwertiger Stellen zu verringern. Die C++-Version arbeitet dabei mit erweiterter Gleitkommapräzision; die Python- und Java-Versionen nutzen dieselbe Kompensationsidee mit Standardpräzision.

Sobald der rechte Endpunkt \(1/1\) erreicht ist, springt die nächste Farey-Aktualisierung über das Einheitsintervall hinaus und der Durchlauf endet. Die ausgegebene Dezimalzahl ist daher direkt die numerische Darstellung der exakten Farey-Summe.

Komplexitätsanalyse

Jedes benachbarte Farey-Intervall wird genau einmal besucht, und jeder Besuch benötigt nur konstante Zeit. Die Gesamtlaufzeit ist also linear in der Anzahl der Intervalle der Farey-Folge der Ordnung \(N\), mithin \(\Theta(N^2)\).

Der Speicherverbrauch ist \(O(1)\): Gespeichert werden nur die aktuellen Nachbarbrüche, die laufende Summe und der Kompensationsterm. Große Tabellen, Siebe oder dynamische Programme kommen nicht vor.

Fußnoten und Quellen

  1. Project-Euler-Problemseite: https://projecteuler.net/problem=965
  2. Farey-Folge: Wikipedia - Farey-Folge
  3. Nachkommateil: Wikipedia - Gebrochener Teil
  4. Diophantische Approximation: Wikipedia - Diophantische Approximation
  5. Kahan-Summationsalgorithmus: Wikipedia - Kahan-Summation

Problem Özeti

\(X\) rastgele değişkenini \([0,1]\) aralığında düzgün dağılımdan seçelim ve her pozitif \(N\) için

$$f_N(x)=\min_{1\le m\le N}\{mx\},\qquad F(N)=\int_0^1 f_N(x)\,dx,$$

tanımını yapalım; burada \(\{y\}=y-\lfloor y\rfloor\) kesir kısmıdır. Problem, rastgele bir \(x\) için ilk \(N\) katın kesir kısımları arasındaki en küçük değerin beklenen değerini, özellikle \(N=10000\) için istemektedir.

Doğrudan yaklaşım verimsizdir: her \(x\) için \(N\) ayrı kesir kısmını karşılaştırmak gerekir ve yoğun bir örnekleme bile kesin sonuç vermez. Çözüm bunun yerine \([0,1]\) aralığını Farey komşularına göre parçalayarak \(f_N(x)\)'i her parçada basit bir doğrusal fonksiyona indirger.

Matematiksel Yaklaşım

\(\{mx\}=mx-\lfloor mx\rfloor\) ifadesi, \(mx\)'in hemen altındaki tam sayıdan ne kadar yukarıda olduğunu gösterir. Dolayısıyla \(1\le m\le N\) üzerindeki minimumu aramak, \(x\)'i alttan en iyi yaklaşık veren ve paydası \(N\)'i aşmayan rasyoneli aramakla aynıdır.

Beklentiyi integrale dönüştürmek

\(X\) düzgün dağıldığı için başlıktaki beklenen değer doğrudan \(f_N\)'in integrali olur. Yani yapılması gereken şey, \(f_N\)'in grafiğini anlayıp altında kalan alanı hesaplamaktır.

Sabit bir \(m\) için

$$\{mx\}=mx-p \qquad\text{ve}\qquad p=\lfloor mx\rfloor,$$

olduğundan her aday değer bir \(p/m\le x\) rasyoneline karşılık gelir. Böylece problem, noktadan noktaya minimizasyon olmaktan çıkıp sınırlı paydalı rasyonellerin düzenine dönüşür.

Farey komşularının neden yeterli olduğu

\(\mathcal{F}_N\) ile \(N\). mertebeden Farey dizisini gösterelim ve

$$\frac{a}{b} \lt \frac{c}{d}$$

iki ardışık terim olsun. Eğer

$$\frac{a}{b}\le x\le \frac{c}{d}$$

ise, paydası \(N\)'i aşanmadan bu iki uç arasında kalan başka indirgenmiş bir rasyonel yoktur. Bu yüzden \(x\)'in altında kalan en iyi rasyonel yaklaşım, bütün aralık boyunca sabit biçimde \(a/b\) olur.

Böylece minimum kesir kısmı payda \(b\) tarafından elde edilir:

$$f_N(x)=bx-a \qquad \text{için } x\in\left[\frac{a}{b},\frac{c}{d}\right].$$

Sol uçta bu değer \(0\)'dır; sağa gidildikçe doğrusal biçimde artar ve bir sonraki Farey sınırında yeni bir doğru parçasına geçilir. Yani \(f_N\)'in grafiği, Farey komşularının ürettiği doğrusal parçaların birleşimidir.

Tek bir Farey aralığının tam katkısı

Farey komşuları şu unimodüler bağıntıyı sağlar:

$$bc-ad=1.$$

Bundan aralık genişliği

$$\frac{c}{d}-\frac{a}{b}=\frac{1}{bd}$$

çıkar; ayrıca sağ uçta fonksiyonun değeri

$$f_N\!\left(\frac{c}{d}\right)=b\frac{c}{d}-a=\frac{bc-ad}{d}=\frac{1}{d}$$

olur. Demek ki her Farey aralığı, tabanı \(1/(bd)\) ve yüksekliği \(1/d\) olan bir üçgen alanı verir:

$$\int_{a/b}^{c/d}(bx-a)\,dx=\frac{1}{2}\cdot\frac{1}{bd}\cdot\frac{1}{d}=\frac{1}{2bd^2}.$$

Kodun her döngüde eklediği kapalı form tam olarak budur.

Küresel toplam formülü

Bütün ardışık Farey çiftleri üzerinden toplarsak

$$\boxed{F(N)=\sum_{\substack{a/b \lt c/d\\ \text{\(\mathcal{F}_N\) içinde ardışık}}} \frac{1}{2bd^2}.}$$

Matematiksel ifade tamdır; sayısal dikkat gerektiren tek nokta, büyük \(N\) için çok sayıda küçük pozitif terimi kararlı biçimde toplamaktır.

Çalışılmış Örnek: \(N=4\)

\(4\). mertebeden Farey dizisi

$$0,\ \frac14,\ \frac13,\ \frac12,\ \frac23,\ \frac34,\ 1$$

şeklindedir. Buna göre \(f_4(x)\) parçalı doğrusal olur:

$$ f_4(x)= \begin{cases} x, & 0\le x\le \frac14,\\ 4x-1, & \frac14\le x\le \frac13,\\ 3x-1, & \frac13\le x\le \frac12,\\ 2x-1, & \frac12\le x\le \frac23,\\ 3x-2, & \frac23\le x\le \frac34,\\ 4x-3, & \frac34\le x\le 1. \end{cases} $$

Bu altı aralığın katkıları

$$\frac{1}{32},\ \frac{1}{72},\ \frac{1}{24},\ \frac{1}{36},\ \frac{1}{96},\ \frac{1}{8}$$

olur ve toplamları

$$F(4)=\frac14$$

eder. Uygulamaların kullandığı kontrol noktası da budur; küçük örnek, genel yöntemin nasıl çalıştığını açıkça gösterir.

Kod Nasıl Çalışır

C++, Python ve Java uygulamaları aynı matematiksel planı izler: \(N\). mertebeden Farey komşularını sırayla üretir, her aralığı \(1/(2bd^2)\) terimine çevirir ve bu terimleri dikkatle toplar.

Ardışık Farey kesirlerini üretmek

Tarama ilk iki komşu olan \(0/1\) ve \(1/N\) ile başlar. Güncel komşu çift \(a/b \lt c/d\) ise bir sonraki Farey terimi standart bağıntıyla bulunur:

$$k=\left\lfloor\frac{N+b}{d}\right\rfloor,\qquad \frac{e}{f}=\frac{kc-a}{kd-b}.$$

\([a/b,c/d]\) aralığı işlendiğinde çift \(c/d \lt e/f\) biçimine kaydırılır. Böylece tüm Farey dizisi artan sırada dolaşılır; önceden büyük bir kesir listesi oluşturmak gerekmez.

Alanları sayısal olarak kararlı toplamak

Her aralık için uygulama

$$\frac{1}{2bd^2}$$

değerini koşan toplama ekler. Taramanın sonlarına doğru bu terimler çok küçüldüğü için üç sürüm de kompanse toplam kullanır. C++ sürümü daha yüksek kayan nokta hassasiyeti tutar; Python ve Java sürümleri ise aynı fikri standart hassasiyet üzerinde uygular.

Sağ uç \(1/1\)'e ulaştığında bir sonraki Farey güncellemesi birim aralığın dışına sıçrar ve döngü biter. Yazdırılan ondalık değer, yukarıdaki tam Farey toplamının sayısal karşılığıdır.

Karmaşıklık Analizi

Her Farey komşu aralığı tam bir kez ziyaret edilir ve her ziyaret sabit zamanlı aritmetik içerir. Bu nedenle toplam süre, \(N\). mertebeden Farey dizisindeki aralık sayısıyla doğrusal, yani \(\Theta(N^2)\) düzeyindedir.

Bellek kullanımı \(O(1)\)'dir: yalnızca güncel komşu kesirler, koşan toplam ve kompanse terimi saklanır. Büyük diziler, eleme yapıları veya dinamik programlama tabloları yoktur.

Dipnotlar ve Kaynaklar

  1. Project Euler problem sayfası: https://projecteuler.net/problem=965
  2. Farey dizisi: Wikipedia - Farey dizisi
  3. Kesir kısmı: Wikipedia - Kesir kısmı
  4. Diofantik yaklaşım: Wikipedia - Diophantine approximation
  5. Kahan toplama algoritması: Wikipedia - Kahan toplama algoritması

Resumen del Problema

Sea \(X\) una variable uniforme en \([0,1]\) y definamos, para cada entero positivo \(N\),

$$f_N(x)=\min_{1\le m\le N}\{mx\},\qquad F(N)=\int_0^1 f_N(x)\,dx,$$

donde \(\{y\}=y-\lfloor y\rfloor\) es la parte fraccionaria. El objetivo es hallar el valor esperado de la menor parte fraccionaria entre los primeros \(N\) múltiplos de un \(x\) aleatorio, en particular para \(N=10000\).

Un enfoque ingenuo sería muy costoso: para cada \(x\) habría que comparar \(N\) valores distintos y luego integrar numéricamente sobre \([0,1]\). La solución real evita cualquier muestreo y aprovecha que \(f_N\) se vuelve lineal en cada intervalo determinado por fracciones vecinas de Farey.

Enfoque Matemático

La identidad \(\{mx\}=mx-\lfloor mx\rfloor\) muestra que cada término mide cuánto supera \(mx\) al entero inmediatamente inferior. Por tanto, minimizar \(\{mx\}\) para \(1\le m\le N\) equivale a buscar la mejor aproximación racional de \(x\) por debajo, con denominador acotado por \(N\).

De la esperanza a una integral

Como \(X\) es uniforme en \([0,1]\), el valor esperado pedido coincide exactamente con el área bajo la curva \(f_N(x)\). El problema se convierte así en describir esa curva de forma exacta.

Para un denominador fijo \(m\), se tiene

$$\{mx\}=mx-p \qquad\text{con}\qquad p=\lfloor mx\rfloor,$$

de modo que cada candidato al mínimo está asociado con una fracción \(p/m\le x\). Eso traslada el problema a la geometría de los racionales de denominador limitado.

Por qué mandan los vecinos de Farey

Sea

$$\frac{a}{b} \lt \frac{c}{d}$$

un par consecutivo de la sucesión de Farey de orden \(N\), \(\mathcal{F}_N\). Si

$$\frac{a}{b}\le x\le \frac{c}{d},$$

entonces no existe ninguna fracción reducida con denominador a lo sumo \(N\) entre esos extremos. Por ello, la mejor aproximación racional por debajo permanece fija en todo el intervalo y es precisamente \(a/b\).

En consecuencia, la menor parte fraccionaria la produce el denominador \(b\):

$$f_N(x)=bx-a \qquad \text{para } x\in\left[\frac{a}{b},\frac{c}{d}\right].$$

En el extremo izquierdo el valor es \(0\); luego crece linealmente hasta el siguiente borde de Farey. El gráfico completo de \(f_N\) es, por tanto, una cadena de segmentos rectos.

Contribución exacta de un intervalo

Las fracciones vecinas de Farey satisfacen

$$bc-ad=1.$$

De ahí se obtiene el ancho del intervalo:

$$\frac{c}{d}-\frac{a}{b}=\frac{1}{bd},$$

y el valor del segmento en el extremo derecho:

$$f_N\!\left(\frac{c}{d}\right)=b\frac{c}{d}-a=\frac{bc-ad}{d}=\frac{1}{d}.$$

Cada intervalo aporta entonces el área de un triángulo de base \(1/(bd)\) y altura \(1/d\):

$$\int_{a/b}^{c/d}(bx-a)\,dx=\frac{1}{2}\cdot\frac{1}{bd}\cdot\frac{1}{d}=\frac{1}{2bd^2}.$$

Ésta es la fórmula cerrada exacta que suman las implementaciones.

La fórmula global

Al sumar sobre todos los pares consecutivos de \(\mathcal{F}_N\), se obtiene

$$\boxed{F(N)=\sum_{\substack{a/b \lt c/d\\ \text{consecutivos en }\mathcal{F}_N}} \frac{1}{2bd^2}.}$$

La parte matemática es exacta; la única cuestión numérica real es sumar de manera estable muchos términos positivos muy pequeños cuando \(N\) es grande.

Ejemplo trabajado: \(N=4\)

La sucesión de Farey de orden \(4\) es

$$0,\ \frac14,\ \frac13,\ \frac12,\ \frac23,\ \frac34,\ 1.$$

Por tanto, \(f_4(x)\) queda descrita por tramos:

$$ f_4(x)= \begin{cases} x, & 0\le x\le \frac14,\\ 4x-1, & \frac14\le x\le \frac13,\\ 3x-1, & \frac13\le x\le \frac12,\\ 2x-1, & \frac12\le x\le \frac23,\\ 3x-2, & \frac23\le x\le \frac34,\\ 4x-3, & \frac34\le x\le 1. \end{cases} $$

Las contribuciones de las seis regiones son

$$\frac{1}{32},\ \frac{1}{72},\ \frac{1}{24},\ \frac{1}{36},\ \frac{1}{96},\ \frac{1}{8},$$

y su suma vale

$$F(4)=\frac14.$$

Este ejemplo pequeño reproduce exactamente la lógica usada para \(N=10000\): sustituir una minimización continua por una suma finita de áreas triangulares.

Cómo Funciona el Código

Las implementaciones en C++, Python y Java siguen el mismo esquema: recorren las fracciones vecinas de Farey de orden \(N\), convierten cada intervalo en el término exacto \(1/(2bd^2)\) y acumulan esos términos con cuidado numérico.

Recorrer la sucesión de Farey

El barrido comienza con los dos primeros vecinos, \(0/1\) y \(1/N\). Si el par actual es \(a/b \lt c/d\), el siguiente término de Farey se obtiene con la recurrencia estándar

$$k=\left\lfloor\frac{N+b}{d}\right\rfloor,\qquad \frac{e}{f}=\frac{kc-a}{kd-b}.$$

Tras procesar \([a/b,c/d]\), el par avanza a \(c/d \lt e/f\). Así se recorre toda la sucesión en orden creciente sin construir previamente una lista completa de fracciones.

Sumar las áreas con estabilidad

En cada paso se añade

$$\frac{1}{2bd^2}$$

a la suma acumulada. Como los términos finales son muy pequeños, las tres versiones usan suma compensada para limitar la pérdida de precisión en los dígitos bajos. La versión en C++ conserva más precisión interna; las de Python y Java aplican la misma idea con aritmética de coma flotante estándar.

Cuando el extremo derecho alcanza \(1/1\), la siguiente actualización de Farey sale del intervalo unitario y el recorrido termina. El número decimal final no es una aproximación heurística, sino la evaluación numérica de la suma exacta deducida arriba.

Análisis de Complejidad

Cada intervalo entre vecinos de Farey se visita una sola vez y cada visita requiere tiempo constante. Por ello, el tiempo total es lineal en el número de intervalos de la sucesión de Farey de orden \(N\), es decir, \(\Theta(N^2)\).

La memoria es \(O(1)\): sólo se mantienen las fracciones vecinas actuales, la suma acumulada y el término de compensación. No hacen falta tablas grandes ni estructuras auxiliares pesadas.

Notas y Referencias

  1. Página del problema: https://projecteuler.net/problem=965
  2. Sucesión de Farey: Wikipedia - Sucesión de Farey
  3. Parte fraccionaria: Wikipedia - Parte fraccionaria
  4. Aproximación diofántica: Wikipedia - Aproximación diofántica
  5. Algoritmo de suma de Kahan: Wikipedia - Suma de Kahan

问题概述

设 \(X\) 在区间 \([0,1]\) 上均匀分布。对每个正整数 \(N\),定义

$$f_N(x)=\min_{1\le m\le N}\{mx\},\qquad F(N)=\int_0^1 f_N(x)\,dx,$$

其中 \(\{y\}=y-\lfloor y\rfloor\) 表示小数部分。题目的含义就是:随机取一个 \(x\),考察 \(x,2x,\dots,Nx\) 的小数部分,其中最小的那个的期望值是多少;目标情形是 \(N=10000\)。

如果直接做,会变成双重困难:对每个 \(x\) 都要比较 \(N\) 个值,而对整个 \([0,1]\) 又必须积分。代码真正利用的结构是,\(f_N(x)\) 并不是杂乱无章的,它会在 Farey 序列划出的每个小区间上退化成一条非常简单的直线。

数学方法

\(\{mx\}=mx-\lfloor mx\rfloor\) 表示 \(mx\) 超过其下方最近整数的那一小段距离。因此,在 \(1\le m\le N\) 中寻找最小的小数部分,本质上是在寻找一个分母不超过 \(N\)、从下方最贴近 \(x\) 的有理数。

先把“期望”改写成面积

因为 \(X\) 在 \([0,1]\) 上均匀分布,所以题目中的期望值就是函数 \(f_N(x)\) 在 \([0,1]\) 上的积分。换句话说,只要能够精确描述 \(f_N\) 的图像,就能把问题变成纯粹的面积计算。

对固定的 \(m\),有

$$\{mx\}=mx-p \qquad\text{其中}\qquad p=\lfloor mx\rfloor.$$

于是每一个候选值都对应一个满足 \(p/m\le x\) 的有理数。原问题因此从“连续函数取最小值”转化为“按分母上界组织这些有理数”。

为什么 Farey 相邻分数决定整段区间

记 \(\mathcal{F}_N\) 为 \(N\) 阶 Farey 序列。设

$$\frac{a}{b} \lt \frac{c}{d}$$

是其中一对相邻分数。如果

$$\frac{a}{b}\le x\le \frac{c}{d},$$

那么在这两个端点之间,不存在分母不超过 \(N\) 的既约分数。也就是说,整个区间内“从下方最接近 \(x\)”的有理数都固定为 \(a/b\)。

因此最小小数部分由分母 \(b\) 给出,并且有

$$f_N(x)=bx-a \qquad \text{在 } x\in\left[\frac{a}{b},\frac{c}{d}\right] \text{ 上成立。}$$

这个表达式在左端点处等于 \(0\),随后随 \(x\) 线性增长,直到碰到下一个 Farey 边界才切换到新的线段。所以 \(f_N\) 的整个图像由一串相接的线性片段组成。

单个 Farey 区间的精确贡献

Farey 相邻分数满足经典关系

$$bc-ad=1.$$

因此区间宽度为

$$\frac{c}{d}-\frac{a}{b}=\frac{1}{bd},$$

而右端点处函数值为

$$f_N\!\left(\frac{c}{d}\right)=b\frac{c}{d}-a=\frac{bc-ad}{d}=\frac{1}{d}.$$

所以这一段曲线下面积就是一个底为 \(1/(bd)\)、高为 \(1/d\) 的三角形面积:

$$\int_{a/b}^{c/d}(bx-a)\,dx=\frac{1}{2}\cdot\frac{1}{bd}\cdot\frac{1}{d}=\frac{1}{2bd^2}.$$

这正是三份实现每一步累加的闭式项。

把所有区间加起来

对 \(\mathcal{F}_N\) 中全部相邻分数求和,就得到

$$\boxed{F(N)=\sum_{\substack{a/b \lt c/d\\ \text{在 }\mathcal{F}_N\text{ 中相邻}}} \frac{1}{2bd^2}.}$$

数学上这里没有近似。真正需要数值技巧的地方,只是当 \(N\) 很大时,如何稳定地累加大量很小的正项。

具体例子:\(N=4\)

\(4\) 阶 Farey 序列为

$$0,\ \frac14,\ \frac13,\ \frac12,\ \frac23,\ \frac34,\ 1.$$

因此 \(f_4(x)\) 的分段形式是

$$ f_4(x)= \begin{cases} x, & 0\le x\le \frac14,\\ 4x-1, & \frac14\le x\le \frac13,\\ 3x-1, & \frac13\le x\le \frac12,\\ 2x-1, & \frac12\le x\le \frac23,\\ 3x-2, & \frac23\le x\le \frac34,\\ 4x-3, & \frac34\le x\le 1. \end{cases} $$

对应的六个面积分别是

$$\frac{1}{32},\ \frac{1}{72},\ \frac{1}{24},\ \frac{1}{36},\ \frac{1}{96},\ \frac{1}{8},$$

总和为

$$F(4)=\frac14.$$

这个小例子已经完整展示了大问题的结构:不是对每个 \(x\) 暴力比较,而是先用 Farey 邻接关系切分区间,再把每段化成一个可直接求面积的三角形。

代码如何工作

C++、Python 和 Java 实现采用完全相同的思路:按顺序遍历 \(N\) 阶 Farey 序列中的相邻分数,把每个区间转换成精确项 \(1/(2bd^2)\),然后稳定地把这些项相加。

按顺序生成 Farey 相邻项

遍历从最前面的两个邻项 \(0/1\) 和 \(1/N\) 开始。如果当前相邻分数是 \(a/b \lt c/d\),那么下一个 Farey 项由标准递推式给出:

$$k=\left\lfloor\frac{N+b}{d}\right\rfloor,\qquad \frac{e}{f}=\frac{kc-a}{kd-b}.$$

处理完区间 \([a/b,c/d]\) 后,相邻对向前推进为 \(c/d \lt e/f\)。这样就能按升序走完整个 Farey 序列,而不需要事先把所有分数存进数组。

稳定累加精确面积

每一步加入的都是

$$\frac{1}{2bd^2}$$

这个精确公式。由于扫描后段的项会越来越小,三份实现都采用了补偿求和来减少浮点舍入误差。C++ 版本使用更高的内部精度;Python 和 Java 版本则用标准浮点数配合同样的补偿思想。

当右端点到达 \(1/1\) 后,再做一次 Farey 更新就会跳出单位区间,循环结束。最终输出的十进制数,就是上面那个 Farey 精确求和公式的数值结果。

复杂度分析

每一个 Farey 相邻区间只会访问一次,而且每次访问只做常数次算术运算。因此总时间与 \(N\) 阶 Farey 序列中的区间数成正比,也就是 \(\Theta(N^2)\)。

空间复杂度为 \(O(1)\):程序只保存当前相邻分数、运行中的总和以及补偿项,不需要大数组、筛法表或动态规划结构。

注释与参考资料

  1. Project Euler 题目页: https://projecteuler.net/problem=965
  2. Farey 序列: Wikipedia - Farey 序列
  3. 小数部分: Wikipedia - 小数部分
  4. 丢番图逼近: Wikipedia - 丢番图逼近
  5. Kahan 求和算法: Wikipedia - Kahan 求和算法

Краткое описание

Пусть \(X\) равномерно распределена на \([0,1]\). Для каждого положительного \(N\) определим

$$f_N(x)=\min_{1\le m\le N}\{mx\},\qquad F(N)=\int_0^1 f_N(x)\,dx,$$

где \(\{y\}=y-\lfloor y\rfloor\) обозначает дробную часть. Требуется найти математическое ожидание наименьшей дробной части среди чисел \(x,2x,\dots,Nx\), в задаче интересует случай \(N=10000\).

Лобовое вычисление было бы неудобным: для каждого \(x\) пришлось бы сравнивать \(N\) значений, а затем ещё численно интегрировать по всему отрезку. Реальное решение использует тот факт, что функция \(f_N(x)\) разбивается на простые линейные куски, задаваемые соседними дробями Фарея.

Математический подход

Равенство \(\{mx\}=mx-\lfloor mx\rfloor\) показывает, насколько \(mx\) находится выше ближайшего меньшего целого. Поэтому минимизация \(\{mx\}\) по \(1\le m\le N\) эквивалентна поиску наилучшего рационального приближения числа \(x\) снизу с ограничением на знаменатель.

От ожидания к площади под графиком

Так как \(X\) равномерна на \([0,1]\), искомое ожидание в точности равно интегралу от \(f_N\). Значит, задача сводится к тому, чтобы точно описать график этой функции.

Для фиксированного \(m\) имеем

$$\{mx\}=mx-p \qquad\text{при}\qquad p=\lfloor mx\rfloor,$$

то есть каждый кандидат на минимум связан с рациональным числом \(p/m\le x\). После этого исходная задача превращается в задачу о рациональных точках с ограниченным знаменателем.

Почему достаточно соседей в последовательности Фарея

Пусть

$$\frac{a}{b} \lt \frac{c}{d}$$

это соседние члены последовательности Фарея порядка \(N\), обозначаемой \(\mathcal{F}_N\). Если

$$\frac{a}{b}\le x\le \frac{c}{d},$$

то между этими концами нет ни одной несократимой дроби со знаменателем не больше \(N\). Следовательно, на всём таком интервале лучшая рациональная аппроксимация снизу остаётся одной и той же, а именно \(a/b\).

Отсюда минимальная дробная часть достигается при знаменателе \(b\):

$$f_N(x)=bx-a \qquad \text{на } \left[\frac{a}{b},\frac{c}{d}\right].$$

В левом конце этот кусок равен нулю, затем линейно возрастает до следующей границы Фарея. Значит, график \(f_N\) состоит из цепочки линейных отрезков.

Точный вклад одного интервала

Для соседних дробей Фарея выполняется соотношение

$$bc-ad=1.$$

Из него следует ширина интервала

$$\frac{c}{d}-\frac{a}{b}=\frac{1}{bd},$$

а значение функции в правом конце равно

$$f_N\!\left(\frac{c}{d}\right)=b\frac{c}{d}-a=\frac{bc-ad}{d}=\frac{1}{d}.$$

Значит, каждый такой участок даёт площадь треугольника с основанием \(1/(bd)\) и высотой \(1/d\):

$$\int_{a/b}^{c/d}(bx-a)\,dx=\frac{1}{2}\cdot\frac{1}{bd}\cdot\frac{1}{d}=\frac{1}{2bd^2}.$$

Именно этот замкнутый вид накапливают реализации.

Итоговая формула

Суммируя по всем соседним парам в \(\mathcal{F}_N\), получаем

$$\boxed{F(N)=\sum_{\substack{a/b \lt c/d\\ \text{соседи в }\mathcal{F}_N}} \frac{1}{2bd^2}.}$$

Математическая часть здесь точна; единственный численный вопрос состоит в устойчивом суммировании большого числа очень маленьких положительных слагаемых.

Разобранный пример: \(N=4\)

Последовательность Фарея порядка \(4\) имеет вид

$$0,\ \frac14,\ \frac13,\ \frac12,\ \frac23,\ \frac34,\ 1.$$

Отсюда функция \(f_4(x)\) задаётся по частям:

$$ f_4(x)= \begin{cases} x, & 0\le x\le \frac14,\\ 4x-1, & \frac14\le x\le \frac13,\\ 3x-1, & \frac13\le x\le \frac12,\\ 2x-1, & \frac12\le x\le \frac23,\\ 3x-2, & \frac23\le x\le \frac34,\\ 4x-3, & \frac34\le x\le 1. \end{cases} $$

Соответствующие площади равны

$$\frac{1}{32},\ \frac{1}{72},\ \frac{1}{24},\ \frac{1}{36},\ \frac{1}{96},\ \frac{1}{8},$$

а их сумма даёт

$$F(4)=\frac14.$$

Этот небольшой пример полностью иллюстрирует общий метод: вместо перебора значений по \(x\) задача сводится к конечной сумме площадей по интервалам Фарея.

Как Работает Код

Реализации на C++, Python и Java используют один и тот же план: последовательно проходят соседние дроби Фарея порядка \(N\), для каждого интервала вычисляют точный член \(1/(2bd^2)\) и аккуратно прибавляют его к общей сумме.

Последовательный обход соседних дробей

Обход начинается с первой пары соседей \(0/1\) и \(1/N\). Если текущая пара равна \(a/b \lt c/d\), следующий член последовательности Фарея находится по стандартной рекуррентной формуле

$$k=\left\lfloor\frac{N+b}{d}\right\rfloor,\qquad \frac{e}{f}=\frac{kc-a}{kd-b}.$$

После обработки интервала \([a/b,c/d]\) пара сдвигается к \(c/d \lt e/f\). Так можно пройти всю последовательность Фарея по возрастанию, не сохраняя заранее большой список дробей.

Численно устойчивое суммирование

На каждом шаге добавляется величина

$$\frac{1}{2bd^2}.$$

Поскольку ближе к концу прохода слагаемые становятся очень малыми, все три реализации используют компенсированное суммирование, уменьшающее потерю точности. Версия на C++ хранит сумму с повышенной внутренней точностью; версии на Python и Java применяют ту же идею с обычной плавающей точкой.

Когда правый конец достигает \(1/1\), следующее обновление Фарея уже выводит процесс за пределы единичного интервала, и цикл завершается. Итоговое десятичное число является численным значением точной формулы, полученной выше.

Анализ сложности

Каждый интервал между соседями Фарея посещается ровно один раз, и на каждый визит требуется только постоянное число арифметических операций. Поэтому общее время линейно по числу интервалов в последовательности Фарея порядка \(N\), то есть \(\Theta(N^2)\).

Память равна \(O(1)\): хранятся только текущие соседние дроби, накопленная сумма и компенсирующий член. Никаких больших таблиц или вспомогательных структур не требуется.

Сноски и Источники

  1. Страница задачи Project Euler: https://projecteuler.net/problem=965
  2. Последовательность Фарея: Wikipedia - Ряд Фарея
  3. Дробная часть: Wikipedia - Дробная часть
  4. Диофантовы приближения: Wikipedia - Диофантовы приближения
  5. Алгоритм суммирования Кэхэна: Wikipedia - Алгоритм Кэхэна

ملخص المسألة

لنأخذ \(X\) موزعًا بانتظام على الفترة \([0,1]\)، ولأي عدد صحيح موجب \(N\) نعرّف

$$f_N(x)=\min_{1\le m\le N}\{mx\},\qquad F(N)=\int_0^1 f_N(x)\,dx,$$

حيث \(\{y\}=y-\lfloor y\rfloor\) تمثل الجزء الكسري. المطلوب هو القيمة المتوقعة لأصغر جزء كسري بين القيم \(x,2x,\dots,Nx\)، والحالة المستهدفة في المسألة هي \(N=10000\).

الطريقة المباشرة غير مناسبة: لكل \(x\) يجب مقارنة \(N\) قيم مختلفة، ثم يلزم تكامل عددي على كامل الفترة. الفكرة الحاسمة في الحل هي أن الدالة \(f_N(x)\) تصبح خطية على كل فترة يحددها زوج متجاور من كسور Farey، ولذلك يمكن تحويل التوقع إلى مجموع مغلق من مساحات بسيطة.

المنهج الرياضي

لدينا \(\{mx\}=mx-\lfloor mx\rfloor\)، أي أن هذا المقدار يقيس المسافة بين \(mx\) وأقرب عدد صحيح أصغر منه. لذا فإن تصغير \(\{mx\}\) على المجال \(1\le m\le N\) يكافئ البحث عن أفضل تقريب نسبي للعدد \(x\) من الأسفل بحيث لا يتجاوز المقام \(N\).

تحويل التوقع إلى مساحة تحت المنحنى

بما أن \(X\) موزع بانتظام على \([0,1]\)، فإن القيمة المتوقعة المطلوبة تساوي تمامًا تكامل \(f_N\) على هذه الفترة. إذن جوهر المسألة هو وصف شكل \(f_N(x)\) بدقة.

ولكل مقام ثابت \(m\) نحصل على

$$\{mx\}=mx-p \qquad\text{with}\qquad p=\lfloor mx\rfloor,$$

وبذلك يرتبط كل مرشح للقيمة الدنيا بكسر نسبي \(p/m\le x\). بهذه الصياغة تتحول المسألة إلى دراسة منظومة الكسور ذات المقامات المحدودة.

لماذا تكفي أزواج Farey المتجاورة

لنرمز إلى متتالية Farey من الرتبة \(N\) بالرمز \(\mathcal{F}_N\)، ولنفترض أن

$$\frac{a}{b} \lt \frac{c}{d}$$

هما حدان متجاوران فيها. إذا كان

$$\frac{a}{b}\le x\le \frac{c}{d},$$

فلا يوجد كسر مختزل مقامه لا يتجاوز \(N\) يقع بين هذين الحدين. لذلك يبقى أفضل تقريب نسبي من الأسفل ثابتًا على كامل الفترة، وهو بالضبط \(a/b\).

إذن يتحقق أصغر جزء كسري عند المقام \(b\)، ويكون

$$f_N(x)=bx-a,\qquad x\in\left[\frac{a}{b},\frac{c}{d}\right].$$

هذه الدالة تساوي الصفر عند الطرف الأيسر، ثم ترتفع خطيًا حتى تصل إلى الحد التالي في Farey. ومن ثم فإن الرسم الكامل لـ \(f_N\) هو سلسلة من القطع الخطية المتصلة.

المساهمة الدقيقة لفترة واحدة

الكسور المتجاورة في Farey تحقق العلاقة

$$bc-ad=1.$$

ومنها نحصل على عرض الفترة

$$\frac{c}{d}-\frac{a}{b}=\frac{1}{bd},$$

كما أن قيمة الدالة عند الطرف الأيمن هي

$$f_N\!\left(\frac{c}{d}\right)=b\frac{c}{d}-a=\frac{bc-ad}{d}=\frac{1}{d}.$$

لذلك فإن مساهمة كل فترة هي مساحة مثلث قاعدته \(1/(bd)\) وارتفاعه \(1/d\):

$$\int_{a/b}^{c/d}(bx-a)\,dx=\frac{1}{2}\cdot\frac{1}{bd}\cdot\frac{1}{d}=\frac{1}{2bd^2}.$$

وهذا هو الحد المغلق الذي تجمعه التطبيقات مباشرة.

الصيغة النهائية للمجموع

بجمع هذه المساهمات على جميع الأزواج المتجاورة في \(\mathcal{F}_N\) نحصل على

$$\boxed{F(N)=\sum_{a/b \lt c/d} \frac{1}{2bd^2}.}$$

الصياغة الرياضية هنا دقيقة تمامًا؛ أما التحدي العددي الوحيد فهو جمع عدد كبير من الحدود الصغيرة الموجبة بطريقة مستقرة.

مثال محلول: \(N=4\)

متتالية Farey من الرتبة \(4\) هي

$$0,\ \frac14,\ \frac13,\ \frac12,\ \frac23,\ \frac34,\ 1.$$

ومن ثم تكون \(f_4(x)\) دالة خطية على مقاطع:

$$ f_4(x)= \begin{cases} x, & 0\le x\le \frac14,\\ 4x-1, & \frac14\le x\le \frac13,\\ 3x-1, & \frac13\le x\le \frac12,\\ 2x-1, & \frac12\le x\le \frac23,\\ 3x-2, & \frac23\le x\le \frac34,\\ 4x-3, & \frac34\le x\le 1. \end{cases} $$

ومساهمات الفترات الست هي

$$\frac{1}{32},\ \frac{1}{72},\ \frac{1}{24},\ \frac{1}{36},\ \frac{1}{96},\ \frac{1}{8},$$

ومجموعها يساوي

$$F(4)=\frac14.$$

هذا المثال الصغير يوضح الفكرة كاملة: بدلًا من تجربة قيم كثيرة لـ \(x\)، نقسم الفترة باستخدام جيران Farey ثم نحول كل جزء إلى مساحة مثلث معروفة بدقة.

كيف تعمل الشيفرة

تتبع تطبيقات C++ وPython وJava الخطة الرياضية نفسها: توليد الكسور المتجاورة في متتالية Farey من الرتبة \(N\)، تحويل كل فترة إلى الحد الدقيق \(1/(2bd^2)\)، ثم جمع هذه الحدود بعناية عددية.

توليد الجيران المتتاليين في Farey

تبدأ العملية بأول زوج متجاور، وهو \(0/1\) و\(1/N\). إذا كان الزوج الحالي هو \(a/b \lt c/d\)، فإن الحد التالي في Farey يعطى بالعلاقة القياسية

$$k=\left\lfloor\frac{N+b}{d}\right\rfloor,\qquad \frac{e}{f}=\frac{kc-a}{kd-b}.$$

بعد معالجة الفترة \([a/b,c/d]\) ينتقل الزوج إلى \(c/d \lt e/f\). بهذه الطريقة يتم اجتياز المتتالية كلها بترتيب تصاعدي من غير الحاجة إلى بناء جدول كامل مسبقًا.

جمع المساحات بدقة عددية أفضل

في كل خطوة يضاف الحد

$$\frac{1}{2bd^2}$$

إلى المجموع الجاري. ولأن الحدود تصبح صغيرة جدًا قرب نهاية المسار، تستخدم النسخ الثلاث الجمع المعوَّض لتقليل فقدان الدقة في الأرقام الدنيا. نسخة C++ تحتفظ بدقة داخلية أعلى، أما نسختا Python وJava فتستخدمان الفكرة نفسها مع الأعداد العائمة القياسية.

عندما يصل الطرف الأيمن إلى \(1/1\)، تدفع خطوة Farey التالية الزوج إلى خارج الفترة الواحدة، وعندها تنتهي الحلقة. العدد العشري النهائي هو التقييم العددي المباشر للمجموع الدقيق المستنتج أعلاه.

تحليل التعقيد

تُزار كل فترة بين جارين في Farey مرة واحدة فقط، وكل زيارة تحتاج إلى عدد ثابت من العمليات الحسابية. لذلك فالزمن الكلي يتناسب مع عدد فترات متتالية Farey من الرتبة \(N\)، أي يساوي \(\Theta(N^2)\).

أما الذاكرة فهي \(O(1)\): لا يُخزَّن إلا الزوج الحالي من الكسور، والمجموع الجاري، وحد التعويض. لا توجد مصفوفات كبيرة ولا جداول مساعدة معقدة.

هوامش ومراجع

  1. صفحة المسألة في Project Euler: https://projecteuler.net/problem=965
  2. متتالية فاري: Wikipedia - متتالية فاري
  3. الجزء الكسري: Wikipedia - الجزء الكسري
  4. التقريب الديوفانتي: Wikipedia - التقريب الديوفانتي
  5. خوارزمية كاهان للجمع: Wikipedia - خوارزمية كاهان