2010-10-01 10 views
13

Wiem, że istnieje sposób na znalezienie sumy cyfr 100! (Lub dowolnej innej silnej liczby) za pomocą Pythona. Ale uważam, że to naprawdę trudne, jeśli chodzi o C++, ponieważ rozmiar nawet LONG LONG to za mało.Czy istnieje sposób na znalezienie sumy cyfr 100 !?

Po prostu chcę wiedzieć, czy jest jakiś inny sposób.

Rozumiem, że nie jest to możliwe, ponieważ nasz procesor ma zazwyczaj 32 bity. To, co mam na myśli, to inny rodzaj skomplikowanej techniki lub algorytmu, który może osiągnąć to samo przy użyciu tych samych zasobów.

Odpowiedz

6

long long nie jest częścią C++. g ++ zapewnia to jako rozszerzenie.

Arbitrary Precision Arithmetic to coś, czego szukasz. Sprawdź pseudokod podany na stronie wiki.

Ponadto long long nie może przechowywać tak dużych wartości. Możesz więc utworzyć klasę BigInteger lub korzystać z bibliotek innych firm, takich jak GMP lub C++ BigInteger.

+2

C++ 0x ma 'long' long', zapożyczone z C, które włączyło go do standardu ponad dekadę temu. – hobbs

6

Jeśli chodzi o problem związany z projektem Euler, moim odczytaniem tego jest to, że chce on napisać własną bibliotekę lub klasę całkowitą o dowolnej dokładności, które mogą mnożyć liczby.

Moja sugestia polega na przechowywaniu dziesięciocyfrowych cyfr numeru, w odwrotnej kolejności, niż zwykle piszesz, ponieważ i tak musisz w końcu przekonwertować liczbę na podstawę 10. Przechowywanie cyfr w odwrotnej kolejności sprawia, że ​​pisanie dodawania i mnożenia jest nieco łatwiejsze, moim zdaniem. Następnie zapisz procedury dodawania i mnożenia, które emulują sposób ręcznego dodawania lub mnożenia liczb.

+2

Uważam to prostsze w użyciu wektor liczb całkowitych, z których każdy używa tylko połowę swoich bitów (w przypadku korzystania z 64 bitową liczbę całkowitą, przechowywać w każdy element ma tylko 32 bity), dzięki czemu można zagwarantować, że w żadnej z operacji nie będzie przepełnienia. Następnie każdą czynność można wykonać najpierw w każdej podelementie, a następnie obiekt można normalizować w sekwencyjny sposób. –

+2

@David Rodríguez - dribeas - Zgadzam się, że ogólnie rzecz biorąc jest to lepsze rozwiązanie, zwłaszcza jeśli ważna jest szybkość użycia pamięci lub szybkość obliczeń. Ale w tym konkretnym przypadku, jeśli wszystko, co chcesz, to suma cyfr w bazie 10, ale skutecznie przechowujesz je w innej bazie, musisz napisać także funkcję podziału lub konwersji bazy. – Doug

+3

Nie wiem, czym jest Projekt Euler, więc jeśli masz rację, możesz mieć lepszy wgląd w wymagania dotyczące wydajności, ale IMO, jeśli uczy się C++ w Pythonie, i używając tego jako ćwiczenia, może zrobić coś gorszego niż umieść cyfry kodowane ASCII w std :: string. Uzyskanie działającego algorytmu mnożenia jest ważniejsze niż wydajna reprezentacja danych, a znany typ, który rośnie i może być trywialnie wyświetlany, ma pewne zalety. Wykonywanie tej cyfry w tym samym czasie jest tak łatwe w obsłudze algorytmu przenoszenia - nie ma potrzeby rezerwowania miejsca w strukturze danych. –

4

Istnieje wiele bibliotek BigInteger dostępnych w C++. Po prostu Google "C++ BigInteger". Ale jeśli jest to problem z programowaniem, powinieneś lepiej spróbować zaimplementować własną bibliotekę BigInteger.

