Kirjautuminen

Haku

Tehtävät

Keskustelu: Koodit: Pascal: Alkuluvuissa esiintyvien numeroiden tilastollista tutkimusta

Sivun loppuun

PetriKeckman [29.10.2023 17:51:02]

#

Alkuluvuissa väliltä 2..20000 kymmenjärjestelmässä esitettynä on numero 0 aliedustettuna ja 1 esiintyy useiten. Luonnollisesti kaikki parilliset luvut 0,2,4,6,8 esiintyvät harvoin, koska viimeinen numero ei voi olla sellainen (kuten ei 5:nkaan) paitsi luvussa alkuluvuissa 2 (ja 5). Ohjelmoimisen ilosta ohjelmoin.

EDIT: 0 ei tietystikään ole parillinen, mutta siihen päättyvät luvut ovat.

Alkuluvuissa võliltõ 2..20000 esiintyy numero 0 540 kertaa.
Alkuluvuissa võliltõ 2..20000 esiintyy numero 1 2278 kertaa.
Alkuluvuissa võliltõ 2..20000 esiintyy numero 2 701 kertaa.
Alkuluvuissa võliltõ 2..20000 esiintyy numero 3 1252 kertaa.
Alkuluvuissa võliltõ 2..20000 esiintyy numero 4 681 kertaa.
Alkuluvuissa võliltõ 2..20000 esiintyy numero 5 673 kertaa.
Alkuluvuissa võliltõ 2..20000 esiintyy numero 6 665 kertaa.
Alkuluvuissa võliltõ 2..20000 esiintyy numero 7 1220 kertaa.
Alkuluvuissa võliltõ 2..20000 esiintyy numero 8 652 kertaa.
Alkuluvuissa võliltõ 2..20000 esiintyy numero 9 1222 kertaa.

Eratostheneen seulaa käytin: https://fi.wikipedia.org/wiki/Eratostheneen_seula

program Eratostheneenseula;
uses SysUtils;
const maxluku=20000; // lasketaan maxluku:a pienemmät alkuluvut Eratostheneen seulalla
var taulukko: array [1..maxluku] of boolean; // totuusarvo sille on indeksi alkuluku
	i,ci: integer;
	neliojuuri: Double;
	luku: integer;
	lukuMerkkijonona: String;
	esiintymat: array [0..9] of integer;
begin
	neliojuuri:=sqrt(maxluku);
	for i:=2 to maxluku do taulukko[i]:=true; //oletetaan kaikki alkuluvuiksi
	taulukko[1]:=false; //paitsi ensimmäinen
	i:=2;
	while i<=maxluku do //poistetaan kakkosen monikerrat
		begin
			taulukko[i]:=false;
			i:=i+2;
		end;
	luku:=2;
	while luku <= neliojuuri do
		begin
			while (taulukko[luku] = false) and (luku < neliojuuri) do // etsitään seuraava alkuluku
				luku:=luku+1;
			i:=2*luku;
			while i<=maxluku do
				begin
					taulukko[i]:=false; //poistetaan sen monikerrat
					i:=i+luku;
				end;
			luku:=luku+1;
		end;
taulukko[2]:=true;
for i:=0 to 9 do esiintymat[i]:=0; // alustetaan esiintymät nolliksi
for i:=1 to maxluku do
	if taulukko[i] then
		begin
			lukuMerkkijonona := IntToStr(i);
			for ci:=1 to Length(lukuMerkkijonona) do
					esiintymat[StrToInt(lukuMerkkijonona[ci])]:=esiintymat[StrToInt(lukuMerkkijonona[ci])]+1;
		end;
//for i:=1 to maxluku do if taulukko[i] then writeln(i);
for i:=0 to 9 do
	writeln('Alkuluvuissa väliltä 2..', maxluku, ' esiintyy numero ', i , ' ', esiintymat[i], ' kertaa.');
end.

Grez [29.10.2023 18:47:08]

#

PetriKeckman kirjoitti:

EDIT: 0 ei tietystikään ole parillinen, mutta siihen päättyvät luvut ovat.

Nolla on parillinen luku ainakin matematiikassa ja ohjelmoinnissa.

