• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Czy dałoby się zrobić to lepiej ?

Mały hosting, OGROMNE możliwości
+1 głos
658 wizyt
pytanie zadane 6 listopada 2015 w C i C++ przez Baakoma Użytkownik (780 p.)
otagowane ponownie 6 listopada 2015 przez Baakoma

Witam, mam do napisania program, którego zadaniem będzie wypisywanie tabliczy mnożenia do podanego wcześniej zakresu liczb (początek i koniec). Napisałem już kod, ale zastanawiam się, czy jest on poprawny i czy nie dałoby się zrobić tego lepiej, łatwiej. Z góry dziękuję i pozdrawiam ! Aha, komentarze są dodane dla nauczyciela :)

#include <iostream>
#include <cstdlib>

using namespace std;

/* stale */
const int MAX_CZYNNIK = 99;
const int MAX_ROZNICA = 13;

/* prototypy */
void wypelnij(int p, int o);
int ustalSzerokosc(int n);
int pobierzDane(int t);
int pobierzDane(int t, int p, int r);

/* glowna funkcja */
int main()
{
    cout << "Podaj liczbe od ktorej zaczynamy: ";
    int pierwszyCzynnik = 0;
    pierwszyCzynnik = pobierzDane(MAX_CZYNNIK); // pobiera dane

    cout << "Podaj liczbe na ktorej konczymy (maksymalnie wieksza o 13 od poprzedniej): ";
    int ostatniCzynnik = 0;
    ostatniCzynnik = pobierzDane(MAX_CZYNNIK, pierwszyCzynnik, MAX_ROZNICA); // pobiera dane

    wypelnij(pierwszyCzynnik, ostatniCzynnik); // wypisuje tabliczke

    //system("Pause"); dla starszych kompilatorow
    return 0;
}

int pobierzDane(int test) // podstawowa wersja funkcji
{
    int dana = 0;

    while(!(cin >> dana)) // sprawdza czy dana jest liczba
    {
        cin.clear(); // czysci flagi bledu
        cin.sync(); // czysci bufor
        cout << "To nie jest liczba ;) Sprobuj ponownie: ";
    }

    if (dana > test || dana <= 0) // sprawdza czy liczba nie jest za duza i nie jest mniejsza lub rowna zero
    {
        cout << "Za duza liczba, zero lub ujemna liczba, sprobuj ponownie: ";
        cin.sync();
        pobierzDane(test); // rekurencja, wywoluje sama siebie
    }
    cin.sync();

    return dana; // zwraca liczbe
}

int pobierzDane(int test, int poprzednia, int roznica) // przeciazona wersja funkcji
{
    int dana = 0;

    while (( ( dana = pobierzDane(test) ) - poprzednia ) > roznica ) // przypisuje danej liczbe z pobierzDane(), nastepnie sprawdza czy nie jest za duza roznica
    {
        cout << "Za duza roznica, kolego :) Sprobuj ponownie: ";
        cin.sync();
    }

    return dana;
}

void wypelnij(int start, int stop)
{
    int szerokosc = ustalSzerokosc(stop * stop); // zmienna potrzebna do ustalenia szerokosci

    cout << endl;
    cout.width(szerokosc); // ustala szerokosc wypisywanych znakow, ulatwienie
    cout << " ";

    for (int i = start; i <= stop; i++) // wypisuje pierwszy wers
    {
        cout.width(szerokosc);
        cout << i;
    }
    cout << endl << endl;

    for (int i = start; i <= stop; i++)
    {
        cout.width(szerokosc);
        cout << i;
        cout << " ";

        for (int j = start; j <= stop; j++)
        {
            cout.width(szerokosc);
            cout << i * j; // mnozenie
        }
        cout << endl;
    }

}

int ustalSzerokosc(int iloczyn) // funkca ustalajaca szerokosc najwiekszej liczby, tzn ilosc znakow
{
    int dlugosc = 2;

    while( (iloczyn /= 10)!=0) // jezeli liczba bedzie jednocyfrowa, to po podzieleniu jej calkowicie przez 10, wynik bedzie rowny 0
        dlugosc++;

    return dlugosc;
}

 

1 odpowiedź

