All Euler problems
Project Euler

A Scoop of Blancmange

The Blancmange curve is blanc(x)=sum_(n=0)^infinity(s(2^n x))/(2^n), s(x)=min_(kinmathbb Z)|x-k|. Consider the circle (x-frac14)^2+(y-frac12)^2=frac116. Find the area of the region that lies both b...

Source sync May 21, 2026
Problem #0226
Level Level 10
Solved By 2,047
Languages C++, Python
Answer 0.11316017
Length 254 words
geometrymodular_arithmeticalgebra

Problem Statement

This archive keeps the full statement, math, and original media on the page.

The blancmange curve is the set of points $(x, y)$ such that $0 \le x \le 1$ and $\displaystyle y = \sum \limits_{n = 0}^{\infty} {\dfrac{s(2^n x)}{2^n}}$, where $s(x)$ is the distance from $x$ to the nearest integer.

The area under the blancmange curve is equal to ½, shown in pink in the diagram below.

Problem illustration

Let $C$ be the circle with centre $\left ( \frac{1}{4}, \frac{1}{2} \right )$ and radius $\frac{1}{4}$, shown in black in the diagram.

What area under the blancmange curve is enclosed by $C$?

Give your answer rounded to eight decimal places in the form $0.abcdefgh$.

Problem 226: A Scoop of Blancmange

Mathematical Development

Since 0≤s(t)≤120 \le s(t) \le \tfrac12, the tail of the Blancmange series is bounded by

∑n=N∞12n+1=2−N.\sum_{n=N}^{\infty}\frac{1}{2^{n+1}}=2^{-N}.

So truncating after 6060 terms leaves an error below 10−1810^{-18}, which is far smaller than the required precision.

The lower arc of the circle is

ylow(x)=12−116−(x−14)2.y_{\mathrm{low}}(x) = \frac12-\sqrt{\frac1{16}-\left(x-\frac14\right)^2}.

The relevant intersection points satisfy

(x−14)2+(blanc⁡(x)−12)2=116.\left(x-\frac14\right)^2+\left(\operatorname{blanc}(x)-\frac12\right)^2=\frac1{16}.

One of them is obvious:

x=12,blanc⁡ ⁣(12)=12.x=\frac12, \qquad \operatorname{blanc}\!\left(\frac12\right)=\frac12.

The other lies near x≈0.0789x \approx 0.0789 and is found numerically. Once that left intersection x1x_1 is known, the desired area is

∫x11/2(blanc⁡(x)−ylow(x)) dx.\int_{x_1}^{1/2}\bigl(\operatorname{blanc}(x)-y_{\mathrm{low}}(x)\bigr)\,dx.

So the whole problem reduces to two numerical tasks:

  1. find the left intersection accurately;
  2. integrate the difference between the curve and the lower arc.

Editorial

The function itself is not the obstacle. Because the Blancmange series has a geometric tail, 6060 terms already give much more accuracy than the final answer needs. That lets us treat blanc⁡(x)\operatorname{blanc}(x) as an ordinary smooth-enough numeric function everywhere in the relevant interval.

From there, the geometry is clean. The enclosed region starts at the nontrivial intersection of the curve with the circle, ends at x=12x=\tfrac12, and its height is simply

blanc⁡(x)−ylow(x).\operatorname{blanc}(x)-y_{\mathrm{low}}(x).

So the program first locates the left intersection with a robust one-dimensional root finder, then integrates that height with Simpson’s rule on a fine grid. There is no symbolic trick after that; the important part is keeping the truncation and quadrature errors comfortably below 10−810^{-8}.

Pseudocode

Approximate blanc(x) by summing the first 60 terms of the series.

Define the circle equation
    f(x) = (x - 1/4)^2 + (blanc(x) - 1/2)^2 - 1/16.

Use a bracketing root finder on the interval near 0.08
to locate the left intersection x1.

Define the lower circle arc y_low(x).
Define the integrand blanc(x) - y_low(x).

Apply Simpson's rule on [x1, 1/2] with a sufficiently fine subdivision.
Print the area to 8 decimal places.

Complexity Analysis

  • Time: O(T⋅M)O(T \cdot M) where T=60T=60 Blancmange terms are evaluated at each of the MM quadrature points.
  • Space: O(1)O(1).

Answer

0.11316017\boxed{0.11316017}

Code

Each problem page includes the exact C++ and Python source files from the local archive.

C++ project_euler/problem_226/solution.cpp
#include <bits/stdc++.h>
using namespace std;

// Triangle wave: distance to nearest integer
double s(double x) {
    return abs(x - round(x));
}

// Blancmange curve value at x (60 terms suffice for ~18 digit precision)
double blanc(double x) {
    double result = 0.0;
    double pow2 = 1.0;
    for (int n = 0; n < 60; n++) {
        result += s(pow2 * x) / pow2;
        pow2 *= 2.0;
    }
    return result;
}

// Circle: (x - 1/4)^2 + (y - 1/2)^2 = 1/16
// Lower arc: y = 1/2 - sqrt(1/16 - (x - 1/4)^2)
double circle_lower(double x) {
    double val = 1.0 / 16.0 - (x - 0.25) * (x - 0.25);
    if (val < 0) return 0.5;
    return 0.5 - sqrt(val);
}

// Function whose root gives the intersection point
double on_circle(double x) {
    double b = blanc(x);
    return (x - 0.25) * (x - 0.25) + (b - 0.5) * (b - 0.5) - 1.0 / 16.0;
}

// Brent's method to find root in [a, b]
double brent(double a, double b, double tol = 1e-15) {
    double fa = on_circle(a), fb = on_circle(b);
    if (fa * fb > 0) return a;
    double c = a, fc = fa, d = b - a, e = d;
    for (int i = 0; i < 200; i++) {
        if (fb * fc > 0) { c = a; fc = fa; d = e = b - a; }
        if (fabs(fc) < fabs(fb)) { a = b; b = c; c = a; fa = fb; fb = fc; fc = fa; }
        double tol1 = 2e-16 * fabs(b) + 0.5 * tol;
        double m = 0.5 * (c - b);
        if (fabs(m) <= tol1 || fb == 0) return b;
        if (fabs(e) >= tol1 && fabs(fa) > fabs(fb)) {
            double s_val;
            if (a == c) {
                s_val = fb / fa; double p = 2 * m * s_val; double q = 1 - s_val;
                if (p > 0) q = -q; else p = -p;
                if (2*p < 3*m*q - fabs(tol1*q) && 2*p < fabs(e*q)) { e = d; d = p/q; }
                else { d = m; e = m; }
            } else { d = m; e = m; }
        } else { d = m; e = m; }
        a = b; fa = fb;
        if (fabs(d) > tol1) b += d;
        else b += (m > 0 ? tol1 : -tol1);
        fb = on_circle(b);
    }
    return b;
}

int main() {
    // Find intersection point x1
    double x1 = brent(0.05, 0.1);
    double x2 = 0.5;

    // Integrand: blanc(x) - circle_lower(x)
    auto integrand = [](double x) -> double {
        return blanc(x) - (0.5 - sqrt(max(0.0, 1.0 / 16.0 - (x - 0.25) * (x - 0.25))));
    };

    // Simpson's rule with 2M subdivisions
    int N = 2000000;
    double h = (x2 - x1) / N;
    double sum = integrand(x1) + integrand(x2);

    for (int i = 1; i < N; i++) {
        double x = x1 + i * h;
        sum += (i % 2 == 0 ? 2.0 : 4.0) * integrand(x);
    }

    double area = sum * h / 3.0;
    printf("%.8f\n", area);
    return 0;
}