Subversion Repositories distributed

Rev

Rev 37 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 37 Rev 38
1
package de.viathinksoft.immortal.genX;
1
package de.viathinksoft.immortal.genX;
2
 
2
 
3
import java.io.BufferedReader;
3
import java.io.BufferedReader;
4
import java.io.BufferedWriter;
4
import java.io.BufferedWriter;
5
import java.io.File;
5
import java.io.File;
6
import java.io.FileNotFoundException;
6
import java.io.FileNotFoundException;
7
import java.io.FileReader;
7
import java.io.FileReader;
8
import java.io.FileWriter;
8
import java.io.FileWriter;
9
import java.io.IOException;
9
import java.io.IOException;
10
import java.math.BigInteger;
10
import java.math.BigInteger;
11
 
11
 
12
/**
12
/**
13
 * Immortable Iterator
13
 * Immortable Iterator
14
 *
14
 *
15
 * @author Daniel Marschall, Big thanks to the users of MatheBoard.de
15
 * @author Daniel Marschall, Big thanks to the users of MatheBoard.de
16
 * @see http://www.matheboard.de/archive/435725/thread.html
16
 * @see http://www.matheboard.de/archive/435725/thread.html
17
 */
17
 */
18
public class ImmortalNumberSearch {
18
public class ImmortalNumberSearch {
19
 
19
 
20
        private static final String SIGNATURE = "Immortal Number Report File Version 2.02";
20
        private static final String SIGNATURE = "Immortal Number Report File Version 2.02";
21
        private static final String SIGNATURE_MINOR = "Iterator GenX Java (100k save-interval, load-integrity-check, int32-r, array-object) r29";
21
        private static final String SIGNATURE_MINOR = "Iterator GenX Java (100k save-interval, load-integrity-check, int32-r, array-object) r38";
22
        private static final String END_SIG = "END OF REPORT";
22
        private static final String END_SIG = "END OF REPORT";
23
        private static final int SOFTBREAK = 76;
23
        private static final int SOFTBREAK = 76;
24
 
24
 
25
        private ByteArray a;
25
        private ByteArray a;
26
        private String filename;
26
        private String filename;
27
        private int saveInterval = 100000;
27
        private int saveInterval = 100000;
28
        private int u = -1;
28
        private int u = -1;
29
        private int r = -1; // FUTURE: r als BigInteger
29
        private int r = -1; // FUTURE: r als BigInteger
30
        private String creation_time;
30
        private String creation_time;
31
        private String backupDir = "backup";
31
        private String backupDir = "backup";
32
 
32
 
33
        private static final int INITIAL_SIZE = 1000000;
33
        private static final int INITIAL_SIZE = 1000000;
34
        private static final int EXPANSION_SIZE = 1000000;
34
        private static final int EXPANSION_SIZE = 1000000;
35
 
35
 
36
        private boolean do_integrity_test = true;
36
        private boolean do_integrity_test = true;
37
        private boolean verbose = true;
37
        private boolean verbose = true;
38
 
38
 
39
        public boolean isDo_integrity_test() {
39
        public boolean isDo_integrity_test() {
40
                return do_integrity_test;
40
                return do_integrity_test;
41
        }
41
        }
42
 
42
 
43
        public void setDo_integrity_test(boolean doIntegrityTest) {
43
        public void setDo_integrity_test(boolean doIntegrityTest) {
44
                do_integrity_test = doIntegrityTest;
44
                do_integrity_test = doIntegrityTest;
45
        }
45
        }
46
 
46
 
47
        public boolean isVerbose() {
47
        public boolean isVerbose() {
48
                return verbose;
48
                return verbose;
49
        }
49
        }
50
 
50
 
51
        public void setVerbose(boolean verbose) {
51
        public void setVerbose(boolean verbose) {
52
                this.verbose = verbose;
52
                this.verbose = verbose;
53
        }
53
        }
54
 
54
 
55
        protected void log(String s) {
55
        protected void log(String s) {
56
                if (verbose) {
56
                if (verbose) {
57
                        String timestamp = DateUtils.now("EEE, d MMM yyyy HH:mm:ss Z");
57
                        String timestamp = DateUtils.now("EEE, d MMM yyyy HH:mm:ss Z");
58
                        // FUTURE: In eine Log-Datei schreiben
58
                        // FUTURE: In eine Log-Datei schreiben
59
                        System.out.println(timestamp + " - " + s);
59
                        System.out.println(timestamp + " - " + s);
60
                }
60
                }
61
        }
61
        }
62
 
62
 
63
        public ImmortalNumberSearch(String filename) throws LoadException {
63
        public ImmortalNumberSearch(String filename) throws LoadException {
64
                this.filename = filename;
64
                this.filename = filename;
65
                load();
65
                load();
66
        }
66
        }
67
 
67
 
68
        public String getBackupDir() {
68
        public String getBackupDir() {
69
                return backupDir;
69
                return backupDir;
70
        }
70
        }
71
 
71
 
72
        public void setBackupDir(String backupDir) {
72
        public void setBackupDir(String backupDir) {
73
                this.backupDir = backupDir;
73
                this.backupDir = backupDir;
74
        }
74
        }
75
 
75
 
76
        public int getSaveInterval() {
76
        public int getSaveInterval() {
77
                return this.saveInterval;
77
                return this.saveInterval;
78
        }
78
        }
79
 
79
 
80
        public ByteArray getA() {
80
        public ByteArray getA() {
81
                return a;
81
                return a;
82
        }
82
        }
83
 
83
 
84
        public int getU() {
84
        public int getU() {
85
                return u;
85
                return u;
86
        }
86
        }
87
 
87
 
88
        public int getR() {
88
        public int getR() {
89
                return r;
89
                return r;
90
        }
90
        }
91
 
91
 
92
        public String getFilename() {
92
        public String getFilename() {
93
                return filename;
93
                return filename;
94
        }
94
        }
95
 
95
 
96
        public void setSaveInterval(int saveInterval) {
96
        public void setSaveInterval(int saveInterval) {
97
                this.saveInterval = saveInterval;
97
                this.saveInterval = saveInterval;
98
        }
98
        }
99
 
99
 
100
        private boolean savePointExists() {
100
        private boolean savePointExists() {
101
                return new File(filename).exists();
101
                return new File(filename).exists();
102
        }
102
        }
103
 
103
 
104
        private void load() throws LoadException {
104
        private void load() throws LoadException {
105
                if (!savePointExists()) {
105
                if (!savePointExists()) {
106
                        this.a = new ByteArray(INITIAL_SIZE, EXPANSION_SIZE);
106
                        this.a = new ByteArray(INITIAL_SIZE, EXPANSION_SIZE);
107
                        return;
107
                        return;
108
                }
108
                }
109
 
109
 
110
                BufferedReader f;
110
                BufferedReader f;
111
                try {
111
                try {
112
                        f = new BufferedReader(new FileReader(filename));
112
                        f = new BufferedReader(new FileReader(filename));
113
                } catch (FileNotFoundException e) {
113
                } catch (FileNotFoundException e) {
114
                        // Will not happen because of savePointExists().
114
                        // Will not happen because of savePointExists().
115
                        return;
115
                        return;
116
                }
116
                }
117
 
117
 
118
                u = -1;
118
                u = -1;
119
                r = -1;
119
                r = -1;
120
 
120
 
121
                try {
121
                try {
122
                        try {
122
                        try {
123
                                String s = f.readLine();
123
                                String s = f.readLine();
124
                                if (!s.equals(SIGNATURE)) {
124
                                if (!s.equals(SIGNATURE)) {
125
                                        throw new LoadException("Corrupt: Wrong signature");
125
                                        throw new LoadException("Corrupt: Wrong signature");
126
                                }
126
                                }
127
 
127
 
128
                                f.readLine(); // Minor. signature
128
                                f.readLine(); // Minor. signature
129
                                f.readLine(); // ""
129
                                f.readLine(); // ""
130
 
130
 
131
                                f.readLine(); // "(Starting time)"
131
                                f.readLine(); // "(Starting time)"
132
                                creation_time = f.readLine();
132
                                creation_time = f.readLine();
133
                                f.readLine(); // ""
133
                                f.readLine(); // ""
134
 
134
 
135
                                f.readLine(); // "(Save timestamp)"
135
                                f.readLine(); // "(Save timestamp)"
136
                                f.readLine(); // Timestamp
136
                                f.readLine(); // Timestamp
137
                                f.readLine(); // ""
137
                                f.readLine(); // ""
138
 
138
 
139
                                f.readLine(); // "(Digits)"
139
                                f.readLine(); // "(Digits)"
140
                                s = f.readLine();
140
                                s = f.readLine();
141
                                u = Integer.parseInt(s) - 1;
141
                                u = Integer.parseInt(s) - 1;
142
                                f.readLine(); // ""
142
                                f.readLine(); // ""
143
 
143
 
144
                                f.readLine(); // "(r)"
144
                                f.readLine(); // "(r)"
145
                                s = f.readLine();
145
                                s = f.readLine();
146
                                r = Integer.parseInt(s); // FUTURE: (1) Multi-Line-Support?
146
                                r = Integer.parseInt(s); // FUTURE: (1) Multi-Line-Support?
147
                                f.readLine(); // ""
147
                                f.readLine(); // ""
148
 
148
 
149
                                this.a = new ByteArray(u + 1 + EXPANSION_SIZE, EXPANSION_SIZE);
149
                                this.a = new ByteArray(u + 1 + EXPANSION_SIZE, EXPANSION_SIZE);
150
 
150
 
151
                                f.readLine(); // "(M5 reversed)"
151
                                f.readLine(); // "(M5 reversed)"
152
                                do {
152
                                do {
153
                                        s = f.readLine();
153
                                        s = f.readLine();
154
                                        for (int i = 0; i < s.length(); i++) {
154
                                        for (int i = 0; i < s.length(); i++) {
155
                                                a.add(Byte.parseByte(s.substring(i, i + 1)));
155
                                                a.add(Byte.parseByte(s.substring(i, i + 1)));
156
                                        }
156
                                        }
157
                                } while (!s.equals(""));
157
                                } while (!s.equals(""));
158
 
158
 
159
                                if (u + 1 != a.count()) {
159
                                if (u + 1 != a.count()) {
160
                                        throw new LoadException(
160
                                        throw new LoadException(
161
                                                        "Corrupt: Formal and actual length mismatch!");
161
                                                        "Corrupt: Formal and actual length mismatch!");
162
                                }
162
                                }
163
 
163
 
164
                                s = f.readLine();
164
                                s = f.readLine();
165
                                if (!s.equals(END_SIG)) {
165
                                if (!s.equals(END_SIG)) {
166
                                        throw new LoadException("Corrupt: End-signature mismatch.");
166
                                        throw new LoadException("Corrupt: End-signature mismatch.");
167
                                }
167
                                }
168
                        } finally {
168
                        } finally {
169
                                f.close();
169
                                f.close();
170
                        }
170
                        }
171
                } catch (IOException e) {
171
                } catch (IOException e) {
172
                        throw new LoadException(e);
172
                        throw new LoadException(e);
173
                }
173
                }
174
        }
174
        }
175
 
175
 
176
        private void save(boolean integrityTest) throws SaveException {
176
        private void save(boolean integrityTest) throws SaveException {
177
                if ((integrityTest) && (do_integrity_test)) {
177
                if ((integrityTest) && (do_integrity_test)) {
178
                        log("Beginne Selbsttest vor erster Speicherung...");
178
                        log("Beginne Selbsttest vor erster Speicherung...");
179
 
179
 
180
                        if (!integryTest()) {
180
                        if (!integryTest()) {
181
                                throw new SaveException(
181
                                throw new SaveException(
182
                                                "Integrity test failed. (Loaded file broken?) Will not save.");
182
                                                "Integrity test failed. (Loaded file broken?) Will not save.");
183
                        }
183
                        }
184
                }
184
                }
185
 
185
 
186
                log("Speichere bei " + (u + 1) + " digits");
186
                log("Speichere bei " + (u + 1) + " digits");
187
 
187
 
188
                String timestamp = DateUtils.now("EEE, d MMM yyyy HH:mm:ss Z");
188
                String timestamp = DateUtils.now("EEE, d MMM yyyy HH:mm:ss Z");
189
                String timestamp_filename = DateUtils.now("dd-MM-yyyy_HH-mm-ss");
189
                String timestamp_filename = DateUtils.now("dd-MM-yyyy_HH-mm-ss");
190
 
190
 
191
                try {
191
                try {
192
                        BufferedWriter f = new BufferedWriter(new FileWriter(filename));
192
                        BufferedWriter f = new BufferedWriter(new FileWriter(filename));
193
 
193
 
194
                        try {
194
                        try {
195
                                f.write(SIGNATURE + "\r\n");
195
                                f.write(SIGNATURE + "\r\n");
196
 
196
 
197
                                f.write(SIGNATURE_MINOR + "\r\n");
197
                                f.write(SIGNATURE_MINOR + "\r\n");
198
                                f.write("\r\n");
198
                                f.write("\r\n");
199
 
199
 
200
                                f.write("(Starting time)\r\n");
200
                                f.write("(Starting time)\r\n");
201
                                f.write(creation_time + "\r\n");
201
                                f.write(creation_time + "\r\n");
202
                                f.write("\r\n");
202
                                f.write("\r\n");
203
 
203
 
204
                                f.write("(Save timestamp)\r\n");
204
                                f.write("(Save timestamp)\r\n");
205
                                f.write(timestamp + "\r\n");
205
                                f.write(timestamp + "\r\n");
206
                                f.write("\r\n");
206
                                f.write("\r\n");
207
 
207
 
208
                                f.write("(Digits)\r\n");
208
                                f.write("(Digits)\r\n");
209
                                f.write((u + 1) + "\r\n");
209
                                f.write((u + 1) + "\r\n");
210
                                f.write("\r\n");
210
                                f.write("\r\n");
211
 
211
 
212
                                f.write("(r)\r\n");
212
                                f.write("(r)\r\n");
213
                                f.write(r + "\r\n"); // FUTURE: (1) Multi-Line-Support?
213
                                f.write(r + "\r\n"); // FUTURE: (1) Multi-Line-Support?
214
                                f.write("\r\n");
214
                                f.write("\r\n");
215
 
215
 
216
                                f.write("(M5 reversed)\r\n");
216
                                f.write("(M5 reversed)\r\n");
217
                                int i;
217
                                int i;
218
                                for (i = 0; i < a.count(); i++) {
218
                                for (i = 0; i < a.count(); i++) {
219
                                        byte xa = a.get(i);
219
                                        byte xa = a.get(i);
220
                                        f.write("" + xa);
220
                                        f.write("" + xa);
221
                                        if ((i + 1) % SOFTBREAK == 0) {
221
                                        if ((i + 1) % SOFTBREAK == 0) {
222
                                                f.write("\r\n");
222
                                                f.write("\r\n");
223
                                        }
223
                                        }
224
                                }
224
                                }
225
                                if ((i + 1) % SOFTBREAK != 0) {
225
                                if (i % SOFTBREAK != 0) { /* nicht +1, da i++ am Ende */
226
                                        f.write("\r\n");
226
                                        f.write("\r\n");
227
                                }
227
                                }
228
                                f.write("\r\n");
228
                                f.write("\r\n");
229
 
229
 
230
                                f.write(END_SIG);
230
                                f.write(END_SIG);
231
                                f.write("\r\n");
231
                                f.write("\r\n");
232
                        } finally {
232
                        } finally {
233
                                f.close();
233
                                f.close();
234
                        }
234
                        }
235
                } catch (IOException e) {
235
                } catch (IOException e) {
236
                        throw new SaveException("Could not save master file.", e);
236
                        throw new SaveException("Could not save master file.", e);
237
                }
237
                }
238
 
238
 
239
                // Make backup
239
                // Make backup
240
 
240
 
241
                new File(backupDir).mkdir();
241
                new File(backupDir).mkdir();
242
                String bak_filename = backupDir + "/immortal_" + timestamp_filename
242
                String bak_filename = backupDir + "/immortal_" + timestamp_filename
243
                                + "_" + (u + 1) + ".txt";
243
                                + "_" + (u + 1) + ".txt";
244
                try {
244
                try {
245
                        FileUtils.copyFile(new File(filename), new File(bak_filename));
245
                        FileUtils.copyFile(new File(filename), new File(bak_filename));
246
                } catch (IOException e) {
246
                } catch (IOException e) {
247
                        throw new SaveException("Could not make backup", e);
247
                        throw new SaveException("Could not make backup", e);
248
                }
248
                }
249
 
249
 
250
                if ((integrityTest) && (do_integrity_test)) {
250
                if ((integrityTest) && (do_integrity_test)) {
251
                        log("Erste Speicherung absolviert. Stabile Phase hat begonnen.");
251
                        log("Erste Speicherung absolviert. Stabile Phase hat begonnen.");
252
                }
252
                }
253
        }
253
        }
254
 
254
 
255
        public void calcIterate(int amount) throws SaveException {
255
        public void calcIterate(int amount) throws SaveException {
256
                log("Beginn der Rechenarbeit...");
256
                log("Beginn der Rechenarbeit...");
257
 
257
 
258
                int cnt = 0;
258
                int cnt = 0;
259
 
259
 
260
                // Wir führen beim ersten Speichern einen weiteren
260
                // Wir führen beim ersten Speichern einen weiteren
261
                // integrity-Test durch. Grund: Wäre bei einer Fortsetzung einer
261
                // integrity-Test durch. Grund: Wäre bei einer Fortsetzung einer
262
                // Datei das "r" falsch (der Datenteil aber korrekt), dann würde
262
                // Datei das "r" falsch (der Datenteil aber korrekt), dann würde
263
                // diese Datei beim Speichern ungültige Daten enthalten (Zahl
263
                // diese Datei beim Speichern ungültige Daten enthalten (Zahl
264
                // nicht immortabel).
264
                // nicht immortabel).
265
                boolean firstSave = true;
265
                boolean firstSave = true;
266
 
266
 
267
                if (a.isEmpty()) {
267
                if (a.isEmpty()) {
268
                        creation_time = DateUtils.now("EEE, d MMM yyyy HH:mm:ss Z");
268
                        creation_time = DateUtils.now("EEE, d MMM yyyy HH:mm:ss Z");
269
                        a.add((byte) 5);
269
                        a.add((byte) 5);
270
                        a.add((byte) 2);
270
                        a.add((byte) 2);
271
                        u = 1;
271
                        u = 1;
272
                        r = 2;
272
                        r = 2;
273
                        cnt += 2;
273
                        cnt += 2;
274
                }
274
                }
275
 
275
 
276
                int s, m, k;
276
                int s, m, k;
277
 
277
 
278
                do {
278
                do {
279
                        r = (r /* - a.get(u) */) / 10 + a.get(u);
279
                        r = (r /* - a.get(u) */) / 10 + a.get(u);
280
                        s = 0;
280
                        s = 0;
281
                        for (m = 1, k = u; m < k; m++, k--) {
281
                        for (m = 1, k = u; m < k; m++, k--) {
282
                                s += a.get(m) * a.get(k);
282
                                s += a.get(m) * a.get(k);
283
                        }
283
                        }
284
                        r += 2 * s;
284
                        r += 2 * s;
285
                        if (m == k) {
285
                        if (m == k) {
286
                                r += a.get(m) * a.get(m);
286
                                r += a.get(m) * a.get(m);
287
                        }
287
                        }
288
                        u++;
288
                        u++;
289
                        a.add((byte) (r % 10));
289
                        a.add((byte) (r % 10));
290
 
290
 
291
                        cnt++;
291
                        cnt++;
292
                        if (cnt % saveInterval == 0) {
292
                        if (cnt % saveInterval == 0) {
293
                                save(firstSave);
293
                                save(firstSave);
294
                                firstSave = false;
294
                                firstSave = false;
295
                        }
295
                        }
296
                } while (cnt != amount);
296
                } while (cnt != amount);
297
 
297
 
298
                // Wir brauchen nicht zwei Mal zu speichern
298
                // Wir brauchen nicht zwei Mal zu speichern
299
                if (cnt - 1 % saveInterval != 0) {
299
                if (cnt - 1 % saveInterval != 0) {
300
                        log("Letzte Speicherung vor Ende...");
300
                        log("Letzte Speicherung vor Ende...");
301
                        save(firstSave);
301
                        save(firstSave);
302
                        // firstSave = false;
302
                        // firstSave = false;
303
                }
303
                }
304
 
304
 
305
                log("Ende der Rechenarbeit...");
305
                log("Ende der Rechenarbeit...");
306
        }
306
        }
307
 
307
 
308
        public byte getDigitReverse(int u) {
308
        public byte getDigitReverse(int u) {
309
                return a.get(u);
309
                return a.get(u);
310
        }
310
        }
311
 
311
 
312
        public StringBuilder M5_StringBuilder(int u) {
312
        public StringBuilder M5_StringBuilder(int u) {
313
                StringBuilder s = new StringBuilder();
313
                StringBuilder s = new StringBuilder();
314
                for (int i = 0; i < a.count(); i++) {
314
                for (int i = 0; i < a.count(); i++) {
315
                        byte xa = a.get(i);
315
                        byte xa = a.get(i);
316
                        s.append("" + xa);
316
                        s.append("" + xa);
317
                }
317
                }
318
                s.reverse();
318
                s.reverse();
319
                return s;
319
                return s;
320
        }
320
        }
321
 
321
 
322
        public String M5_String(int u) {
322
        public String M5_String(int u) {
323
                return M5_StringBuilder(u).toString();
323
                return M5_StringBuilder(u).toString();
324
        }
324
        }
325
 
325
 
326
        public BigInteger M5_BigInteger(int u) {
326
        public BigInteger M5_BigInteger(int u) {
327
                return new BigInteger(M5_String(u));
327
                return new BigInteger(M5_String(u));
328
        }
328
        }
329
 
329
 
330
        public StringBuilder M6_StringBuilder(int u) {
330
        public StringBuilder M6_StringBuilder(int u) {
331
                StringBuilder s = new StringBuilder();
331
                StringBuilder s = new StringBuilder();
332
                for (int i = 0; i < a.count(); i++) {
332
                for (int i = 0; i < a.count(); i++) {
333
                        byte xa = a.get(i);
333
                        byte xa = a.get(i);
334
                        if (i > 0) {
334
                        if (i > 0) {
335
                                s.append("" + (9 - xa));
335
                                s.append("" + (9 - xa));
336
                        } else {
336
                        } else {
337
                                s.append("" + (11 - xa));
337
                                s.append("" + (11 - xa));
338
                        }
338
                        }
339
                }
339
                }
340
                s.reverse();
340
                s.reverse();
341
                return s;
341
                return s;
342
        }
342
        }
343
 
343
 
344
        public String M6_String(int u) {
344
        public String M6_String(int u) {
345
                return M6_StringBuilder(u).toString();
345
                return M6_StringBuilder(u).toString();
346
        }
346
        }
347
 
347
 
348
        public BigInteger M6_BigInteger(int u) {
348
        public BigInteger M6_BigInteger(int u) {
349
                return new BigInteger(M6_String(u));
349
                return new BigInteger(M6_String(u));
350
        }
350
        }
351
 
351
 
352
        protected static boolean isImmortable(BigInteger num, int m) {
352
        protected static boolean isImmortable(BigInteger num, int m) {
353
                // Alternativ
353
                // Alternativ
354
                // return num.pow(2).toString().endsWith(num.toString());
354
                // return num.pow(2).toString().endsWith(num.toString());
355
 
355
 
356
                // n² === n (mod 10^m) <===> n²%10^m == n%10^m == n
356
                // n² === n (mod 10^m) <===> n²%10^m == n%10^m == n
357
 
357
 
358
                BigInteger m_pow = BigInteger.TEN.pow(m);
358
                BigInteger m_pow = BigInteger.TEN.pow(m);
359
                return num.pow(2).mod(m_pow).equals(num);
359
                return num.pow(2).mod(m_pow).equals(num);
360
        }
360
        }
361
 
361
 
362
        protected static boolean isImmortable(BigInteger num) {
362
        protected static boolean isImmortable(BigInteger num) {
363
                int m = num.toString().length();
363
                int m = num.toString().length();
364
                return isImmortable(num, m);
364
                return isImmortable(num, m);
365
        }
365
        }
366
 
366
 
367
        public boolean integryTest() {
367
        public boolean integryTest() {
368
                // return isImmortable(M5_BigInteger(u), a.count());
368
                // return isImmortable(M5_BigInteger(u), a.count());
369
                return isImmortable(M6_BigInteger(u), a.count());
369
                return isImmortable(M6_BigInteger(u), a.count());
370
        }
370
        }
371
}
371
}
372
 
372