Subversion Repositories distributed

Rev

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

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