Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

[lekcja 18] losowanie liczb o danej długości

Ostatnio zmodyfikowano 2013-05-29 21:43
Autor Wiadomość
jaro98
Temat założony przez niniejszego użytkownika
[lekcja 18] losowanie liczb o danej długości
» 2013-05-28 00:10:56
Po lekcji o tablicach doszedłem do wniosku, że spróbuję napisać program, który będzie wypisywał liczby o danej liczbie cyfr - niestety nie działa dla liczby o długości jednej cyfry, nie mogę znaleźć błędu(poniższy kod). Zauważyłem też, że jedna na kilka prób wygenerowała same zera(np. dla ilosc=34 zawsze same zera oO). Dodatkowo dla większych liczb np. 8-cyfrowych program generuje dużo mniejszą różnorodność liczb(w sensie, że przyjmują wartości poniżej pewnego pułapu), niż dla 2 czy 3-cyfrowych. To kwestia generatora liczb czy słabość kodu(pewnie obie wersje)?
C/C++
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;

int potegowanie( int ile_znakow ) /* ma liczyć potęgę dziesiątki do funkcji flos; przypisywana do zmiennej b */
{
    int licznik = 0;
    int a = 1;
   
    do
    {
        a = a * 10;
        licznik++;
    } while(( ile_znakow - 1 ) != licznik );
   
    return a;
}

int flos( int ile_znakow, int b ) /* ma być przypisywana do wyrazów tablicy */
{
    int a;
    if( ile_znakow == 1 )
         a =( rand() % 10 ); /* dalsze: (rand()%9*10^1)+10^1 ; rand()%9*10^2+10^2 itd.*/
   
    if( a > 1 )
         a = rand() %( 9 * b ) + b; /*było: a=((rand()%(9*10^(ile_znakow-1)))+10^(ile_znakow-1));*/
   
    return a;
}
int main()
{
    srand( time( NULL ) );
   
    int ile_znakow, ilosc, numer_tablicy = 0;
    int b; /* docelowo do wczytania przez funkcję flos */
   
    cout << "Program wylosuje okreslona liczbe liczb o okreslonej dlugosci." << endl;
    cout << "Podaj dlugosc liczby (z ilu cyfr ma sie skladac) : ";
    cin >> ile_znakow;
    cout << "Ile chcesz tych liczb: ";
    cin >> ilosc;
   
    int tablica[ ilosc - 1 ];
    b = potegowanie( ile_znakow ); /* b=10^(ile_znakow-1)  */
    do
    {
        tablica[ numer_tablicy ] = flos( ile_znakow, b );
        numer_tablicy++;
       
    } while( numer_tablicy != ilosc );
   
    numer_tablicy = 0;
    do
    {
        cout << numer_tablicy + 1 << ": " << tablica[ numer_tablicy ] << endl;
        numer_tablicy++;
    } while( numer_tablicy != ilosc );
   
    return 0;
}
P-84164
Rafals
» 2013-05-28 08:17:18
Cześć.
Chociaż sam co dopiero kończę kurs, to postaram się pomóc (forma sprawdzenia się;)).
1) Deklarując tablice o danej liczbie elementów nie odejmujesz od tej danej liczby "1". Pewnie tak pomyślałeś ze względu na to, że indeksy tablic numeruje się od "0". Chcąc uzyskać tablicę o l. el. 10 deklarujesz "tab[10]". Ale już numerujesz od "0" do "9".
C/C++
int ilosc = 10;
int tab[ ilosc ];
int numer_tablicy = 0;
do
{
    tab[ numer_tablicy ] = /*...kod...*/;
    numer_tablicy++;
} while( numer_tablicy != ilosc );
Jak w powyższym, najpierw wykonuje kod dla pierwszego elementu tablicy, następnie zwiększa indeks o 1 i sprawdza czy jest różne od "ilość". Przy "9" indeksie (czyli 10 elemencie), wykona kod i zakończy. W Twoim przykładzie 10 element jest poza tablicą, bo nie ma "9" indeksu.
Wiem nie umiem tłumaczyć ;p Najprościej to, deklarujesz tab[x] tyle ile rzeczywiście chcesz tych elementów, ale wywołujesz je "x-1".

