Znajdowanie liczba Mersenne'a z zadanego przedziału

0

Witam, dopiero zaczynam pracę z językiem Delphi. Mam do napisania program :

Liczba Mersenne'a to liczba pierwsza postaci 2^p-1, przy czym p samo jest liczbą pierwszą. Napisz program znajdujący takie liczby w przedziale [1, max].

Widziałem, że był już podobny temat, jednak po skopiowaniu kodu i skompilowaniu go program nie działał tak jak powinien.

Z góry dzięki za pomoc :).

0

A z czym konkretnie masz problem?

Widziałem, że był już podobny temat, jednak po skopiowaniu kodu i skompilowaniu go program nie działał tak jak powinien.

Skoro masz już jakiś kod to wklej go do posta, a sprawdzi się co z nim nie tak.

0

na razie wygląda to tak. Nie wiem teraz co zrobić, żeby zamiast tych liczb pierwszych wypisywało te liczby Mersenne'a

program ExCzyLiczbaPierwsza;

{$APPTYPE CONSOLE}

uses
  Math,
  SysUtils;

function ND(N: Int64): Int64;
var
  i: Int64;
begin
  if N<2 then  ND := 0
   else
    if N<4 then  ND := N
     else
      if (N mod 2=0) then ND := 2
       else
        if (N mod 3=0) then ND := 3
         else
          begin
            ND := N;   i := 1;
            while 6*i-1<=Int(Power(N, 0.5)) do
             begin
               if N mod(6*i-1)=0 then
                begin
                  ND := 6*i-1;   Break;
                end
                else
                 if N mod(6*i+1)=0 then
                  begin
                    ND := 6*i+1;   Break;
                  end;
               if i mod 1000000=0 then
                 Write( #13, i div 1000000, 'M (',
                        100.0*i/Int(Power(N, 0.5)): 0:1, '%)'#13 );
               Inc(i);
             end
          end;
end;

var
  tylko_pierwsze, tylko_ilosc, znak : Char;
  i, ile_pierwszych, iND, M, N : Int64;
  czas, czas_calk : TDateTime;

begin
  Writeln( 'Program szuka liczb Mersenne '
           + 'z podanego zakresu.' );
  repeat
    tylko_pierwsze := #0;
    Write(#13#10#13#10'Podaj poczatek zakresu: ');   Readln(M);
    Write('Podaj koniec zakresu:   ');   Readln(N);
     begin
       Write('Pokaz tylko liczby pierwsze [t/n]:');
       Readln(tylko_pierwsze);
     end;

    if M mod 2=0 then  M := M + 1;
    czas_calk := Now;   Writeln;   i:=M;   ile_pierwszych := 0;

    while i<N do
     begin
       czas := Now;   iND := ND(i);   czas := 86400*(Now - czas);

       if iND=i then
        begin
          if UpCase(tylko_ilosc)<>'T' then
            Writeln(i, #9'czas: ', czas:0:3, ' s <--- liczba pierwsza ---');
          ile_pierwszych := ile_pierwszych + 1;
        end
        else
         if (UpCase(tylko_pierwsze)<>'T')and(UpCase(tylko_ilosc)<>'T') then
          Writeln(i, #9'czas: ', czas:0:3, ' s'#9'najmniejszy dzielnik: ', iND);
       i := i + 2;
     end;

    czas_calk := 86400*(Now - czas_calk);
    Writeln( #13#10'Ilosc znalezionych liczb pierwszych: ', ile_pierwszych,
             #13#10'Calkowity czas wyszukiwania (z wyswietl.): ', czas_calk:0:3,
             ' s'#13#10'(UWAGA! wyswietlanie bardzo wydluza oczekiwanie na ',
             'wyniki)' );
    Write(#13#10#13#10'Czy rozpoczac nowe wyszukiwanie [T/N]? ');  Readln(znak);
   until UpCase(znak)<>'T';
end.
0

Miałem program do wyszukiwania wszystkich liczb pierwszych i dodałem przefiltrowywanie.
Tych liczb Mersenne'a będzie 8 w zakresie 32b ( i 9 w zakresie 64b), więc lepiej jest przeanalizować w innym programie, a następnie wrzucić na stałe (jako tablica const).
Później tylko wyszukiwać z tablicy.
W załączniku masz program do takiego analizowania (32b), a niżej taki do wyszukiwania z tablicy.

program Project1;
{$APPTYPE CONSOLE}        //tu na podstawie Wikipedii rozszerzyłem tablicę do 64b
const L : array[0..8] of uInt64 = (3, 7, 31, 127, 8191, 131071, 524287, 2147483647, 2305843009213693951);
var       //ostatnia liczba została błędnie wyliczona zmieniona z 536870911 na 2305843009213693951 
 Max : uInt64;
 loop : integer;

begin
 readln(Max);
 for loop := 0 to 7 do
 begin
  If L[loop] <= Max then
   writeln(l[loop])
   else
   Break;
 end;
end.

Drugi kod całkowicie zgodny z Wiki:
https://pl.wikipedia.org/wiki/Liczby_Mersenne%E2%80%99a#Liczby_pierwsze_Mersenne.E2.80.99a

0

@pawel24pl, ostatnia liczba w Twojej macierzy jest niewłaściwa - jest mniejsza od przedostatniej; Dla 64-bitowego zakresu i typu UInt64 istnieje dziewięć liczb Mersenne'a o poniższych wartościach:

2^2-1   ⟶  3
2^3-1   ⟶  7
2^5-1   ⟶  31
2^7-1   ⟶  127
2^13-1  ⟶  8191
2^17-1  ⟶  131071
2^19-1  ⟶  524287
2^31-1  ⟶  2147483647
2^61-1  ⟶  2305843009213693951

Przy czym ostatnią trzeba obliczyć jakimś kalkulatorem obsługującym tak duże liczby, np. tym; Stąd też macierz takich liczb powinna wyglądać tak jak poniżej:

const
  MERSENNE_NUMS: array [0 .. 8] of UInt64 = (3, 7, 31, 127, 8191, 131071, 524287, 2147483647, 2305843009213693951);

Powyższe wartości w postaci heksadecymalnej wyglądają lepiej.

0

@furious programming dzięki za poprawkę
Tak liczone trochę na szybko (niestety). Podejrzewam, że mi rzutowało na typ 32b :

writeln(1 shl 61 -1);

Ale tworząc nową zmienną uInt64 można obliczyć poprawnie:

var
 i : uInt64;
begin
 i := 1;
 i := i shl 61;
 dec(i);
 writeln(i);

Naniosłem poprawkę na post

0

No dobrze, co nie zmienia faktu, że ten kod:

i := 1;
i := i shl 61;
Dec(i);

można spokojnie zapisać w jednej linii przypisania:

i := 1 shl 61 - 1;

Oba operandy dla Shl mogą być literałami, stałymi lub zmiennymi; Poza tym, operator Shl ma wyższy priorytet niż operator odejmowania, więc nawiasy grupujące przesunięcie bitowe nie są potrzebne;

writeln(1 shl 61 -1);

Tak liczone trochę na szybko (niestety). Podejrzewam, że mi rzutowało na typ 32b :

Tego nie wiem, choć całość zawsze można rzutować na konkretny typ:

WriteLn(UInt64(1 shl 61 - 1));

FPC nie widzi problemu w dobraniu odpowiedniego typu, dzięki czemu rzutowanie nie jest konieczne.

0

A mam pytanie. Jak bym chciał przerobić swój program na okienkowy to duzo byłoby zabawy? Ma on polegać na tym, że po kliknieciu button'a w memo mają się wyświetlić wszystkie liczby Mersenn'a z danego zakresu, a w drugim okienku czas w jakim to się wykonywało.

0

Nie, nie powinno być.
W SpinEdit1 i SpinEdit2 (TSpinEdit) wpisujesz zakresy, a w Memo1 (TMemo) wyświetla Ci liczby
Procedurka do OnClick buttona:

procedure TForm1.Button1Click(Sender: TObject);
const L : array[0..8] of uInt64 = (3, 7, 31, 127, 8191, 131071, 524287, 2147483647, 2305843009213693951);
var
 TMP, Max, Min : uInt64;
 loop : integer;
begin
 memo1.Lines.Clear; //czyści memo
 Max := SpinEdit1.Value;
 {Jeżeli dolny zakres to zero, to kasujesz od tej linii}
 Min := SpinEdit2.Value;
 If Min > Max then
 begin //szybszej zamiany nie znam
   TMP := Max; // (co nie znaczy, że nie istnieje)
   Max := Min; // (bo w końcu też się uczę)
   Min := TMP;
 end;
 {do tej, a następnie usuwasz zmienną TMP i Min}
 for loop := 0 to 7 do
 begin
  If L[loop] <= Max then
   begin
    If l[Loop] >= Min then //jak minimum jest zerem, kasujesz warunek
     memo1.Lines.add(IntToStr(l[loop]));
   end
   else
   Break;
 end;
end;

No a jeśli chodzi o czas to nie ma większego sensu liczyć, bo to max 2 ms
chyba, że Ci zamuli jakimś innym programem.
No ale czas można liczyć tak:

var
 t1, t2 : LongWord;
 //reszta zmiennych
begin
 t1 := GetTickCount;
 //dalsze instrukcje
 t2 := GetTickCount;
 ShowMessage( IntToStr(t2-t1) + 'ms' ); //pokazuje czas w milisekundach
end; //koniec procedury/funkcji

1 użytkowników online, w tym zalogowanych: 0, gości: 1