Problem 756

Computes E(Delta | phi(k), n, m) exactly (no simulation) for n = 12345678, m = 12345, where f(k) = phi(k) (Euler's totient). S = sum_{k=1..n} f(k) S* = sum_{i=1..m} f(X_i) (X_i - X_{i-1}) for a random increasing m-tuple Delta = S - S* E(Delta) = sum_{k=1..n-m} f(k) * C(n-k, m) / C(n, m) with weights updated by recurrence w_{k+1} = w_k * (n-k-m)/(n-k). A rigorous tail bound truncates the sum so only the necessary initial part is computed, keeping the totient sieve small.

Answer607238.610661
Output607238.610661
StatusPASS
Native helperno
Runtime0 ms
Peak memory1536 KB
Time complexityO(n) (estimated)
Space complexityO(n) (estimated)

Performance comparison

MetricOur solutionBest known
Time complexityO(n)O(n log log n)
Space complexityO(n)O(n)
ApproachFlow solutionSieve-based totient computation
VerdictOptimal

Flow source

# Project Euler 756: Approximating a Sum
#
# Computes E(Delta | phi(k), n, m) exactly (no simulation) for
# n = 12345678, m = 12345, where f(k) = phi(k) (Euler's totient).
#
# S  = sum_{k=1..n} f(k)
# S* = sum_{i=1..m} f(X_i) (X_i - X_{i-1})   for a random increasing m-tuple
# Delta = S - S*
#
# E(Delta) = sum_{k=1..n-m} f(k) * C(n-k, m) / C(n, m)
# with weights updated by recurrence w_{k+1} = w_k * (n-k-m)/(n-k).
#
# A rigorous tail bound truncates the sum so only the necessary initial
# part is computed, keeping the totient sieve small.

extern {
    function calloc(n: i64, size: i64) -> ptr<void>
    function free(p: ptr<void>) -> void
}

# Euler's linear sieve: phi[k] = totient(k) for 0 <= k <= n.
function totients_up_to(n: i64) -> ptr<i32> {
    let phi: ptr<i32> = calloc(n + 1, 4)
    if phi == null {
        return null
    }
    if n >= 1 {
        phi[1] = 1
    }

    # primes list — generous cap (number of primes <= n is well under n).
    let primes: ptr<i32> = calloc(n + 1, 4)
    let mut count: i64 = 0

    let mut i: i64 = 2
    while i <= n {
        if phi[i] == 0 {
            # i is prime
            primes[count] = (i as i32)
            count = count + 1
            phi[i] = ((i - 1) as i32)
        }
        let mut j: i64 = 0
        while j < count {
            let p: i64 = (primes[j] as i64)
            let ip: i64 = i * p
            if ip > n {
                break
            }
            if i % p == 0 {
                phi[ip] = (phi[i] as i64) * p
                break
            } else {
                phi[ip] = (phi[i] as i64) * (p - 1)
            }
            j = j + 1
        }
        i = i + 1
    }

    free(primes)
    return phi
}

# Find a safe truncation index K (<= n-m) such that the remaining tail
# contribution is provably < eps. Uses phi(k) <= k <= n and non-increasing
# weights: sum_{k>K} phi(k) w_k <= n * (n-m-K) * w_{K+1}.
function cutoff_index(n: i64, m: i64, eps: f64) -> i64 {
    let limit: i64 = n - m
    if limit <= 0 {
        return 0
    }

    let mut w: f64 = ((n - m) as f64) / (n as f64)
    let mut k: i64 = 1
    while k <= limit {
        let remaining: i64 = limit - k
        let nk: i64 = n - k
        let mut w_next: f64
        if nk <= m {
            w_next = 0.0
        } else {
            w_next = w * ((nk - m) as f64) / (nk as f64)
        }
        if (n as f64) * (remaining as f64) * w_next < eps {
            return k
        }
        w = w_next
        k = k + 1
    }
    return limit
}

function expected_error_for_phi(n: i64, m: i64) -> f64 {
    let limit: i64 = n - m
    if limit <= 0 {
        return 0.0
    }

    let mut upto: i64 = cutoff_index(n, m, 5e-8)
    if upto > limit {
        upto = limit
    }

    let phi: ptr<i32> = totients_up_to(upto)

    let mut w: f64 = ((n - m) as f64) / (n as f64)
    let mut total: f64 = 0.0
    let mut c: f64 = 0.0

    let mut k: i64 = 1
    while k <= upto {
        let x: f64 = ((phi[k]) as f64) * w
        # Kahan compensated summation
        let y: f64 = x - c
        let t: f64 = total + y
        c = (t - total) - y
        total = t

        let nk: i64 = n - k
        if nk <= m {
            break
        }
        w = w * ((nk - m) as f64) / (nk as f64)
        k = k + 1
    }

    free(phi)
    return total
}

function main() -> i32 {
    let n: i64 = 12345678
    let m: i64 = 12345
    printf("%.6f\n", expected_error_for_phi(n, m))
    return 0
}

Generated C

#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* Flow runtime helpers */
typedef struct flow_temp_node { struct flow_temp_node* next; } flow_temp_node;
static flow_temp_node* flow_temp_head = NULL;
static int flow_temp_atexit_set = 0;
__attribute__((unused)) static void flow_temp_free_all(void) {
    while (flow_temp_head) {
        flow_temp_node* n = flow_temp_head;
        flow_temp_head = n->next;
        free(n);
    }
}
__attribute__((unused)) static void* flow_temp_alloc(size_t nbytes) {
    flow_temp_node* node = (flow_temp_node*)malloc(sizeof(flow_temp_node) + nbytes);
    if (!node) return NULL;
    node->next = flow_temp_head;
    flow_temp_head = node;
    if (!flow_temp_atexit_set) {
        flow_temp_atexit_set = 1;
        atexit(flow_temp_free_all);
    }
    return (void*)(node + 1);
}
#ifndef FLOW_DIAG
#define FLOW_DIAG(msg) fprintf(stderr, "%s", (msg))
#endif
#ifndef FLOW_LOG
#define FLOW_LOG(fmt, ...) printf(fmt, __VA_ARGS__)
#endif
#ifndef FLOW_LOG_EMPTY
#define FLOW_LOG_EMPTY(fmt) printf(fmt)
#endif
static char* flow_strcat(const char* a, const char* b) {
    size_t la = strlen(a ? a : ""), lb = strlen(b ? b : "");
    char* r = (char*)flow_temp_alloc(la + lb + 1);
    if (!r) return NULL;
    if (la) memcpy(r, a, la);
    if (lb) memcpy(r + la, b, lb);
    r[la + lb] = '\0';
    return r;
}

#define __flow_in_arr(arr, val) __extension__ ({ \
    int _found = 0; \
    size_t _n = sizeof(arr)/sizeof((arr)[0]); \
    for (size_t _i = 0; _i < _n; _i++) { \
        if ((arr)[_i] == (val)) { _found = 1; break; } \
    } _found; })

