Ressu 2.0 Uusi limitin laskenta

Kaikki oikeudet pidätetään. Edellinen posti jäi auki limitin laskennan osalta. Edellisessä kokeiltiin sqrt() ja cbrt() funktioita, mutta todellisuudessa kumpikaan niistä ei toimi halutulla tavalla. Tässä postissa limit lasketaan selailemalla vaihteluja alimmasta ylimpään, ja tarkastamalla onko edellinen vaihtelu*1.6 suurempi kun tämän kierroksen vaihtelu. Tässä postissa on myös muutos debukkaustulosteeseen. Edellisessä postissa kerroin että kellojono koostuu perusmateriaalista ja pienistä vaihteluista, joista jälkimmäistä käytetään teoreettisten satunnaisbittien laskentaan. newressu.deb tulosteeseen on lisätty merkkijono chains, joka listaa perusjonon tähtinä ja pienemmät vaihtelut numeroina.

Jos haluat kokeilla edellisen postin satunnaislukulelua kopioi sen vaatimat rutiinit edellisestä postista tämän generaattorin perään.

Taas kerran vanha tuttu millisekuntien alimman merkin lukemiseen. Tässä rutiinissa on pieni muutos, joka tallettaa kellojonon newressu.deb raportin chains kenttää varten. (DEBUG4)

unsigned long periods[1024];
unsigned long genbytes=0;
unsigned long clockbytes=0;

#define DEBUG2 2
#define DEBUG4 2

#ifdef DEBUG4
unsigned char cc[256*1048576]; // clock_chain
unsigned char *ccp;
int cc_bytes;
#endif

unsigned char ressu_clockbyte() /* JariK 2013 */
{
  unsigned char c;
  struct timeval tv;
  gettimeofday(&tv, NULL);
  c=tv.tv_usec & 0xff;
#ifdef DEBUG4
  if(cc_bytes<sizeof(cc)) {
    *ccp++ = c;
    cc_bytes++;
  }
#endif
  return(c);
}

Seuraava rutiini on kuten edellisessä postissa, se tekee yhden kierroksen satunnaisbittigeneraattoria. Huomaa että tässä yhteen kierrokseen kuuluvat kaikki kahdeksan bittiä.

void ressu_genbytes_fast(int size, unsigned char *buffer)
{
  int c, d, e, byte;
  static int f = 0, prevbyte = -1, count = 0;

  for(c=0; c<8; c++) {
    for(d=0; d<size; d++) {
      e = buffer[d];
      e = ((e&0x80)>>7) | ((e&0x7f)<<1); // rotate left 1
      //e=((e&0xe0)>>5) | ((e&0x1f)<<3); // rotate left 3
      //e=((e&0xfe)>>1) | ((e&0x1)<<7);  // rotate right 1
      byte = ressu_clockbyte();
      if(prevbyte==-1)
        prevbyte=byte;
      buffer[d] = e^byte;
      if(prevbyte!=byte) {
        periods[count]++;
        clockbytes+=count;
        count=0;
        prevbyte=byte;
      }
      count++;
    }
    for(d=0; d<size; d++) {
      f = (f+buffer[d])%size;
      e = buffer[d];
      buffer[d] = buffer[f];
      buffer[f] = e;
    }
  }
}

Tämä on varsinainen asiakkaan käyttämä satunnaislukujen generointirutiini. Limitin laskennan muutos on while (ok) kappaleessa. Luuppi kiertää kelloketjut läpi yksi kerrallaan pienimmästä suurimpaan. Jokaisesta kelloketjusta verrataan kelloketjujen lukumäärää ja edellisten kelloketjujen lukumäärää. Jos kelloketjujen lukumäärä on pienempi kuin edellisten kelloketjujen lukumäärä * 1.6 kelloketju kuuluu pienten ketjujen joukkoon jos taas suurempi, se kuuluu ohitettavien kelloketjujen joukkoon. Limitiksi jää viimeinen kelvannut kelloketju.

#define RESSUT_BYTES 4096
#define RESSU_BITS_NEEDED 128
#define RESSU_MIN_ROUNDS 2

