Optymalizacja iteracji metodą rekurencji.

0

Witam Forumowiczów,
Czas wykonywania Voida jest zbyt długi i wynosi dla wszystkich ciał voida mniej więcej tyle samo +/- 20.5 sek.
Proszę o pomysł na alternatywne ciała voida, a w szczególności rekurencyjne.
Poniżej przykładowy kod do wywołania funkcji void.
Podaję poniżej przykładowy kod jak wywoływana jest funkcja void. Dane w tabeli Z[] są zawsze rosnące i unikalne, bez powtórzeń.
Napisałem kod do generatora losowego, tak by liczby w tabeli były rosnące, w przykładzie liczby się powtarzają,
co będzie można zobaczyć po kompilacji podanego niżej kodu.
Pierwsze i trzecie ciało działa na tej samej zasadzie, zlicza niepowtarzalne liczby, oraz te powtarzalne,
tak może robić bo w rzeczywistym kodzie jak pisałem wartości są unikalne i rosnące.
Natomiast drugie ciało voida zlicza unikalne wartości w tabeli, co tez jest poprawne , gdy są unikalne wartości w tabeli Z[].
Z kolei zmienna 'q' po każdej iteracji funkcji zlicza zera w tabeli Z[], także na tym przykładzie zmienna q na starcie ma wartość 19 i maleje wraz z ilościa iterowań funkcji.
Zmienna q jest potrzeba w dalszym kodzie do optymalizacji innych iteracji.

include <iostream>
include <cstdlib>
include <time.h>
include <fstream>
include <cmath>
include <random>
include <chrono>
include <iomanip>

using namespace std;
double liczby[]={1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0,16.0,17.0,18.0,19.0,20.0};
double Z[19];
int tabl[19];
void Zliczanie(double B1[], double B2[], int B3[])
{
    int q=0;
    for(int S=0;S<=19;S++)
    {
    for(int s=q; s<=19;s++)

    {   double a=(B1[s]-B2[S])/B2[S];
        if(a<0){a*=-1;};
        if(a<0.000000001){B3[s]+=1;q=s;break;};}
    }
}

/*{
//q=0;
int s=-1;
double a;
    for(int S=0;S<=19;S++)
    {
        do
        {
          ++s;
          a=(B1[s]-B2[S])/B2[S];
          if(a<0){a*=-1;};

        }while(a>0.000000001);

    ++B3[s];
    }
//q=s;
}*/

/*{
    //q=0;
    int s=0;
    int S = 0;
    while(true)
    {
        double a=(B1[s]-B2[S])/B2[S];
        if(a<0){a*=-1;};
        if(a>0.000000001)
        {
            ++s;
        }
        else
        {
            ++S;
            ++B3[s];
        }

        if(S==20)
            break;
    }
    //q=s;
}*/

int main()
{
    unsigned seed = static_cast<int> (chrono::system_clock::now().time_since_epoch().count());
    mt19937 generator(seed);
    uniform_int_distribution<int> distribution(1, 20);

for(int k=0;k<=0;k++) // nie dzialajaca pêtla, by zilustrowac jak jest iterowane wywolanie voida
{                      // i zmieniajace siê wartoœci w tablicy Z[] przed kazda iteracji voida

    for(int S=0;S<=19;S++)
    {
     n:
     Z[S]=distribution(generator);
     if(Z[S]<Z[S-1]){goto n;};
    }


    Zliczanie(liczby,Z,tabl);


    for(int w=0;w<=19;w++)
    {
     cout<<liczby[w]<<"  "<<tabl[w]<<"  "<<Z[w]<<endl;
    }
}

    return 0;
}
0

Fasadin się zagotował xD
Napisz co chcesz konkretnie uzyskać. We wcześniejszym wątku pytali Ciebie o to, bo być może jest to wina algorytmu zastosowana przez Twój kod.

1

Co Ty nazywasz ciałem voida i funkcją void? Nie ma takich pojęć.

