Subversion Repositories distributed

Rev

Rev 14 | 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 2000";
  24.         private static final String SIGNATURE_MINOR = "Iterator GenX Java int";
  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(
  156.                                                 "Integrity test failed. Will not save.");
  157.                         }
  158.                 }
  159.  
  160.                 String timestamp = DateUtils.now("EEE, d MMM yyyy HH:mm:ss Z");
  161.                 String timestamp_filename = DateUtils.now("dd-MM-yyyy_HH-mm-ss");
  162.                
  163.                 try {
  164.                         BufferedWriter f = new BufferedWriter(new FileWriter(filename));
  165.  
  166.                         try {
  167.                                 f.write(SIGNATURE + "\r\n");
  168.  
  169.                                 f.write(SIGNATURE_MINOR + "\r\n");
  170.                                 f.write("\r\n");
  171.  
  172.                                 f.write("(Starting time)\r\n");
  173.                                 f.write(creation_time + "\r\n");
  174.                                 f.write("\r\n");
  175.  
  176.                                 f.write("(Save timestamp)\r\n");
  177.                                 f.write(timestamp + "\r\n");
  178.                                 f.write("\r\n");
  179.  
  180.                                 f.write("(u)\r\n");
  181.                                 f.write(u + "\r\n");
  182.                                 f.write("\r\n");
  183.  
  184.                                 f.write("(r)\r\n");
  185.                                 f.write(r + "\r\n"); // FUTURE: (1) Multi-Line-Support?
  186.                                 f.write("\r\n");
  187.  
  188.                                 f.write("(M5rev)\r\n");
  189.                                 int i = 0;
  190.                                 for (Integer xa : a) {
  191.                                         f.write(xa.toString());
  192.                                         if (++i % SOFTBREAK == 0) {
  193.                                                 f.write("\r\n");
  194.                                         }
  195.                                 }
  196.                                 if (++i % SOFTBREAK != 0) {
  197.                                         f.write("\r\n");
  198.                                 }
  199.                                 f.write("\r\n");
  200.  
  201.                                 f.write(END_SIG);
  202.                         } finally {
  203.                                 f.close();
  204.                         }
  205.                 } catch (IOException e) {
  206.                         throw new SaveException("Could not save master file.", e);
  207.                 }
  208.  
  209.                 // Make backup
  210.  
  211.                 new File(backupDir).mkdir();
  212.                 String bak_filename = backupDir + "/immortal_" + timestamp_filename + "_" + (u+1)
  213.                                 + ".txt";
  214.                 try {
  215.                         FileUtils.copyFile(new File(filename), new File(bak_filename));
  216.                 } catch (IOException e) {
  217.                         throw new SaveException("Could not make backup", e);
  218.                 }
  219.         }
  220.  
  221.         public void calcIterate(int amount) throws SaveException {
  222.                 int s, m, k;
  223.                 int cnt = 0;
  224.  
  225.                 // Wir führen beim ersten Speichern einen weiteren
  226.                 // integrity-Test durch. Grund: Wäre bei einer Fortsetzung einer
  227.                 // Datei das "r" falsch (der Datenteil aber korrekt), dann würde
  228.                 // diese Datei beim Speichern ungültige Daten enthalten (Zahl
  229.                 // nicht immortabel).
  230.                 boolean firstSave = true;
  231.  
  232.                 if (a == null) {
  233.                         creation_time = DateUtils.now("EEE, d MMM yyyy HH:mm:ss Z");
  234.                         a = new Vector<Integer>();
  235.                         a.add(5);
  236.                         a.add(2);
  237.                         u = 1;
  238.                         r = 2;
  239.                         cnt += 2;
  240.                 }
  241.  
  242.                 do {
  243.                         r = (r - a.elementAt(u)) / 10 + a.elementAt(u);
  244.                         s = 0;
  245.                         for (m = 1, k = u; m < k; m++, k--) {
  246.                                 s += a.elementAt(m) * a.elementAt(k);
  247.                         }
  248.                         r += 2 * s;
  249.                         if (m == k) {
  250.                                 r += a.elementAt(m) * a.elementAt(m);
  251.                         }
  252.                         u++;
  253.                         a.add(r % 10);
  254.  
  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.