int ressu_bits_needed=RESSU_BITS_NEEDED;
int ressut_bytes = RESSUT_BYTES;

void ressu_genbytes(int size, unsigned char *buffer) // 6.5.2021 JariK
{
  int c,d,e;
  static int ressut_first=1,
    ressut_pos = 0,
    ressut_f = 0;
  static unsigned char ressut[RESSUT_BYTES];

  for(c=0; c<size; c++) {
    if(ressut_pos == 0) {
      if(ressut_first) {
        memset(ressut,0,ressut_bytes);
        ressut_first=0;
      }

      clockbytes=0;
      for(d=0;d<1024;d++)
        periods[d]=0;

#ifdef DEBUG4
      ccp=cc;
      cc_bytes=0;
#endif

#ifdef DEBUG2
      while(ressu_clockbyte()!=0);
      while(ressu_clockbyte()==0);
#endif

#ifdef DEBUG4
      ccp=cc;
      cc_bytes=0;
#endif

      int rndbits=0, rounds=0;
      int lim1, lim2, lim3, lim=0;

      for(d=0; rndbits<ressu_bits_needed ||
          d<RESSU_MIN_ROUNDS; d++) {

        rounds++;

        ressu_genbytes_fast(ressut_bytes,ressut);

        lim=1;

        int ok=1, f, prevf=-1;
        while(ok==1) {
          ok=0;
          f=-1;
          for(e=0;e<1024;e++) {
            if(periods[e]>lim && (f==-1 || periods[e]<f)) {
              f=periods[e];
            }
          }
          if(prevf==-1 || (f!=-1 &&f<=(double)prevf*1.6)) {
            lim=f;
            prevf=f;
            ok=1;
          }
        } // while(ok==1)
        lim1=lim;

        // find next greater than lim

        f=-1;
        for(e=0;e<1024;e++) {
          if(periods[e]>lim && (f==-1 || periods[e]<f))
            f=periods[e];
        }
        lim2=f;
        lim=lim2;

        int prev_rndbits=rndbits;
        rndbits=0;
        for(e=0;e<1024;e++) {
          if(periods[e]>0 && periods[e]<lim) {
            rndbits+=periods[e];
          }
        }

        if(rndbits==0 || prev_rndbits == rndbits) { // restart
          clockbytes=0;
          for(e=0;e<1024;e++)
            periods[e]=0;
          ccp=cc;
          cc_bytes=0;
          rndbits=0;
        }
      } // for(d=0;

#ifdef DEBUG4
      FILE *fp1;
      if((fp1=fopen("newressu.deb","a"))!=NULL) {

        for(d=0;d<32;d++)
          fprintf(fp1,"%02x",ressut[d]);

        fprintf(fp1,", ressut_bytes: %d",ressut_bytes);
        fprintf(fp1,", ressu_bits_needed: %d",ressu_bits_needed);
        fprintf(fp1,", clockbytes: %ld",clockbytes);

        unsigned long total=0;
        fprintf(fp1,", fluctuations:");
        for(d=0;d<1024;d++) {
          if(periods[d]!=0) {
            fprintf(fp1," %d:%lu",d,periods[d]);
            total+=(periods[d]*d);
          }
        }
        fprintf(fp1,", total: %lu",total);

        fprintf(fp1,", limit1: %d",lim1);
        fprintf(fp1,", limit2: %d",lim2);

        fprintf(fp1,", limit: %d",lim);

        fprintf(fp1,", skipped:");

        for(d=0;d<1024;d++) {
          if(periods[d]>=lim) {
            fprintf(fp1," %d:%lu",d,periods[d]);
          }
        }

        fprintf(fp1,", counted:");
        for(d=0;d<1024;d++) {
          if(periods[d]>0 && periods[d]<lim) {
            fprintf(fp1," %d:%lu",d,periods[d]);
          }
        }
        fprintf(fp1,", rndbits: %d",rndbits);
        fprintf(fp1,", rounds: %d",rounds);

        int prevbyte=-1, count=0, count2=0;
        unsigned char byte, small=-1;
        fprintf(fp1,", chains:");
        for(d=0;d<cc_bytes;d++) {
          byte=cc[d];
          if(prevbyte==-1) {
            prevbyte=byte;
            count=1;
          }
          if(prevbyte!=byte) {
            if(periods[count]>=lim) {
              if(small==1 || small==-1)
                fprintf(fp1," *");
              small=0;
            } else small=1;
            if(small) {
              fprintf(fp1," %d",count);
              count2++;
            }
            count=0;
            prevbyte=byte;
          }
          count++;
        }
        if(small) {
          fprintf(fp1," %d",count);
          count2++;
        }
        fprintf(fp1,", count: %d",count2);

        fprintf(fp1,"\n");
        fflush(fp1);
        fclose(fp1);
      } // if((fp1=fopen
#endif
    } // if(ressut_pos == 0)
    ressut_f = (ressut_f + ressut[ressut_pos]) % ressut_bytes;
    buffer[c] ^= ressut[ressut_f];
    ressut_pos = (ressut_pos+1) % ressut_bytes;
  } // for(c=0; c<size; c++)

  genbytes+=size;
}