3
  1. Masz off-by-one w tych wszystkich pętlach bo tablica na 19 elementów ma indeksy od 0 do 18.
  2. Ja nadal nie rozumiem co ty chcesz osiagnąć. Przeczytaj ten swój post młodszej siostrze albo mamie i spytaj czy rozumieją o co pytasz...
  3. Rekurencja w C/C++ to pomysł chybiony bo mogę ci zaręczyć że nie będzie szybciej a wielokrotnie wolniej.
  4. goto w kodzie? Serio? Upadłeś na głowę?
  5. Nie rozumiem czemu w taki dziwny sposób chcesz liczyć liczby powtarzalne i niepowtarzalne. Nie wystarczy ci ze (x-y) < eps ? Po co tam to dzielenie?
  6. To jest niemożliwe żeby prosty jak budowa cepa algorytm O(n2) z n=19 wykonywal ci się 20s chyba że masz komputer na węgiel. Oczywiście te dwa wykomentowane kody są idiotyczne i mogą sie kręcic i do końca świata bo tam to robisz w ogóle off-by-bardzo-dużo i chyba tylko cudem ten program sie nie wywala. Przecież ty tam w ogóle nie kontrolujesz indeksów nigdzie - podbijasz sobie wesoło zmienne s patrząc tylko i wyłącznie na wynik a i w ogóle nie myśląc o tym co się stanie jak s przekroczy 18 ;] Ten pierwszy kod z dwoma forami jest ok z dokładnością do off-by-one bo warunek pętli powinien być < 19. Ale te dwa while True są zupełnie źle.
0

Im dłużej na to patrze tym mniej rozumie o co ci biega. Zrozumiałem że chodzi o to by pozliczać z tablicy Z wartości które się powtarzają, ale to można zrobić o wiele prościej np biorąc pierwszy element tablicy i porównując go z następnymi i tak po kolei. Z drugiej strony piszesz że elementy tablicy Z są rosnące i niepowtarzalne to po co je zliczać?

1

a nie lepiej uzyc std::map do teg? (bo z tego co zrozumialem to chcesz sprawdzic czy liczba juz istnieje). Dostep do elementu jest zawsze staly i jezeli istnieje to juz wiesz ze istnieje taki element. Na pewno szybsze niz to co masz

1

Do sprawdzenia czy cos istnieje std::unordered_set a do samego zliczania faktycznie std::map albo std::unordered_map byłyby najlepsze.

0

No faktycznie do zliczania std::map, ta rekurencja zbiła mnie z tropu xD

0

Dziękuję za podpowiedzi a można poproprosić o przykładowy kod bo nie mam pojęcia jak zastosować std::unoldered oraz std::map

0

Bylem już na tej www , jednakże jestem początkującym koderem c++ i nie ogarniam jak stosuje się unoldered_set oraz unoldered_map. Prosiłbym o przykładowy kod odnosząć się do mojego przykładu jaki podawałem na początku.

1
    std::unordered_map<int, int> occurences;
    int max = 10000;
    for (int i = 0; i < max; ++i) {
        occurences[get_random()] += 1;
    }
    
    for (auto it = occurences.cbegin(); it != occurences.cend(); ++it) {
        std::cout << it->first << " occured " << it->second << " times\n";
    }

Czy jeszcze czegoś potrzebujesz? Kawy do tego? ;)

0

A dziękuję, ale kawy nie pijam, natomiast skuszę się na słodki deserek w postaci:

std::unoldered_map<double, double> occurences; 

tzn. porównywanie liczb niewymiernych, a nie dla całkowitych dodatnich.
Czy w ogóle jest to możliwe hmm

0

a no tak, literówka :P czyli rozumiem, że na

<double, double>

też będzie działać

1

Nie mam pojęcia co masz na myśli. Mapowanie double do double jest oczywiście możliwe, ale nie bardzo widzę jak może się dana liczba w zestawie pojawić 4.23 razy.

No i przy dostępie można się oczywiście nadziać, jak zwykle przy używaniu floating point.

0

no bo zdeklarowane typy danych voida jako argumenty to double oraz w ciele voida jest porównanie dwóch liczb niewymiernych i gdy będą się równać do określonej dokładności wówczas jest +=1

1