14

Jak znaleźć sumę cyfr 100 !. Jeśli obliczysz 100! najpierw, a następnie znaleźć sumę, a następnie jaki jest sens. Będziesz musiał użyć jakiejś inteligentnej logiki, aby go znaleźć bez faktycznego obliczania 100 !. Usuń wszystkie czynniki pięciu, ponieważ będą one tylko dodawać zera. Myśl w tym kierunku, zamiast myśleć o dużej liczbie. Jestem także pewien, że ostateczna odpowiedź to znaczy, że suma cyfr będzie w LONG LONG.

Istnieją duże biblioteki int C++, ale myślę, że nacisk jest położony na algorytm, a nie na bibliotekę.

+0

Ostateczna odpowiedź tego, co będzie pasować do 'long long'? Łatwo zauważyć, że górna granica sumy cyfr jest znacznie poniżej 100 * 2 * 10 = 2000, która łatwo mieści się w "krótkim". Tymczasem "100!" To 158 cyfr (525 bitów) lub 134 cyfry (445 bitów) bez końcowych zer, więc te nie zmieszczą się w "długim czasie"! – Gabe

+0

Nawet po usunięciu współczynników 10, wynik nadal nie zmieści się w "długim czasie", w ogromnej ilości - patrz komentarz Hobbsa w jednej z pozostałych odpowiedzi. Istnieje forum dla osób, które rozwiązały ten problem i chcą opublikować swoje rozwiązanie, a praktycznie każda odpowiedź na tym forum korzysta z funkcji biblioteki/języka BigNum lub sama tworzy odpowiednik wystarczająco dobry. – Doug

+0

Dlaczego ma tak wiele przebojów? To tylko myślenie życzeniowe, nie sądzę, że istnieje rzeczywiste rozwiązanie zgodne z tym postem. –

0

Możesz wziąć łatwą drogę i użyć perl/python/lisp/scheme/erlang/etc, aby obliczyć 100! używając jednej z ich wbudowanych bibliotek bignum lub faktu, że niektóre języki używają dokładnej liczby całkowitej arytmetyki. Następnie weź ten numer, zapisz go w ciągu znaków i znajdź sumę znaków (z uwzględnieniem "0" = 48 itd.).

Albo, możesz wziąć to pod uwagę w 100 !, dostaniesz naprawdę dużą liczbę z wieloma zerami. Jeśli obliczysz 100! iteracyjnie, rozważ podzielenie przez 10 za każdym razem, gdy aktualna silnia jest podzielna przez 10. Wierzę, że da to wynik w zakresie długiego czasu lub czegoś.

Prawdopodobnie lepszym ćwiczeniem jest napisanie własnej biblioteki int. Będziesz potrzebował go na kilka późniejszych problemów, jeśli nie określisz sprytnych sztuczek.

+0

Re: drugi akapit: twoje przypuszczenie jest wyłączone. Factorial rośnie zbyt szybko. Zwykle 64-bitowa wartość int przepełnia między 20! i 21 !. Usuwanie dziesiątek tak często, jak to tylko możliwe, daje ci aż 23 !. Są tylko cztery zera do usunięcia (10 000), a 22 * ​​23 * 24 to 12 144 - już ponad 10 000. – hobbs

+0

Błąd tak. Spojrzałem tylko na mój kod źródłowy dla problemu 20 projektu Eulera (ten problem), i zasadniczo zrobiłem to w połączeniu z pomysłem abelenky'ego, używając wektora bitowego do śledzenia numerów użytkowych. – Kizaru

+0

Jeśli masz bibliotekę bignum, możesz ogólnie użyć 'div' i' mod', które prawie zawsze będą szybsze niż konwersja do ciągu znaków i użycie tych cyfr. Na przykład: 'digitSum = 0; while (n! = 0) {digitSum + = n.mod (10); n = n.div (10); } ' – Olathe