2) Hmm tutaj z tym losowaniem.
W funkcji potęgowania jak ilosc_znakow podasz 1 to pętla będzie się wykonywać w nieskończoność.
Dla przedziału 0-9 przy 1 cyfrowych liczbach, to ok:
( rand() % 10 );

Nie wiem jak to słownie wytłumaczyć i z matematycznego punktu widzenia, ale ja to rozkminiłem sobie tak:
A - najmniejsza liczba z zakresu
B - największa liczba z zakresu
rand() %( B - A + 1 ) + A
Czyli dla liczb o "x" cyfrach
(B-A+1)^x+A

3) W funkcji flos błąd z:
if( a > 1 )

Mam nadzieję, że coś pomogłem, jak mnie nie zrozumiałeś to pewnie wynika z mojego nieobeznania jeszcze, ale na pewno wyjadacze wytłumaczą lepiej.
Po poprawieniu powyższych śmiga jak należy.

Edit
Musisz także pamiętać jak duże wartości może przechowywać dany typ zmiennych. Dla int to: 2 147 483 647 bez znaku. Także Twój generator może generować maksymalnie liczby 9 cyfrowe.

Edit
No i ostatnia rzecz, matematyka, matematyka, matematyka i jeszcze raz matematyka. Nawet mogę się pokusić o stwierdzenie, że należy posiadać większą wiedzę z matematyki aniżeli programowania.

Edit
W końcu zdążyłem przed kimś ;D
P-84166
jaro98
Temat założony przez niniejszego użytkownika
» 2013-05-28 10:18:57
1) Rozumiem, zapomniałem o tym, poprawione :P.
2) Tu nie rozumiem ostatniego przekształcenia - jeśli możesz to rozwiń. Moje rozumowanie było takie:
C/C++
if( ile_znakow == 1 )
     a =( rand() % 10 );


a dla znaków większych od 1 zauważyłem, że zawsze jest tak, że najmniejsza liczba jest wielokrotnością dziesiątki, a reszty z dzielenia muszą być w postaci rand()%(9*10^x), czyli mamy kolejno:

dla 2 cyfr: rand()%(9*10^1)+10^1       <100,999>   
dla 3 cyfr: rand()%(9*10^2)+10^2       <1000,9999>
...                                    ....
dla 9 cyfr: rand()%(9*10^8)+10^8
dla 10 cyfr: rand()%(9*10^9)+10^9

czyli odnosząc się do programu: rand()%(9*10^(ile_znakow-1))+10^(ile_znakow-1)

