Subversion Repositories distributed

Rev

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