content: // <XMP>
  // Decomposition of a number in a sum of four cubes
  //
  // Written by Dario Alejandro Alpern (Buenos Aires - Argentina)
  // Last updated March 27th, 2005.
  // See http://www.alpertron.com.ar/FCUBES.HTM
  //
  // No part of this code can be used for commercial purposes without
  // the written consent from the author. Otherwise it can be used freely
  // except that you have to write somewhere in the code this header.
  // 
  import java.applet.*;
  import java.awt.*;
  import java.math.*;
  
  public final class fcubes extends Applet implements Runnable {
  
    private TextField textNumber;
    private TextArea lowerTextArea;
    private boolean TerminateThread;
    private Thread calcThread;
    private String StringToLabel;
    private StringBuffer textAreaContents;
    private int digitsInGroup = 6;
    private String paneFooter;
    private BigInteger Nbr, mult1, mult2, mult3, mult4;
    private int[] sums =
    {
      6, 0, 1, -1, -1, 0, -1, 0, 1, 1,
      6, 3, 1, 0, -1, 4, 2, -5, -2, 4,
      18, 1, 2, 14, -2, -23, -3, -26, 3, 30,
      18, 7, 1, 2, 6, -1, 8, -2, -9, 2,
      18, 8, 1, -5, -1, 14, -3, 29, 3, -30,
      18, 10, 1, 6, -1, -15, -3, -32, 3, 33,
      18, 11, 1, -1, 6, 7, 8, 10, -9, -11,
      18, 17, 2, -12, -2, 21, -3, 23, 3, -27,
      54, 20, 3, -11, -3, 10, 1, 2, -1, 7,
      72, 56, -9, 4, 1, 4, 6, -2, 8, -4,
      108, 2, -1, -22, 1, 4, -3, -41, 3, 43,
      216, 92, 3, -164, -3, 160, 1, -35, -1, 71,
      270, 146, -60, 91, -3, 13, 22, -37, 59, -89,
      270, 200, 3, 259, -3, -254, 1, 62, -1, -107,
      270, 218, -3, -56, 3, 31, -5, -69, 5, 78,
      432, 380, -3, 64, 3, -80, 2, -29, -2, 65,
      540, 38, 5, -285, -5, 267, 3, -140, -3, 190,
      810, 56, 5, -755, -5, 836, 9, -1445, -9, 1420,
      1080, 380, -1, -1438, 1, 1258, -3, -4037, 3, 4057,
      1620, 1334, -5, -3269, 5, 3107, -9, -5714, 9, 5764,
      1620, 1352, -5, 434, 5, -353, 9, -722, -9, 697,
      2160, 362, -5, -180, 5, 108, -6, -149, 6, 199,
      6480, 794, -5, -83, 5, 11, -6, -35, 6, 85, 
    };
  
    public void init() {
      Label labelTop, labelBottom;
      setBackground(Color.lightGray);
      setLayout(null);
      labelTop = new Label("Type number or numerical expression here and press Return");
      labelTop.reshape(10, 10, 570, 14);
      labelTop.setFont(new Font("Courier", Font.PLAIN, 12));
      labelTop.setAlignment(Label.CENTER);
      add(labelTop);
      textNumber = new TextField(1000);
      textNumber.reshape(10, 30, 570, 30);
      textNumber.setEditable(true);
      add(textNumber);
      lowerTextArea = new TextArea("", 6,75, TextArea.SCROLLBARS_VERTICAL_ONLY);
      lowerTextArea.reshape(10, 70, 570, 200);
      lowerTextArea.setEditable(false); 
      lowerTextArea.setFont(new Font("Courier", Font.PLAIN, 12));
      add(lowerTextArea);
      labelBottom = new Label("Written by Dario Alejandro Alpern. Last updated March 27th, 2005");
      labelBottom.reshape(10, 280, 570, 14);
      labelBottom.setFont(new Font("Courier", Font.PLAIN, 12));
      labelBottom.setAlignment(Label.CENTER);
      add(labelBottom);
      textNumber.requestFocus();
      validate();
      }
  
    public void destroy() {           /* Applet end */
      TerminateThread = true;
    }
  
  public boolean handleEvent(Event e) {
    if (e.id == Event.KEY_PRESS && e.key == Event.ENTER) {
      if (calcThread != null) {
        TerminateThread = true;
        try {
          calcThread.join();        /* Wait until the solving thread dies */
          } catch (InterruptedException ie) {};
        }
      calcThread = new Thread(this);  /* Start solving thread */
      calcThread.start();
      return true;
      }
    return false;
    }
  
    public void run() {
      BigInteger nbr, k, x, Mult1, Mult2, Mult3, Mult4;
      BigInteger mod = BigInteger.valueOf(0);
      BigInteger [] ExpressionResult = new BigInteger[1];
      int ExpressionRC;
      long StartTime;
      int i, j, mask;
      boolean converted = false;
  
      StartTime = System.currentTimeMillis();
      TerminateThread = false;
      mult1 = mult2 = mult3 = mult4 = BigInteger.valueOf(0);
      lowerTextArea.setText("Computing input expression...");
      try {
        ExpressionRC = expression.ComputeExpression(textNumber.getText().trim(),1,ExpressionResult);
      } catch (OutOfMemoryError e) {
        lowerTextArea.setText("Out of memory.");
        return;
      } catch (ArithmeticException e) {
        return;
      }
      Nbr = nbr = ExpressionResult[0];
      if (ExpressionRC != 0) {
        switch (ExpressionRC) {
          case -2:
            lowerTextArea.setText("Number too high (more than 1000 digits).");
            break;
          case -3:
            lowerTextArea.setText("Intermediate expression too high (more than 2000 digits).");
            break;
          case -4:
            lowerTextArea.setText("Non-integer division.");
            break;
          case -5:
            lowerTextArea.setText("Parentheses mismatch.");
            break;
          case -6:
            lowerTextArea.setText("Syntax error.");
            break;
          case -7:
            lowerTextArea.setText("Too many parentheses.");
            break;
          case -8:
            lowerTextArea.setText("Invalid parameter.");
            break;
          }
        return;
        }
      int mod18 = nbr.mod(BigInteger.valueOf(18)).intValue();
      if (mod18 == 4 || mod18 == 5 || mod18 == 13 || mod18 == 14) {
        lowerTextArea.setText("This applet does not work if the number is\ncongruent to 4 or 5 (mod 9).");
        return;
        }
      if (mod18 == 16) {
        converted = true;
        nbr = nbr.negate();
        }
      for (i=0; i<sums.length; i+=10) {
        mod = BigInteger.valueOf(sums[i]);
        if (nbr.mod(mod).intValue() == sums[i+1]) {
          break;
          }
        }
      if (i<sums.length) {
        x = nbr.subtract(BigInteger.valueOf(sums[i+1])).divide(mod);
        Mult1 = BigInteger.valueOf(sums[i+2]).multiply(x).
                add(BigInteger.valueOf(sums[i+3]));
        Mult2 = BigInteger.valueOf(sums[i+4]).multiply(x).
                add(BigInteger.valueOf(sums[i+5]));
        Mult3 = BigInteger.valueOf(sums[i+6]).multiply(x).
                add(BigInteger.valueOf(sums[i+7]));
        Mult4 = BigInteger.valueOf(sums[i+8]).multiply(x).
                add(BigInteger.valueOf(sums[i+9]));
        }
      else {
        mod = BigInteger.valueOf(54);
        if (nbr.mod(mod).intValue() == 2) {
          x = nbr.subtract(BigInteger.valueOf(2)).divide(mod);
          Mult1 = BigInteger.valueOf(29484).multiply(x).
                  add(BigInteger.valueOf(2211)).multiply(x).
                  add(BigInteger.valueOf(43));
          Mult2 = BigInteger.valueOf(-29484).multiply(x).
                  add(BigInteger.valueOf(-2157)).multiply(x).
                  add(BigInteger.valueOf(-41));
          Mult3 = BigInteger.valueOf(9828).multiply(x).
                  add(BigInteger.valueOf(485)).multiply(x).
                  add(BigInteger.valueOf(4));
          Mult4 = BigInteger.valueOf(-9828).multiply(x).
                  add(BigInteger.valueOf(-971)).multiply(x).
                  add(BigInteger.valueOf(-22));
          }
        else {
          mod = BigInteger.valueOf(83*108);
          if (nbr.mod(mod).intValue() == 83*46) {
            x = nbr.subtract(BigInteger.valueOf(83*46)).divide(mod);
            Mult1 = BigInteger.valueOf(29484).multiply(x).
                    add(BigInteger.valueOf(25143)).multiply(x).
                    add(BigInteger.valueOf(5371));
            Mult2 = BigInteger.valueOf(-29484).multiply(x).
                    add(BigInteger.valueOf(-25089)).multiply(x).
                    add(BigInteger.valueOf(-5348));
            Mult3 = BigInteger.valueOf(9828).multiply(x).
                    add(BigInteger.valueOf(8129)).multiply(x).
                    add(BigInteger.valueOf(1682));
            Mult4 = BigInteger.valueOf(-9828).multiply(x).
                    add(BigInteger.valueOf(-8615)).multiply(x).
                    add(BigInteger.valueOf(-1889));
            }
          else {
            lowerTextArea.setText("Computing solutions...");
            // Perform Pell solution of Demjanenko's theorem
              // Using these values of P, Q, R and S, a and b will be
              // always one and zero (mod 6) respectively.
            BigInteger P = new BigInteger("-112488782561");
            BigInteger Q = new BigInteger("-6578430178320");
            BigInteger R = new BigInteger("-1923517596");
            BigInteger S = P;
            BigInteger tmpA;
            int mod83 = nbr.mod(BigInteger.valueOf(83)).intValue();
            int pow = 71;
            int exp = 0;
            while (pow != mod83) {
              exp++;
              pow = (pow*50)%83;
              }
            if (exp > 82/2) {
              exp = 82 - exp;
              Q = Q.negate();
              R = R.negate();
              }
            BigInteger P1 = BigInteger.valueOf(1);
            BigInteger Q1 = BigInteger.valueOf(0);
            BigInteger R1 = Q1;
            BigInteger S1 = P1;
            mask = 32;
            while (mask > 0) {
              BigInteger tmpP1 = P1.pow(2).add(Q1.multiply(R1));
              BigInteger tmpQ1 = P1.add(S1).multiply(Q1);
              BigInteger tmpR1 = P1.add(S1).multiply(R1);
              BigInteger tmpS1 = S1.pow(2).add(Q1.multiply(R1));
              P1 = tmpP1;
              Q1 = tmpQ1;
              R1 = tmpR1;
              S1 = tmpS1;
              if ((exp & mask) != 0) {
                tmpP1 = P.multiply(P1).add(Q.multiply(R1));
                tmpQ1 = P.multiply(Q1).add(Q.multiply(S1));
                tmpR1 = R.multiply(P1).add(S.multiply(R1));
                tmpS1 = R.multiply(Q1).add(S.multiply(S1));
                P1 = tmpP1;
                Q1 = tmpQ1;
                R1 = tmpR1;
                S1 = tmpS1;
                }
              mask /= 2;
              }
            BigInteger a = P1.multiply(BigInteger.valueOf(-3041)).
                           add(Q1.multiply(BigInteger.valueOf(-52)));
            BigInteger b = R1.multiply(BigInteger.valueOf(-3041)).
                           add(S1.multiply(BigInteger.valueOf(-52)));
  
            Mult1 = a.multiply(BigInteger.valueOf(27)).
                    add(b.multiply(BigInteger.valueOf(-928)));
            Mult2 = a.multiply(BigInteger.valueOf(-9)).
                    add(b.multiply(BigInteger.valueOf(-602)));
            Mult3 = a.multiply(BigInteger.valueOf(25)).
                    add(b.multiply(BigInteger.valueOf(-2937)));
            Mult4 = a.multiply(BigInteger.valueOf(-19)).
                    add(b.multiply(BigInteger.valueOf(2746)));
            k = nbr.subtract(Mult1.pow(3)).subtract(Mult2.pow(3)).
                    subtract(Mult3.pow(3)).subtract(Mult4.pow(3)).
                    divide(BigInteger.valueOf(18*83));
            Mult1 = Mult1.add(k.multiply(BigInteger.valueOf(10)));
            Mult2 = Mult2.add(k.multiply(BigInteger.valueOf(-19)));
            Mult3 = Mult3.add(k.multiply(BigInteger.valueOf(-24)));
            Mult4 = Mult4.add(k.multiply(BigInteger.valueOf(27)));
            }
          }
        }
  
      if (converted) {
        Mult1 = Mult1.negate();
        Mult2 = Mult2.negate();
        Mult3 = Mult3.negate();
        Mult4 = Mult4.negate();
        nbr = nbr.negate();
        }
      // Validate
  
      lowerTextArea.setText("Validating...");
      if (Mult1.pow(3).add(Mult2.pow(3)).add(Mult3.pow(3)).add(Mult4.pow(3)).
          equals(nbr) == false)
      {
        lowerTextArea.setText("Internal error!\n\nPlease send the number to the author of the applet");
        return;
      }
  
      lowerTextArea.setText("Formatting output...");
      mult1 = Mult1;
      mult2 = Mult2;
      mult3 = Mult3;
      mult4 = Mult4;
      Nbr = nbr;
      long t=(System.currentTimeMillis()-StartTime)/1000;
      String timeElapsed = "Time elapsed: "+t/86400+"d "+(t%86400)/3600+"h "+((t%3600)/60)+"m "+(t%60)+"s";
      paneFooter = "\n\n"+timeElapsed;
      ShowPane();
    }
  
    private void ShowPane()
    {
      textAreaContents = new StringBuffer();
      StringToLabel = "n = ";
      insertBigNbr(Nbr);
      textAreaContents = textAreaContents.append(StringToLabel + "\n\n").
                         append("n = a^3 + b^3 + c^3 + d^3\n");
      StringToLabel = "a = ";            // Start new line.
      insertBigNbr(mult1);
      textAreaContents = textAreaContents.append(StringToLabel + "\n");
      StringToLabel = "b = ";            // Start new line.
      insertBigNbr(mult2);
      textAreaContents = textAreaContents.append(StringToLabel + "\n");
      StringToLabel = "c = ";            // Start new line.
      insertBigNbr(mult3);
      textAreaContents = textAreaContents.append(StringToLabel + "\n");
      StringToLabel = "d = ";            // Start new line.
      insertBigNbr(mult4);
      textAreaContents = textAreaContents.append(StringToLabel + paneFooter);
      lowerTextArea.setText(textAreaContents.toString());
    }
  
    private void addStringToLabel(String value) {
      if (value.length() + 1 + StringToLabel.length() >= 79) {
        textAreaContents = textAreaContents.append(StringToLabel + "\n");
        StringToLabel = value+" ";
      }
      else {
        StringToLabel += value+" ";
      }
    }
  
    private void insertBigNbr(BigInteger N)
    {
      int i,dig,len;
      dig = digitsInGroup & 0x3FF;
      String value = N.toString();
      len = value.length();
      i = (len + dig - 1)%dig + 1;
      addStringToLabel(value.substring(0,i));
      while (i<value.length())
      {
        addStringToLabel(value.substring(i,i+dig));
        i += dig;
      }
      if (value.charAt(0) == '-')
      {
        len--;
      }
      if (len > 100)
      {
        addStringToLabel("("+len+" digits)");
      }
    }
  
    public String getTextFromPane()
    {
      if ((calcThread == null || calcThread.isAlive() == false) &&
           lowerTextArea.getText() != "")
      {
        String text="<HTML><TITLE>Sum of four cubes</TITLE><BODY><H2>Sum of four cubes</H2><P><I>Written by Dario Alejandro Alpern (alpertron@hotmail.com)</I><P><PRE>"
                 + lowerTextArea.getText() + "</PRE><BODY></HTML>";
        return text;
      }
      return "";
    }
  
    public void setDigits(int digits)
    {
      digitsInGroup = digits;
      if ((calcThread == null || calcThread.isAlive() == false) &&
           lowerTextArea.getText() != "")
      {
        ShowPane();
      }
    }
  }       // End applet class
  
  // </XMP>
  