Rechnen mit extrem großen Zahlen

OP #4815090
Hallo ich habe ein C++ (lern) Projekt bei dem ich mit sehr großen 
"Exponenten" (ich hoffe das schreibt man so) Rechnen muss / naja eher 
WILL :) ...

ich bin noch in der "Lernphase" und möchte verstehen wie man so ein 
"Problem" angeht. Ich arbeite mit Code::Blocks und habe mir ein paar 
Grundkenntnisse angeeignet.

jetzt steh ich vor dem Problem, dass aber einer gewissen Zahlengröße 
"gerundet" wird oder der Überlauf zu Negativen zahlen... <- soweit so 
logisch.

meine Rechung 4378^120

Der Windows Taschenrechner macht das gut... WOBEI mich das Ergebnis 
nicht wirklich interessiert denn es wird weiterverarbeitet mit einen 
MODULO
(4378^120) MOD 317 = 48

und lediglich dieser KLEINE INTEGER (in diesen Fall) 48 wird benötigt!

Vermutlich komme ich nicht drumrum noch eine "Library" einzubinden!? 
Wenn ja, woher bekomme ich die und wie mache ich das...

Vielen Dank für jeden Hinweis :)
Gast
Baeri B. schrieb:
> (4378^120) MOD 317 = 48
>
> und lediglich dieser KLEINE INTEGER (in diesen Fall) 48 wird benötigt!
>
> Vermutlich komme ich nicht drumrum noch eine "Library" einzubinden!?
> Wenn ja, woher bekomme ich die und wie mache ich das...

Das ist der passende Algorithmus für das Problem:

https://en.wikipedia.org/wiki/Modular_exponentiation

und in optimierter Form kombiniert man das mit:

https://en.wikipedia.org/wiki/Exponentiation_by_squaring
Gast
Schau dir mal an, ob sich die Modulo-Operation schon auf die Operanden 
deiner Rechnung anwenden lässt.

Bei + -  z.B.  ist es für das Ergebnis egal, ob die Summanden vorher 
zusätzlich nochmal modulo genommen wurden. Dito Multiplikation.
Baeri B. schrieb:
> jetzt steh ich vor dem Problem, dass aber einer gewissen Zahlengröße
> "gerundet" wird oder der Überlauf zu Negativen zahlen... <- soweit so
> logisch.
>
> meine Rechung 4378^120
>
> Der Windows Taschenrechner macht das gut... WOBEI mich das Ergebnis
> nicht wirklich interessiert denn es wird weiterverarbeitet mit einen
> MODULO
> (4378^120) MOD 317 = 48
>
> und lediglich dieser KLEINE INTEGER (in diesen Fall) 48 wird benötigt!

Nur als kleine Randnotiz: Bei mir kommt da in vier verschiedenen 
Programmen (darunter der Windows-Taschenrechner) 259 raus. (Unter der 
Voraussetzung, dass mit ^ nicht wie in C das exklusive Oder, sondern das 
Potenzieren gemeint ist)
Persönliche Seite
Hier eine elementare Implementation in C — die übrigens auch 259 liefert 
— welche ohne Multiplikation, Division und Modulo auskommt (mul, div und 
mod mit 2 rechne ich mal nicht mit, weil das einfachste Bitoperationen 
sind).
1
#include <stdio.h>
2

3
typedef unsigned T;
4

5
static T mod_mul (T n, T a, T b);
6

7
// Return a mod n im kleinsten, nicht-negativen Restsystem (T ist unsigned).
8

9
static T mod_norm (T n, T a)
10
{
11
    if (a < n)
12
        return a;
13

14
    if (n < 2)
15
        return 0;
16

17
    return mod_mul (n, a, 1);
18
}
19

20
// Return a*b mod n
21

