CS-PROJECTS / fuzzylloyd / oracle.c
oracle.c
Raw
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "oracle.h"

void oracle(double* data,long start,long n){
    // I picked randomish seeds. It shouldn't matter much
    long seeds[] = {28470,31023,4437};
    double w;
    int i;

    // Advance the seeds
    // Double the number of values to skip point since
    // each data point takes two random numbers.
    rand_look_ahead(start*2,seeds);

    // To approximate the long term behavior of a random walk,
    // assume that the start steps before we began
    // reached a distance of sqrt(start)/2 from the origin
    w = rand_advance(seeds);
    w *= sqrt(start)/2;
    for(i=0;i<n;++i){
        data[2*i] = w;
        w += rand_advance(seeds)*2-1;
    }

    w = rand_advance(seeds);
    w *= sqrt(start)/2;
    for(i=0;i<n;++i){
        data[2*i+1] = w;
        w += rand_advance(seeds)*2-1;
    }
}

// Based on
// https://en.wikipedia.org/wiki/Wichmann%E2%80%93Hill
void rand_look_ahead(long n,long* seeds){
    const static long m[] = {30269,30307,30323};
    const static long t[] = {171,172,170};

    int i;
    for(i=0;i<3;++i){
        seeds[i] *= pow_mod(t[i],n,m[i]);
        seeds[i] %= m[i];
    }

}

double rand_advance(long* seeds){
    const static long m[] = {30269,30307,30323};
    const static long t[] = {171,172,170};
    int i;
    double sum = 0;
    for(i=0;i<3;++i){
        seeds[i] = seeds[i]*t[i] % m[i];
        sum += (double)seeds[i] / m[i];
    }
    double x = sum - (int)sum;
    return x;
}

long pow_mod(long b,long p,long m){
    if(p == 0)
        return 1;
    long a;
    if(p%2 == 0){
        a = pow_mod(b,p/2,m);
        return a*a % m;
    }
    a = pow_mod(b,p-1,m);
    return a*b % m;
}