Subversion Repositories distributed

Rev

Rev 21 | Rev 24 | 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";
23 daniel-mar 21
        private static final String SIGNATURE_MINOR = "Iterator GenX Java (100k save-interval, load-integrity-check, int32-r, array-object) r22";
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
 
15 daniel-mar 33
        public ImmortableNumberSearch(String filename) throws LoadException {
20 daniel-mar 34
                this.a = new ByteArray(1000000, 1000000);
14 daniel-mar 35
                this.filename = filename;
36
                load();
37
        }
38
 
15 daniel-mar 39
        public String getBackupDir() {
40
                return backupDir;
41
        }
42
 
43
        public void setBackupDir(String backupDir) {
44
                this.backupDir = backupDir;
45
        }
46
 
14 daniel-mar 47
        public int getSaveInterval() {
48
                return this.saveInterval;
49
        }
50
 
20 daniel-mar 51
        public ByteArray getA() {
15 daniel-mar 52
                return a;
53
        }
54
 
55
        public int getU() {
56
                return u;
57
        }
58
 
59
        public int getR() {
60
                return r;
61
        }
62
 
63
        public String getFilename() {
64
                return filename;
65
        }
66
 
14 daniel-mar 67
        public void setSaveInterval(int saveInterval) {
68
                this.saveInterval = saveInterval;
69
        }
70
 
71
        private boolean savePointExists() {
72
                return new File(filename).exists();
73
        }
74
 
