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

jak przyspieszyc rekurencje

Aruba Cloud VPS - 50% taniej przez 3 miesiące!
0 głosów
426 wizyt
pytanie zadane 27 grudnia 2022 w C i C++ przez polandonion Dyskutant (7,560 p.)

Witam, zastanawiam się dlaczego zadanie link nie wchodzi mi na 100%. Na komputerze dla najwiekszego testu liczby mi +/- 10s, natomiast na szkopule ledwo zmiescilem sie w czasie (tj. 19.98s / 20.00s)? Czy to przez rekurencje? A jak tak to jak to przyspieszyć? Dodam, ze oryginalne zadanie (z OIJ) robilem identycznym sposobem (tj. rekurencyjne "doklejanie" cyfr).

moj kod: link.

Tutaj dla porownania oryginalne zadanie: link oraz rozwiązanie: link.

komentarz 27 grudnia 2022 przez Oscar Nałogowiec (29,340 p.)

Wydaje mi się, że nadużywasz funkcji pow. Szczególnie, że wywołujesz ją wielokrotnie z tymi samymi argumentami.

komentarz 27 grudnia 2022 przez polandonion Dyskutant (7,560 p.)
sprawdzalem, to nie tu lezy blad, byc moze po prostu szkopul ma jakis wolniejszy kompilator

1 odpowiedź

+2 głosów
odpowiedź 27 grudnia 2022 przez Gynvael Coldwind Nałogowiec (30,110 p.)
wybrane 27 grudnia 2022 przez polandonion
 
Najlepsza
Na samym cache'owaniu prim() można ściąć połowę czasu btw.

Ten pow(10, dl) faktycznie nie wygląda tam zbyt szczęśliwie, ale on sam raczej nie wprowadzi zbyt dużego laga.
komentarz 27 grudnia 2022 przez polandonion Dyskutant (7,560 p.)
tylko dlaczego oryginalne zadanie dla wartosci 10^18 dziala .2s a to tutaj ok 20 dla wartosci 10^6 razy mniejszych? musi byc jakies wytlumaczenie i to raczej nie przez prime() bo w tamtym zadaniu licze pierwszosc liczby w ten sam sposob
komentarz 27 grudnia 2022 przez Gynvael Coldwind Nałogowiec (30,110 p.)
Oryginalne zadanie aż tak bardzo się nie rozgałęzia. Dla tych samych liczb testowych (1 1000000000000) w oryginalnym zadaniu będziesz mieć tak ze 300 wywołań rekDokl w sumie, gdzie w zmodyfikowanym to będzie około 32000.
komentarz 27 grudnia 2022 przez polandonion Dyskutant (7,560 p.)
edycja 27 grudnia 2022 przez polandonion
nie bardzo rozumiem co to jest cachowanie i jak tego uzyc, ale moze sie przydac, wiec bylbym wdzieczny za pokazanie jak tego uzyc
2
komentarz 27 grudnia 2022 przez Gynvael Coldwind Nałogowiec (30,110 p.)

Cache'owanie wyników to po prostu zapisywanie wyników po ich wyliczeniu do jakiejś struktury danych (np. unordered_map), a potem przy kolejnym wywołaniu funkcji przed przejściem do kosztownych obliczeń sprawdza się najpierw czy w tej "pamięci podręcznej" czasem wyniku już nie ma. Np.:

unordered_map<ull, int> prim_cache;

bool prim(ull x) {
        const auto cache = prim_cache.find(x);
        if (cache != prim_cache.end()) {
                return cache->second;
        }

        for (ull i = 2; i * i <= x; i ++) {
                if (x % i == 0) {
                        prim_cache[x] = 0;
                        return 0;
                }
        }
        prim_cache[x] = 1;
        return 1;
}

Można by jeszcze rzucić potem okiem na rozkład tych liczb w pamięci podręcznej. Może użycie sita Eratostenesa żeby trochę wypełnić pamięć podręczną dało by też jakiegoś boosta.

