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

Silnia dużej liczby

Object Storage Arubacloud
0 głosów
2,286 wizyt
pytanie zadane 15 października 2018 w C i C++ przez Piotrek32 Obywatel (1,610 p.)
nk jak oblcizyc silnie z miliona zeby program sie nie runował przez 2 minuty
komentarz 15 października 2018 przez PanRik Gaduła (4,510 p.)
Może słyszałeś o czymś takim jak przetwarzanie równoległe?
Jeśli chcesz to obliczać na urządzeniu, którego procesor ma wiele wątków to polecam :)

Edit: Jeżeli byś już robił to polecam program odpalać z wykorzystaniem:
(Możliwa ilość wątków - 1), bo jeśli to urządzenia ma interfejs graficzny to się może nieźle ściąć :D
1
komentarz 15 października 2018 przez criss Mędrzec (172,590 p.)
edycja 16 października 2018 przez criss

Może słyszałeś o czymś takim jak przetwarzanie równoległe?

Współbieżność/równoległość nic tu nie pomoże. Dla żadnego współczesnego procesora nie jest problemem wykonać milion mnożeń czy to stało- czy zmiennoprzecinkowych w pomijalnym czasie. Problemem jest ilość pamięci.

Silni z miliona nie policzysz nawet gdybyś symulował obliczenia korzystając ze stringów. Wynikowy string nie zmieści ci się w pamięci. Chyba, że opracujesz jakiś swój sposób zapisu liczb :P

komentarz 15 października 2018 przez mokrowski Mędrzec (155,460 p.)
Czy ja wiem... właśnie sprawdziłem naiwną implementację. Dla 8 wątków z użyciem biblioteki GMP liczy się 15 sek. Jakoś tego specjalnie nie optymalizowałem.
komentarz 16 października 2018 przez PanRik Gaduła (4,510 p.)
Właśnie też mi się wydawało, ludzkość jakoś liczy większe rzeczy niż silnie z miliona i problemem nie jest właśnie ilość pamięci , a czas obliczeń
1
komentarz 16 października 2018 przez mokrowski Mędrzec (155,460 p.)
edycja 16 października 2018 przez mokrowski

Liczba wynikowa ma 5565709 cyfr czyli ~ 5.5 MB. Raczej się zmieści w RAM.

Wersja prosta dla jednego wątku może wyglądać tak:

(C99)

#include <gmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

size_t mpz_out_str (FILE *, int, const mpz_t);

void factorial(int n){
  mpz_t value;

  mpz_init_set_ui(value, 1);

  for (int i = 1; mpz_mul_ui(value, value, i), i <= n ; ++i) {}

  mpz_out_str(stdout, 10, value);
  putchar('\n');
  mpz_clear(value);
}

int main(void){
  int n = 1000000;

  assert( n >= 0);
  factorial(n);

  return EXIT_SUCCESS;
}

Liczy się (oczywiście w zależności od mocy obliczeniowej danego CPU) około 1.5-2 min.

Wielowątkowo trochę mniej czytelny kod. (dodam w wolnej chwili bo mam poza swoim komputerem).

komentarz 16 października 2018 przez criss Mędrzec (172,590 p.)
Oh, to przepraszam za wprowadzenie w błąd
komentarz 16 października 2018 przez PanRik Gaduła (4,510 p.)

@mokrowski, Dzięki, aż w siebie zwątpiłem kiedy VIP napisał , że się nie da :D

komentarz 16 października 2018 przez criss Mędrzec (172,590 p.)
Przepraszam XD nie powinno być tych tytułów punktowych
2
komentarz 16 października 2018 przez mokrowski Mędrzec (155,460 p.)

No .. i jak do tego choć trochę przysiąść to i wyniki lepsze :-) 3.5 sekundy na 8 rdzeniach.

#include <gmpxx.h>
#include <iostream>
#include <vector>
#include <thread>
#include <future>

mpz_class factorial_worker(int start, int end) {
    mpz_class result{1};
    for(auto i = start; i <= end; ++i) {
        result *= i;
    }
    return result;
}