0 głosów
odpowiedź 6 listopada 2015 przez niezalogowany
//system("Pause"); dla starszych kompilatorow

Czemu system ("PAUSE") jest dla starszych kompilatorów? Jak rozumiem odnosi się to do znikania z konsoli, a nie pauzowania jej (co jest nawiasem mówiąc poprawnym zachowaniem), najnowszy Visual potrzebuje tej linii aby konsola nie zniknęła, a ciężko nazwać go żeby był starszym kompilatorem.

Poza tym z tego widzę to nie korzystasz z symetrii w mnożeniu, tzn nie korzystasz z faktu, że a*b = b*a, zaoszczędziłbyś dzięki temu masę obliczeń.

@edit program się sypie jeżeli się poda liczbę zmiennoprzecinkową lub dowolny ciąg znaków.

komentarz 6 listopada 2015 przez Baakoma Użytkownik (780 p.)
Tego niestety nie wiedziałem, dzięki za wytłumaczenie, u nas w szkole jest jakiś stary kompilator, dlatego myślałem, że to tego wina.

Trochę nie rozumiem na jakiej zasadzie miałaby działać symetria, mógłbyś rozwinąć ?

Mógłbyś też powiedzieć na jakiej zasadzie się sypie ? U siebie nie zauważyłem tego problemu.
komentarz 6 listopada 2015 przez niezalogowany

"Sypie" to faktycznie złe słowo, ja ten kod kompilowałem przy użyciu g++ 4.9.2 na Linuksie. W momencie wpisania:

2.5

asdf

Jako output otrzymałem niekończoną pętlę proszącą o wpisanie poprawnych danych (bez przerwy wyświetlał się komunikat z prośbą o ponowne wpisanie liczby).

 

Co do symetrii:

  1. Wiemy, że a*b = b*a, np 3*4 = 12 = 4*3
  2. Zauważamy, że tablica mnożenia to kwadrat, więc łatwo jest wyznaczyć elementy, które leżą na przekątnej.
  3. Zauważamy, że elementy są ułożone w sposób symetryczny względem przekątnej

Np. weźmy tablicę dla liczb [2-5]:

     2  3  4  5

  2   4  6  8 10
  3   6  9 12 15
  4   8 12 16 20
  5  10 15 20 25

Liczby leżące na przekątnej się nie powtarzają, w naszym przypadku to: {4, 9, 16, 25}, wszystkie inne mają swoje lustrzane odbicie.

Uogolniąjąc tablicę otrzymamy coś takiego:

     [0][1][2][3]

  [0] X  a  b  c
  [1] a  Y  d  e
  [2] b  d  Z  f
  [3] c  e  f  T

Małe litery {a,b,c,d,e,f} to liczby które się powtarzają, duże litery to liczby, które leżą na przekątnej {X,Y,Z,T}.

Powinieneś być już w stanie zauważyć pewną zależność, która pozwoli ci zmniejszyć dość znacząco ilość przebiegów pętli (pętla powinna być "trójkątna", a nie "kwadratowa"), następnie wystarczy obliczyć drugą pozycję zmiennej i voilà).

     [0][1][2][3]

  [0] X
  [1] a  Y
  [2] b  d  Z
  [3] c  e  f  T

Oczywiście obecna forma zapisu pozwala na łatwiejsze wstawianie wartości w konsoli, do tego o czym wspomniałem musiałbyś użyć jakiejś tablicy, albo stringa (w zasadzie to jedno i to samo), ale myślę że warto wiedzieć o czymś takim.

Przy większej skali dałoby się łatwo zauważyć, że skorzystanie z symetrii w znaczący sposób jest w stanie wpłynąć na czas działania programu.