/* Unified fault handler (MISRA #279) — override with -DFLOW_FAULT_HANDLER=fn */
#ifndef FLOW_FAULT_HANDLER
__attribute__((unused)) static inline void flow_fault_handler(const char* msg) {
    fprintf(stderr, "flow: %s\n", msg ? msg : "fault");
    abort();
#if defined(__GNUC__) || defined(__clang__)
    __builtin_unreachable();
#endif
}
#else
#define flow_fault_handler FLOW_FAULT_HANDLER
#endif
#define flow_div_by_zero_handler() flow_fault_handler("division by zero")
#define flow_shift_ub_handler() flow_fault_handler("invalid shift (amount out of range or left-shift of negative)")

#ifndef FLOW_CHECKED_DIV
#define FLOW_CHECKED_DIV(L, R) (((R) != 0) ? ((L) / (R)) : (flow_div_by_zero_handler(), (L) * 0))
#endif
#ifndef FLOW_CHECKED_MOD
#define FLOW_CHECKED_MOD(L, R) (((R) != 0) ? ((L) % (R)) : (flow_div_by_zero_handler(), (L) * 0))
#endif
#ifndef FLOW_CHECKED_SHL
#define FLOW_CHECKED_SHL(L, R) ((((R) >= 0) && ((unsigned long long)(R) < (sizeof(L) * 8ull)) && ((L) >= 0)) ? ((L) << (R)) : (flow_shift_ub_handler(), (L) * 0))
#endif
#ifndef FLOW_CHECKED_SHR
#define FLOW_CHECKED_SHR(L, R) ((((R) >= 0) && ((unsigned long long)(R) < (sizeof(L) * 8ull))) ? ((L) >> (R)) : (flow_shift_ub_handler(), (L) * 0))
#endif

