internal GenericGFPoly[] longDivide(GenericGFPoly other) { if (!field.Equals(other.field)) { throw new ArgumentException("GenericGFPolys do not have same GenericGF field"); } if (other.isZero) { throw new ArgumentException("Divide by 0"); } var quotient = field.Zero; var remainder = this; while (remainder.Degree >= other.Degree) { var degreeDifference = remainder.Degree - other.Degree; var shifted = other.multiplyByMonomial(degreeDifference, 1); var resultOfSingleDivide = field.divide(remainder.getCoefficient(remainder.Degree), shifted.getCoefficient(shifted.Degree)); var iterationQuotient = new GenericGFPoly(field, new[] { resultOfSingleDivide }); iterationQuotient = iterationQuotient.multiplyByMonomial(degreeDifference, 1); quotient = quotient.addOrSubtract(iterationQuotient); shifted = shifted.multiply(resultOfSingleDivide); remainder = remainder.addOrSubtract(shifted); } return(new [] { quotient, remainder }); }
internal GenericGFPoly multiply(GenericGFPoly other) { if (!field.Equals(other.field)) { throw new ArgumentException("GenericGFPolys do not have same GenericGF field"); } if (isZero || other.isZero) { return(field.Zero); } int[] aCoefficients = this.coefficients; int aLength = aCoefficients.Length; int[] bCoefficients = other.coefficients; int bLength = bCoefficients.Length; int[] product = new int[aLength + bLength - 1]; for (int i = 0; i < aLength; i++) { int aCoeff = aCoefficients[i]; for (int j = 0; j < bLength; j++) { product[i + j] = GenericGF.addOrSubtract(product[i + j], field.multiply(aCoeff, bCoefficients[j])); } } return(new GenericGFPoly(field, product)); }
internal GenericGFPoly[] divide(GenericGFPoly other) { if (!field.Equals(other.field)) { throw new ArgumentException("GenericGFPolys do not have same GenericGF field"); } if (other.isZero) { throw new ArgumentException("Divide by 0"); } GenericGFPoly quotient = field.Zero; GenericGFPoly remainder = this; int denominatorLeadingTerm = other.getCoefficient(other.Degree); int inverseDenominatorLeadingTerm = field.inverse(denominatorLeadingTerm); while (remainder.Degree >= other.Degree && !remainder.isZero) { int degreeDifference = remainder.Degree - other.Degree; int scale = field.multiply(remainder.getCoefficient(remainder.Degree), 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 }); }
/// <summary> /// Create a representation of GF(size) using the given primitive polynomial. /// </summary> /// <param name="primitive">irreducible polynomial whose coefficients are represented by /// * the bits of an int, where the least-significant bit represents the constant /// * coefficient</param> /// <param name="size">the size of the field</param> /// <param name="genBase">the factor b in the generator polynomial can be 0- or 1-based /// * (g(x) = (x+a^b)(x+a^(b+1))...(x+a^(b+2t-1))). /// * In most cases it should be 1, but for QR code it is 0.</param> public GenericGF(int primitive, int size, int genBase) { this.primitive = primitive; this.size = size; this.generatorBase = genBase; expTable = new int[size]; logTable = new int[size]; int x = 1; for (int i = 0; i < size; i++) { expTable[i] = x; x <<= 1; // x = x * 2; we're assuming the generator alpha is 2 if (x >= size) { x ^= primitive; x &= size - 1; } } for (int i = 0; i < size - 1; i++) { logTable[expTable[i]] = i; } // logTable[0] == 0 but this should never be used zero = new GenericGFPoly(this, new int[] { 0 }); one = new GenericGFPoly(this, new int[] { 1 }); }
public bool Decode(int[] received, int ecBytes) { if (ecBytes == 0) { throw new ArgumentException("No error correction bytes"); } var dataBytes = received.Length - ecBytes; if (dataBytes <= 0) { throw new ArgumentException("No data bytes provided"); } var errorsCorrected = false; var generator = BuildGenerator(ecBytes); var count = 0; GenericGFPoly remainder = null; var iteratorTemp = new int[received.Length]; Array.Copy(received, iteratorTemp, received.Length); var tempInfo = new GenericGFPoly(_field, iteratorTemp); while (count <= dataBytes) { remainder = tempInfo.divide(generator)[1]; if (remainder.Coefficients.Count(coeff => coeff != 0) <= ecBytes / 2) { errorsCorrected = true; break; } count++; Array.Copy(received, 0, iteratorTemp, count, received.Length - count); Array.Copy(received, received.Length - count, iteratorTemp, 0, count); tempInfo = new GenericGFPoly(_field, iteratorTemp); } if (!errorsCorrected) { return false; } if (count == 0) { return true; } var correctedInfo = tempInfo.addOrSubtract(remainder); var missingZerosCorrection = received.Length - correctedInfo.Coefficients.Length; correctedInfo = correctedInfo.multiplyByMonomial(missingZerosCorrection, 1); correctedInfo = correctedInfo.shiftLeft(count - missingZerosCorrection); missingZerosCorrection = received.Length - correctedInfo.Coefficients.Length; correctedInfo = correctedInfo.multiplyByMonomial(missingZerosCorrection, 1); Array.Copy(correctedInfo.Coefficients, 0, received, missingZerosCorrection, correctedInfo.Coefficients.Length - missingZerosCorrection); Array.Copy(correctedInfo.Coefficients, correctedInfo.Coefficients.Length - missingZerosCorrection, received, 0, missingZerosCorrection); return true; }
internal GenericGFPoly addOrSubtract(GenericGFPoly other) { if (!field.Equals(other.field)) { throw new ArgumentException("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 Array.Copy(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)); }
public bool Decode(int[] received, int ecBytes) { if (ecBytes == 0) { throw new ArgumentException("No error correction bytes"); } var dataBytes = received.Length - ecBytes; if (dataBytes <= 0) { throw new ArgumentException("No data bytes provided"); } var errorsCorrected = false; var generator = BuildGenerator(ecBytes); var count = 0; GenericGFPoly remainder = null; var iteratorTemp = new int[received.Length]; Array.Copy(received, iteratorTemp, received.Length); var tempInfo = new GenericGFPoly(_field, iteratorTemp); while (count <= dataBytes) { remainder = tempInfo.divide(generator)[1]; if (remainder.Coefficients.Count(coeff => coeff != 0) <= ecBytes / 2) { errorsCorrected = true; break; } count++; Array.Copy(received, 0, iteratorTemp, count, received.Length - count); Array.Copy(received, received.Length - count, iteratorTemp, 0, count); tempInfo = new GenericGFPoly(_field, iteratorTemp); } if (!errorsCorrected) { return(false); } if (count == 0) { return(true); } var correctedInfo = tempInfo.addOrSubtract(remainder); var missingZerosCorrection = received.Length - correctedInfo.Coefficients.Length; correctedInfo = correctedInfo.multiplyByMonomial(missingZerosCorrection, 1); correctedInfo = correctedInfo.shiftLeft(count - missingZerosCorrection); missingZerosCorrection = received.Length - correctedInfo.Coefficients.Length; correctedInfo = correctedInfo.multiplyByMonomial(missingZerosCorrection, 1); Array.Copy(correctedInfo.Coefficients, 0, received, missingZerosCorrection, correctedInfo.Coefficients.Length - missingZerosCorrection); Array.Copy(correctedInfo.Coefficients, correctedInfo.Coefficients.Length - missingZerosCorrection, received, 0, missingZerosCorrection); return(true); }
internal GenericGFPoly multiply(GenericGFPoly other) { if (!field.Equals(other.field)) { throw new ArgumentException("GenericGFPolys do not have same GenericGF field"); } if (isZero || other.isZero) { return field.Zero; } int[] aCoefficients = this.coefficients; int aLength = aCoefficients.Length; int[] bCoefficients = other.coefficients; int bLength = bCoefficients.Length; int[] product = new int[aLength + bLength - 1]; for (int i = 0; i < aLength; i++) { int aCoeff = aCoefficients[i]; for (int j = 0; j < bLength; j++) { product[i + j] = GenericGF.addOrSubtract(product[i + j], field.multiply(aCoeff, bCoefficients[j])); } } return new GenericGFPoly(field, product); }
internal GenericGFPoly[] longDivide(GenericGFPoly other) { if (!field.Equals(other.field)) { throw new ArgumentException("GenericGFPolys do not have same GenericGF field"); } if (other.isZero) { throw new ArgumentException("Divide by 0"); } var quotient = field.Zero; var remainder = this; while (remainder.Degree >= other.Degree) { var degreeDifference = remainder.Degree - other.Degree; var shifted = other.multiplyByMonomial(degreeDifference, 1); var resultOfSingleDivide = field.divide(remainder.getCoefficient(remainder.Degree), shifted.getCoefficient(shifted.Degree)); var iterationQuotient = new GenericGFPoly(field, new[] { resultOfSingleDivide }); iterationQuotient = iterationQuotient.multiplyByMonomial(degreeDifference, 1); quotient = quotient.addOrSubtract(iterationQuotient); shifted = shifted.multiply(resultOfSingleDivide); remainder = remainder.addOrSubtract(shifted); } return new [] { quotient, remainder }; }
internal GenericGFPoly[] divide(GenericGFPoly other) { if (!field.Equals(other.field)) { throw new ArgumentException("GenericGFPolys do not have same GenericGF field"); } if (other.isZero) { throw new ArgumentException("Divide by 0"); } GenericGFPoly quotient = field.Zero; GenericGFPoly remainder = this; int denominatorLeadingTerm = other.getCoefficient(other.Degree); int inverseDenominatorLeadingTerm = field.inverse(denominatorLeadingTerm); while (remainder.Degree >= other.Degree && !remainder.isZero) { int degreeDifference = remainder.Degree - other.Degree; int scale = field.multiply(remainder.getCoefficient(remainder.Degree), 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 }; }
internal GenericGFPoly addOrSubtract(GenericGFPoly other) { if (!field.Equals(other.field)) { throw new ArgumentException("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 Array.Copy(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); }