Modulo out of Range

  • C#
  • .NET (FX) 4.0

Es gibt 6 Antworten in diesem Thema. Der letzte Beitrag () ist von φConst.

    Modulo out of Range

    Hallo.

    Die Ausgangssituation :

    Ich habe eine Input Zahl, deren wert von Int32.MinValue bis Int32.MaxValue sein kann.
    Ich möchte diesen Inputwert in zwei Zahlen zerlegen die per Modulo Operation (%) wieder den Ausgangswert ergeben.
    Dabei nutze ich folgende Funktion :

    C#-Quellcode

    1. private static Random rnd = new Random();
    2. private static int[] DetermineMod(int val)
    3. {
    4. int[] result = new int[2];
    5. result[0] = rnd.Next(int.MaxValue / 2, int.MaxValue);
    6. result[1] = result[0] - val;
    7. return result;
    8. }


    Wende ich dies bspw auf den Wert 12345 an bekomme ich bspw 1608184877 und 1608172532 zurück.
    Wenn man nun 1608184877 % 1608172532 berechnet kommt man auf 12345. Alles wunderbar.

    Das Problem :

    Ist der Input eine große Zahl, bspw Int32.MaxValue, oder etwas darunter, oder aber Int32.MinValue oder etwas darüber, stimmt die Ausgabe nicht.
    Folglich ergibt die Rechnung auch keinen Sinn mehr und ich bekomme ein falsches Ergebnis zurückgeliefert.

    Meine Fragen :

    1) Warum werden bei großen Zahlen ungültige Werte zurückgegeben?
    2) Welcher Zahlenbereich ist bei meiner Funktion noch legitim, also welche Range als Input resultiert in einem richtigen Output?
    3) Wie kann ich diese Funktion umschreiben so das alle Werte von Int32.MinValue bis Int32.MaxValue als Input gegeben werden können und ein korrekter Output produziert wird?

    Mfg,
    Rikduo
    C# Developer
    Learning C++
    Wenn die Zahl val Größer-gleich (größer wird es nicht sein) int.MaxValue ist, ist das Element bei Index [1] ja logischerweise negativ.
    Setze mal für val -1 raus... auch falsches Ergebnis.

    Die Range ist 0- 529999999, ab dann - so erscheint es an meinem PC - gibt die Methode falsche Ergebnisse zurück.

    Ohne Random.Next:

    C#-Quellcode

    1. private static Random rnd = new Random();
    2. private static int[] DetermineMod(int val)
    3. {
    4. int[] result = new int[2];
    5. result[0] = int.MaxValue ;
    6. result[1] = result[0] - val;
    7. return result;
    8. }


    0-1069999999

    Auf jeden Fall:

    Hier der Fix:

    C#-Quellcode

    1. private static Random rnd = new Random();
    2. private static BigInteger[] DetermineMod(BigInteger val)
    3. {
    4. BigInteger[] result = new BigInteger[2];
    5. result[0] = new BigInteger(double.MaxValue);
    6. result[1] = result[0] - val;
    7. return result;
    8. }


    Einfach BigInteger verwenden.
    Nur wirst du mit negativen Zahlen Probleme haben.


    Hier der vollständige Fix:

    C#-Quellcode

    1. private static Random rnd = new Random();
    2. private static BigInteger[] DetermineMod(BigInteger val)
    3. {
    4. bool isNegative = false;
    5. if (isNegative = val < 0)
    6. val = -val;
    7. BigInteger[] result = new BigInteger[2];
    8. result[0] = new BigInteger(double.MaxValue);
    9. result[1] = result[0] - val;
    10. return isNegative ? new BigInteger[] { -result[0], -result[1] } : result;
    11. }



    C#-Quellcode

    1. var mods = DetermineMod(BigInteger.Parse("1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001"));
    2. Console.WriteLine((mods[0] % mods[1]) );




    Viel Spaß...
    Bilder
    • Screenshot (523).png

      4,33 kB, 639×300, 116 mal angesehen
    Und Gott alleine weiß alles am allerbesten und besser.
    @Rikudo Nimm einfach long, da solltest Du in int-Grenzbereichen keine Probleme bekommen.
    @φConst Random arbeitet auf einem Zufallszahlengenerator, dessen Wertebereich mit int völlig abgedeckt wird, da ist BigInteger völlig oversized.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @Rikudo Wieso überhaupt randomisierte Zahlen wiedergeben?

    C#-Quellcode

    1. private static BigInteger[] DetermineMod(BigInteger val)
    2. {
    3. bool isNegative = false;
    4. if (isNegative = val < 0)
    5. val = -val;
    6. BigInteger[] result = new BigInteger[2];
    7. result[0] = new BigInteger(double.MaxValue);
    8. result[1] = result[0] - val;
    9. return isNegative ? new BigInteger[] { -result[0], -result[1] } : result;
    10. }


    tut es doch auch? (BitInteger, weil "beliebig" große Zahl, long reicht aber sicherlich in der Regel..)
    Und Gott alleine weiß alles am allerbesten und besser.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „φConst“ ()

    @φConst Zuweisungen in konditionalen Auswertungen halte ich für unschön, weil man schnell mal den Operator mit dem Vergleichsoperator verwechselt. Warum also nicht statt false direkt val < 0 zuweisen?
    Aber das brauchst Du doch alles gar nicht. Einfach BigInteger.Abs(BigInteger) nutzen und man spart sich das. Außerdem würdest Du das Vorzeichen bei Dir ja 2 mal umkehren.
    #define for for(int z=0;z<2;++z)for // Have fun!
    Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

    Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:

    Trade schrieb:

    Zuweisungen in konditionalen Auswertungen halte ich für unschön,

    Und?
    Muss ich es "un"schön finden?
    Dann soll der TE es umschreiben.

    Aber das brauchst Du doch alles gar nicht

    Doch, imho schon.
    Wenn der Input negativ ist, dann wird dieser negiert, sodass er positiv ist, ( anders geht es nicht, siehe Post #2 ) und abschließend wird in einer konditionalen Auswertung entschieden ob
    es vorher negativ , oder positiv war.
    Wenn ersteres, dann negiere, sodass der Output wie erwartet auch negativ ist, andernfalls lassen.
    Und Gott alleine weiß alles am allerbesten und besser.