22
static T mod_mul (T n, T a, T b)
23
{
24
    // Anstatt  "return (a * b) % n"  berechnen wir das Produkt von Hand,
25
    // was den Bereich erlaubter Moduli von  [sqrt (max_T)] auf
26
    // [max_T / 2] erweitert.
27

28
    // Im folgenden gehen wir davon aus, dass b normiert ist.
29

30
    b = mod_norm (n, b);
31
    
32
    for (T ab = 0;;)
33
    {
34
        if (a % 2 == 1)
35
        {
36
            ab += b;
37
            if (ab >= n)
38
                ab -= n;
39
        }
40
        
41
        if (a < 2)
42
            return ab;
43
        a = a / 2;
44
            
45
        b = b * 2;
46
        if (b >= n)
47
            b -= n;
48
    }
49
}
50

51
// Return a^k mod n
52
//
53
// Exponentiation mit dem gleichen Ansatz wie oben, nur dass
54
// anstatt eines Faktors der Exponent binaer expandiert wird.
55

56
static T mod_pow (T n, T a, unsigned k)
57
{
58
    if (n == 1)
59
        return 0;
60
        
61
    for (T a_k = 1;;)
62
    {
63
        if (k % 2 == 1)
64
            a_k = mod_mul (n, a, a_k);
65
            
66
        if (k < 2)
67
            return a_k;
68
        k = k / 2;
69
            
70
        a = mod_mul (n, a, a);
71
    }
72
}
73

74
int main (void)
75
{
76
    printf ("erg= %u\n", mod_pow (317, 4378, 120));
77
    return 0;
78
}

Negative Exponenten hab ich nicht durchexerziert, dazu nimmt man

https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm#Computing_multiplicative_inverses_in_modular_structures
Wer begrenzte Stellengenauigkeit nicht mag, der kann auch den guten 
alten "bc" bemühen. Gibts seit Anbeginn der Zeit auf jedem 
Unix/Linux-Maschinchen.
https://www.gnu.org/software/bc/
1
> bc
2
bc 1.06.95
3
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
4
This is free software with ABSOLUTELY NO WARRANTY.
5
For details type `warranty'.
6
(4378^120)%317
7
259

Und wer es lieber umgekehrt polnisch mag, der nimmt "dc".
Gast
A. K. schrieb:
> Wer begrenzte Stellengenauigkeit nicht mag, der kann auch den guten
> alten "bc" bemühen. Gibts seit Anbeginn der Zeit auf jedem...
> Und wer es lieber umgekehrt polnisch mag, der nimmt "dc".

Danke für den Hinweis. Ich benutze Linux schon eine Weile, aber das war 
mir neu.
A. K. schrieb:
> Wer begrenzte Stellengenauigkeit nicht mag, der kann auch den guten
> alten "bc" bemühen. Gibts seit Anbeginn der Zeit auf jedem
> Unix/Linux-Maschinchen.

Das war eins der Programme, mit denen ich's ausgerechnet hab. Ein 
anderes war Python, das diese Begrenzung auch nicht hat.
Gast
1
Python 3.5.2+ (default, Nov 22 2016, 01:00:20)
2
[GCC 6.2.1 20161119] on linux
3
Type "help", "copyright", "credits" or "license" for more information.
4
>>> (4378 ** 120) % 317
5
259
Gast
Hallo zusammen,

ich habe gerade mal ausprobiert, ob mein Rechner auch Python kann.
Er kann, und folgendes kommt heraus:

fritz@linux-ot5a:~> python
Python 2.7.12 (default, Jul 01 2016, 15:34:22) [GCC] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> (4378 ** 120) % 317
259L

Aber was bedeutet das "L" hinter der 259?
Gast
fritz schrieb:
> Aber was bedeutet das "L" hinter der 259?

Das bedeutet, dass dies ein long integer ist und somit länger als die 
native Wortlänge der Maschine ist (bedingt durch die Berechnung).
In Python 3 sind alle integers long ints und diese Unterscheidung fällt 
weg.
Gast
Mike B. schrieb:
> sorry, aber 40000^120 ist nicht sonderlich groß

Also für mich ist das eine recht große Zahl.
1
>>> 40000**120
2
1766847064778384329583297500742918515827483896875618958121606201292619776000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Persönliche Seite
MaWin schrieb:
> Mike B. schrieb:
>> sorry, aber 40000^120 ist nicht sonderlich groß
>
> Also für mich ist das eine recht große Zahl.
>>>> 40000**120
> 176684706477838432958329750074291851582748389687561895812160620129261977 
600000000000000000000000000000000000000000000000000000000000000000000000 
000000000000000000000000000000000000000000000000000000000000000000000000 
000000000000000000000000000000000000000000000000000000000000000000000000 
000000000000000000000000000000000000000000000000000000000000000000000000 
000000000000000000000000000000000000000000000000000000000000000000000000 
000000000000000000000000000000000000000000000000000000000000000000000000 
0000000000000000000000000000000000000000000000000

überschaubar

eine 10^3200 braucht schon ein ganze 43*80-Seite...
SCM version 5e5, Copyright (C) 1990-2006 Free Software Foundation.
SCM comes with ABSOLUTELY NO WARRANTY; for details type `(terms)'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `(terms)' for details.
;loading /usr/share/slib/require
;done loading /usr/share/slib/require.scm
;loading /usr/share/slib/require
;done loading /usr/share/slib/require.scm
;loading /usr/lib/scm/Link
;done loading /usr/lib/scm/Link.scm
;loading /usr/lib/scm/Transcen
;done loading /usr/lib/scm/Transcen.scm
> (mod (expt 4378 120) 317)
259
Persönliche Seite
Mike B. schrieb:
> sorry, aber 40000^120 ist nicht sonderlich groß
>
> Ich empfehle die Bibliothek MPArith von Wolfgang Ehrhardt
> http://www.wolfgang-ehrhardt.de/mp_intro.html für Delphi/Freepascal.
>
> Da geht es glaube ich bis 10E1.000.063.