En oikein keksi missä yhteydessä se olisi pariton luku, eli siis luku, jossa muodostettaessa pareja jäisi yksi yli.

PetriKeckman [29.10.2023 19:17:14]

#

Alkulukujen joukossa 0 ei ole parillinen, koska se ei edes kuulu alkulukujen joukkoon ;)

PetriKeckman [29.10.2023 20:17:47]

#

Jatkan turhia tutkimuksiani - ohjelmoimisen ilosta. Nyt kun alkuluvut väliltä 2..20000 on selvitetty totuusarvoiseen taulukkoon Array[1..20000] Of BOOLEAN, niin niiden avulla voidaan tsekata onko jokin luku väliltä 20000..(20000*20000)=400 miljoonaa alkuluku. Edellisessä ohjelmassa taulukon kokoa rajoittaa, että const saa olla vain korkeintaan 32767 (tosin se oli 20000).

Jätin ohjelman pyörimään kello 20:11. Saa nähdä valmistuuko huomiseksi :) Mitä veikkaatte?

program Eratostheneenseula;
uses SysUtils;
const maxluku=20000; // lasketaan maxluku:a pienemmät alkuluvut Eratostheneen seulalla
var taulukko: array [1..maxluku] of boolean; // totuusarvo sille on indeksi alkuluku
	i,ci: integer;
	neliojuuri: Double;
	luku,indeksi: integer;
	lukuMerkkijonona: String;
	esiintymat: array [0..9] of integer;
	suurin,j: LongInt;
function onalkuluku(tutkittavaluku:LongInt):boolean; //tutkitaan onko tutkittavaluku alkuluku
//Eratostheneen seulalla saadun taulukon avulla
var onalku: boolean;
begin
	if (tutkittavaluku=2) or (tutkittavaluku=3) then onalku:=true
		else
			begin
				onalku:=true; //oletetaan alkuluvuksi
				indeksi:=3;
				while (onalku and (indeksi<=sqrt(tutkittavaluku))) do
					begin
						if taulukko[indeksi] then
							begin
								if  (tutkittavaluku mod indeksi)=0 then
								begin
									onalku:=false;
								end;
							end;
						indeksi:=indeksi+2;
					end;
					//siirrytään seuraavaan alkulukuun
					while (taulukko[indeksi]=false) and (indeksi<=sqrt(tutkittavaluku)) do
						begin
							indeksi:=indeksi+2;
						end;
			end;
		onalkuluku:=onalku;
end;
begin
	neliojuuri:=sqrt(maxluku);
	for i:=2 to maxluku do taulukko[i]:=true; //oletetaan kaikki alkuluvuiksi
	taulukko[1]:=false; //paitsi ensimmäinen
	i:=2;
	while i<=maxluku do //poistetaan kakkosen monikerrat
		begin
			taulukko[i]:=false;
			i:=i+2;
		end;
	luku:=2;
	while luku <= neliojuuri do
		begin
			while (taulukko[luku] = false) and (luku < neliojuuri) do // etsitään seuraava alkuluku
				luku:=luku+1;
			i:=2*luku;
			while i<=maxluku do
				begin
					taulukko[i]:=false; //poistetaan sen monikerrat
					i:=i+luku;
				end;
			luku:=luku+1;
		end;
taulukko[2]:=true;
//nyt ollaan taulukoitu lukujen 1..maxluku alkuluvullisuuden totuusarvot
for i:=0 to 9 do esiintymat[i]:=0; // alustetaan esiintymät nolliksi
esiintymat[2]:=1; //paitsi 2
suurin:=maxluku*maxluku;
j:=3;
while j<=suurin do
	begin
		if onalkuluku(j) then
			begin
				lukuMerkkijonona := IntToStr(j);
				for ci:=1 to Length(lukuMerkkijonona) do
						esiintymat[StrToInt(lukuMerkkijonona[ci])]:=esiintymat[StrToInt(lukuMerkkijonona[ci])]+1;
			end;
		j:=j+2;
	end;
