Subversion Repositories distributed

Rev

Rev 20 | Rev 23 | 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";
20 daniel-mar 21
        private static final String SIGNATURE_MINOR = "Iterator GenX Java (100k save-interval, load-integrity-check, int32-r, array-object) r20";
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
 
128
                                if (!integryTest()) {
129
                                        throw new LoadException("Corrupt: Not immortable!");
130
                                }
131
 
20 daniel-mar 132
                                if (u + 1 != a.count()) {
15 daniel-mar 133
                                        throw new LoadException(
134
                                                        "Corrupt: Formal and actual length mismatch!");
135
                                }
136
 
137
                                s = f.readLine();
138
                                if (!s.equals(END_SIG)) {
139
                                        throw new LoadException("Corrupt: End-signature mismatch.");
140
                                }
141
                        } finally {
142
                                f.close();
143
                        }
144
                } catch (IOException e) {
145
                        throw new LoadException(e);
14 daniel-mar 146
                }
15 daniel-mar 147
        }
14 daniel-mar 148
 
15 daniel-mar 149
        private void save(boolean integrityTest) throws SaveException {
150
                if (integrityTest) {
151
                        if (!integryTest()) {
17 daniel-mar 152
                                throw new SaveException("Integrity test failed. Will not save.");
14 daniel-mar 153
                        }
15 daniel-mar 154
                }
155
 
156
                String timestamp = DateUtils.now("EEE, d MMM yyyy HH:mm:ss Z");
157
                String timestamp_filename = DateUtils.now("dd-MM-yyyy_HH-mm-ss");
17 daniel-mar 158
 
15 daniel-mar 159
                try {
160
                        BufferedWriter f = new BufferedWriter(new FileWriter(filename));
14 daniel-mar 161
 
15 daniel-mar 162
                        try {
163
                                f.write(SIGNATURE + "\r\n");
14 daniel-mar 164
 
15 daniel-mar 165
                                f.write(SIGNATURE_MINOR + "\r\n");
166
                                f.write("\r\n");
14 daniel-mar 167
 
15 daniel-mar 168
                                f.write("(Starting time)\r\n");
169
                                f.write(creation_time + "\r\n");
170
                                f.write("\r\n");
14 daniel-mar 171
 
15 daniel-mar 172
                                f.write("(Save timestamp)\r\n");
173
                                f.write(timestamp + "\r\n");
174
                                f.write("\r\n");
14 daniel-mar 175
 
19 daniel-mar 176
                                f.write("(Digits)\r\n");
20 daniel-mar 177
                                f.write((u + 1) + "\r\n");
15 daniel-mar 178
                                f.write("\r\n");
14 daniel-mar 179
 
15 daniel-mar 180
                                f.write("(r)\r\n");
181
                                f.write(r + "\r\n"); // FUTURE: (1) Multi-Line-Support?
14 daniel-mar 182
                                f.write("\r\n");
15 daniel-mar 183
 
184
                                f.write("(M5rev)\r\n");
20 daniel-mar 185
                                int i;
186
                                for (i = 0; i < a.count(); i++) {
187
                                        byte xa = a.get(i);
188
                                        f.write("" + xa);
189
                                        if (i + 1 % SOFTBREAK == 0) {
15 daniel-mar 190
                                                f.write("\r\n");
191
                                        }
192
                                }
20 daniel-mar 193
                                if (i + 1 % SOFTBREAK != 0) {
15 daniel-mar 194
                                        f.write("\r\n");
195
                                }
196
                                f.write("\r\n");
197
 
198
                                f.write(END_SIG);
199
                        } finally {
200
                                f.close();
14 daniel-mar 201
                        }
15 daniel-mar 202
                } catch (IOException e) {
203
                        throw new SaveException("Could not save master file.", e);
14 daniel-mar 204
                }
15 daniel-mar 205
 
206
                // Make backup
207
 
208
                new File(backupDir).mkdir();
17 daniel-mar 209
                String bak_filename = backupDir + "/immortal_" + timestamp_filename
210
                                + "_" + (u + 1) + ".txt";
15 daniel-mar 211
                try {
212
                        FileUtils.copyFile(new File(filename), new File(bak_filename));
213
                } catch (IOException e) {
214
                        throw new SaveException("Could not make backup", e);
14 daniel-mar 215
                }
216
        }
217
 
