Kirjautuminen

Haku

Tehtävät

Keskustelu: Yleinen keskustelu: Vielä yksi random-olio

jone2712 [24.04.2025 13:57:42]

#

Ohessa 8 bittinen random-funktio, joka etsii pi-ketjuja. Joka kierroksella etsitään myös toistoa.

/********************
* *** Jouni Aro *** *
* *** 24.4.2025 *** *
********************/

#include <stdio.h>
#include <memory.h>

typedef unsigned char uint8;

class random
{
    public:

    random(void);
    ~random(void);

    unsigned rnd(unsigned);

    private:

    void inc4(void);
    uint8 tmp8(void);

    unsigned Z;
    uint8 R8A, R8B;
    uint8 avain[256];
    int p1, p2, p3, p4;
};

random::random(void)
{
    memset(this, 0, sizeof(random));
    Z=1+(2<<8)+(3<<16)+(4<<24);
    p1=1; p2=2; p3=3; p4=4;
    R8A=101; R8B=202;

    for (int i=0; i<256; i++)
    avain[i]=(uint8)i;
}

random::~random(void)
{
}

inline void random::inc4(void)
{
    ++Z; p1=Z&255;
    p2=(Z>>8)&255;
    p3=(Z>>16)&255;
    p4=(Z>>24)&255;
}

inline uint8 random::tmp8(void)
{
    R8A+=(uint8)((avain[p1]>>4)^(avain[p2]<<4));
    R8B-=(uint8)((avain[p1]<<4)^(avain[p2]>>4));

    R8A-=avain[p3]&(uint8)255;
    R8B+=avain[p4]&(uint8)255;

    inc4();
    return R8A^R8B;
}

inline void swap(uint8 &x, uint8 &y)
{
    register uint8 z=x; x=y; y=z;
}

inline unsigned random::rnd(unsigned max)
{
    register unsigned x=tmp8();
    register unsigned y=tmp8();
    swap(avain[x], avain[y]);
    return tmp8()%max;
}

/*
main-funktio tutkii, kuinka pitkiä pi-ketjuja
löytyy, samalla etsitään, koska toisto alkaa.
toistaako-funktio etsii rnd-syklistä toistoa.
*/

int toistaako(random &F0, random &F, double &loop)
{
    char *A=(char*)&F0;
    char *B=(char*)&F;
    int size=sizeof(random);

    for (int i=0; i<size; i++)
    if (A[i]!=B[i]) return 0;

    for (unsigned k=0x01; k!=0; k++)
    printf("toistaa %0.0f\n", loop);

    return 1;
}

int main(void)
{
    char *pi="1415926535897932384626433832795028841971693993751058209749445923";
    unsigned maxKpl=0, i=0;
    double loop=0.00;
    random F0, F;

    for (;; loop+=1.0)
    {
        int x=F.rnd(10)+(int)'0';

        if ((char)x==*(pi+i))
        {
            ++i;
        }
        else
        {
            if (i>maxKpl)
            {
                maxKpl=i;
                printf("pi %d numeron tarkkuudella\n", maxKpl);
                printf("loop=%0.0f\n\n", loop);
                i=0;
            }
            else i=0;
        }
        if (toistaako(F0, F, loop)) break;
    }
    return 1;
}

Ohjelma tulostaa pi-ketjuja, ja tulos näyttää tältä:

pi 1 numeron tarkkuudella
loop=16

pi 2 numeron tarkkuudella
loop=24

pi 3 numeron tarkkuudella
loop=2128

pi 4 numeron tarkkuudella
loop=17743

pi 5 numeron tarkkuudella
loop=52605

pi 6 numeron tarkkuudella
loop=1296831

pi 8 numeron tarkkuudella
loop=22506900

pi 9 numeron tarkkuudella
loop=5882993429

pi 10 numeron tarkkuudella
loop=15768925109

pi 11 numeron tarkkuudella
loop=47846462953

pi 12 numeron tarkkuudella
loop=1749902211599

jne...

pr0l3 [25.04.2025 09:14:38]

#

Minulla on tällainen random-olio. Voitko analysoida, kumpi näistä on parempi? Tämäkin testi etsii piin desimaaleja. Silmukan näkee siitä, että toistuu täsmälleen sama tulos ja tulosta edeltävä puskuri.

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <ctype.h>

template <typename UINT, int POW> struct prandom {
	static_assert(POW > 0, "SIZE must be greater than 0");
	static_assert(POW <= 32, "SIZE must be less than or equal to 32");

	typedef UINT uint_type;
	const int size = 1 << POW;
	const uint_type mask = (1 << POW) - 1;

	UINT state[1 << POW];
	int index;

	prandom(uint64_t seed = 0) : index(0) {
		for (int i = 0; i < size; ++i) {
			state[i] = i + (seed >> (i * (sizeof(uint_type) * 8)));
		}
	}
	uint_type next() {
		uint_type a = state[index] + 1;
		index = (index + 1) & mask;
		uint_type b = state[index];
		state[index] = (b << 4) ^ (b >> 4) ^ (a << 3) ^ (a >> 3);
		return state[index];
	}
};

typedef prandom<uint8_t, 8> p8rng_t;

void pi_test() {
	const char pi[] = "1415926535897932384626433832795028841971693993751058209749445923";

	const int buf_size = strlen(pi);
	char buf[buf_size + 1] = {0};

	int found_max = 0, found_now = 0;
	uintmax_t i = 0;
	p8rng_t rng;
	while (pi[found_max] != '\0') {
		++i;
		uint8_t r = (rng.next() % 10) + '0';
		const int buf_i = i % buf_size;
		buf[buf_i] = r;
		if (r == pi[found_now]) {
			found_now++;
			if (found_now >= found_max) {
				found_max = found_now;
				printf("Found %d digits of pi ending at [%ju]\n", found_max, i);
				for (int j = 0; j < buf_size; ++j) {
					if (!isprint(buf[j])) {
						buf[j] = '.';
					}
				}
				printf("last %d values: %.*s%.*s\n", buf_size, buf_size - buf_i - 1, buf + buf_i + 1, buf_i + 1, buf);
			}
		} else {
			found_now = 0;
		}
	}
}

int main() {
	pi_test();
	return 0;
}

Vastaus

Muista lukea kirjoitusohjeet.
Tietoa sivustosta