//for i:=1 to maxluku do if taulukko[i] then writeln(i);
for i:=0 to 9 do
	writeln('Alkuluvuissa väliltä 2..', maxluku*maxluku, ' esiintyy numero ', i , ' ', esiintymat[i], ' kertaa.');
end.

PetriKeckman [29.10.2023 20:25:42]

#

Veikkaan, että ohjelma tietysti kaatuu Number Overflow...siis lukujen esiintymiä tulee niin paljon, täytyy laittaa uudestaan pyörimään. Muutan taulukon alkion tyypiksi LongInt. Saa nähdä auttaako, tai ehkä Double?

EDIT: Väärä hälytys! :) Integer tyyppihän saa olla jopa 2147483647

PetriKeckman [29.10.2023 20:31:03]

#

Ehän tuohon mennyt kuin 20 minuuttia!

Alkuluvuissa võliltõ 2..400000000 esiintyy numero 0 23683 kertaa.
Alkuluvuissa võliltõ 2..400000000 esiintyy numero 1 12196 kertaa.
Alkuluvuissa võliltõ 2..400000000 esiintyy numero 2 14774 kertaa.
Alkuluvuissa võliltõ 2..400000000 esiintyy numero 3 -4103 kertaa.
Alkuluvuissa võliltõ 2..400000000 esiintyy numero 4 -16508 kertaa.
Alkuluvuissa võliltõ 2..400000000 esiintyy numero 5 -29616 kertaa.
Alkuluvuissa võliltõ 2..400000000 esiintyy numero 6 26234 kertaa.
Alkuluvuissa võliltõ 2..400000000 esiintyy numero 7 -20672 kertaa.
Alkuluvuissa võliltõ 2..400000000 esiintyy numero 8 12151 kertaa.
Alkuluvuissa võliltõ 2..400000000 esiintyy numero 9 26365 kertaa.

EDIT: Oho! Kiersivät jotkin luvut ympäri negatiiviseksi.
EDIT2: En tajua mitä tässä on tapahtunut. Testasin ohjelmaa 10:llä ja se toimi eli välillä 2..10*10.

Grez [29.10.2023 21:00:23]

#

Kenties sulla on käytössä 16-bittiset kokonaisuluvut, ainakin kaikki sopisivat välille -32768 - +32767.

Itse sain tällaisen tulokset 2 - 400 000 000
0 : 14310531
1 : 25636772
2 : 20134326
3 : 25358329
4 : 14925700
5 : 14912592
6 : 14902906
7 : 20229952
8 : 14888823
9 : 20211453

Laskennassa meni aikaa vajaa 6 sekuntia Eratostheneen seulalla.

const int maxNum = 20000;

//Alkuluvut 2-400 000 000
//Käsitellään vain parittomia lukuja, niin säästyy puolet muistista
int sieveSize = (maxNum * maxNum) >> 1;
int halfMaxNum = maxNum >> 1;
var sieve = new byte[sieveSize];

//Siivilöidään alkuluvuilla, jotka välillä [3,19999]
for (int i = 1; i < halfMaxNum; i++)
{
    if (sieve[i] == 0)
    {
        var a = (i << 1) + 1;
        var j = a + i;
        while (j < sieveSize)
        {
            sieve[j] = 1;
            j += a;
        }
    }
}

//Lasketaan jäljelle jääneiden alkulukujen numerot
var num = new int[10];
for (int i = 1; i < sieveSize; i++)
{
    if (sieve[i] == 0)
    {
        var n = (i << 1) + 1;
        while (n > 0)
        {
            num[n % 10]++;
            n /= 10;
        }
    }
}
num[2]++; //Lisätään ainoa parillinen alkuluku 2, koska sitä ei käsitellä ylempänä

for (int i = 0; i < 10; i++)
{
    Console.WriteLine($"{i} : {num[i]}");
}

PetriKeckman [29.10.2023 21:28:27]

#

Grez kirjoitti:

0 : 14310531
1 : 25636772
2 : 20134326
3 : 25358329
4 : 14925700
5 : 14912592
6 : 14902906
7 : 20229952
8 : 14888823
9 : 20211453

Joo. Nyt sain samat tulokset kuin sinä, kun käytin esiintymien laskentaan Currency liukulukua.

