Subversion Repositories distributed

Rev

Rev 24 | Rev 28 | 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
 
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
 */
18
public class ImmortableNumberSearch {
14 daniel-mar 19
 
19 daniel-mar 20
        private static final String SIGNATURE = "Immortable Number Report File Version 2.01";
27 daniel-mar 21
        private static final String SIGNATURE_MINOR = "Iterator GenX Java (100k save-interval, load-integrity-check, int32-r, array-object) r25";
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
 
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
 
20 daniel-mar 53
        public ByteArray getA() {
15 daniel-mar 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()) {
27 daniel-mar 79
                        this.a = new ByteArray(INITIAL_SIZE, EXPANSION_SIZE);
14 daniel-mar 80
                        return;
15 daniel-mar 81
                }
14 daniel-mar 82
 
15 daniel-mar 83
                BufferedReader f;
84
                try {
85
                        f = new BufferedReader(new FileReader(filename));
86
                } catch (FileNotFoundException e) {
87
                        // Will not happen because of savePointExists().
88
                        return;
89
                }
14 daniel-mar 90
 
20 daniel-mar 91
                a.clear();
15 daniel-mar 92
                u = -1;
93
                r = -1;
94
 
95
                try {
96
                        try {
97
                                String s = f.readLine();
98
                                if (!s.equals(SIGNATURE)) {
99
                                        throw new LoadException("Wrong signature");
100
                                }
101
 
102
                                f.readLine(); // Minor. signature
103
                                f.readLine(); // ""
17 daniel-mar 104
 
15 daniel-mar 105
                                f.readLine(); // "(Starting time)"
106
                                creation_time = f.readLine();
107
                                f.readLine(); // ""
108
 
109
                                f.readLine(); // "(Save timestamp)"
110
                                f.readLine(); // Timestamp
111
                                f.readLine(); // ""
112
 
19 daniel-mar 113
                                f.readLine(); // "(Digits)"
15 daniel-mar 114
                                s = f.readLine();
20 daniel-mar 115
                                u = Integer.parseInt(s) - 1;
15 daniel-mar 116
                                f.readLine(); // ""
17 daniel-mar 117
 
15 daniel-mar 118
                                f.readLine(); // "(r)"
119
                                s = f.readLine();
120
                                r = Integer.parseInt(s); // FUTURE: (1) Multi-Line-Support?
121
                                f.readLine(); // ""
122
 
27 daniel-mar 123
                                this.a = new ByteArray(u + 1 + EXPANSION_SIZE, EXPANSION_SIZE);
124
 
24 daniel-mar 125
                                f.readLine(); // "(M5 reversed)"
15 daniel-mar 126
                                do {
127
                                        s = f.readLine();
128
                                        for (int i = 0; i < s.length(); i++) {
20 daniel-mar 129
                                                a.add(Byte.parseByte(s.substring(i, i + 1)));
15 daniel-mar 130
                                        }
131
                                } while (!s.equals(""));
132
 
20 daniel-mar 133
                                if (u + 1 != a.count()) {
15 daniel-mar 134
                                        throw new LoadException(
135
                                                        "Corrupt: Formal and actual length mismatch!");
136
                                }
137
 
138
                                s = f.readLine();
139
                                if (!s.equals(END_SIG)) {
140
                                        throw new LoadException("Corrupt: End-signature mismatch.");
141
                                }
142
                        } finally {
143
                                f.close();
144
                        }
145
                } catch (IOException e) {
146
                        throw new LoadException(e);
14 daniel-mar 147
                }
15 daniel-mar 148
        }
14 daniel-mar 149
 
15 daniel-mar 150
        private void save(boolean integrityTest) throws SaveException {
151
                if (integrityTest) {
24 daniel-mar 152
                        System.out.println("Beginne Selbsttest vor erster Speicherung...");
153
 
15 daniel-mar 154
                        if (!integryTest()) {
23 daniel-mar 155
                                throw new SaveException(
156
                                                "Integrity test failed. (Loaded file broken?) 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");
17 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
 
19 daniel-mar 180
                                f.write("(Digits)\r\n");
20 daniel-mar 181
                                f.write((u + 1) + "\r\n");
15 daniel-mar 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
 
24 daniel-mar 188
                                f.write("(M5 reversed)\r\n");
20 daniel-mar 189
                                int i;
190
                                for (i = 0; i < a.count(); i++) {
191
                                        byte xa = a.get(i);
192
                                        f.write("" + xa);
24 daniel-mar 193
                                        if ((i + 1) % SOFTBREAK == 0) {
15 daniel-mar 194
                                                f.write("\r\n");
195
                                        }
196
                                }
24 daniel-mar 197
                                if ((i + 1) % SOFTBREAK != 0) {
15 daniel-mar 198
                                        f.write("\r\n");
199
                                }
200
                                f.write("\r\n");
201
 
202
                                f.write(END_SIG);
203
                        } finally {
204
                                f.close();
14 daniel-mar 205
                        }
15 daniel-mar 206
                } catch (IOException e) {
207
                        throw new SaveException("Could not save master file.", e);
14 daniel-mar 208
                }
15 daniel-mar 209
 
210
                // Make backup
211
 
212
                new File(backupDir).mkdir();
17 daniel-mar 213
                String bak_filename = backupDir + "/immortal_" + timestamp_filename
214
                                + "_" + (u + 1) + ".txt";
15 daniel-mar 215
                try {
216
                        FileUtils.copyFile(new File(filename), new File(bak_filename));
217
                } catch (IOException e) {
218
                        throw new SaveException("Could not make backup", e);
14 daniel-mar 219
                }
24 daniel-mar 220
 
221
                if (integrityTest) {
222
                        System.out
223
                                        .println("Erste Speicherung absolviert. Stabile Phase hat begonnen.");
224
                }
14 daniel-mar 225
        }