15 daniel-mar 218
        public void calcIterate(int amount) throws SaveException {
14 daniel-mar 219
                int s, m, k;
220
                int cnt = 0;
221
 
15 daniel-mar 222
                // Wir führen beim ersten Speichern einen weiteren
223
                // integrity-Test durch. Grund: Wäre bei einer Fortsetzung einer
224
                // Datei das "r" falsch (der Datenteil aber korrekt), dann würde
225
                // diese Datei beim Speichern ungültige Daten enthalten (Zahl
226
                // nicht immortabel).
227
                boolean firstSave = true;
228
 
20 daniel-mar 229
                if (a.isEmpty()) {
15 daniel-mar 230
                        creation_time = DateUtils.now("EEE, d MMM yyyy HH:mm:ss Z");
20 daniel-mar 231
                        a.add((byte) 5);
232
                        a.add((byte) 2);
14 daniel-mar 233
                        u = 1;
234
                        r = 2;
235
                        cnt += 2;
236
                }
237
 
15 daniel-mar 238
                do {
20 daniel-mar 239
                        r = (r - a.get(u)) / 10 + a.get(u);
14 daniel-mar 240
                        s = 0;
241
                        for (m = 1, k = u; m < k; m++, k--) {
20 daniel-mar 242
                                s += a.get(m) * a.get(k);
14 daniel-mar 243
                        }
244
                        r += 2 * s;
245
                        if (m == k) {
20 daniel-mar 246
                                r += a.get(m) * a.get(m);
14 daniel-mar 247
                        }
248
                        u++;
20 daniel-mar 249
                        a.add((byte) (r % 10));
14 daniel-mar 250
 
17 daniel-mar 251
                        cnt++;
14 daniel-mar 252
                        if (cnt % saveInterval == 0) {
15 daniel-mar 253
                                save(firstSave);
254
                                firstSave = false;
14 daniel-mar 255
                        }
17 daniel-mar 256
                } while (cnt != amount);
14 daniel-mar 257
 
15 daniel-mar 258
                // Wir brauchen nicht zwei Mal zu speichern
17 daniel-mar 259
                if (cnt - 1 % saveInterval != 0) {
15 daniel-mar 260
                        save(firstSave);
261
                        firstSave = false;
262
                }
263
        }
264
 
20 daniel-mar 265
        public byte getDigitReverse(int u) {
266
                return a.get(u);
15 daniel-mar 267
        }
268
 
269
        public StringBuilder M5_StringBuilder(int u) {
270
                StringBuilder s = new StringBuilder();
20 daniel-mar 271
                for (int i = 0; i < a.count(); i++) {
272
                        byte xa = a.get(i);
273
                        s.append("" + xa);
15 daniel-mar 274
                }
275
                s.reverse();
276
                return s;
277
        }
278
 
279
        public String M5_String(int u) {
280
                return M5_StringBuilder(u).toString();
281
        }
282
 
283
        public BigInteger M5_BigInteger(int u) {
284
                return new BigInteger(M5_String(u));
285
        }
286
 
287
        public StringBuilder M6_StringBuilder(int u) {
288
                StringBuilder s = new StringBuilder();
289
                boolean first = true;
20 daniel-mar 290
                for (int i = 0; i < a.count(); i++) {
291
                        byte xa = a.get(i);
15 daniel-mar 292
                        if (first) {
293
                                s.append(6); // xa = 5
294
                                first = false;
295
                        } else {
20 daniel-mar 296
                                s.append("" + (9 - xa));
14 daniel-mar 297
                        }
298
                }
15 daniel-mar 299
                s.reverse();
300
                return s;
14 daniel-mar 301
        }
302
 
15 daniel-mar 303
        public String M6_String(int u) {
304
                return M6_StringBuilder(u).toString();
305
        }
306
 
307
        public BigInteger M6_BigInteger(int u) {
308
                return new BigInteger(M6_String(u));
309
        }
310
 
311
        private static boolean isImmortable(BigInteger num) {
312
                // Ist das auch OK?
313
                // return num.pow(2).toString().endsWith(num.toString());
314
 
315
                // n² === n (mod 10^m) <===> n²%10^m == n%10^m
316
                int m = num.toString().length();
317
                BigInteger m_pow = BigInteger.TEN.pow(m);
318
                return num.pow(2).mod(m_pow).equals(num.mod(m_pow));
319
 
320
        }
321
 
322
        public boolean integryTest() {
323
                // return isImmortable(M5_BigInteger(u));
324
                return isImmortable(M6_BigInteger(u));
325
        }
14 daniel-mar 326
}