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

enum {
    MAX = ~0ull,
    base = 1ull << 32
};

uint64_t clamp_mul(uint64_t a, uint64_t b)
{
    if (MAX / a < b) return MAX;
    
    return a * b;
}

uint64_t mod_mul(uint64_t a, uint64_t b)
{
    uint64_t a1 = a / base;
    uint64_t a0 = a % base;
    uint64_t b1 = b / base;
    uint64_t b0 = b % base;
    
    uint64_t lo = a0 * b0;
    uint64_t hi = clamp_mul(a1, b0) % base
                + clamp_mul(a0, b1) % base
                + lo / base;
                
    return (hi % base) * base + (lo % base);
}

uint64_t stdc_mul(uint64_t a, uint64_t b)
{
    return a * b;
}

void roll(unsigned n, uint64_t a, uint64_t x, 
    uint64_t (*mul)(uint64_t a, uint64_t b))
{
    while (n-- ) {
        x = mul(x, a);
        
        printf("%lu\n", x);
    }
    
    puts("");
}


int main(void)
{
    uint64_t a = 1181783497276652981ull;
    uint64_t x = 1000000000;
    
    unsigned n = 10;
    
    puts("Matlab:");    roll(n, a, x, clamp_mul);
    puts("Std C");      roll(n, a, x, stdc_mul);
    puts("Modulo");     roll(n, a, x, mod_mul);
    
    return 0;
}