Alkuluvuissa võliltõ 2..400000000 esiintyy numero 0 1.4310531000000E+07 kertaa.
Alkuluvuissa võliltõ 2..400000000 esiintyy numero 1 2.5636772000000E+07 kertaa.
Alkuluvuissa võliltõ 2..400000000 esiintyy numero 2 2.0134326000000E+07 kertaa.
Alkuluvuissa võliltõ 2..400000000 esiintyy numero 3 2.5358329000000E+07 kertaa.
Alkuluvuissa võliltõ 2..400000000 esiintyy numero 4 1.4925700000000E+07 kertaa.
Alkuluvuissa võliltõ 2..400000000 esiintyy numero 5 1.4912592000000E+07 kertaa.
Alkuluvuissa võliltõ 2..400000000 esiintyy numero 6 1.4902906000000E+07 kertaa.
Alkuluvuissa võliltõ 2..400000000 esiintyy numero 7 2.0229952000000E+07 kertaa.
Alkuluvuissa võliltõ 2..400000000 esiintyy numero 8 1.4888823000000E+07 kertaa.
Alkuluvuissa võliltõ 2..400000000 esiintyy numero 9 2.0211453000000E+07 kertaa.

Free Pascalissa on se ongelma, että tosiaan CONST vakioita ei voi määrittää kuin kai 16-bittisinä ja sitä tarvitaan taulukon määrittämiseen. Yritin kyllä kokeilla jotain Array[1..400000000] taulukkoa - se meni kääntäjästä läpi, mutta muu koodi kaatui muistaakseni jo käännösvaiheessa sitten.

Grez [29.10.2023 21:32:22]

#

Joo freepascalissa kannattanee käyttää LongInt tyyppiä jos varmasti haluaa 32-bittisen kokonaisluvun. Ilmeisesti integer voi tarkoittaa joko SmallInt (16-bit) tai LongInt. On siellä Int64 myös jos tarvii n. 2 miljardia (tai etumerkittömillä Uint32 n. 4 miljardia) isompia.

PetriKeckman kirjoitti:

käytin esiintymien laskentaan Currency liukulukua.

Currency ei käsittääkseni ole varsinaisesti liukuluku vaan 64-bittinen kokonaisluku, jossa piste on lukittu 4 desimaalin päähän lopusta. (Eli siis fixed point, ei floating point). No freepascalin wikissäkin nähtävästi se on laitettu liukuluvut (floating point) -kategoriaan, että sinänsä ei voi sinua syyttää tuon termin käytöstä :D

PetriKeckman [30.10.2023 13:50:58]

#

Kuinka monta prosenttia Fibonaccin luvuista on alkulukuja? Raja-arvo? Onko se nolla? Hankala sanoa...Mitenhän sitä empiirisesti tutkisi? Huomasin:

"Unsolved problem in mathematics:
Are there an infinite number of Fibonacci primes?
"
https://en.wikipedia.org/wiki/Fibonacci_prime

Eli, jos niitä olisi äärellinen määrä, niin sitten raja-arvo ei olisikaan nolla. EDIT: Heh! Sori! Eiku toistepäin!! :)

Fibonaccin lukuja võlillõ 1..4 on 4, joista alkulukuja 2 kappaletta eli 5.0E+0001 prosenttia.
Fibonaccin lukuja võlillõ 1..9 on 6, joista alkulukuja 4 kappaletta eli 6.7E+0001 prosenttia.
Fibonaccin lukuja võlillõ 1..16 on 7, joista alkulukuja 5 kappaletta eli 7.1E+0001 prosenttia.
Fibonaccin lukuja võlillõ 1..25 on 8, joista alkulukuja 5 kappaletta eli 6.3E+0001 prosenttia.
Fibonaccin lukuja võlillõ 1..36 on 9, joista alkulukuja 6 kappaletta eli 6.7E+0001 prosenttia.
Fibonaccin lukuja võlillõ 1..49 on 9, joista alkulukuja 6 kappaletta eli 6.7E+0001 prosenttia.
Fibonaccin lukuja võlillõ 1..64 on 10, joista alkulukuja 6 kappaletta eli 6.0E+0001 prosenttia.
Fibonaccin lukuja võlillõ 1..81 on 10, joista alkulukuja 6 kappaletta eli 6.0E+0001 prosenttia.
Fibonaccin lukuja võlillõ 1..100 on 11, joista alkulukuja 7 kappaletta eli 6.4E+0001 prosenttia.
.
.
.
Fibonaccin lukuja võlillõ 1..100000000 on 39, joista alkulukuja 11 kappaletta eli 2.8E+0001 prosenttia.
.
.
.
Fibonaccin lukuja võlillõ 1..1024000000 on 44, joista alkulukuja 12 kappaletta eli 2.7E+0001 prosenttia.