zdeklarowane typy danych voida ... w ciele voida
Jakiego znowu "voida"? Jeśli masz na myśli funkcję Zliczanie to zwij żesz ją pan po imieniu. Kultura tego wymaga. ;)
Poza tym, funkcja Zliczanie nie bierze wcale danych double, tylko wskaźniki na double (ta notacja jest traktowana jak foo(double*, double*, double*)).

No ale wracając - ja to tam widzę std::unordered_map<double, int>. Jeśli tych wartości może być bardzo dużo to rozważ zmianę int na jakiś "szerszy" pod względem ilości przydatnych wartości typ (unsigned int, intmax_t, uintmax_t __uint128_t, ...).

0

A jak dane wynikowe zapisać do dwóch tablic(pierwsza tablica z danymi a druga z ilością występować tych danych), a nie wyświetlać cout-em ?

0

A muszą być tablice? Czemu nie posłać do funkcji std::vector i mapę przez referencje? Po prostu pracuj na nich i po powrocie z funkcji wszystko masz na tacy.

0

no dobrze byłoby z tablicami i prosiłbym też o przykład jak odczytać za pomocą

std::vector

Albo inaczej, wyciągnąć jedną dowolną wartość wraz jej powtórzeniami.

0

Może to kac obniża mi tolerancję w niedzielny poranek, ale nie sądzisz, że troszeczkę, deczko, ociupinkę, tyyyyci tyci przeginasz? :P Dokumentacja odnośnie std::vector i std::map/std::unordered_map jest na wyciągnięcie ręki, czy tam myszki. Są tam przykłady użycia tych kontenerów. Ba, sam Ci podrzuciłem przykład zliczania powyżej. Żeby działał on z double potrzebna jest jedynie trywialna zmiana.

Nie rozmawiamy tu przecież o czarnej magii, jeżeli mając te wszystkie źródła informacji nie potrafisz czegoś działającego sklecić do kupy, to znaczy, że nie masz opanowanych podstaw. Uczenie się programowania ma jednak coś wspólnego z uczeniem się matematyki - jeśli podstaw nie opanujesz, to reszty nie połapiesz, bo wszystko na tych podstawach bazuje.

Przyłóż się, poczytaj jeszcze raz o funkcjach i parametrach funkcji, o referencjach.

0

Spokojna Twoja rozczochrana Xupicor, dałem radę ogarnąć tzn. jak wyciągnąć z kontenera daną o najmniejszej ilości powtórzeń (poniżej podaję kod). Teraz rodzi się pytanie, chyba już jedno z ostatnich, jak taki kontener opróżnić za jednym zamachem.? Prosi bym o przklad na instniejacym kodzie.

#include <iostream>
#include <cstdlib>
#include <time.h>
#include <fstream>
#include <cmath>
#include <random>
#include <chrono>
#include <iomanip>
#include <unordered_map>

using namespace std;
unordered_map<int, int> occurences;
int main()
{

int j,a,b=100;
unsigned seed = static_cast<int> (chrono::system_clock::now().time_since_epoch().count());
    mt19937 generator(seed);
    uniform_int_distribution<int> distribution(1, 10);


int max = 100;
for (int i = 0; i < max; ++i)
{
        occurences[distribution(generator)] += 1;
        occurences[distribution(generator)] += 1;
}

for (auto it = occurences.cbegin(); it != occurences.cend(); ++it)
{

cout<<it->first<<"  ";
cout<<it->second<<endl;

}
cout<<endl;

for(int j=1;j<=9;j++)
{
    if(b>occurences[j]){a=j;b=occurences[j];};
}


cout<<a<<" "<<b;

    return 0;
}
2
Jakub_30 napisał(a):

Teraz rodzi się pytanie, chyba już jedno z ostatnich, jak taki kontener opróżnić za jednym zamachem.? Prosi bym o przklad na instniejacym kodzie.

@Jakub_30 Waść dokumentacji nawet nie otworzyłeś!

occurances.clear()
0

Dziękuję za poprawną krytykę oraz użyteczne przykłady. Pozdrawiam i do napisania w innych postach/tematach. Temat uważam za zamknięty.

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