15

Użyj tablicy cyfrowej za pomocą standardowej, papierowej metody namnażania.Na przykład, w C  :

#include <stdio.h> 

#define DIGIT_COUNT 256 

void multiply(int* digits, int factor) { 
    int carry = 0; 
    for (int i = 0; i < DIGIT_COUNT; i++) { 
    int digit = digits[i]; 
    digit *= factor; 
    digit += carry; 
    digits[i] = digit % 10; 
    carry = digit/10; 
    } 
} 

int main(int argc, char** argv) { 
    int n = 100; 

    int digits[DIGIT_COUNT]; 
    digits[0] = 1; 
    for (int i = 1; i < DIGIT_COUNT; i++) { digits[i] = 0; } 

    for (int i = 2; i < n; i++) { multiply(digits, i); } 

    int digitSum = 0; 
    for (int i = 0; i < DIGIT_COUNT; i++) { digitSum += digits[i]; } 
    printf("Sum of digits in %d! is %d.\n", n, digitSum); 

    return 0; 
} 
+4

Mogę się spóźnić w komentowaniu, ale wciąż nie wiem, dlaczego OP nie zaakceptował tego jako rozwiązania. To jest proste, czyste, pomysłowość jest najlepsza (w zasadzie robi się mnożenie papieru z każdą cyfrą jako element tablicy, aby zająć się problemami bignum.) Kiedy inni używają binarnych i arbitralnych bibliotek precyzji, to rozwiązanie wyróżnia się prostotą, ale niesamowitą skuteczność (widzę, że to byłoby rozwiązanie O (N)), dlaczego jest to tak cicho niezauważone, nieskomentowane, gdy ludzie komentują wiele banalnych "tylko dla samego siebie" odpowiedzi w ogóle na SO.Nadzwyczajne – goldenmean

+0

bardzo efektowne rozwiązanie. :) –

5

Zauważmy, że pomnożenie przez dowolną liczbę lub nie zmienia sumę cyfr.

Kiedy uznają, że widać, że mnożenie przez 2 i 5, lub przez 20 i 50, również nie zmienia sumę, ponieważ 2x5 = 10 i 20x50 = 1000.

Następnie zauważ, że za każdym razem, gdy twoje obecne obliczenie kończy się na 0, możesz po prostu podzielić przez 10 i kontynuować obliczanie silni.

Wykonaj kilka dodatkowych obserwacji dotyczących skrótów, aby wyeliminować liczby od 1 do 100, i myślę, że możesz dopasować odpowiedź do standardowych int.

+2

Powinienem wycofać tę odpowiedź. Po pracy z kilkoma "skrótami" dzisiaj nie znalazłem praktycznego rozwiązania. Sprawdziłem opublikowane rozwiązania do Eulera nr 20 i wszyscy wydawali się robić to z biblioteką BigNum jednej odmiany. Nie jestem już przekonany, że ten problem można rozwiązać w UInt64. Czy ktoś może mi powiedzieć, że tak może być? – abelenky

+0

100 silnia ma długość 158 cyfr i zawiera tylko 24 końcowe zera (źródło [WolframAlpha] (http://www.wolframalpha.com/input/?i=100%21)). Usunięcie zera nie wystarczy, ponieważ [nawet przy usuniętych zerach wymaga 446 bitów] (http://www.wolframalpha.com/input/?i=Ceil%5BLog%5B2%2C+100%21 % 2F10% 5E24% 5D% 5D). – Olathe

1

Nic w projekcie Euler wymaga więcej niż __int64.

Sugerowałbym próbuje zrobić to za pomocą baza 10000.

+2

Python jest bardzo, bardzo sprytny, aby móc to zrobić. Oszałamiająca, że ​​mój 3-letni laptop zwraca 'print sum (map (int, str (math.factorial (30000)))' '' 511470' w ciągu zaledwie kilku sekund. – Potatoswatter

Powiązane problemy