import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;

public class Euler454 {

    static long integerSqrt(long n) {
        long r = (long) Math.sqrt(n);
        while ((r + 1) <= n / (r + 1)) {
            r++;
        }
        while (r > n / r) {
            r--;
        }
        return r;
    }

    public static String solve() {
        long L = 1000000000000L;
        long root = integerSqrt(1L + 4L * L);
        final int maxB = (int) ((root - 1L) / 2L);

        int[] mu = new int[maxB + 1];
        List<Integer> primes = new ArrayList<>(maxB / 10);
        boolean[] isComposite = new boolean[maxB + 1];
        mu[1] = 1;

        for (int i = 2; i <= maxB; i++) {
            if (!isComposite[i]) {
                primes.add(i);
                mu[i] = -1;
            }
            for (int p : primes) {
                long v = (long) i * p;
                if (v > maxB)
                    break;
                isComposite[(int) v] = true;
                if (i % p == 0) {
                    mu[(int) v] = 0;
                    break;
                }
                mu[(int) v] = -mu[i];
            }
        }

        int[] divisorCount = new int[maxB + 1];
        for (int d = 1; d <= maxB; d++) {
            if (mu[d] == 0)
                continue;
            for (int b = d; b <= maxB; b += d) {
                divisorCount[b]++;
            }
        }

        int[] offset = new int[maxB + 2];
        for (int b = 1; b <= maxB; b++) {
            offset[b + 1] = offset[b] + divisorCount[b];
        }

        int[] signedDivisor = new int[offset[maxB + 1]];
        int[] fill = new int[maxB + 2];
        System.arraycopy(offset, 0, fill, 0, maxB + 2);

        for (int d = 1; d <= maxB; d++) {
            int mud = mu[d];
            if (mud == 0)
                continue;
            int sd = mud * d;
            for (int b = d; b <= maxB; b += d) {
                signedDivisor[fill[b]++] = sd;
            }
        }

        int threads = Math.max(1, Runtime.getRuntime().availableProcessors());
        int initialChunkSize = maxB / threads;
        final int chunkSize = initialChunkSize == 0 ? 1 : initialChunkSize;

        int totalChunks = (maxB + chunkSize - 1) / chunkSize;

        long answer = IntStream.range(0, totalChunks).parallel().mapToLong(chunkIdx -> {
            int startB = chunkIdx * chunkSize + 1;
            int endB = Math.min(maxB, startB + chunkSize - 1);
            long localAns = 0;

            for (int b = startB; b <= endB; b++) {
                long M = L / b;
                long upper = Math.min(2L * b - 1L, M);
                if (upper <= b)
                    continue;

                long c = (long) b + 1L;
                int offStart = offset[b];
                int offEnd = offset[b + 1];

                while (c <= upper) {
                    long q = M / c;
                    long c2 = Math.min(upper, M / q);

                    long leftMinus1 = c - 1L;
                    long coprimeCount = 0;

                    for (int idx = offStart; idx < offEnd; idx++) {
                        int sd = signedDivisor[idx];
                        int d = sd > 0 ? sd : -sd;
                        long term = (c2 / d) - (leftMinus1 / d);
                        if (sd > 0)
                            coprimeCount += term;
                        else
                            coprimeCount -= term;
                    }

                    localAns += q * coprimeCount;
                    c = c2 + 1L;
                }
            }
            return localAns;
        }).sum();

        return Long.toString(answer);
    }

    public static void main(String[] args) {
        System.out.println(solve());
    }
}
