/** * Decodes given set of received codewords, which include both data and error-correction * codewords. Really, this means it uses Reed-Solomon to detect and correct errors, in-place, in * the input. * * @param received data and error-correction codewords * @param twoS number of error-correction codewords available * @throws ReedSolomonException if decoding fails for any reason */ public void decode(int[] received, int twoS) throws ReedSolomonException { 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) { noError = false; } } if (noError) { return; } GenericGFPoly syndrome = new GenericGFPoly(field, syndromeCoefficients); GenericGFPoly[] sigmaOmega = runEuclideanAlgorithm(field.buildMonomial(twoS, 1), syndrome, twoS); GenericGFPoly sigma = sigmaOmega[0]; GenericGFPoly omega = sigmaOmega[1]; int[] errorLocations = findErrorLocations(sigma); int[] errorMagnitudes = findErrorMagnitudes(omega, errorLocations); for (int i = 0; i < errorLocations.length; i++) { int position = received.length - 1 - field.log(errorLocations[i]); if (position < 0) { throw new ReedSolomonException("Bad error location"); } received[position] = GenericGF.addOrSubtract(received[position], errorMagnitudes[i]); } }
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; }
/** * Decodes given set of received codewords, which include both data and error-correction * codewords. Really, this means it uses Reed-Solomon to detect and correct errors, in-place, in * the input. * * @param received data and error-correction codewords * @param twoS number of error-correction codewords available * @throws ReedSolomonException if decoding fails for any reason */ public void decode(int[] received, int twoS) throws ReedSolomonException { GenericGFPoly poly = new GenericGFPoly(field, received); int[] syndromeCoefficients = new int[twoS]; boolean dataMatrix = field.equals(GenericGF.GenericGFs.AZTEC_DATA_8.mGf); boolean noError = true; for (int i = 0; i < twoS; i++) { // Thanks to sanfordsquires for this fix: int eval = poly.evaluateAt(field.exp(dataMatrix ? i + 1 : i)); syndromeCoefficients[syndromeCoefficients.length - 1 - i] = eval; if (eval != 0) { noError = false; } } if (noError) { return; } GenericGFPoly syndrome = new GenericGFPoly(field, syndromeCoefficients); GenericGFPoly[] sigmaOmega = runEuclideanAlgorithm(field.buildMonomial(twoS, 1), syndrome, twoS); GenericGFPoly sigma = sigmaOmega[0]; GenericGFPoly omega = sigmaOmega[1]; int[] errorLocations = findErrorLocations(sigma); int[] errorMagnitudes = findErrorMagnitudes(omega, errorLocations, dataMatrix); for (int i = 0; i < errorLocations.length; i++) { int position = received.length - 1 - field.log(errorLocations[i]); if (position < 0) { throw new ReedSolomonException("Bad error location"); } received[position] = GenericGF.addOrSubtract(received[position], errorMagnitudes[i]); } }
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; }