komentarz 6 listopada 2015 przez Macek Kolo Mądrala (5,480 p.)
Stare IDE. Przeczytaj czym jest kompilator, a czym IDE :)
komentarz 6 listopada 2015 przez niezalogowany
Bardzo często stare IDE => stary kompilator, a to akurat czy jakaś funkcja działa zależy od kompilatora, a nie od IDE więc w gruncie rzeczy się nie pomylił.
komentarz 6 listopada 2015 przez Macek Kolo Mądrala (5,480 p.)
IDE != kompilator. I nie można tego mylić. A akurat jeśli chodzi o system() to pokaż mi kompilator który tego nie przetrawi. PO drugie IDE jeśli nie jest gówniane to samo zatrzymuje konsole, bez wariacji z pałzowaniem, co jest glupie i błędne to już lepiej jakiegoś getline wstawić. Choć osobiście bym radził zmienić środowisko.
komentarz 6 listopada 2015 przez niezalogowany
Nie powiedziałbym że Visual Studio "jest głupie", zauważ że w większości przypadków (poza rozpoczęciem nauki programowania) efekt pauzowanej konsoli jest niepożądany.

Dla twojej informacji: funkcji system("PAUSE") nie przetrawi poprawnie g++.

Widzę, że nie zrozumiałeś zapisu "Bardzo często stare IDE => stary kompilator", który oznacza, że na starym IDE zazwyczaj jest stary kompilator, nie wspomniałem nigdzie że to jest bez znaczenia, a raczej że autor faktycznie mógł mieć na myśli kompilator, a nie IDE (w gruncie rzeczy ty powinieneś sprawdzić czym się różni kompilator od IDE bo po tej swojej nieco wulgarno-dziecinnej odpowiedzi sprawiasz wrażenie, że tego nie rozróżniasz do końca).
komentarz 6 listopada 2015 przez Macek Kolo Mądrala (5,480 p.)
Przecież od początku twierdzę, że pałzowanie jest złe. Niektóre środowiska jak np. QtCreator potrafi to zrobić bez problemów.

Dla twojej informacji, nie wiem co ty masz na kompie ale moje g++ jak najbardziej poprawnie wszystko skompilowało.

Wulgarnej?

Ale czytając co napisał autor widać że miał na myśli IDE. Nie zamierzam tracić czasu na takich jak ty, bo widzę że masz problem ze sobą.
komentarz 6 listopada 2015 przez niezalogowany
Ehh, czemu nie czytasz ze zrozumieniem? "nie przetrawi poprawnie g++" =/> "przekompiluje", po prostu nie działa poprawnie (i "pauzowanie", nie "pałzowanie").

Najprawdopodobniej autor myślał o IDE, ale czy jesteś w stanie wskazać konkretną linię która by wskazywała bez żadnych wątpliwości że miał na myśli IDE, a nie kompilator?

Z resztą mniejsza, bo zeszliśmy z tematu tego wpisu dość mocno.
komentarz 7 listopada 2015 przez Baakoma Użytkownik (780 p.)
U mnie na CodeBlocks na Windows nie ma takiego problemu, więc nie wiem co możnaby zrobić ;/

Dziękuję za wyłumaczenie, postaram się wdrążyć to do programu :)
komentarz 7 listopada 2015 przez niezalogowany
Chciałbym cię jeszcze uświadomić, że to co ci przedstawiłem jest na wyższym poziomie, więc twoje rozwiązanie powinno zupełnie wystarczyć w liceum/technikum (może wystarczy jedynie wspomnienie przy nauczycielu, że wiesz jak zrobić to lepiej), różnica w złożoności jest dość spora
komentarz 8 listopada 2015 przez Baakoma Użytkownik (780 p.)
Tak czy siak spróbuję to zaimplementować, dla siebie :) dziękuję jeszcze raz i pozdrawiam !

Podobne pytania

0 głosów
2 odpowiedzi 1,129 wizyt
pytanie zadane 1 sierpnia 2015 w C i C++ przez kmieciak_m Mądrala (7,450 p.)
0 głosów
1 odpowiedź 2,150 wizyt
pytanie zadane 26 stycznia 2021 w C i C++ przez Marak123 Stary wyjadacz (11,190 p.)
0 głosów
0 odpowiedzi 542 wizyt
pytanie zadane 21 kwietnia 2019 w C i C++ przez Dawid Markiewicz Obywatel (1,590 p.)

93,715 zapytań

142,629 odpowiedzi

323,259 komentarzy

63,255 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj

Twierdza Linux. Bezpieczeństwo dla dociekliwych

Aby uzyskać rabat -10%, użyjcie kodu pasja-linux, wpisując go w specjalne pole w koszyku.

...