komentarz 27 grudnia 2022 przez mokrowski Mędrzec (156,460 p.)
edycja 28 grudnia 2022 przez mokrowski

Zanim włączał bym memoizację (czyli cache), przyśpieszył bym sam algorytm sprawdzania liczby pierwszej. Daje to wg. moich pomiarów przyśpieszenie (co nie dziwne bo mniej pętli):

bool prim(ull x) {    
        if ((x == 2) or (x == 3)) {    
                return true;    
        }    
    
        if ((x <= 1) or ((x % 2) == 0) or ((x % 3) == 0)) {    
                return false;    
        }    
    
        for (auto i = 5ULL; i * i <= x; i += 6) {    
                if (((x % i) == 0) or ((x % (i + 2)) == 0)) {    
                        return false;    
                }    
        }    
    
        return true;    
}

Krótki test rozwiązania orig.:

$ time echo "1 10000000000" | ./prim 
2683
real	0m1,285s
user	0m1,285s
sys	0m0,001s

Po poprawce:

$ time echo "1 10000000000" | ./prim
2683
real    0m0,430s
user    0m0,423s
sys    0m0,008s

Teraz dodanie memoizacji (co nie jest raczej rozwiązaniem eleganckim w takich konkursach ale może dawać przyśpieszenie), która może wyglądać tak (proszę mnie poprawić jeśli jest jakaś niezręczność związana z wydajnością):

bool prim(ull x) {
	if ((x == 2) or (x == 3)) {
		return true;
	}

	if ((x <= 1) or ((x % 2) == 0) or ((x % 3) == 0)) {
		return false;
	}

	static unordered_map<ull, bool> prim_cache;
	const auto & cache = prim_cache.find(x);
	if (cache != prim_cache.end()) {
		return cache->second;
	}

	for (auto i = 5ULL; i * i <= x; i += 6) {
		if (((x % i) == 0) or ((x % (i + 2)) == 0)) {
			return prim_cache[x] = false;
		}
	}
	return prim_cache[x] = true;
}

I efekt:

$ time echo "1 10000000000" | ./prim
2683
real    0m0,320s
user    0m0,321s
sys    0m0,000s

No i wyszło ~ 4 x szybciej

A dalsze przyśpieszenie, zgadzam się.. Sito.

Podobne pytania

0 głosów
3 odpowiedzi 613 wizyt
pytanie zadane 16 kwietnia 2020 w C i C++ przez XiverKi Bywalec (2,050 p.)
0 głosów
2 odpowiedzi 1,367 wizyt
pytanie zadane 21 stycznia 2017 w C i C++ przez Darven Użytkownik (860 p.)
0 głosów
5 odpowiedzi 286 wizyt
pytanie zadane 15 października 2015 w Nasze projekty przez Mariusz Szczerbal Użytkownik (580 p.)

93,187 zapytań

142,202 odpowiedzi

322,012 komentarzy

62,513 pasjonatów

Advent of Code 2024

Top 15 użytkowników

  1. 2365p. - dia-Chann
  2. 2326p. - Łukasz Piwowar
  3. 2315p. - Łukasz Eckert
  4. 2269p. - Tomasz Bielak
  5. 2235p. - Łukasz Siedlecki
  6. 2192p. - CC PL
  7. 2119p. - rucin93
  8. 2006p. - Michal Drewniak
  9. 1946p. - Adrian Wieprzkowicz
  10. 1901p. - Mikbac
  11. 1744p. - rafalszastok
  12. 1734p. - Anonim 3619784
  13. 1586p. - Dawid128
  14. 1520p. - Marcin Putra
  15. 1480p. - ssynowiec
Szczegóły i pełne wyniki

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

Wprowadzenie do ITsec, tom 1 Wprowadzenie do ITsec, tom 2

Można już zamawiać dwa tomy książek o ITsec pt. "Wprowadzenie do bezpieczeństwa IT" - mamy dla Was kod: pasja (użyjcie go w koszyku), dzięki któremu uzyskamy aż 15% zniżki! Dziękujemy ekipie Sekuraka za fajny rabat dla naszej Społeczności!

...