teraz tworzę funkcję, która liczy 10^(ile_znakow-1), później przypisuję wartość funkcji do b (tu był błąd ze złą zmienną, dzięki za wskazanie :P)
C/C++
int flos( int ile_znakow, int b ) /* ma być przypisywana do wyrazów tablicy */
{
    int a;
    if( ile_znakow == 1 )
         a =( rand() % 10 );
   
    if( ile_znakow > 1 ) /*tu było a zamiast ile_znakow...*/
         a = rand() %( 9 * b ) + b;
   
    return a;


Jednakże, jak wskazałeś funkcja licząca b zapętlała się w nieskończoność dla ile_znakow=1 - nie wziąłem pod uwagę tego, że przecież funkcja flos będzie chciała wczytać b nawet jeśli nie będzie jej potrzebowała przy zwracaniu. Więc poprawiłem
C/C++
int potegowanie( int ile_znakow )
{
    int licznik = 0;
    int a = 1;
   
    if( ile_znakow > 1 ) /*dodane teraz*/
    do
    {
        a = a * 10;
        licznik++;
    } while(( ile_znakow - 1 ) != licznik );
   
    return a;
}

Teraz działa ;p, dzięki za pomoc. Na razie nie zapętlona i nie ochroniona przed złymi wartościami wejściowymi:
C/C++
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;

int potegowanie( int ile_znakow )
{
    int licznik = 0;
    int a = 1;
   
    if( ile_znakow > 1 )
    do
    {
        a = a * 10;
        licznik++;
    } while(( ile_znakow - 1 ) != licznik );
   
    return a;
}

int flos( int ile_znakow, int b )
{
    int a;
    if( ile_znakow == 1 )
         a =( rand() % 10 );
   
    if( ile_znakow > 1 )
         a = rand() %( 9 * b ) + b;
   
    return a;
}
int main()
{
    srand( time( NULL ) );
   
    int ile_znakow, ilosc, numer_tablicy = 0;
    int b;
   
    cout << "Program wylosuje okreslona liczbe liczb o okreslonej dlugosci." << endl;
    cout << "Podaj dlugosc liczby (z ilu cyfr ma sie skladac) : ";
    cin >> ile_znakow;
    cout << "Ile chcesz tych liczb: ";
    cin >> ilosc;
   
    int tablica[ ilosc ];
    b = potegowanie( ile_znakow );
    do
    {
        tablica[ numer_tablicy ] = flos( ile_znakow, b );
        numer_tablicy++;
       
    } while( numer_tablicy != ilosc );
   
    numer_tablicy = 0;
    do
    {
        cout << numer_tablicy + 1 << ": " << tablica[ numer_tablicy ] << endl;
        numer_tablicy++;
    } while( numer_tablicy != ilosc );
   
    return 0;
}

Jednak dalej pozostaje aktualne, że im wyższa ilość cyfr w liczbie, tym liczby są mniej różnorodne - ostatnie pytanie z otwierającego posta wciąż aktualne. Wystarczy porównać 20 cyfr 8-cyfrowych z dwudziestoma cyframi 4-cyfrowymi wygenerowanymi przez ten program - od razu widać o co mi chodzi.
P-84167
Rafals
» 2013-05-28 13:23:33
Ok to ja źle zrozumiałem co ma robić ten program, myślałem, że jak np 2 cyfrowe liczby to ma losować od 0 do 99, a Tobie chodziło, że jak dwu cyfrowe to tylko dwu cyfrowe.
Co do ostatniego pytania to chyba chodzi o "rand()", po prostu chyba "nie ogarnia". Próbowałem sam z ciekawości znaleźć coś w dokumentacji, ale nic nie widzę. Jedyne co to:
" Notice though that this modulo operation does not generate uniformly distributed random numbers in the span (since in most cases this operation makes lower numbers slightly more likely)."

EDIT
O jest znalazłem:
rand()
"Returns a pseudo-random integral number in the range between 0 and RAND_MAX."
"This value is library-dependent, but is guaranteed to be at least 32767 on any standard library implementation."
P-84171
jaro98
Temat założony przez niniejszego użytkownika
» 2013-05-28 13:38:12
Dzięki, to jest pomocne, już rozumiem. Żeby zwiększyć użyteczność dla większych liczb chyba zrobię coś w rodzaju, np. że wylosuję dwie czterocyfrowe, w tym jedną pomnożę przez 10000 i dodam do drugiej otrzymując ośmiocyfrową, analogicznie dla innych, coś wykombinuję, najwyżej wrócę do tego jak będę więcej umieć.
P-84173
usmiech
» 2013-05-28 16:14:25
Zauwazylem, ze czesto wiele osob woli uzywac petle do...while, niz while.. Moze warto przeanalizowac prosty przyklad tych petli. Niby warunki te same, ale wynik jakby inny...

Oto przyklad, na poczatek 'odkryta' petla while... pozniej zmiencie to odkrycie, schowajcie while, a odkryjcie do....while ;)
C/C++
#include "stdafx.h"
#include <iostream>
using namespace std;

int main()
{
    int i = 11;
   
    while( i <= 10 )
    {
        cout << i << " ";
        cout << endl;
    }
   
    /* do
    {
    cout << i << " ";
    cout << endl;
    } while (i <=10); */
   
    system( "pause" );
    return 0;
}

//wnioski pozostawiam Wam, ale jak widac nieraz petla do..while moze niezle namieszac ;-)
//pojdzmy dalej w naszych rozwazaniach....

C/C++
#include "stdafx.h"
#include <iostream>
using namespace std;

int main()
{
    int i = 11;
   
    while( i <= 10 )
    {
        cout << i << " ";
        i = i + 5;
       
    }
   
    /* do
    {
    cout << i << " ";
    i = i + 5;
   
    } while (i <=10); */
   
    cout << endl;
    cout << i;
    cout << endl;
   
    system( "pause" );
    return 0;
}
P-84186
Rafals
» 2013-05-28 20:03:03
@Usmiech tylko, że przerabiając kurs pętla while jest pod sam koniec :)
P-84228
usmiech
» 2013-05-28 21:35:52
no tak... Rozumiem :)
A odnosnie Twojego zadania , to skupilbym sie na algorytmie okreslajacym dlugosc jakiejs liczby n, a losowalbym juz normalnie ....:)

