Subversion Repositories distributed

Rev

Rev 13 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
30 daniel-mar 1
package de.viathinksoft.immortal.gen2.math;
5 daniel-mar 2
 
3
import java.math.BigInteger;
4
 
5
public class MathUtils2 {
6
 
7 daniel-mar 7
        public static BigInteger length(BigInteger x) throws Exception {
5 daniel-mar 8
                // TODO: größer als MAX_INTEGER erlauben!
7 daniel-mar 9
                BigInteger z = new BigInteger(""+x.toString().length());
10
 
11
                if (z.signum() == -1) {
12
                        throw new Exception("Integer overflow! (BigInteger-Length)");
13
                }
14
 
15
                return z;
5 daniel-mar 16
        }
17
 
18
        public static BigInteger pow(BigInteger base, BigInteger exponent) {
7 daniel-mar 19
                if (exponent.signum() == -1) {
5 daniel-mar 20
                        throw new ArithmeticException("Negative exponent");
21
                }
22
 
23
                BigInteger i = new BigInteger("0");
24
                BigInteger res = new BigInteger("1");
25
 
26
                while (i.compareTo(exponent) != 0) {
27
                        i = i.add(BigInteger.ONE);
28
                        res = res.multiply(base);
29
                }
30
 
31
                return res;
32
        }
33
 
34
        /**
35
         * Division with remainder method - based on the original Java<br>
36
         * 'divideAndRemainder' method<br>
37
         * returns an object of results (of type BigInteger):<br>
38
         * -> the division result (q=a/b)<br>
39
         * result[1] -> the remainder (r=a-q*b)<br>
40
         * If b==0 then result will be 0. No ArithmeticException!
41
         *
42
         * @param a
43
         * @param b
44
         * @return
45
         * @see http://tupac.euv-frankfurt-o.de/www/kryptos/demos/Demos.java
46
         **/
47
        public static DivisionAndRemainderResult divRem(BigInteger a, BigInteger b) {
48
                // if (b==0) {
49
                // -> divideAndRemainder() throws ArithmeticException when b==0
7 daniel-mar 50
                if (b.signum() == 0) {
5 daniel-mar 51
                        return new DivisionAndRemainderResult(BigInteger.ZERO,
52
                                        BigInteger.ZERO);
53
                }
54
 
55
                BigInteger[] x = a.divideAndRemainder(b);
56
                return new DivisionAndRemainderResult(x[0], x[1]);
57
        }
58
 
59
        /**
60
         *
61
         * @param a
62
         * @param b
63
         * @return
64
         * @see http://www.arndt-bruenner.de/mathe/scripts/chineRestsatz.js
65
         */
66
        private static BigInteger[] extGGT(BigInteger a, BigInteger b) {
7 daniel-mar 67
                if (b.signum() == 0) {
5 daniel-mar 68
                        return new BigInteger[] { BigInteger.ONE, BigInteger.ZERO };
69
                }
70
 
71
                BigInteger rem = divRem(a, b).getRemainder();
7 daniel-mar 72
                if (rem.signum() == 0) {
5 daniel-mar 73
                        return new BigInteger[] { BigInteger.ZERO, BigInteger.ONE };
74
                }
75
 
76
                BigInteger[] c = extGGT(b, rem);
77
                BigInteger x = c[0];
78
                BigInteger y = c[1];
79
 
80
                return new BigInteger[] { y, x.subtract(y.multiply(a.divide(b))) };
81
        }
82
 
83
        /**
84
         * Erweiterter euklidscher Algorithmus
85
         *
86
         * @param a
87
         * @param b
88
         * @return Erzeugt Objekt mit mit gcd=ggT(a,b) und gcd=alpha*a+beta*b
89
         * @see http://www.arndt-bruenner.de/mathe/scripts/chineRestsatz.js
90
         */
91
        private static ExtEuclResult erwGGT(BigInteger a, BigInteger b) {
92
                BigInteger aa = new BigInteger("1");
93
                BigInteger bb = new BigInteger("1");
94
 
7 daniel-mar 95
                if (a.signum() == -1) {
5 daniel-mar 96
                        aa = new BigInteger("-1");
97
                        a = a.negate();
98
                }
99
 
7 daniel-mar 100
                if (b.signum() == -1) {
5 daniel-mar 101
                        bb = new BigInteger("-1");
102
                        b = b.negate();
103
                }
104
 
105
                BigInteger[] c = extGGT(a, b);
106
                BigInteger g = a.gcd(b);
107
 
108
                return new ExtEuclResult(c[0].multiply(aa), c[1].multiply(bb), g);
109
        }
110
 
111
        /**
112
         * Allgemeines Lösen zweier Kongruenzen (Chinesischer Restsatz)
113
         *
114
         * @param a
115
         * @param n
116
         * @param b
117
         * @param m
118
         * @return
119
         * @throws CRTNotSolveableException
120
         * @throws RemainderNotSmallerThanModulusException
121
         * @see http://de.wikipedia.org/wiki/Chinesischer_Restsatz#Direktes_L.C3.B6sen_von_simultanen_Kongruenzen_ganzer_Zahlen
122
         */
123
        public static BigInteger chineseRemainder(BigInteger a, BigInteger n,
13 daniel-mar 124
                        BigInteger b, BigInteger m) throws CRTException {
5 daniel-mar 125
 
126
                // Frage: Ist es notwendig, dass wir divRem() verwenden, das von a%0==0 ausgeht?
127
 
7 daniel-mar 128
                if (a.signum() == -1) {
5 daniel-mar 129
                        a = a.negate();
130
                }
131
 
7 daniel-mar 132
                if (b.signum() == -1) {
5 daniel-mar 133
                        b = b.negate();
134
                }
135
 
7 daniel-mar 136
                if (n.signum() == -1) {
5 daniel-mar 137
                        n = n.negate();
138
                }
139
 
7 daniel-mar 140
                if (m.signum() == -1) {
5 daniel-mar 141
                        m = m.negate();
142
                }
143
 
144
                if ((a.compareTo(n) >= 0) || (b.compareTo(m) >= 0)) {
145
                        throw new RemainderNotSmallerThanModulusException();
146
                }
147
 
148
                // d = ggT(n,m)
149
                BigInteger d = n.gcd(m);
150
 
151
                // a === b (mod d) erfüllt?
152
                if (!divRem(a, d).getRemainder().equals(divRem(b, d).getRemainder())) {
153
                        throw new CRTNotSolveableException();
154
                }
155
 
156
                // ggT(n,m) = yn + zm
157
                BigInteger y = erwGGT(n, m).getAlpha();
158
 
159
                // x = a - y*n*((a-b)/d) mod (n*m/d)
160
                BigInteger N = n.multiply(m).divide(d);
161
                BigInteger x = divRem(
162
                                a.subtract(y.multiply(n).multiply(a.subtract(b).divide(d))), N)
163
                                .getRemainder();
164
                x = a.subtract(y.multiply(n).multiply(a.subtract(b).divide(d)));
165
 
7 daniel-mar 166
                while (x.signum() == -1) {
5 daniel-mar 167
                        x = x.add(N);
168
                }
169
 
170
                return x;
171
        }
172
 
173
        private MathUtils2() {
174
        }
175
 
176
}