Seuraavassa esimerkki debukkailurivistä: bytes kertoo sisäisen puskurin koon. bits needed kertoo, kuinka monta pikkuketjua tarvitaan. clockbytes kertoo, kuinka paljon kelloketjua on käytetty. fluctuations kertoo tämän ressu ajon vaihtelut. total kertoo loppusumman fluctuations kentästä. limit1 kertoo pikkuvaihtelujen suurimman arvon. limit2 kertoo isojen vaihtelujen pienimmän kentän. skipped luettelee ohitetut isot vaihtelut. counted taas listaa teoreettisiin satunnaisbitteihin lasketut vaihtelut. rndbits kertoo counted kentässä olevien ketjujen lukumäärän. rounds kertoo tällä kerralla ajettujen kierrostan lukumääärän. chains näyttää ajon kellojonojen rakenteen.

Chainssissa perusmerkkijonoa kuvataan tähdillä. Tähdillä merkityt jonot ovat listassa ohitettujen alla. Numeroilla kuvataan pieniä vaihteluita. Kuten sanottu kellojono on enimmäkseen perusmateriaalia, ja lyhyitä jonoja on satunnaisesti koko kellojonon matkalla. Chains kentän jälkeen on count kenttä, joka kertoo lyhyiden ketjujen määrän chains:issa. Count kenttä pyöristyy ylöspäin lähimpään kierrokseen, joten se on tavallisesti suurempi kuin bits_needed kenttä.

82e936ee06841321134b74b2981f8df79a001999ee43bebb38f7302d77513ccc, ressut_bytes: 4096, ressu_bits_needed: 128, clockbytes: 163826, fluctuations: 1:16 2:10 3:11 4:10 5:10 6:21 7:10 8:10 9:15 10:12 11:9 12:25 13:2225 14:9558, total: 163826, limit1: 25, limit2: 2225, limit: 2225, skipped: 13:2225 14:9558, counted: 1:16 2:10 3:11 4:10 5:10 6:21 7:10 8:10 9:15 10:12 11:9 12:25, rndbits: 159, rounds: 5, chains: 10 * 10 5 * 7 6 * 10 5 * 7 8 * 12 8 * 4 10 * 2 5 * 9 5 * 3 * 9 4 * 8 6 * 9 * 9 1 * 3 1 * 11 1 * 2 8 * 4 10 * 6 1 * 11 3 * 7 * 4 10 * 9 12 * 1 12 * 9 12 * 2 12 * 10 * 2 12 * 6 * 6 8 * 1 6 * 7 1 * 12 * 6 10 * 1 12 * 7 11 * 12 * 6 1 6 * 12 * 12 * 11 4 * 12 * 7 3 * 3 * 9 6 * 8 6 * 3 5 * 9 6 * 6 12 * 1 12 * 2 12 * 2 12 * 9 10 * 4 10 * 2 6 * 6 1 5 * 12 * 12 * 12 12 * 1 * 4 11 * 3 * 12 2 * 4 * 3 * 5 * 9 6 * 7 6 * 10 6 * 3 3 * 1 9 * 12 1 * 11 * 9 1 * 2 * 12 * 9 8 * 5 10 * 7 8 * 6 8 * 12 * 5 2 * 11 4 * 6 11 * 1 12 * 4 5 * 7 7 * 9 3 * 8 6 * 10 11 *, count: 159