#include <math.h>

void* _ui_state = NULL;

static inline float i32_to_f32(int32_t v) { return (float)v; }

/* Host stub for @gpu kernels (device codegen replaces this). */
static inline int32_t gpu_thread_id(void) { return 0; }

int32_t* totients_up_to_i64(int64_t n);
int64_t cutoff_index_i64_i64_f64(int64_t n, int64_t m, double eps);
double expected_error_for_phi_i64_i64(int64_t n, int64_t m);
int32_t main(void);



int32_t* totients_up_to_i64(int64_t n) {
    int32_t* phi = (int32_t*)(calloc((n + 1), 4));
    if (phi == NULL) {
        return NULL;
    }
    if (n >= 1) {
        phi[1] = 1;
    }
    int32_t* primes = (int32_t*)(calloc((n + 1), 4));
    int64_t count = 0;
    int64_t i = 2;
    while (i <= n) {
        if (phi[i] == 0) {
            primes[count] = ((int32_t)(i));
            count = (count + 1);
            phi[i] = ((int32_t)((i - 1)));
        }
        int64_t j = 0;
        while (j < count) {
            int64_t p = ((int64_t)(primes[j]));
            int64_t ip = (i * p);
            if (ip > n) {
                break;
            }
            if (FLOW_CHECKED_MOD((i), (p)) == 0) {
                phi[ip] = (((int64_t)(phi[i])) * p);
                break;
            } else {
                phi[ip] = (((int64_t)(phi[i])) * (p - 1));
            }
            j = (j + 1);
        }
        i = (i + 1);
    }
    free(primes);
    return phi;
}

int64_t cutoff_index_i64_i64_f64(int64_t n, int64_t m, double eps) {
    int64_t limit = (n - m);
    if (limit <= 0) {
        return 0;
    }
    double w = (((double)((n - m))) / ((double)(n)));
    int64_t k = 1;
    while (k <= limit) {
        int64_t remaining = (limit - k);
        int64_t nk = (n - k);
        double w_next;
        if (nk <= m) {
            w_next = 0.0;
        } else {
            w_next = ((w * ((double)((nk - m)))) / ((double)(nk)));
        }
        if (((((double)(n)) * ((double)(remaining))) * w_next) < eps) {
            return k;
        }
        w = w_next;
        k = (k + 1);
    }
    return limit;
}

double expected_error_for_phi_i64_i64(int64_t n, int64_t m) {
    int64_t limit = (n - m);
    if (limit <= 0) {
        return 0.0;
    }
    int64_t upto = cutoff_index_i64_i64_f64(n, m, 5e-8);
    if (upto > limit) {
        upto = limit;
    }
    int32_t* phi = (int32_t*)(totients_up_to_i64(upto));
    double w = (((double)((n - m))) / ((double)(n)));
    double total = 0.0;
    double c = 0.0;
    int64_t k = 1;
    while (k <= upto) {
        double x = (((double)(phi[k])) * w);
        double y = (x - c);
        double t = (total + y);
        c = ((t - total) - y);
        total = t;
        int64_t nk = (n - k);
        if (nk <= m) {
            break;
        }
        w = ((w * ((double)((nk - m)))) / ((double)(nk)));
        k = (k + 1);
    }
    free(phi);
    return total;
}

int32_t main(void) {
    int64_t n = 12345678;
    int64_t m = 12345;
    printf("%.6f\n", expected_error_for_phi_i64_i64(n, m));
    return 0;
}

Generated MLIR