program Eratostheneenseula;
uses SysUtils;
const maxluku=32000; // lasketaan maxluku:a pienemmät alkuluvut Eratostheneen seulalla
var taulukko: array [1..maxluku] of boolean; // totuusarvo sille onko indeksi alkuluku
	i: integer;
	neliojuuri: Double;
	luku,indeksi,luku1,luku2,luku3: LongInt;
	suurin,lukumaaraalkuluku,lukumaarafib,maxluku2: LongInt;
function onalkuluku(tutkittavaluku:LongInt):boolean; //tutkitaan onko tutkittavaluku alkuluku
//Eratostheneen seulalla saadun taulukon avulla
var onalku: boolean;
begin
	if (tutkittavaluku=1) then onalku:=false
		else
			if (tutkittavaluku=2) or (tutkittavaluku=3) then onalku:=true
				else
					begin
						onalku:=true; //oletetaan alkuluvuksi
						indeksi:=3;
						while (onalku and (indeksi<=sqrt(tutkittavaluku))) do
							begin
								if taulukko[indeksi] then
									begin
										if  (tutkittavaluku mod indeksi)=0 then
										begin
											onalku:=false;
										end;
									end;
								indeksi:=indeksi+2;
							end;
							//siirrytään seuraavaan alkulukuun
							while (taulukko[indeksi]=false) and (indeksi<=sqrt(tutkittavaluku)) do
								begin
									indeksi:=indeksi+2;
								end;
					end;
	onalkuluku:=onalku;
end;
begin
	neliojuuri:=sqrt(maxluku);
	for i:=2 to maxluku do taulukko[i]:=true; //oletetaan kaikki alkuluvuiksi
	taulukko[1]:=false; //paitsi ensimmäinen
	i:=2;
	while i<=maxluku do //poistetaan kakkosen monikerrat
		begin
			taulukko[i]:=false;
			i:=i+2;
		end;
	luku:=2;
	while luku <= neliojuuri do
		begin
			while (taulukko[luku] = false) and (luku < neliojuuri) do // etsitään seuraava alkuluku
				luku:=luku+1;
			i:=2*luku;
			while i<=maxluku do
				begin
					taulukko[i]:=false; //poistetaan sen monikerrat
					i:=i+luku;
				end;
			luku:=luku+1;
		end;
taulukko[2]:=true;
//nyt ollaan taulukoitu lukujen 1..maxluku alkuluvullisuuden totuusarvot
for maxluku2:=2 to 32000 do
	begin
		suurin:=maxluku2*maxluku2;
		luku1:=1;
		luku2:=1;
		luku3:=luku1+luku2;
		lukumaaraalkuluku:=0;
		lukumaarafib:=2;
		while luku3<=suurin do
			begin
				lukumaarafib:=lukumaarafib+1;
				//writeln(luku3, ' on Fibonaccin luku');
				if onalkuluku(luku3) then
					begin
						lukumaaraalkuluku:=lukumaaraalkuluku+1;
						//writeln(luku3, 'on alkuluku');
					end;
				luku1:=luku2;
				luku2:=luku3;
				luku3:=luku1+luku2;
			end;
		writeln('Fibonaccin lukuja välillä 1..', suurin, ' on ', lukumaarafib, ', joista alkulukuja ', lukumaaraalkuluku, ' kappaletta eli ' ,100*lukumaaraalkuluku/lukumaarafib:4 , ' ', 'prosenttia.');
	end;
end.

Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta