/**
   ZGZ - Ziemlich Grosse Zahl
   --------------------------
   Autor:  Fabian Wleklinski
   Inhalt: Klasse ZGZ: Speichert "ziemlich große Zahlen" in vier long-Variablen und
           bietet elementare Operationen an
*/

/* Die Klasse ZGZ hat einen vorzeichenbehafteten Wertebereich von (-2^255) bis (+2^255-1).
Intern wird der Wert in vier Variablen vom Typ "long" gespeichert.
Bei den Operationen wird keine Bereichsüberprüfung vorgenommen.
*/

public class ZGZ {

   /** Konstruktor **/
   public ZGZ() {
      // vererbten Konstruktor aufrufen
      super();

      // Array initialisieren
      Ziffern = new long [4];
   }

   // Konstruktor, mit dem eine Zahl übergeben werden kann
   public ZGZ( long Ziffer4, long Ziffer3, long Ziffer2, long Ziffer1 ) {
      this();
      Ziffern[3] = Ziffer4;
      Ziffern[2] = Ziffer3;
      Ziffern[1] = Ziffer2;
      Ziffern[0] = Ziffer1;
   }

   /** Gibt den gespeicherten Wert aus **/
   public void Ausgabe () {

      // ein String, in den wir alles reinschreiben
      String output = new String();
      // eine Variable, die den Rest einer Division hält
      long rest;

      long tempziffer0,tempziffer1,tempziffer2,tempziffer3,tempziffer4,tempziffer5,tempziffer6,tempziffer7;
      long temp;
      tempziffer0 = Ziffern[0] & 0xFFFFFFFF;
      tempziffer1 = Ziffern[0] >> 32;
      tempziffer2 = Ziffern[1] & 0xFFFFFFFF;
      tempziffer3 = Ziffern[1] >> 32;
      tempziffer4 = Ziffern[2] & 0xFFFFFFFF;
      tempziffer5 = Ziffern[2] >> 32;
      tempziffer6 = Ziffern[3] & 0xFFFFFFFF;
      tempziffer7 = Ziffern[3] >> 32;

      // Alle Stellen durchlaufen
      boolean fuehrNull;
      fuehrNull = false;
      for (int stelle=1; stelle < 100; stelle++) {

         rest = 0;

         temp = tempziffer7;
         tempziffer7 = ((rest << 32) + temp) / 10;
         rest        = ((rest << 32) + temp) % 10;

         temp = tempziffer6;
         tempziffer6 = ((rest << 32) + temp) / 10;
         rest        = ((rest << 32) + temp) % 10;

         temp = tempziffer5;
         tempziffer5 = ((rest << 32) + temp) / 10;
         rest        = ((rest << 32) + temp) % 10;

         temp = tempziffer4;
         tempziffer4 = ((rest << 32) + temp) / 10;
         rest        = ((rest << 32) + temp) % 10;

         temp = tempziffer3;
         tempziffer3 = ((rest << 32) + temp) / 10;
         rest        = ((rest << 32) + temp) % 10;

         temp = tempziffer2;
         tempziffer2 = ((rest << 32) + temp) / 10;
         rest        = ((rest << 32) + temp) % 10;

         temp = tempziffer1;
         tempziffer1 = ((rest << 32) + temp) / 10;
         rest        = ((rest << 32) + temp) % 10;

         temp = tempziffer0;
         tempziffer0 = ((rest << 32) + temp) / 10;
         rest        = ((rest << 32) + temp) % 10;

         if (rest > 0) {
            fuehrNull = true;
         }

         if ((fuehrNull==false) | (rest > 0)) {
            output = Long.toString( rest ) + output;
         }


      }

      System.out.print( output );
   }

   /** Addiert den übergebenen Wert **/
   public void add( ZGZ src ) {
      /* Die Vorgehensweise ist wie folgt: Jede der vier 64 Bit-Variablen, die den zu addierenden Wert enthalten,
      wird auf die entsprechende Variable der vier 64 Bit-Variablen addiert, die den aktuellen Wert halten. Dies
      ergibt insgesamt vier Additionen. Vor jeder Addition wird geprüft, ob evtl. ein Übertrag auf die nächste
      Variable zustande kommt. Dieser Übertrag wird in einer eigenenen Variable "gemerkt". Bei der nächsten Addition
      von zwei 64 Bit-Variablen wird der Übertrag dann mit verrechnet.
      */

      int i;
      int zifferI;
      long value1;
      long value2;
      long temp;
      long invertedMask;
      boolean Uebertrag;
      boolean curBit;
      boolean curSrcBit;

      Uebertrag = false;

      // Alle vier Variablen abarbeiten
      for (zifferI=0; zifferI<4; zifferI++) {

        value1 = Ziffern[zifferI];
        value2 = src.Ziffern[zifferI];
        temp = 0;

         // Alle 64 Bit abarbeiten
         for (i=0; i<=63; i++) {

            // Das entsprechende Bit des aktuellen Wertes laden
            curBit = ((value1 & 1) != 0);
            value1 = value1 >> 1;

            // Das entsprechende Bit des aktuellen Wertes (Summand) laden
            curSrcBit = ((value2 & 1) != 0);
            value2 = value2 >> 1;

            // Die Bit-Addition ausführen
            if (curBit ^ curSrcBit ^ Uebertrag) {
               temp = temp + 1;
            }

            temp = temp << 1;

            // Wenn ein Übertrag zustande kommt -> merken!
            if ((curBit && curSrcBit) || (curBit && Uebertrag) || (curSrcBit && Uebertrag)) {
               Uebertrag = true;
            } else {
               Uebertrag = false;
            }
         }

         Ziffern[zifferI] = 0;
         // Alle 64 Bit abarbeiten
         for (i=0; i<=63; i++) {
            if ((temp & 1) == 1) {
               Ziffern[zifferI] = Ziffern[zifferI] + 1;
            }
            Ziffern[zifferI] = Ziffern[zifferI] << 1;
            temp = temp >> 1;
         }
      }

   }

   // Hält den Wert
   public long Ziffern[];
}

