Subversion Repositories distributed

Rev

Rev 16 | Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. package de.viathinksoft.immortable.genX;
  2.  
  3. // TODO: r als BigInteger
  4.  
  5. import java.io.BufferedReader;
  6. import java.io.BufferedWriter;
  7. import java.io.File;
  8. import java.io.FileNotFoundException;
  9. import java.io.FileReader;
  10. import java.io.FileWriter;
  11. import java.io.IOException;
  12. import java.math.BigInteger;
  13. import java.util.Vector;
  14.  
  15. /**
  16.  * Immortable Iterator
  17.  *
  18.  * @author Daniel Marschall, René Gruber
  19.  * @see http://www.matheboard.de/thread.php?postid=1259938
  20.  */
  21. public class ImmortableNumberSearch {
  22.  
  23.         private static final String SIGNATURE = "Immortable Number Report File Version 2.0";
  24.         private static final String SIGNATURE_MINOR = "Iterator GenX Java (backup, selftest, int32) r17";
  25.         private static final String END_SIG = "END OF REPORT";
  26.         private static final int SOFTBREAK = 76;
  27.  
  28.         private Vector<Integer> a = null;
  29.         private String filename;
  30.         private int saveInterval = 10000;
  31.         private int u = -1;
  32.         private int r = -1;
  33.         private String creation_time;
  34.         private String backupDir = "backup";
  35.  
  36.         public ImmortableNumberSearch(String filename) throws LoadException {
  37.                 this.filename = filename;
  38.                 load();
  39.         }
  40.  
  41.         public String getBackupDir() {
  42.                 return backupDir;
  43.         }
  44.  
  45.         public void setBackupDir(String backupDir) {
  46.                 this.backupDir = backupDir;
  47.         }
  48.  
  49.         public int getSaveInterval() {
  50.                 return this.saveInterval;
  51.         }
  52.  
  53.         public Vector<Integer> getA() {
  54.                 return a;
  55.         }
  56.  
  57.         public int getU() {
  58.                 return u;
  59.         }
  60.  
  61.         public int getR() {
  62.                 return r;
  63.         }
  64.  
  65.         public String getFilename() {
  66.                 return filename;
  67.         }
  68.  
  69.         public void setSaveInterval(int saveInterval) {
  70.                 this.saveInterval = saveInterval;
  71.         }
  72.  
  73.         private boolean savePointExists() {
  74.                 return new File(filename).exists();
  75.         }
  76.  
  77.         private void load() throws LoadException {
  78.                 if (!savePointExists()) {
  79.                         return;
  80.                 }
  81.  
  82.                 BufferedReader f;
  83.                 try {
  84.                         f = new BufferedReader(new FileReader(filename));
  85.                 } catch (FileNotFoundException e) {
  86.                         // Will not happen because of savePointExists().
  87.                         return;
  88.                 }
  89.  
  90.                 a = null;
  91.                 u = -1;
  92.                 r = -1;
  93.  
  94.                 try {
  95.                         try {
  96.                                 String s = f.readLine();
  97.                                 if (!s.equals(SIGNATURE)) {
  98.                                         throw new LoadException("Wrong signature");
  99.                                 }
  100.  
  101.                                 f.readLine(); // Minor. signature
  102.                                 f.readLine(); // ""
  103.  
  104.                                 f.readLine(); // "(Starting time)"
  105.                                 creation_time = f.readLine();
  106.                                 f.readLine(); // ""
  107.  
  108.                                 f.readLine(); // "(Save timestamp)"
  109.                                 f.readLine(); // Timestamp
  110.                                 f.readLine(); // ""
  111.  
  112.                                 f.readLine(); // "(u)"
  113.                                 s = f.readLine();
  114.                                 u = Integer.parseInt(s);
  115.                                 f.readLine(); // ""
  116.  
  117.                                 f.readLine(); // "(r)"
  118.                                 s = f.readLine();
  119.                                 r = Integer.parseInt(s); // FUTURE: (1) Multi-Line-Support?
  120.                                 f.readLine(); // ""
  121.  
  122.                                 f.readLine(); // "(M5rev)"
  123.                                 a = new Vector<Integer>();
  124.                                 do {
  125.                                         s = f.readLine();
  126.                                         for (int i = 0; i < s.length(); i++) {
  127.                                                 a.add(new Integer(s.substring(i, i + 1)));
  128.                                         }
  129.                                 } while (!s.equals(""));
  130.  
  131.                                 if (!integryTest()) {
  132.                                         throw new LoadException("Corrupt: Not immortable!");
  133.                                 }
  134.  
  135.                                 if (u + 1 != a.size()) {
  136.                                         throw new LoadException(
  137.                                                         "Corrupt: Formal and actual length mismatch!");
  138.                                 }
  139.  
  140.                                 s = f.readLine();
  141.                                 if (!s.equals(END_SIG)) {
  142.                                         throw new LoadException("Corrupt: End-signature mismatch.");
  143.                                 }
  144.                         } finally {
  145.                                 f.close();
  146.                         }
  147.                 } catch (IOException e) {
  148.                         throw new LoadException(e);
  149.                 }
  150.         }
  151.  
  152.         private void save(boolean integrityTest) throws SaveException {
  153.                 if (integrityTest) {
  154.                         if (!integryTest()) {
  155.                                 throw new SaveException("Integrity test failed. Will not save.");
  156.                         }
  157.                 }
  158.  
  159.                 String timestamp = DateUtils.now("EEE, d MMM yyyy HH:mm:ss Z");
  160.                 String timestamp_filename = DateUtils.now("dd-MM-yyyy_HH-mm-ss");
  161.  
  162.                 try {
  163.                         BufferedWriter f = new BufferedWriter(new FileWriter(filename));
  164.  
  165.                         try {
  166.                                 f.write(SIGNATURE + "\r\n");
  167.  
  168.                                 f.write(SIGNATURE_MINOR + "\r\n");
  169.                                 f.write("\r\n");
  170.  
  171.                                 f.write("(Starting time)\r\n");
  172.                                 f.write(creation_time + "\r\n");
  173.                                 f.write("\r\n");
  174.  
  175.                                 f.write("(Save timestamp)\r\n");
  176.                                 f.write(timestamp + "\r\n");
  177.                                 f.write("\r\n");
  178.  
  179.                                 f.write("(u)\r\n");
  180.                                 f.write(u + "\r\n");
  181.                                 f.write("\r\n");
  182.  
  183.                                 f.write("(r)\r\n");
  184.                                 f.write(r + "\r\n"); // FUTURE: (1) Multi-Line-Support?
  185.                                 f.write("\r\n");
  186.  
  187.                                 f.write("(M5rev)\r\n");
  188.                                 int i = 0;
  189.                                 for (Integer xa : a) {
  190.                                         f.write(xa.toString());
  191.                                         if (++i % SOFTBREAK == 0) {
  192.                                                 f.write("\r\n");
  193.                                         }
  194.                                 }
  195.                                 if (++i % SOFTBREAK != 0) {
  196.                                         f.write("\r\n");
  197.                                 }
  198.                                 f.write("\r\n");
  199.  
  200.                                 f.write(END_SIG);
  201.                         } finally {
  202.                                 f.close();
  203.                         }
  204.                 } catch (IOException e) {
  205.                         throw new SaveException("Could not save master file.", e);
  206.                 }
  207.  
  208.                 // Make backup
  209.  
  210.                 new File(backupDir).mkdir();
  211.                 String bak_filename = backupDir + "/immortal_" + timestamp_filename
  212.                                 + "_" + (u + 1) + ".txt";
  213.                 try {
  214.                         FileUtils.copyFile(new File(filename), new File(bak_filename));
  215.                 } catch (IOException e) {
  216.                         throw new SaveException("Could not make backup", e);
  217.                 }
  218.         }
  219.  
  220.         public void calcIterate(int amount) throws SaveException {
  221.                 int s, m, k;
  222.                 int cnt = 0;
  223.  
  224.                 // Wir führen beim ersten Speichern einen weiteren
  225.                 // integrity-Test durch. Grund: Wäre bei einer Fortsetzung einer
  226.                 // Datei das "r" falsch (der Datenteil aber korrekt), dann würde
  227.                 // diese Datei beim Speichern ungültige Daten enthalten (Zahl
  228.                 // nicht immortabel).
  229.                 boolean firstSave = true;
  230.  
  231.                 if (a == null) {
  232.                         creation_time = DateUtils.now("EEE, d MMM yyyy HH:mm:ss Z");
  233.                         a = new Vector<Integer>();
  234.                         a.add(5);
  235.                         a.add(2);
  236.                         u = 1;
  237.                         r = 2;
  238.                         cnt += 2;
  239.                 }
  240.  
  241.                 do {
  242.                         r = (r - a.elementAt(u)) / 10 + a.elementAt(u);
  243.                         s = 0;
  244.                         for (m = 1, k = u; m < k; m++, k--) {
  245.                                 s += a.elementAt(m) * a.elementAt(k);
  246.                         }
  247.                         r += 2 * s;
  248.                         if (m == k) {
  249.                                 r += a.elementAt(m) * a.elementAt(m);
  250.                         }
  251.                         u++;
  252.                         a.add(r % 10);
  253.  
  254.                         cnt++;
  255.                         if (cnt % saveInterval == 0) {
  256.                                 save(firstSave);
  257.                                 firstSave = false;
  258.                         }
  259.                 } while (cnt != amount);
  260.  
  261.                 // Wir brauchen nicht zwei Mal zu speichern
  262.                 if (cnt - 1 % saveInterval != 0) {
  263.                         save(firstSave);
  264.                         firstSave = false;
  265.                 }
  266.         }
  267.  
  268.         public int getDigit(int u) {
  269.                 return a.elementAt(u);
  270.         }
  271.  
  272.         public StringBuilder M5_StringBuilder(int u) {
  273.                 StringBuilder s = new StringBuilder();
  274.                 for (Integer xa : a) {
  275.                         s.append(xa);
  276.                 }
  277.                 s.reverse();
  278.                 return s;
  279.         }
  280.  
  281.         public String M5_String(int u) {
  282.                 return M5_StringBuilder(u).toString();
  283.         }
  284.  
  285.         public BigInteger M5_BigInteger(int u) {
  286.                 return new BigInteger(M5_String(u));
  287.         }
  288.  
  289.         public StringBuilder M6_StringBuilder(int u) {
  290.                 StringBuilder s = new StringBuilder();
  291.                 boolean first = true;
  292.                 for (Integer xa : a) {
  293.                         if (first) {
  294.                                 s.append(6); // xa = 5
  295.                                 first = false;
  296.                         } else {
  297.                                 s.append(9 - xa);
  298.                         }
  299.                 }
  300.                 s.reverse();
  301.                 return s;
  302.         }
  303.  
  304.         public String M6_String(int u) {
  305.                 return M6_StringBuilder(u).toString();
  306.         }
  307.  
  308.         public BigInteger M6_BigInteger(int u) {
  309.                 return new BigInteger(M6_String(u));
  310.         }
  311.  
  312.         private static boolean isImmortable(BigInteger num) {
  313.                 // Ist das auch OK?
  314.                 // return num.pow(2).toString().endsWith(num.toString());
  315.  
  316.                 // n² === n (mod 10^m) <===> n²%10^m == n%10^m
  317.                 int m = num.toString().length();
  318.                 BigInteger m_pow = BigInteger.TEN.pow(m);
  319.                 return num.pow(2).mod(m_pow).equals(num.mod(m_pow));
  320.  
  321.         }
  322.  
  323.         public boolean integryTest() {
  324.                 // return isImmortable(M5_BigInteger(u));
  325.                 return isImmortable(M6_BigInteger(u));
  326.         }
  327. }
  328.