#include <stdio.h>
#include <math.h>
#include "zufall.h"

/*-
 * portable lagged Fibonacci series uniform random number generator with
 * "lags" -273 und -607:
 *
 *        t    = u(i-273)+buff(i-607)  (floating pt.)
 *        u(i) = t - float(int(t))
 *
 * W.P. Petersen, IPS, ETH Zuerich, 19 Mar. 92
 */

struct klotz0 klotz0_1;
struct klotz1 klotz1_1;

int zufall(int n, double *a)
{
    static int buffsz = 607;
    int left, aptr, bptr, aptr0, i, k, q, nn, vl, qq, k273, k607;
    double t;
    extern struct klotz0 klotz0_1;

    --a;
    aptr = 0;
    nn = n;

L1:
    if (nn <= 0)
        return 0;

    q = (nn - 1) / 607; /* factor nn = q*607 + r */
    left = buffsz - klotz0_1.ptr;

    if (q <= 1) { /* only one or fewer full segments */
        if (nn < left) {
            for (i = 1; i <= nn; ++i)
                a[i + aptr] = klotz0_1.buff[klotz0_1.ptr + i - 1];
            klotz0_1.ptr += nn;
            return 0;
        }
        else {
            for (i = 1; i <= left; ++i)
                a[i + aptr] = klotz0_1.buff[klotz0_1.ptr + i - 1];
            klotz0_1.ptr = 0;
            aptr += left;
            nn -= left;
            /* buff -> buff case */
            vl = 273;
            k273 = 334;
            k607 = 0;
            for (k = 1; k <= 3; ++k) {
                /* dir$ ivdep */
                /* vdir nodep */
                /* VOCL LOOP, TEMP(t), NOVREC(buff) */
                for (i = 1; i <= vl; ++i) {
                    t = klotz0_1.buff[k273 + i - 1] +
                        klotz0_1.buff[k607 + i - 1];
                    klotz0_1.buff[k607 + i - 1] = t - (float)((int)t);
                }
                k607 += vl;
                k273 += vl;
                vl = 167;
                if (k == 1) {
                    k273 = 0;
                }
            }
            goto L1;
        }
    }
    else {
        /* more than 1 full segment */
        for (i = 1; i <= left; ++i)
            a[i + aptr] = klotz0_1.buff[klotz0_1.ptr + i - 1];
        nn -= left;
        klotz0_1.ptr = 0;
        aptr += left;

        /* buff -> a(aptr0) */

        vl = 273;
        k273 = 334;
        k607 = 0;
        for (k = 1; k <= 3; ++k) {
            if (k == 1) {
                /* VOCL LOOP, TEMP(t) */
                for (i = 1; i <= vl; ++i) {
                    t = klotz0_1.buff[k273 + i - 1] +
                        klotz0_1.buff[k607 + i - 1];
                    a[aptr + i] = t - (float)((int)t);
                }
                k273 = aptr;
                k607 += vl;
                aptr += vl;
                vl = 167;
            }
            else {
                /* dir$ ivdep */
                /* vdir nodep */
                /* VOCL LOOP, TEMP(t) */
                for (i = 1; i <= vl; ++i) {
                    t = a[k273 + i] + klotz0_1.buff[k607 + i - 1];
                    a[aptr + i] = t - (float)((int)t);
                }
                k607 += vl;
                k273 += vl;
                aptr += vl;
            }
        }
        nn += -607;

        /* a(aptr-607) -> a(aptr) for last of the q-1 segments */

        aptr0 = aptr - 607;
        vl = 607;

        /* vdir novector */
        for (qq = 1; qq <= q - 2; ++qq) {
            k273 = aptr0 + 334;
            /* dir$ ivdep */
            /* vdir nodep */
            /* VOCL LOOP, TEMP(t), NOVREC(a) */
            for (i = 1; i <= vl; ++i) {
                t = a[k273 + i] + a[aptr0 + i];
                a[aptr + i] = t - (float)((int)t);
            }
            nn += -607;
            aptr += vl;
            aptr0 += vl;
        }

        /* a(aptr0) -> buff, last segment before residual */

        vl = 273;
        k273 = aptr0 + 334;
        k607 = aptr0;
        bptr = 0;
        for (k = 1; k <= 3; ++k) {
            if (k == 1) {
                /* VOCL LOOP, TEMP(t) */
                for (i = 1; i <= vl; ++i) {
                    t = a[k273 + i] + a[k607 + i];
                    klotz0_1.buff[bptr + i - 1] = t - (double)((int)t);
                }
                k273 = 0;
                k607 += vl;
                bptr += vl;
                vl = 167;
            }
            else {
                /* dir$ ivdep */
                /* vdir nodep */
                /* VOCL LOOP, TEMP(t), NOVREC(buff) */
                for (i = 1; i <= vl; ++i) {
                    t = klotz0_1.buff[k273 + i - 1] + a[k607 + i];
                    klotz0_1.buff[bptr + i - 1] = t - (float)((int)t);
                }
                k607 += vl;
                k273 += vl;
                bptr += vl;
            }
        }
        goto L1;
    }
} /* zufall */