226
 
15 daniel-mar 227
        public void calcIterate(int amount) throws SaveException {
14 daniel-mar 228
                int s, m, k;
229
                int cnt = 0;
230
 
15 daniel-mar 231
                // Wir führen beim ersten Speichern einen weiteren
232
                // integrity-Test durch. Grund: Wäre bei einer Fortsetzung einer
233
                // Datei das "r" falsch (der Datenteil aber korrekt), dann würde
234
                // diese Datei beim Speichern ungültige Daten enthalten (Zahl
235
                // nicht immortabel).
236
                boolean firstSave = true;
237
 
20 daniel-mar 238
                if (a.isEmpty()) {
15 daniel-mar 239
                        creation_time = DateUtils.now("EEE, d MMM yyyy HH:mm:ss Z");
20 daniel-mar 240
                        a.add((byte) 5);
241
                        a.add((byte) 2);
14 daniel-mar 242
                        u = 1;
243
                        r = 2;
244
                        cnt += 2;
245
                }
246
 
15 daniel-mar 247
                do {
20 daniel-mar 248
                        r = (r - a.get(u)) / 10 + a.get(u);
14 daniel-mar 249
                        s = 0;
250
                        for (m = 1, k = u; m < k; m++, k--) {
20 daniel-mar 251
                                s += a.get(m) * a.get(k);
14 daniel-mar 252
                        }
253
                        r += 2 * s;
254
                        if (m == k) {
20 daniel-mar 255
                                r += a.get(m) * a.get(m);
14 daniel-mar 256
                        }
257
                        u++;
20 daniel-mar 258
                        a.add((byte) (r % 10));
14 daniel-mar 259
 
17 daniel-mar 260
                        cnt++;
14 daniel-mar 261
                        if (cnt % saveInterval == 0) {
15 daniel-mar 262
                                save(firstSave);
263
                                firstSave = false;
14 daniel-mar 264
                        }
17 daniel-mar 265
                } while (cnt != amount);
14 daniel-mar 266
 
15 daniel-mar 267
                // Wir brauchen nicht zwei Mal zu speichern
17 daniel-mar 268
                if (cnt - 1 % saveInterval != 0) {
15 daniel-mar 269
                        save(firstSave);
270
                        firstSave = false;
271
                }
272
        }
273
 
20 daniel-mar 274
        public byte getDigitReverse(int u) {
275
                return a.get(u);
15 daniel-mar 276
        }
277
 
278
        public StringBuilder M5_StringBuilder(int u) {
279
                StringBuilder s = new StringBuilder();
20 daniel-mar 280
                for (int i = 0; i < a.count(); i++) {
281
                        byte xa = a.get(i);
282
                        s.append("" + xa);
15 daniel-mar 283
                }
284
                s.reverse();
285
                return s;
286
        }
287
 
288
        public String M5_String(int u) {
289
                return M5_StringBuilder(u).toString();
290
        }
291
 
292
        public BigInteger M5_BigInteger(int u) {
293
                return new BigInteger(M5_String(u));
294
        }
295
 
296
        public StringBuilder M6_StringBuilder(int u) {
297
                StringBuilder s = new StringBuilder();
20 daniel-mar 298
                for (int i = 0; i < a.count(); i++) {
299
                        byte xa = a.get(i);
24 daniel-mar 300
                        if (i > 0) {
301
                                s.append("" + (9 - xa));
15 daniel-mar 302
                        } else {
24 daniel-mar 303
                                s.append("" + (11 - xa));
14 daniel-mar 304
                        }
305
                }
15 daniel-mar 306
                s.reverse();
307
                return s;
14 daniel-mar 308
        }
309
 
15 daniel-mar 310
        public String M6_String(int u) {
311
                return M6_StringBuilder(u).toString();
312
        }
313
 
314
        public BigInteger M6_BigInteger(int u) {
315
                return new BigInteger(M6_String(u));
316
        }
317
 
24 daniel-mar 318
        protected static boolean isImmortable(BigInteger num, int m) {
319
                // Alternativ
15 daniel-mar 320
                // return num.pow(2).toString().endsWith(num.toString());
321
 
23 daniel-mar 322
                // n² === n (mod 10^m) <===> n²%10^m == n%10^m == n
323
 
15 daniel-mar 324
                BigInteger m_pow = BigInteger.TEN.pow(m);
23 daniel-mar 325
                return num.pow(2).mod(m_pow).equals(num);
15 daniel-mar 326
        }
327
 
24 daniel-mar 328
        protected static boolean isImmortable(BigInteger num) {
329
                int m = num.toString().length();
330
                return isImmortable(num, m);
331
        }
332
 
15 daniel-mar 333
        public boolean integryTest() {
24 daniel-mar 334
                // return isImmortable(M5_BigInteger(u), a.count());
335
                return isImmortable(M6_BigInteger(u), a.count());
15 daniel-mar 336
        }
14 daniel-mar 337
}