Lopuksi vielä generaattori ilman debukkailulauseita:

unsigned long periods[1024];
unsigned long genbytes=0;
unsigned long clockbytes=0;

unsigned char ressu_clockbyte() /* JariK 2013 */
{
  unsigned char c;
  struct timeval tv;
  gettimeofday(&tv, NULL);
  c=tv.tv_usec & 0xff;
  return(c);
}

void ressu_genbytes_fast(int size, unsigned char *buffer)
{
  int c, d, e, byte;
  static int f = 0, prevbyte = -1, count = 0;

  for(c=0; c<8; c++) {
    for(d=0; d<size; d++) {
      e = buffer[d];
      e = ((e&0x80)>>7) | ((e&0x7f)<<1); // rotate left 1
      //e=((e&0xe0)>>5) | ((e&0x1f)<<3); // rotate left 3
      //e=((e&0xfe)>>1) | ((e&0x1)<<7);  // rotate right 1
      byte = ressu_clockbyte();
      if(prevbyte==-1)
        prevbyte=byte;
      buffer[d] = e^byte;
      if(prevbyte!=byte) {
        periods[count]++;
        clockbytes+=count;
        count=0;
        prevbyte=byte;
      }
      count++;
    }
    for(d=0; d<size; d++) {
      f = (f+buffer[d])%size;
      e = buffer[d];
      buffer[d] = buffer[f];
      buffer[f] = e;
    }
  }
}

#define RESSUT_BYTES 4096
#define RESSU_BITS_NEEDED 128
#define RESSU_MIN_ROUNDS 2

int ressu_bits_needed=RESSU_BITS_NEEDED;
int ressut_bytes = RESSUT_BYTES;

void ressu_genbytes(int size, unsigned char *buffer) // 6.5.2021 JariK
{
  int c,d,e;
  static int ressut_first=1,
    ressut_pos = 0,
    ressut_f = 0;
  static unsigned char ressut[RESSUT_BYTES];

  for(c=0; c<size; c++) {
    if(ressut_pos == 0) {
      if(ressut_first) {
        memset(ressut,0,ressut_bytes);
        ressut_first=0;
      }

      clockbytes=0;
      for(d=0;d<1024;d++)
        periods[d]=0;

      int rndbits=0, lim;

      for(d=0; rndbits<ressu_bits_needed ||
          d<RESSU_MIN_ROUNDS; d++) {

        ressu_genbytes_fast(ressut_bytes,ressut);

        lim=1;

        int ok=1, f, prevf=-1;

        while(ok==1) {
          ok=0;
          f=-1;
          for(e=0;e<1024;e++) {
            if(periods[e]>lim && (f==-1 || periods[e]<f)) {
              f=periods[e];
            }
          }
          if(prevf==-1 || f<=(double)prevf*1.6) {
            lim=f;
            prevf=f;
            ok=1;
          }
        }

        // find next greater than lim

        f=-1;
        for(e=0;e<1024;e++) {
          if(periods[e]>lim && (f==-1 || periods[e]<f))
            f=periods[e];
        }
        lim=f;

        int prev_rndbits=rndbits;

        rndbits=0;
        for(e=0;e<1024;e++) {
          if(periods[e]>0 && periods[e]<lim) {
            rndbits+=periods[e];
          }
        }

        if(rndbits==0 || prev_rndbits == rndbits) { // restart
          clockbytes=0;
          for(e=0;e<1024;e++)
            periods[e]=0;
          rndbits=0;
        }
      } // for(d=0;
    } // if(ressut_pos == 0)
    ressut_f = (ressut_f + ressut[ressut_pos]) % ressut_bytes;
    buffer[c] ^= ressut[ressut_f];
    ressut_pos = (ressut_pos+1) % ressut_bytes;
  } // for(c=0; c<size; c++)
  genbytes+=size;
}