Wieso bekomm ich dafür eine negative Bewertung?

Weil ich satirisch meinte, dass die Zahl nicht besonders groß sei?
etwas überempfindlich?
Persönliche Seite
Der Witz an der Sache ist doch, dass überhaupt keine "großen" Zahlen für 
die Berechnung benötigt werden:

Die größte Zahl, die in der Berechnung und in allen Zwischenschritten 
vorkommt, ist die 4378.  Nachdem diese Reduziert ist, braucht's keine 
größere Zahl mehr als 2*317 = 634; und das alles ließe sich sogar 
komfortabel mit 16-Bit int implementieren.

Und der TO hat das auch gerafft und ist glücklich damit:

Baeri B. schrieb:
> was will man mehr...
>
> tausend dank :)

Natürlich kann man mit roher Gewalt 4378^120 ausrechnen und dass dann 
mod 317 reduzieren, indem man es in Python eintippt oder wo auch immer. 
Der gewünschte Lerneffekt bzgl. des C++ Projekts des TO ist aber gleich 
Null...

Aber immerhin ist der Groschen meim TO gefallen :-))
Gast
Martin K. schrieb:
> Auch wenn der TO jetzt seine Lösung hat, bleibt aber schon die
> Frage,
> wie man das grundsätzlich machen würde.

Naja, entweder schreibt man eine eigene Klasse die sowas kann oder man 
verwendet eine fertige von jemand anderem.

Ich habe vor Jahren mal eine Klasse zum rechnen mit großen Zahlen 
geschrieben, die Zahlen als Strings speichert und auf diese dann 
schriftliche Addition, Subtraktion, Multiplikation und Division 
anwendet. So wie ich es vor langer Zeit in der Grundschule gelernt habe. 
Das war natürlich unglaublich langsam, aber lustig war es trotzdem und 
funktioniert hat es auch.
Beitrag #5164854 wurde von einem Moderator gelöscht.

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 9 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.