Modulo von großer Zahl

Gast
Lutz H. schrieb:
> So programmieren.

Eher nicht, jedenfalls wenn das nicht mal wieder irgendwelche 
Hausaufgaben sind oder man unbedingt "selber machen" will. Vernünftig 
wäre nämlich, nicht ständig das Rad neu zu erfinden und stattdessen eine 
bestehende Bibliothek für "big numbers" in der gewünschten Sprache zu 
benutzen.

Für C wäre das z.B. GMP (gmplib.org).
Gast
Ja, oder sich einfach auf eingebaute Typen verlassen. GCC kann 
folgendes, bei anderen Compiler funktioniert das ähnlich:
1
#include <stdint.h>
2
#include <stdio.h>
3
#include <string.h>
4

5
int main() {
6
  __uint128_t zahl = 0;
7
  char const* string = "123456789012345678901234";
8

9
  for (auto i = 0; i < strlen(string); ++i) {
10
    zahl += (string[i] - '0');
11
    zahl *= 10;
12
  }
13

14
  zahl /= 10;
15

16
  zahl %= 42;
17

18
  printf("%d\n", (uint64_t)zahl);
19
}

Das ist nur ein Proof of Concept... ;)
Gast
Restklassenring
https://de.wikipedia.org/wiki/Restklassenring

Danach kannst du die Zahl durch eine beliebige andere Zahl aus dem 
entsprechenden Restklassenring ersetzten.

Beispiel: 13 % 4
Es spielt keine Rolle, ob du nun 13 % 4 oder 5 % 4 oder -3 % 4 rechnest, 
das Ergenis ist das selbe. Bei negativen Zahlen muss man in C/C++ 
aufpassen.

Du musst also nur feststellen, in welchem Restklassenring sich deine 
Zahl befindet, und deine Zahl gegen eine andere aus dem Ring ersetzen.
OP
nocheinGast schrieb:

>
1
> #include <stdint.h>
2
> #include <stdio.h>
3
> #include <string.h>
4
> 
5
> int main() {
6
>   __uint128_t zahl = 0;
7
>
8
> 
9
>
>
> Das ist nur ein Proof of Concept... ;)

uint128_t habe ich noch nie von gehört. Aber mein Compiler kennt den 
Datentyp auch gar nicht. Oder wie implementiere ich den in das Programm?
Persönliche Seite
Für eine einfache Implementierung brauchst du folgende Grundarithmetik:

- Rechts-Schieben mit Carry ("mod 2" und "div 2" im Pseudo-Code)
- Links-Schieben ("2 *" im Pseudo-Code)
- Vergleich auf Größergleich " >= " und Ungleichheit " != "
- Addition " + " und Subtraktion " - "
1
// Input: N, M
2
// Output R := N mod M
3

4
R := 0
5
B := 1
6
while N != 0
7
    C := N mod 2
8
    N := N div 2
9

10
    if C != 0
11
        R := R + B
12
        if R >= M
13
            R := R - M
14

15
    B := 2 * B
16
    if B >= M
17
        B := B - M
Gast
Rainer B. schrieb:
> Christian M. schrieb:
>> willst Du durch irgendwelche Zahlen teilen, oder immer durch die
>> Gleiche?
>
> Bei 24-stelliger Ausgangszahl würde ich mal vermuten: Immer die gleiche
> B-)

wohl noch durch 10^n :-))

Gruss Chregu
Persönliche Seite
Wenn die Zahl in einem String gespeichert ist und der Modul wirklich so 
klein ist, dann ist die Hin- und Herwandlung zu 128-Bit int bereits fast 
mehr Aufwand als den Rest zu berechnen :-)

Beispiel in C99, das mit auf einem "normalen" PC mit 32-Bit int immerhin 
für Moduln bis 429496729 taucht:
 
1
#include <stdio.h>
2
#include <stdlib.h>
3
#include <string.h>
4
#include <limits.h>
5
#include <assert.h>
6

7
unsigned mod (char *digits, unsigned mod)
8
{
9
    assert (mod <= UINT_MAX / 10);
10

11
    unsigned rest = 0;
12
    unsigned mod10 = 1;
13
    size_t n_digits = strlen (digits);
14
    
15
    for (size_t n = 0; n < n_digits; n++)
16
    {
17
        unsigned dig = digits[n] - '0';
18
        rest = (rest + dig * mod10) % mod;
19
        mod10 = (10 * mod10) % mod;
20
    }
21

22
    return rest;
23
}
 
Dabei steht die Zahl als little-endian in String digits[], d.h. die 
kleinste Stelle kommt zuerst.  120 ist also dargestellt durch "021". 
Und für big-endian ist's genauso einfach:
 
1
unsigned mod_big_endian (char *digits, unsigned mod)
2
{
3
    assert (mod <= UINT_MAX / 10);
4

5
    unsigned rest = 0;
6
    size_t n_digits = strlen (digits);
7
    
8
    for (size_t n = 0; n < n_digits; n++)
9
    {
10
        unsigned dig = digits[n] - '0';
11
        rest = (10 * rest + dig) % mod;
12
    }
13

14
    return rest;
15
}
Moderator
MH schrieb:
> Hier eine Bibliothek für .Net
>
> http://www.sse-web.de/downloads/c-klassenbibliothek-uint8192/

Man kann auch die Klasse BigInteger aus der .NET-Klassenbibliothek
verwenden.

Aber auch hier gilt (erst recht) der Einwand von Johann:

Wenn der Modul im normalen Integer-Format darstellbar ist und mit der
Zahl nicht noch weitere Berechnungen ausgeführt werden müssen, ist es
wohl besser, direkt auf der ASCII-Darstellung der Zahl zu operieren.

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.