int main() {
    int n = 1000000;
    unsigned cpu_cores = std::thread::hardware_concurrency();
    // TODO: dodanie kalkulacji jeżeli n / cpu_cores nie jest całkowite.
    int chunk = n / cpu_cores;

    // map... 
    std::vector<std::future<mpz_class>> partial_results;
    partial_results.reserve(cpu_cores);

    for(auto i = 0; i < cpu_cores; ++i) {
        partial_results.emplace_back(
                std::async(std::launch::async, factorial_worker, i * chunk + 1, (i + 1) * chunk)
        );
    }

    // reduce...
    mpz_class result{1};
    for(auto& p: partial_results) {
        result *= p.get();
    }
    std::cout << result << '\n';
}

 

3 odpowiedzi

–1 głos
odpowiedź 15 października 2018 przez mhdv Obywatel (1,580 p.)
wybrane 15 października 2018 przez Piotrek32
 
Najlepsza

Przykro mi, ale nawet jeśli zaczniesz operować na string'ach to nie obliczysz silni z miliona :).

Jeśli chcesz przyspieszyć pracę takiego programu to poszukaj A) gotowych bibliotek obsługujących lepsze algorytmy do obliczania silni B) sam przejrzyj np. wikipedie w poszukiwaniu takowych i zaimplementuj samemu w C++.

Chyba nie zdajesz sobie sprawy ze złożoności obliczenia silni z miliona wink

komentarz 15 października 2018 przez Piotrek32 Obywatel (1,610 p.)
dzięki

i zdaje sobie sprawę jak to ogromna i trudna do obliczenia liczba,
komentarz 15 października 2018 przez RafalS VIP (122,820 p.)

Jasne, że to da się zrobić. Np w pythonie int nie ma ograniczeń:

from math import factorial
print(factorial(1000000))

Pomieli dosyć dlugo a liczba prawdopodobnie nie zmiesci się w konsoli xD ale policzy.

0 głosów
odpowiedź 15 października 2018 przez RafalS VIP (122,820 p.)
edycja 15 października 2018 przez RafalS

Da się to zrobić, ale ze względu na złożoność wynikającą z obsługi wielgachnych integerów szybko się to nie policzy.

Potrzebujesz więc jedynie dobrej biblioteki obsługującej duze integery, która w pythonie od wersji 3 jest po cichu wbudowana w normalnego inta i nie ma on ograniczeń, dlatego w najbardziej pytonicznym stylu:

from solutions import solution
print(solution())

Twój problem wygląda tak:

from math import factorial
print(factorial(1_000_000))

Co prawda liczyło sie dobre pare minut i liczba nie zmiesciła się w konsoli, ale policzył :D.

W przypadku innych języków prawdopodobnie będziesz potrzebował jakiejś zewnętrznej biblioteki do obsługi dużych integerów.

–1 głos
odpowiedź 15 października 2018 przez Dominik Kostencki Użytkownik (650 p.)

z tym nk chodzi o symbol Newtona? Czy pytasz po prostu o 1000000! ???

Bo jeśli o newtona to tutaj masz przykład rekurencji która dosyć sprawnie skraca ze sobą liczby podczas liczenia

unsigned long long Newton(unsigned n, unsigned k) {
    if (n == k || k == 0) return 1;
    return Newton(n - 1, k - 1) * n / k;
}

 

komentarz 15 października 2018 przez Piotrek32 Obywatel (1,610 p.)
nk to po prostu niech ktoś
komentarz 15 października 2018 przez Dominik Kostencki Użytkownik (650 p.)
aa okej :D to w takim razie nie wiem czy jest jakiś sposób na obliczenie tak dużej liczby.

Podobne pytania

0 głosów
2 odpowiedzi 2,667 wizyt
pytanie zadane 30 października 2017 w C i C++ przez niezalogowany
0 głosów
1 odpowiedź 159 wizyt
pytanie zadane 30 sierpnia 2017 w Java przez LukasHardwares Początkujący (490 p.)
0 głosów
1 odpowiedź 1,239 wizyt
pytanie zadane 9 kwietnia 2017 w C i C++ przez maciek259 Nowicjusz (240 p.)

92,576 zapytań

141,426 odpowiedzi

319,652 komentarzy

61,961 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.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...