ps

mozesz pozniej uzyc switch, if.... no co wolisz :)
sposobow zapewne jest wiele, dlatego c++ jest taki fajne ;)

Przeanalizuj ten kod :)

C/C++
#include "stdafx.h"
#include <ctime>
#include <cmath>
#include <iostream>
using namespace std;
int myRand( int Min, int Max )
{
    return rand() %( Max - Min + 1 ) + Min;
}

int main()
{
   
    int n;
    int iloscLosowanych;
    int losowa[ 100 ];
    srand( time( NULL ) );
   
    cout << "Prosze wprowadzic rozmiar liczby /ilosc cyfr/, ktore maja byc losowane: ";
   
    while( !( cin >> n ) || n <= 0 )
    {
        cout << "\nWprowadzono niepoprawne dane !!!\n"
        << "Sprobuj jeszcze raz :)\n";
        cin.clear();
        cin.ignore( 10000, '\n' );
        cout << "\nProsze wprowadzic rozmiar liczby /ilosc cyfr/, ktore maja byc losowane: ";
    }
    cout << "\nProsze wprowadzic ilosc losowanych liczb w wybranym zakresie : ";
   
    while( !( cin >> iloscLosowanych ) || iloscLosowanych <= 0 )
    {
        cout << "\nWprowadzono niepoprawne dane !!!\n"
        << "Sprobuj jeszcze raz :)\n";
        cin.clear();
        cin.ignore( 10000, '\n' );
        cout << "\nProsze wprowadzic ilosc losowanych liczb w wybranym zakresie : ";
    }
   
    cout << endl;
    int min = pow( 10, n - 1 );
    int max = pow( 10, n ) - 1;
    for( int i = 0; i < iloscLosowanych; )
    {
        losowa[ i ] = myRand( min, max );
        bool czyWylosowana = false;
       
        for( int j = 0; j < i; j++ )
        {
            if( losowa[ j ] == losowa[ i ] )
            {
                czyWylosowana = true;
                break;
            }
        }
       
        if( !czyWylosowana ) ++i;
       
    }
   
    cout << "Wylosowane liczby to : \n";
   
    for( int i = 0; i < iloscLosowanych; ++i )
    {
        cout << losowa[ i ] << " ";
    }
    cout << endl;
   
    system( "pause" );
    return 0;
}

// na poczatku chcialem sie pobawic z switch czy if, ale chyba tak lepiej :)
// minus tablicy... tu okreslono ilosc losowan do 100... mozna to zrobic inaczej, ale nie teraz ...;-)
// klasy sa podstawa C++, ale moja rada... opanuj perfect podstawy :)
// aha ... i nie 'bawilem' sie z ulamkami :)

Poprawiony kod dla n = 1;

C/C++
#include "stdafx.h"
#include <ctime>
#include <cmath>
#include <iostream>
using namespace std;
int myRand( int Min, int Max )
{
    return rand() %( Max - Min + 1 ) + Min;
}