module {
  llvm.func @printf(!llvm.ptr, ...) -> i32
  llvm.mlir.global internal constant @str_0("%.6f\n\00") {addr_space = 0 : i32} : !llvm.array<6 x i8>
  func.func private @calloc(i64, i64) -> !llvm.ptr
  func.func private @free(!llvm.ptr) -> ()
  func.func @totients_up_to(%arg0: i64) -> !llvm.ptr {
    %1 = arith.constant 1 : i32
    %3 = arith.extsi %1 : i32 to i64
    %2 = arith.addi %arg0, %3 : i64
    %4 = arith.constant 4 : i32
    %5 = arith.extsi %4 : i32 to i64
    %0 = func.call @calloc(%2, %5) : (i64, i64) -> !llvm.ptr
    %6 = llvm.mlir.zero : !llvm.ptr
    %7 = llvm.icmp "eq" %0, %6 : !llvm.ptr
    cf.cond_br %7, ^bb0, ^bb1
    ^bb0:
      %8 = llvm.mlir.zero : !llvm.ptr
      func.return %8 : !llvm.ptr
    ^bb1:
      cf.br ^bb2
    ^bb2:
    %9 = arith.constant 1 : i32
    %11 = arith.extsi %9 : i32 to i64
    %10 = arith.cmpi sge, %arg0, %11 : i64
    cf.cond_br %10, ^bb3, ^bb4
    ^bb3:
      %12 = arith.constant 1 : i32
      %13 = arith.constant 1 : i32
      %14 = arith.extsi %13 : i32 to i64
      %15 = llvm.getelementptr %0[%14] : (!llvm.ptr, i64) -> !llvm.ptr, i32
      llvm.store %12, %15 : i32, !llvm.ptr
      cf.br ^bb5
    ^bb4:
      cf.br ^bb5
    ^bb5:
    %17 = arith.constant 1 : i32
    %19 = arith.extsi %17 : i32 to i64
    %18 = arith.addi %arg0, %19 : i64
    %20 = arith.constant 4 : i32
    %21 = arith.extsi %20 : i32 to i64
    %16 = func.call @calloc(%18, %21) : (i64, i64) -> !llvm.ptr
    %22 = arith.constant 0 : i32
    %23 = arith.extsi %22 : i32 to i64
    %24 = llvm.mlir.constant(1 : i64) : i64
    %25 = llvm.alloca %24 x i64 : (i64) -> !llvm.ptr
    llvm.store %23, %25 : i64, !llvm.ptr
    %26 = arith.constant 2 : i32
    %27 = arith.extsi %26 : i32 to i64
    %28 = llvm.mlir.constant(1 : i64) : i64
    %29 = llvm.alloca %28 x i64 : (i64) -> !llvm.ptr
    llvm.store %27, %29 : i64, !llvm.ptr
    cf.br ^bb6
    ^bb6:
    %30 = llvm.load %29 : !llvm.ptr -> i64
    %31 = arith.cmpi sle, %30, %arg0 : i64
    cf.cond_br %31, ^bb7, ^bb8
    ^bb7:
      %33 = llvm.load %29 : !llvm.ptr -> i64
      %34 = llvm.getelementptr %0[%33] : (!llvm.ptr, i64) -> !llvm.ptr, i32
      %32 = llvm.load %34 : !llvm.ptr -> i32
      %35 = arith.constant 0 : i32
      %36 = arith.cmpi eq, %32, %35 : i32
      cf.cond_br %36, ^bb9, ^bb10
      ^bb9:
        %37 = llvm.load %29 : !llvm.ptr -> i64
        %38 = arith.trunci %37 : i64 to i32
        %39 = llvm.load %25 : !llvm.ptr -> i64
        %40 = llvm.getelementptr %16[%39] : (!llvm.ptr, i64) -> !llvm.ptr, i32
        llvm.store %38, %40 : i32, !llvm.ptr
        %41 = llvm.load %25 : !llvm.ptr -> i64
        %42 = arith.constant 1 : i32
        %44 = arith.extsi %42 : i32 to i64
        %43 = arith.addi %41, %44 : i64
        llvm.store %43, %25 : i64, !llvm.ptr
        %45 = llvm.load %29 : !llvm.ptr -> i64
        %46 = arith.constant 1 : i32
        %48 = arith.extsi %46 : i32 to i64
        %47 = arith.subi %45, %48 : i64
        %49 = arith.trunci %47 : i64 to i32
        %50 = llvm.load %29 : !llvm.ptr -> i64
        %51 = llvm.getelementptr %0[%50] : (!llvm.ptr, i64) -> !llvm.ptr, i32
        llvm.store %49, %51 : i32, !llvm.ptr
        cf.br ^bb11
      ^bb10:
        cf.br ^bb11
      ^bb11:
      %52 = arith.constant 0 : i32
      %53 = arith.extsi %52 : i32 to i64
      %54 = llvm.mlir.constant(1 : i64) : i64
      %55 = llvm.alloca %54 x i64 : (i64) -> !llvm.ptr
      llvm.store %53, %55 : i64, !llvm.ptr
      cf.br ^bb12
      ^bb12:
      %56 = llvm.load %55 : !llvm.ptr -> i64
      %57 = llvm.load %25 : !llvm.ptr -> i64
      %58 = arith.cmpi slt, %56, %57 : i64
      cf.cond_br %58, ^bb13, ^bb14
      ^bb13:
        %60 = llvm.load %55 : !llvm.ptr -> i64
        %61 = llvm.getelementptr %16[%60] : (!llvm.ptr, i64) -> !llvm.ptr, i32
        %59 = llvm.load %61 : !llvm.ptr -> i32
        %62 = arith.extsi %59 : i32 to i64
        %63 = llvm.load %29 : !llvm.ptr -> i64
        %64 = arith.muli %63, %62 : i64
        %65 = arith.cmpi sgt, %64, %arg0 : i64
        cf.cond_br %65, ^bb15, ^bb16
        ^bb15:
          cf.br ^bb14
        ^bb16:
          cf.br ^bb17
        ^bb17:
        %66 = llvm.load %29 : !llvm.ptr -> i64
        %67 = arith.remsi %66, %62 : i64
        %68 = arith.constant 0 : i32
        %70 = arith.extsi %68 : i32 to i64
        %69 = arith.cmpi eq, %67, %70 : i64
        cf.cond_br %69, ^bb18, ^bb19
        ^bb18:
          %72 = llvm.load %29 : !llvm.ptr -> i64
          %73 = llvm.getelementptr %0[%72] : (!llvm.ptr, i64) -> !llvm.ptr, i32
          %71 = llvm.load %73 : !llvm.ptr -> i32
          %74 = arith.extsi %71 : i32 to i64
          %75 = arith.muli %74, %62 : i64
          %76 = arith.trunci %75 : i64 to i32
          %77 = llvm.getelementptr %0[%64] : (!llvm.ptr, i64) -> !llvm.ptr, i32
          llvm.store %76, %77 : i32, !llvm.ptr
          cf.br ^bb14
        ^bb19:
          %79 = llvm.load %29 : !llvm.ptr -> i64
          %80 = llvm.getelementptr %0[%79] : (!llvm.ptr, i64) -> !llvm.ptr, i32
          %78 = llvm.load %80 : !llvm.ptr -> i32
          %81 = arith.extsi %78 : i32 to i64
          %82 = arith.constant 1 : i32
          %84 = arith.extsi %82 : i32 to i64
          %83 = arith.subi %62, %84 : i64
          %85 = arith.muli %81, %83 : i64
          %86 = arith.trunci %85 : i64 to i32
          %87 = llvm.getelementptr %0[%64] : (!llvm.ptr, i64) -> !llvm.ptr, i32
          llvm.store %86, %87 : i32, !llvm.ptr
          cf.br ^bb20
        ^bb20:
        %88 = llvm.load %55 : !llvm.ptr -> i64
        %89 = arith.constant 1 : i32
        %91 = arith.extsi %89 : i32 to i64
        %90 = arith.addi %88, %91 : i64
        llvm.store %90, %55 : i64, !llvm.ptr
        cf.br ^bb12
      ^bb14:
      %92 = llvm.load %29 : !llvm.ptr -> i64
      %93 = arith.constant 1 : i32
      %95 = arith.extsi %93 : i32 to i64
      %94 = arith.addi %92, %95 : i64
      llvm.store %94, %29 : i64, !llvm.ptr
      cf.br ^bb6
    ^bb8:
    func.call @free(%16) : (!llvm.ptr) -> ()
    func.return %0 : !llvm.ptr
  }
  func.func @cutoff_index(%arg0: i64, %arg1: i64, %arg2: f64) -> i64 {
    %97 = arith.subi %arg0, %arg1 : i64
    %98 = arith.constant 0 : i32
    %100 = arith.extsi %98 : i32 to i64
    %99 = arith.cmpi sle, %97, %100 : i64
    cf.cond_br %99, ^bb21, ^bb22
    ^bb21:
      %101 = arith.constant 0 : i32
      %102 = arith.extsi %101 : i32 to i64
      func.return %102 : i64
    ^bb22:
      cf.br ^bb23
    ^bb23:
    %103 = arith.subi %arg0, %arg1 : i64
    %104 = arith.sitofp %103 : i64 to f64
    %105 = arith.sitofp %arg0 : i64 to f64
    %106 = arith.divf %104, %105 : f64
    %107 = llvm.mlir.constant(1 : i64) : i64
    %108 = llvm.alloca %107 x f64 : (i64) -> !llvm.ptr
    llvm.store %106, %108 : f64, !llvm.ptr
    %109 = arith.constant 1 : i32
    %110 = arith.extsi %109 : i32 to i64
    %111 = llvm.mlir.constant(1 : i64) : i64
    %112 = llvm.alloca %111 x i64 : (i64) -> !llvm.ptr
    llvm.store %110, %112 : i64, !llvm.ptr
    cf.br ^bb24
    ^bb24:
    %113 = llvm.load %112 : !llvm.ptr -> i64
    %114 = arith.cmpi sle, %113, %97 : i64
    cf.cond_br %114, ^bb25, ^bb26
    ^bb25:
      %115 = llvm.load %112 : !llvm.ptr -> i64
      %116 = arith.subi %97, %115 : i64
      %117 = llvm.load %112 : !llvm.ptr -> i64
      %118 = arith.subi %arg0, %117 : i64
      %119 = llvm.mlir.undef : f64
      %120 = arith.cmpi sle, %118, %arg1 : i64
      %121 = scf.if %120 -> (f64) {
        %122 = arith.constant 0.0 : f32
        %123 = arith.extf %122 : f32 to f64
        scf.yield %123 : f64
      } else {
        %124 = llvm.load %108 : !llvm.ptr -> f64
        %125 = arith.subi %118, %arg1 : i64
        %126 = arith.sitofp %125 : i64 to f64
        %127 = arith.mulf %124, %126 : f64
        %128 = arith.sitofp %118 : i64 to f64
        %129 = arith.divf %127, %128 : f64
        scf.yield %129 : f64
      }
      %130 = arith.sitofp %arg0 : i64 to f64
      %131 = arith.sitofp %116 : i64 to f64
      %132 = arith.mulf %130, %131 : f64
      %133 = arith.mulf %132, %121 : f64
      %134 = arith.cmpf olt, %133, %arg2 : f64
      cf.cond_br %134, ^bb27, ^bb28
      ^bb27:
        %135 = llvm.load %112 : !llvm.ptr -> i64
        func.return %135 : i64
      ^bb28:
        cf.br ^bb29
      ^bb29:
      llvm.store %121, %108 : f64, !llvm.ptr
      %136 = llvm.load %112 : !llvm.ptr -> i64
      %137 = arith.constant 1 : i32
      %139 = arith.extsi %137 : i32 to i64
      %138 = arith.addi %136, %139 : i64
      llvm.store %138, %112 : i64, !llvm.ptr
      cf.br ^bb24
    ^bb26:
    func.return %97 : i64
  }
  func.func @expected_error_for_phi(%arg0: i64, %arg1: i64) -> f64 {
    %140 = arith.subi %arg0, %arg1 : i64
    %141 = arith.constant 0 : i32
    %143 = arith.extsi %141 : i32 to i64
    %142 = arith.cmpi sle, %140, %143 : i64
    cf.cond_br %142, ^bb30, ^bb31
    ^bb30:
      %144 = arith.constant 0.0 : f32
      %145 = arith.extf %144 : f32 to f64
      func.return %145 : f64
    ^bb31:
      cf.br ^bb32
    ^bb32:
    %147 = arith.constant 0.00000005 : f32
    %148 = arith.extf %147 : f32 to f64
    %146 = func.call @cutoff_index(%arg0, %arg1, %148) : (i64, i64, f64) -> i64
    %149 = llvm.mlir.constant(1 : i64) : i64
    %150 = llvm.alloca %149 x i64 : (i64) -> !llvm.ptr
    llvm.store %146, %150 : i64, !llvm.ptr
    %151 = llvm.load %150 : !llvm.ptr -> i64
    %152 = arith.cmpi sgt, %151, %140 : i64
    cf.cond_br %152, ^bb33, ^bb34
    ^bb33:
      llvm.store %140, %150 : i64, !llvm.ptr
      cf.br ^bb35
    ^bb34:
      cf.br ^bb35
    ^bb35:
    %154 = llvm.load %150 : !llvm.ptr -> i64
    %153 = func.call @totients_up_to(%154) : (i64) -> !llvm.ptr
    %155 = arith.subi %arg0, %arg1 : i64
    %156 = arith.sitofp %155 : i64 to f64
    %157 = arith.sitofp %arg0 : i64 to f64
    %158 = arith.divf %156, %157 : f64
    %159 = llvm.mlir.constant(1 : i64) : i64
    %160 = llvm.alloca %159 x f64 : (i64) -> !llvm.ptr
    llvm.store %158, %160 : f64, !llvm.ptr
    %161 = arith.constant 0.0 : f32
    %162 = arith.extf %161 : f32 to f64
    %163 = llvm.mlir.constant(1 : i64) : i64
    %164 = llvm.alloca %163 x f64 : (i64) -> !llvm.ptr
    llvm.store %162, %164 : f64, !llvm.ptr
    %165 = arith.constant 0.0 : f32
    %166 = arith.extf %165 : f32 to f64
    %167 = llvm.mlir.constant(1 : i64) : i64
    %168 = llvm.alloca %167 x f64 : (i64) -> !llvm.ptr
    llvm.store %166, %168 : f64, !llvm.ptr
    %169 = arith.constant 1 : i32
    %170 = arith.extsi %169 : i32 to i64
    %171 = llvm.mlir.constant(1 : i64) : i64
    %172 = llvm.alloca %171 x i64 : (i64) -> !llvm.ptr
    llvm.store %170, %172 : i64, !llvm.ptr
    cf.br ^bb36
    ^bb36:
    %173 = llvm.load %172 : !llvm.ptr -> i64
    %174 = llvm.load %150 : !llvm.ptr -> i64
    %175 = arith.cmpi sle, %173, %174 : i64
    cf.cond_br %175, ^bb37, ^bb38
    ^bb37:
      %177 = llvm.load %172 : !llvm.ptr -> i64
      %178 = llvm.getelementptr %153[%177] : (!llvm.ptr, i64) -> !llvm.ptr, i32
      %176 = llvm.load %178 : !llvm.ptr -> i32
      %179 = arith.sitofp %176 : i32 to f64
      %180 = llvm.load %160 : !llvm.ptr -> f64
      %181 = arith.mulf %179, %180 : f64
      %182 = llvm.load %168 : !llvm.ptr -> f64
      %183 = arith.subf %181, %182 : f64
      %184 = llvm.load %164 : !llvm.ptr -> f64
      %185 = arith.addf %184, %183 : f64
      %186 = llvm.load %164 : !llvm.ptr -> f64
      %187 = arith.subf %185, %186 : f64
      %188 = arith.subf %187, %183 : f64
      llvm.store %188, %168 : f64, !llvm.ptr
      llvm.store %185, %164 : f64, !llvm.ptr
      %189 = llvm.load %172 : !llvm.ptr -> i64
      %190 = arith.subi %arg0, %189 : i64
      %191 = arith.cmpi sle, %190, %arg1 : i64
      cf.cond_br %191, ^bb39, ^bb40
      ^bb39:
        cf.br ^bb38
      ^bb40:
        cf.br ^bb41
      ^bb41:
      %192 = llvm.load %160 : !llvm.ptr -> f64
      %193 = arith.subi %190, %arg1 : i64
      %194 = arith.sitofp %193 : i64 to f64
      %195 = arith.mulf %192, %194 : f64
      %196 = arith.sitofp %190 : i64 to f64
      %197 = arith.divf %195, %196 : f64
      llvm.store %197, %160 : f64, !llvm.ptr
      %198 = llvm.load %172 : !llvm.ptr -> i64
      %199 = arith.constant 1 : i32
      %201 = arith.extsi %199 : i32 to i64
      %200 = arith.addi %198, %201 : i64
      llvm.store %200, %172 : i64, !llvm.ptr
      cf.br ^bb36
    ^bb38:
    func.call @free(%153) : (!llvm.ptr) -> ()
    %203 = llvm.load %164 : !llvm.ptr -> f64
    func.return %203 : f64
  }
  func.func @main() -> i32 {
    %204 = arith.constant 12345678 : i32
    %205 = arith.extsi %204 : i32 to i64
    %206 = arith.constant 12345 : i32
    %207 = arith.extsi %206 : i32 to i64
    %208 = llvm.mlir.addressof @str_0 : !llvm.ptr
    %209 = func.call @expected_error_for_phi(%205, %207) : (i64, i64) -> f64
    %210 = llvm.call @printf(%208, %209) vararg(!llvm.func<i32 (ptr, ...)>) : (!llvm.ptr, f64) -> i32
    %211 = arith.constant 0 : i32
    func.return %211 : i32
  }
}