More minor code improvements
[zxing.git] / core / src / com / google / zxing / common / reedsolomon / GF256Poly.java
1 /*
2  * Copyright 2007 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.google.zxing.common.reedsolomon;
18
19 /**
20  * <p>Represents a polynomial whose coefficients are elements of GF(256).
21  * Instances of this class are immutable.</p>
22  *
23  * <p>Much credit is due to William Rucklidge since portions of this code are an indirect
24  * port of his C++ Reed-Solomon implementation.</p>
25  *
26  * @author srowen@google.com (Sean Owen)
27  */
28 final class GF256Poly {
29
30   private final GF256 field;
31   private final int[] coefficients;
32
33   /**
34    * @param field the {@link GF256} instance representing the field to use
35    * to perform computations
36    * @param coefficients coefficients as ints representing elements of GF(256), arranged
37    * from most significant (highest-power term) coefficient to least significant
38    * @throws IllegalArgumentException if argument is null or empty,
39    * or if leading coefficient is 0 and this is not a
40    * constant polynomial (that is, it is not the monomial "0")
41    */
42   GF256Poly(GF256 field, int[] coefficients) {
43     if (coefficients == null || coefficients.length == 0) {
44       throw new IllegalArgumentException();
45     }
46     this.field = field;
47     int coefficientsLength = coefficients.length;
48     if (coefficientsLength > 1 && coefficients[0] == 0) {
49       // Leading term must be non-zero for anything except the constant polynomial "0"
50       int firstNonZero = 1;
51       while (firstNonZero < coefficientsLength && coefficients[firstNonZero] == 0) {
52         firstNonZero++;
53       }
54       if (firstNonZero == coefficientsLength) {
55         this.coefficients = field.getZero().coefficients;
56       } else {
57         this.coefficients = new int[coefficientsLength - firstNonZero];
58         System.arraycopy(coefficients,
59             firstNonZero,
60             this.coefficients,
61             0,
62             this.coefficients.length);
63       }
64     } else {
65       this.coefficients = coefficients;
66     }
67   }
68
69   /**
70    * @return degree of this polynomial
71    */
72   int getDegree() {
73     return coefficients.length - 1;
74   }
75
76   /**
77    * @return true iff this polynomial is the monomial "0"
78    */
79   boolean isZero() {
80     return coefficients[0] == 0;
81   }
82
83   /**
84    * @return coefficient of x^degree term in this polynomial
85    */
86   int getCoefficient(int degree) {
87     return coefficients[coefficients.length - 1 - degree];
88   }
89
90   /**
91    * @return evaluation of this polynomial at a given point
92    */
93   int evaluateAt(int a) {
94     if (a == 0) {
95       // Just return the x^0 coefficient
96       return getCoefficient(0);
97     }
98     int size = coefficients.length;
99     if (a == 1) {
100       // Just the sum of the coefficients
101       int result = 0;
102       for (int i = 0; i < size; i++) {
103         result = GF256.addOrSubtract(result, coefficients[i]);
104       }
105       return result;
106     }
107     int result = coefficients[0];
108     for (int i = 1; i < size; i++) {
109       result = GF256.addOrSubtract(field.multiply(a, result), coefficients[i]);
110     }
111     return result;
112   }
113
114   /*
115   int evaluateFormatDerivativeAt(int a) {
116     int degree = getDegree();
117     if (degree == 0) {
118       // Derivative of a constant is zero.
119       return 0;
120     }
121
122     int aToTheI = 1;
123     int sum = getCoefficient(1);
124     int aSquared = field.multiply(a, a);
125     for (int i = 2; i < degree; i += 2) {
126       aToTheI = field.multiply(aSquared, aToTheI);
127       sum = field.addOrSubtract(sum, field.multiply(aToTheI, getCoefficient(i + 1)));
128     }
129     return sum;
130   }
131    */
132
133   GF256Poly addOrSubtract(GF256Poly other) {
134     if (!field.equals(other.field)) {
135       throw new IllegalArgumentException("GF256Polys do not have same GF256 field");
136     }
137     if (isZero()) {
138       return other;
139     }
140     if (other.isZero()) {
141       return this;
142     }
143
144     int[] smallerCoefficients = this.coefficients;
145     int[] largerCoefficients = other.coefficients;
146     if (smallerCoefficients.length > largerCoefficients.length) {
147       int[] temp = smallerCoefficients;
148       smallerCoefficients = largerCoefficients;
149       largerCoefficients = temp;
150     }
151     int[] sumDiff = new int[largerCoefficients.length];
152     int lengthDiff = largerCoefficients.length - smallerCoefficients.length;
153     // Copy high-order terms only found in higher-degree polynomial's coefficients
154     System.arraycopy(largerCoefficients, 0, sumDiff, 0, lengthDiff);
155
156     for (int i = lengthDiff; i < largerCoefficients.length; i++) {
157       sumDiff[i] = GF256.addOrSubtract(smallerCoefficients[i - lengthDiff], largerCoefficients[i]);
158     }
159
160     return new GF256Poly(field, sumDiff);
161   }
162
163   GF256Poly multiply(GF256Poly other) {
164     if (!field.equals(other.field)) {
165       throw new IllegalArgumentException("GF256Polys do not have same GF256 field");
166     }
167     if (isZero() || other.isZero()) {
168       return field.getZero();
169     }
170     int[] aCoefficients = this.coefficients;
171     int aLength = aCoefficients.length;
172     int[] bCoefficients = other.coefficients;
173     int bLength = bCoefficients.length;
174     int[] product = new int[aLength + bLength - 1];
175     for (int i = 0; i < aLength; i++) {
176       int aCoeff = aCoefficients[i];
177       for (int j = 0; j < bLength; j++) {
178         product[i + j] = GF256.addOrSubtract(product[i + j],
179             field.multiply(aCoeff, bCoefficients[j]));
180       }
181     }
182     return new GF256Poly(field, product);
183   }
184
185   GF256Poly multiply(int scalar) {
186     if (scalar == 0) {
187       return field.getZero();
188     }
189     if (scalar == 1) {
190       return this;
191     }
192     int size = coefficients.length;
193     int[] product = new int[size];
194     for (int i = 0; i < size; i++) {
195       product[i] = field.multiply(coefficients[i], scalar);
196     }
197     return new GF256Poly(field, product);
198   }
199
200   GF256Poly multiplyByMonomial(int degree, int coefficient) {
201     if (degree < 0) {
202       throw new IllegalArgumentException();
203     }
204     if (coefficient == 0) {
205       return field.getZero();
206     }
207     int size = coefficients.length;
208     int[] product = new int[size + degree];
209     for (int i = 0; i < size; i++) {
210       product[i] = field.multiply(coefficients[i], coefficient);
211     }
212     return new GF256Poly(field, product);
213   }
214
215 }