int main()
{
   
    int n;
    int iloscLosowanych;
    int losowa[ 100 ];
    srand( time( NULL ) );
   
    cout << "Prosze wprowadzic rozmiar liczby /ilosc cyfr/, ktore maja byc losowane: ";
   
    while( !( cin >> n ) || n <= 0 )
    {
        cout << "\nWprowadzono niepoprawne dane !!!\n"
        << "Sprobuj jeszcze raz :)\n";
        cin.clear();
        cin.ignore( 10000, '\n' );
        cout << "\nProsze wprowadzic rozmiar liczby /ilosc cyfr/, ktore maja byc losowane: ";
    }
    cout << "\nProsze wprowadzic ilosc losowanych liczb w wybranym zakresie : ";
   
    while( !( cin >> iloscLosowanych ) || iloscLosowanych <= 0 )
    {
        cout << "\nWprowadzono niepoprawne dane !!!\n"
        << "Sprobuj jeszcze raz :)\n";
        cin.clear();
        cin.ignore( 10000, '\n' );
        cout << "\nProsze wprowadzic rozmiar liczby /ilosc cyfr/, ktore maja byc losowane: ";
       
    }
    while( n == 1 && iloscLosowanych > 9 )
    {
        cout << "\nDla liczb o dlugosci 1 max ilosc losowan to 9 !!!!\n";
        cin.clear();
        cin.ignore( 10000, '\n' );
        cout << "\nProsze wprowadzic rozmiar liczby /ilosc cyfr/, ktore maja byc losowane: ";
        cin >> iloscLosowanych;
        break;
    }
   
    cout << endl;
    int min = pow( 10, n - 1 );
    int max = pow( 10, n ) - 1;
   
   
    for( int i = 0; i < iloscLosowanych; )
    {
        losowa[ i ] = myRand( min, max );
        bool czyWylosowana = false;
       
        for( int j = 0; j < i; j++ )
        {
            if( losowa[ j ] == losowa[ i ] )
            {
                czyWylosowana = true;
                break;
            }
        }
       
        if( !czyWylosowana ) ++i;
       
    }
   
    cout << "Wylosowane liczby to : \n";
   
    for( int i = 0; i < iloscLosowanych; ++i )
    {
        cout << losowa[ i ] << " ";
    }
    cout << endl;
   
    system( "pause" );
    return 0;
}

// i ostatnia poprawka ....

C/C++
#include "stdafx.h"
#include <ctime>
#include <cmath>
#include <iostream>
using namespace std;
int myRand( int Min, int Max )
{
    return rand() %( Max - Min + 1 ) + Min;
}

int main()
{
   
    int n;
    int iloscLosowanych;
    int losowa[ 100 ];
    srand( time( NULL ) );
   
    cout << "Prosze wprowadzic rozmiar liczby /ilosc cyfr/, ktore maja byc losowane: ";
   
    while( !( cin >> n ) || n <= 0 )
    {
        cout << "\nWprowadzono niepoprawne dane !!!\n"
        << "Sprobuj jeszcze raz :)\n";
        cin.clear();
        cin.ignore( 10000, '\n' );
        cout << "\nProsze wprowadzic rozmiar liczby /ilosc cyfr/, ktore maja byc losowane: ";
    }
    cout << "\nProsze wprowadzic ilosc losowanych liczb w wybranym zakresie : ";
   
    while( !( cin >> iloscLosowanych ) || iloscLosowanych < 0 )
    {
        cout << "\nWprowadzono niepoprawne dane !!!\n"
        << "Sprobuj jeszcze raz :)\n";
        loop: cin.clear();
        cin.ignore( 10000, '\n' );
        cout << "\nProsze wprowadzic ilosc losowanych liczb w wybranym zakresie : ";
       
    }
    while( n == 1 && iloscLosowanych > 10 )
    {
        cout << "\nDla liczb o dlugosci 1 max ilosc losowan to 10 !!!!\n";
        cin.clear();
        cin.ignore( 10000, '\n' );
        cout << "\nProsze wprowadzic ilosc losowanych liczb w wybranym zakresie : ";
        cin >> iloscLosowanych;
        if( iloscLosowanych > 10 )
             cout << "Teraz to juz bawisz sie ze mna :)\n";
       
        goto loop;
        break;
    }
   
    cout << endl;
    int min;
    if( n == 1 )
    {
        min = 0;
    }
    else
    {
        min = pow( 10, n - 1 );
    }
   
    int max = pow( 10, n ) - 1;
   
   
    for( int i = 0; i < iloscLosowanych; )
    {
        losowa[ i ] = myRand( min, max );
        bool czyWylosowana = false;
       
        for( int j = 0; j < i; j++ )
        {
            if( losowa[ j ] == losowa[ i ] )
            {
                czyWylosowana = true;
                break;
            }
        }
       
        if( !czyWylosowana ) ++i;
       
    }
   
    cout << "Wylosowane liczby to : \n";
   
    for( int i = 0; i < iloscLosowanych; ++i )
    {
        cout << losowa[ i ] << " ";
    }
    cout << endl;
   
    system( "pause" );
    return 0;
}
P-84243
« 1 » 2
  Strona 1 z 2 Następna strona