public void encode(int[] toEncode, int ecBytes) { if (ecBytes == 0) { throw new IllegalArgumentException("No error correction bytes"); } int dataBytes = toEncode.length - ecBytes; if (dataBytes <= 0) { throw new IllegalArgumentException("No data bytes provided"); } GenericGFPoly generator = buildGenerator(ecBytes); int[] infoCoefficients = new int[dataBytes]; System.arraycopy(toEncode, 0, infoCoefficients, 0, dataBytes); GenericGFPoly info = new GenericGFPoly(field, infoCoefficients); info = info.multiplyByMonomial(ecBytes, 1); GenericGFPoly remainder = info.divide(generator)[1]; int[] coefficients = remainder.getCoefficients(); int numZeroCoefficients = ecBytes - coefficients.length; for (int i = 0; i < numZeroCoefficients; i++) { toEncode[dataBytes + i] = 0; } System.arraycopy(coefficients, 0, toEncode, dataBytes + numZeroCoefficients, coefficients.length); }
GenericGFPoly[] divide(GenericGFPoly other) { if (!field.equals(other.field)) { throw new IllegalArgumentException("GenericGFPolys do not have same GenericGF field"); } if (other.isZero()) { throw new IllegalArgumentException("Divide by 0"); } GenericGFPoly quotient = field.getZero(); GenericGFPoly remainder = this; int denominatorLeadingTerm = other.getCoefficient(other.getDegree()); int inverseDenominatorLeadingTerm = field.inverse(denominatorLeadingTerm); while (remainder.getDegree() >= other.getDegree() && !remainder.isZero()) { int degreeDifference = remainder.getDegree() - other.getDegree(); int scale = field.multiply(remainder.getCoefficient(remainder.getDegree()), inverseDenominatorLeadingTerm); GenericGFPoly term = other.multiplyByMonomial(degreeDifference, scale); GenericGFPoly iterationQuotient = field.buildMonomial(degreeDifference, scale); quotient = quotient.addOrSubtract(iterationQuotient); remainder = remainder.addOrSubtract(term); } return new GenericGFPoly[] { quotient, remainder }; }
private int[] findErrorLocations(GenericGFPoly errorLocator) throws ReedSolomonException { // This is a direct application of Chien's search int numErrors = errorLocator.getDegree(); if (numErrors == 1) { // shortcut return new int[] { errorLocator.getCoefficient(1) }; } int[] result = new int[numErrors]; int e = 0; for (int i = 1; i < field.getSize() && e < numErrors; i++) { if (errorLocator.evaluateAt(i) == 0) { result[e] = field.inverse(i); e++; } } if (e != numErrors) { throw new ReedSolomonException("Error locator degree does not match number of roots"); } return result; }
private GenericGFPoly buildGenerator(int degree) { if (degree >= cachedGenerators.size()) { GenericGFPoly lastGenerator = cachedGenerators.get(cachedGenerators.size() - 1); for (int d = cachedGenerators.size(); d <= degree; d++) { GenericGFPoly nextGenerator = lastGenerator.multiply( new GenericGFPoly(field, new int[] { 1, field.exp(d - 1 + field.getGeneratorBase()) })); cachedGenerators.add(nextGenerator); lastGenerator = nextGenerator; } } return cachedGenerators.get(degree); }
GenericGFPoly addOrSubtract(GenericGFPoly other) { if (!field.equals(other.field)) { throw new IllegalArgumentException("GenericGFPolys do not have same GenericGF field"); } if (isZero()) { return other; } if (other.isZero()) { return this; } int[] smallerCoefficients = this.coefficients; int[] largerCoefficients = other.coefficients; if (smallerCoefficients.length > largerCoefficients.length) { int[] temp = smallerCoefficients; smallerCoefficients = largerCoefficients; largerCoefficients = temp; } int[] sumDiff = new int[largerCoefficients.length]; int lengthDiff = largerCoefficients.length - smallerCoefficients.length; // Copy high-order terms only found in higher-degree polynomial's coefficients System.arraycopy(largerCoefficients, 0, sumDiff, 0, lengthDiff); for (int i = lengthDiff; i < largerCoefficients.length; i++) { sumDiff[i] = GenericGF.addOrSubtract(smallerCoefficients[i - lengthDiff], largerCoefficients[i]); } return new GenericGFPoly(field, sumDiff); }
/** * @return the monomial representing coefficient * x^degree */ GenericGFPoly buildMonomial(int degree, int coefficient) { if (degree < 0) { throw new IllegalArgumentException(); } if (coefficient == 0) { return zero; } int[] coefficients = new int[degree + 1]; coefficients[0] = coefficient; return new GenericGFPoly(this, coefficients); }
@Override public String toString() { StringBuilder result = new StringBuilder(8 * getDegree()); for (int degree = getDegree(); degree >= 0; degree--) { int coefficient = getCoefficient(degree); if (coefficient != 0) { if (coefficient < 0) {
GenericGFPoly poly = new GenericGFPoly(field, received); int[] syndromeCoefficients = new int[twoS]; boolean noError = true; for (int i = 0; i < twoS; i++) { int eval = poly.evaluateAt(field.exp(i + field.getGeneratorBase())); syndromeCoefficients[syndromeCoefficients.length - 1 - i] = eval; if (eval != 0) { return; GenericGFPoly syndrome = new GenericGFPoly(field, syndromeCoefficients); GenericGFPoly[] sigmaOmega = runEuclideanAlgorithm(field.buildMonomial(twoS, 1), syndrome, twoS);
/** * @return evaluation of this polynomial at a given point */ int evaluateAt(int a) { if (a == 0) { // Just return the x^0 coefficient return getCoefficient(0); } if (a == 1) { // Just the sum of the coefficients int result = 0; for (int coefficient : coefficients) { result = GenericGF.addOrSubtract(result, coefficient); } return result; } int result = coefficients[0]; int size = coefficients.length; for (int i = 1; i < size; i++) { result = GenericGF.addOrSubtract(field.multiply(a, result), coefficients[i]); } return result; }
private int[] findErrorMagnitudes(GenericGFPoly errorEvaluator, int[] errorLocations) { // This is directly applying Forney's Formula int s = errorLocations.length; int[] result = new int[s]; for (int i = 0; i < s; i++) { int xiInverse = field.inverse(errorLocations[i]); int denominator = 1; for (int j = 0; j < s; j++) { if (i != j) { //denominator = field.multiply(denominator, // GenericGF.addOrSubtract(1, field.multiply(errorLocations[j], xiInverse))); // Above should work but fails on some Apple and Linux JDKs due to a Hotspot bug. // Below is a funny-looking workaround from Steven Parkes int term = field.multiply(errorLocations[j], xiInverse); int termPlus1 = (term & 0x1) == 0 ? term | 1 : term & ~1; denominator = field.multiply(denominator, termPlus1); } } result[i] = field.multiply(errorEvaluator.evaluateAt(xiInverse), field.inverse(denominator)); if (field.getGeneratorBase() != 0) { result[i] = field.multiply(result[i], xiInverse); } } return result; }
GenericGFPoly addOrSubtract(GenericGFPoly other) { if (!field.equals(other.field)) { throw new IllegalArgumentException("GenericGFPolys do not have same GenericGF field"); } if (isZero()) { return other; } if (other.isZero()) { return this; } int[] smallerCoefficients = this.coefficients; int[] largerCoefficients = other.coefficients; if (smallerCoefficients.length > largerCoefficients.length) { int[] temp = smallerCoefficients; smallerCoefficients = largerCoefficients; largerCoefficients = temp; } int[] sumDiff = new int[largerCoefficients.length]; int lengthDiff = largerCoefficients.length - smallerCoefficients.length; // Copy high-order terms only found in higher-degree polynomial's coefficients System.arraycopy(largerCoefficients, 0, sumDiff, 0, lengthDiff); for (int i = lengthDiff; i < largerCoefficients.length; i++) { sumDiff[i] = GenericGF.addOrSubtract(smallerCoefficients[i - lengthDiff], largerCoefficients[i]); } return new GenericGFPoly(field, sumDiff); }
/** * @return the monomial representing coefficient * x^degree */ GenericGFPoly buildMonomial(int degree, int coefficient) { if (degree < 0) { throw new IllegalArgumentException(); } if (coefficient == 0) { return zero; } int[] coefficients = new int[degree + 1]; coefficients[0] = coefficient; return new GenericGFPoly(this, coefficients); }
private GenericGFPoly buildGenerator(int degree) { if (degree >= cachedGenerators.size()) { GenericGFPoly lastGenerator = cachedGenerators.get(cachedGenerators.size() - 1); for (int d = cachedGenerators.size(); d <= degree; d++) { GenericGFPoly nextGenerator = lastGenerator.multiply( new GenericGFPoly(field, new int[] { 1, field.exp(d - 1 + field.getGeneratorBase()) })); cachedGenerators.add(nextGenerator); lastGenerator = nextGenerator; } } return cachedGenerators.get(degree); }
@Override public String toString() { StringBuilder result = new StringBuilder(8 * getDegree()); for (int degree = getDegree(); degree >= 0; degree--) { int coefficient = getCoefficient(degree); if (coefficient != 0) { if (coefficient < 0) {
GenericGFPoly poly = new GenericGFPoly(field, received); int[] syndromeCoefficients = new int[twoS]; boolean noError = true; for (int i = 0; i < twoS; i++) { int eval = poly.evaluateAt(field.exp(i + field.getGeneratorBase())); syndromeCoefficients[syndromeCoefficients.length - 1 - i] = eval; if (eval != 0) { return; GenericGFPoly syndrome = new GenericGFPoly(field, syndromeCoefficients); GenericGFPoly[] sigmaOmega = runEuclideanAlgorithm(field.buildMonomial(twoS, 1), syndrome, twoS);
/** * @return evaluation of this polynomial at a given point */ int evaluateAt(int a) { if (a == 0) { // Just return the x^0 coefficient return getCoefficient(0); } if (a == 1) { // Just the sum of the coefficients int result = 0; for (int coefficient : coefficients) { result = GenericGF.addOrSubtract(result, coefficient); } return result; } int result = coefficients[0]; int size = coefficients.length; for (int i = 1; i < size; i++) { result = GenericGF.addOrSubtract(field.multiply(a, result), coefficients[i]); } return result; }
private int[] findErrorMagnitudes(GenericGFPoly errorEvaluator, int[] errorLocations) { // This is directly applying Forney's Formula int s = errorLocations.length; int[] result = new int[s]; for (int i = 0; i < s; i++) { int xiInverse = field.inverse(errorLocations[i]); int denominator = 1; for (int j = 0; j < s; j++) { if (i != j) { //denominator = field.multiply(denominator, // GenericGF.addOrSubtract(1, field.multiply(errorLocations[j], xiInverse))); // Above should work but fails on some Apple and Linux JDKs due to a Hotspot bug. // Below is a funny-looking workaround from Steven Parkes int term = field.multiply(errorLocations[j], xiInverse); int termPlus1 = (term & 0x1) == 0 ? term | 1 : term & ~1; denominator = field.multiply(denominator, termPlus1); } } result[i] = field.multiply(errorEvaluator.evaluateAt(xiInverse), field.inverse(denominator)); if (field.getGeneratorBase() != 0) { result[i] = field.multiply(result[i], xiInverse); } } return result; }
GenericGFPoly[] divide(GenericGFPoly other) { if (!field.equals(other.field)) { throw new IllegalArgumentException("GenericGFPolys do not have same GenericGF field"); } if (other.isZero()) { throw new IllegalArgumentException("Divide by 0"); } GenericGFPoly quotient = field.getZero(); GenericGFPoly remainder = this; int denominatorLeadingTerm = other.getCoefficient(other.getDegree()); int inverseDenominatorLeadingTerm = field.inverse(denominatorLeadingTerm); while (remainder.getDegree() >= other.getDegree() && !remainder.isZero()) { int degreeDifference = remainder.getDegree() - other.getDegree(); int scale = field.multiply(remainder.getCoefficient(remainder.getDegree()), inverseDenominatorLeadingTerm); GenericGFPoly term = other.multiplyByMonomial(degreeDifference, scale); GenericGFPoly iterationQuotient = field.buildMonomial(degreeDifference, scale); quotient = quotient.addOrSubtract(iterationQuotient); remainder = remainder.addOrSubtract(term); } return new GenericGFPoly[] { quotient, remainder }; }
public void encode(int[] toEncode, int ecBytes) { if (ecBytes == 0) { throw new IllegalArgumentException("No error correction bytes"); } int dataBytes = toEncode.length - ecBytes; if (dataBytes <= 0) { throw new IllegalArgumentException("No data bytes provided"); } GenericGFPoly generator = buildGenerator(ecBytes); int[] infoCoefficients = new int[dataBytes]; System.arraycopy(toEncode, 0, infoCoefficients, 0, dataBytes); GenericGFPoly info = new GenericGFPoly(field, infoCoefficients); info = info.multiplyByMonomial(ecBytes, 1); GenericGFPoly remainder = info.divide(generator)[1]; int[] coefficients = remainder.getCoefficients(); int numZeroCoefficients = ecBytes - coefficients.length; for (int i = 0; i < numZeroCoefficients; i++) { toEncode[dataBytes + i] = 0; } System.arraycopy(coefficients, 0, toEncode, dataBytes + numZeroCoefficients, coefficients.length); }
private int[] findErrorLocations(GenericGFPoly errorLocator) throws ReedSolomonException { // This is a direct application of Chien's search int numErrors = errorLocator.getDegree(); if (numErrors == 1) { // shortcut return new int[] { errorLocator.getCoefficient(1) }; } int[] result = new int[numErrors]; int e = 0; for (int i = 1; i < field.getSize() && e < numErrors; i++) { if (errorLocator.evaluateAt(i) == 0) { result[e] = field.inverse(i); e++; } } if (e != numErrors) { throw new ReedSolomonException("Error locator degree does not match number of roots"); } return result; }