15 daniel-mar 75
        private void load() throws LoadException {
76
                if (!savePointExists()) {
14 daniel-mar 77
                        return;
15 daniel-mar 78
                }
14 daniel-mar 79
 
15 daniel-mar 80
                BufferedReader f;
81
                try {
82
                        f = new BufferedReader(new FileReader(filename));
83
                } catch (FileNotFoundException e) {
84
                        // Will not happen because of savePointExists().
85
                        return;
86
                }
14 daniel-mar 87
 
20 daniel-mar 88
                a.clear();
15 daniel-mar 89
                u = -1;
90
                r = -1;
91
 
92
                try {
93
                        try {
94
                                String s = f.readLine();
95
                                if (!s.equals(SIGNATURE)) {
96
                                        throw new LoadException("Wrong signature");
97
                                }
98
 
99
                                f.readLine(); // Minor. signature
100
                                f.readLine(); // ""
17 daniel-mar 101
 
15 daniel-mar 102
                                f.readLine(); // "(Starting time)"
103
                                creation_time = f.readLine();
104
                                f.readLine(); // ""
105
 
106
                                f.readLine(); // "(Save timestamp)"
107
                                f.readLine(); // Timestamp
108
                                f.readLine(); // ""
109
 
19 daniel-mar 110
                                f.readLine(); // "(Digits)"
15 daniel-mar 111
                                s = f.readLine();
20 daniel-mar 112
                                u = Integer.parseInt(s) - 1;
15 daniel-mar 113
                                f.readLine(); // ""
17 daniel-mar 114
 
15 daniel-mar 115
                                f.readLine(); // "(r)"
116
                                s = f.readLine();
117
                                r = Integer.parseInt(s); // FUTURE: (1) Multi-Line-Support?
118
                                f.readLine(); // ""
119
 
120
                                f.readLine(); // "(M5rev)"
121
                                do {
122
                                        s = f.readLine();
123
                                        for (int i = 0; i < s.length(); i++) {
20 daniel-mar 124
                                                a.add(Byte.parseByte(s.substring(i, i + 1)));
15 daniel-mar 125
                                        }
126
                                } while (!s.equals(""));
127
 
23 daniel-mar 128
                                // Wir prüfen auf Integrität beim nächsten Abspeichern
129
                                // if (!integryTest()) {
130
                                // throw new LoadException("Corrupt: Not immortable!");
131
                                // }
15 daniel-mar 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) {
152
                        if (!integryTest()) {
23 daniel-mar 153
                                throw new SaveException(
154
                                                "Integrity test failed. (Loaded file broken?) Will not save.");
14 daniel-mar 155
                        }
15 daniel-mar 156
                }
157
 
158
                String timestamp = DateUtils.now("EEE, d MMM yyyy HH:mm:ss Z");
159
                String timestamp_filename = DateUtils.now("dd-MM-yyyy_HH-mm-ss");
17 daniel-mar 160
 
15 daniel-mar 161
                try {
162
                        BufferedWriter f = new BufferedWriter(new FileWriter(filename));
14 daniel-mar 163
 
15 daniel-mar 164
                        try {
165
                                f.write(SIGNATURE + "\r\n");
14 daniel-mar 166
 
15 daniel-mar 167
                                f.write(SIGNATURE_MINOR + "\r\n");
168
                                f.write("\r\n");
14 daniel-mar 169
 
15 daniel-mar 170
                                f.write("(Starting time)\r\n");
171
                                f.write(creation_time + "\r\n");
172
                                f.write("\r\n");
14 daniel-mar 173
 
15 daniel-mar 174
                                f.write("(Save timestamp)\r\n");
175
                                f.write(timestamp + "\r\n");
176
                                f.write("\r\n");
14 daniel-mar 177
 
19 daniel-mar 178
                                f.write("(Digits)\r\n");
20 daniel-mar 179
                                f.write((u + 1) + "\r\n");
15 daniel-mar 180
                                f.write("\r\n");
14 daniel-mar 181
 
15 daniel-mar 182
                                f.write("(r)\r\n");
183
                                f.write(r + "\r\n"); // FUTURE: (1) Multi-Line-Support?
14 daniel-mar 184
                                f.write("\r\n");
15 daniel-mar 185
 
186
                                f.write("(M5rev)\r\n");
20 daniel-mar 187
                                int i;
188
                                for (i = 0; i < a.count(); i++) {
189
                                        byte xa = a.get(i);
190
                                        f.write("" + xa);
191
                                        if (i + 1 % SOFTBREAK == 0) {
15 daniel-mar 192
                                                f.write("\r\n");
193
                                        }
194
                                }
20 daniel-mar 195
                                if (i + 1 % SOFTBREAK != 0) {
15 daniel-mar 196
                                        f.write("\r\n");
197
                                }
198
                                f.write("\r\n");
199
 
200
                                f.write(END_SIG);
201
                        } finally {
202
                                f.close();
14 daniel-mar 203
                        }
15 daniel-mar 204
                } catch (IOException e) {
205
                        throw new SaveException("Could not save master file.", e);
14 daniel-mar 206
                }
15 daniel-mar 207
 
208
                // Make backup
209
 
210
                new File(backupDir).mkdir();
17 daniel-mar 211
                String bak_filename = backupDir + "/immortal_" + timestamp_filename
212
                                + "_" + (u + 1) + ".txt";
15 daniel-mar 213
                try {
214
                        FileUtils.copyFile(new File(filename), new File(bak_filename));
215
                } catch (IOException e) {
216
                        throw new SaveException("Could not make backup", e);
14 daniel-mar 217
                }
218
        }
219
 
15 daniel-mar 220
        public void calcIterate(int amount) throws SaveException {
14 daniel-mar 221
                int s, m, k;
222
                int cnt = 0;
223
 
15 daniel-mar 224
                // Wir führen beim ersten Speichern einen weiteren
225
                // integrity-Test durch. Grund: Wäre bei einer Fortsetzung einer
226
                // Datei das "r" falsch (der Datenteil aber korrekt), dann würde
227
                // diese Datei beim Speichern ungültige Daten enthalten (Zahl
228
                // nicht immortabel).
229
                boolean firstSave = true;
230
 
20 daniel-mar 231
                if (a.isEmpty()) {
15 daniel-mar 232
                        creation_time = DateUtils.now("EEE, d MMM yyyy HH:mm:ss Z");
20 daniel-mar 233
                        a.add((byte) 5);
234
                        a.add((byte) 2);
14 daniel-mar 235
                        u = 1;
236
                        r = 2;
237
                        cnt += 2;
238
                }
239
 
15 daniel-mar 240
                do {
20 daniel-mar 241
                        r = (r - a.get(u)) / 10 + a.get(u);
14 daniel-mar 242
                        s = 0;
243
                        for (m = 1, k = u; m < k; m++, k--) {
20 daniel-mar 244
                                s += a.get(m) * a.get(k);
14 daniel-mar 245
                        }
246
                        r += 2 * s;
247
                        if (m == k) {
20 daniel-mar 248
                                r += a.get(m) * a.get(m);
14 daniel-mar 249
                        }
250
                        u++;
20 daniel-mar 251
                        a.add((byte) (r % 10));
14 daniel-mar 252
 
17 daniel-mar 253
                        cnt++;
14 daniel-mar 254
                        if (cnt % saveInterval == 0) {
15 daniel-mar 255
                                save(firstSave);
256
                                firstSave = false;
14 daniel-mar 257
                        }
17 daniel-mar 258
                } while (cnt != amount);
14 daniel-mar 259
 
15 daniel-mar 260
                // Wir brauchen nicht zwei Mal zu speichern
17 daniel-mar 261
                if (cnt - 1 % saveInterval != 0) {
15 daniel-mar 262
                        save(firstSave);
263
                        firstSave = false;
264
                }
265
        }
266
 
20 daniel-mar 267
        public byte getDigitReverse(int u) {
268
                return a.get(u);
15 daniel-mar 269
        }
270
 
271
        public StringBuilder M5_StringBuilder(int u) {
272
                StringBuilder s = new StringBuilder();
20 daniel-mar 273
                for (int i = 0; i < a.count(); i++) {
274
                        byte xa = a.get(i);
275
                        s.append("" + xa);
15 daniel-mar 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;
20 daniel-mar 292
                for (int i = 0; i < a.count(); i++) {
293
                        byte xa = a.get(i);
15 daniel-mar 294
                        if (first) {
295
                                s.append(6); // xa = 5
296
                                first = false;
297
                        } else {
20 daniel-mar 298
                                s.append("" + (9 - xa));
14 daniel-mar 299
                        }
300
                }
15 daniel-mar 301
                s.reverse();
302
                return s;
14 daniel-mar 303
        }
304
 
15 daniel-mar 305
        public String M6_String(int u) {
306
                return M6_StringBuilder(u).toString();
307
        }
308
 
309
        public BigInteger M6_BigInteger(int u) {
310
                return new BigInteger(M6_String(u));
311
        }
312
 
313
        private static boolean isImmortable(BigInteger num) {
314
                // Ist das auch OK?
315
                // return num.pow(2).toString().endsWith(num.toString());
316
 
23 daniel-mar 317
                // n² === n (mod 10^m) <===> n²%10^m == n%10^m == n
318
 
15 daniel-mar 319
                int m = num.toString().length();
320
                BigInteger m_pow = BigInteger.TEN.pow(m);
23 daniel-mar 321
                return num.pow(2).mod(m_pow).equals(num);
15 daniel-mar 322
        }
323
 
324
        public boolean integryTest() {
325
                // return isImmortable(M5_BigInteger(u));
326
                return isImmortable(M6_BigInteger(u));
327
        }
14 daniel-mar 328
}