Subversion Repositories distributed

Rev

Rev 14 | Rev 16 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
14 daniel-mar 1
package de.viathinksoft.immortable.genX;
2
 
15 daniel-mar 3
// TODO: r als BigInteger
14 daniel-mar 4
 
5
import java.io.BufferedReader;
6
import java.io.BufferedWriter;
7
import java.io.File;
15 daniel-mar 8
import java.io.FileNotFoundException;
14 daniel-mar 9
import java.io.FileReader;
10
import java.io.FileWriter;
11
import java.io.IOException;
15 daniel-mar 12
import java.math.BigInteger;
14 daniel-mar 13
import java.util.Vector;
14
 
15 daniel-mar 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 {
14 daniel-mar 22
 
15 daniel-mar 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";
14 daniel-mar 26
        private static final int SOFTBREAK = 76;
27
 
15 daniel-mar 28
        private Vector<Integer> a = null;
14 daniel-mar 29
        private String filename;
15 daniel-mar 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";
14 daniel-mar 35
 
15 daniel-mar 36
        public ImmortableNumberSearch(String filename) throws LoadException {
14 daniel-mar 37
                this.filename = filename;
38
                load();
39
        }
40
 
15 daniel-mar 41
        public String getBackupDir() {
42
                return backupDir;
43
        }
44
 
45
        public void setBackupDir(String backupDir) {
46
                this.backupDir = backupDir;
47
        }
48
 
14 daniel-mar 49
        public int getSaveInterval() {
50
                return this.saveInterval;
51
        }
52
 
15 daniel-mar 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
 
14 daniel-mar 69
        public void setSaveInterval(int saveInterval) {
70
                this.saveInterval = saveInterval;
71
        }
72
 
73
        private boolean savePointExists() {
74
                return new File(filename).exists();
75
        }
76
 
15 daniel-mar 77
        private void load() throws LoadException {
78
                if (!savePointExists()) {
14 daniel-mar 79
                        return;
15 daniel-mar 80
                }
14 daniel-mar 81
 
15 daniel-mar 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
                }
14 daniel-mar 89
 
15 daniel-mar 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);
14 daniel-mar 149
                }
15 daniel-mar 150
        }
14 daniel-mar 151
 
15 daniel-mar 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.");
14 daniel-mar 157
                        }
15 daniel-mar 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");
14 daniel-mar 162
 
15 daniel-mar 163
                try {
164
                        BufferedWriter f = new BufferedWriter(new FileWriter(filename));
14 daniel-mar 165
 
15 daniel-mar 166
                        try {
167
                                f.write(SIGNATURE + "\r\n");
14 daniel-mar 168
 
15 daniel-mar 169
                                f.write(SIGNATURE_MINOR + "\r\n");
170
                                f.write("\r\n");
14 daniel-mar 171
 
15 daniel-mar 172
                                f.write("(Starting time)\r\n");
173
                                f.write(creation_time + "\r\n");
174
                                f.write("\r\n");
14 daniel-mar 175
 
15 daniel-mar 176
                                f.write("(Save timestamp)\r\n");
177
                                f.write(timestamp + "\r\n");
178
                                f.write("\r\n");
14 daniel-mar 179
 
15 daniel-mar 180
                                f.write("(u)\r\n");
181
                                f.write(u + "\r\n");
182
                                f.write("\r\n");
14 daniel-mar 183
 
15 daniel-mar 184
                                f.write("(r)\r\n");
185
                                f.write(r + "\r\n"); // FUTURE: (1) Multi-Line-Support?
14 daniel-mar 186
                                f.write("\r\n");
15 daniel-mar 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();
14 daniel-mar 204
                        }
15 daniel-mar 205
                } catch (IOException e) {
206
                        throw new SaveException("Could not save master file.", e);
14 daniel-mar 207
                }
15 daniel-mar 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);
14 daniel-mar 218
                }
219
        }
220
 
15 daniel-mar 221
        public void calcIterate(int amount) throws SaveException {
14 daniel-mar 222
                int s, m, k;
223
                int cnt = 0;
224
 
15 daniel-mar 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>();
14 daniel-mar 235
                        a.add(5);
236
                        a.add(2);
237
                        u = 1;
238
                        r = 2;
239
                        cnt += 2;
240
                }
241
 
15 daniel-mar 242
                do {
14 daniel-mar 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) {
15 daniel-mar 256
                                save(firstSave);
257
                                firstSave = false;
14 daniel-mar 258
                        }
15 daniel-mar 259
                } while (++cnt != amount);
14 daniel-mar 260
 
15 daniel-mar 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);
14 daniel-mar 298
                        }
299
                }
15 daniel-mar 300
                s.reverse();
301
                return s;
14 daniel-mar 302
        }
303
 
15 daniel-mar 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
        }
14 daniel-mar 327
}