// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- /* * Copyright 2012 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * 2012-09-19 HFN translation from Java into C++ */ #include #include using zxing::Ref; using zxing::ArrayRef; using zxing::pdf417::decoder::ec::ModulusGF; using zxing::pdf417::decoder::ec::ModulusPoly; /** * @author Sean Owen * @see com.google.zxing.common.reedsolomon.GenericGFPoly */ ModulusPoly::ModulusPoly(ModulusGF& field, ArrayRef coefficients) : field_(field) { if (coefficients->size() == 0) { throw IllegalArgumentException("no coefficients!"); } int coefficientsLength = coefficients->size(); if (coefficientsLength > 1 && coefficients[0] == 0) { // Leading term must be non-zero for anything except the constant polynomial "0" int firstNonZero = 1; while (firstNonZero < coefficientsLength && coefficients[firstNonZero] == 0) { firstNonZero++; } if (firstNonZero == coefficientsLength) { coefficientsLength = field_.getZero()->getCoefficients()->size(); coefficients_.reset(new Array (coefficientsLength)); *coefficients_ = *(field_.getZero()->getCoefficients()); } else { ArrayRef c(coefficients); coefficientsLength -= firstNonZero; coefficients_.reset(new Array (coefficientsLength)); for (int i = 0; i < coefficientsLength; i++) { coefficients_[i] = c[i + firstNonZero]; } /* coefficientsLength -= firstNonZero; coefficients_.reset(new Array(coefficientsLength - firstNonZero)); for (int i = 0; i < coefficientsLength; i++) { coefficients_[i] = coefficients[i + firstNonZero]; } */ } } else { coefficients_ = coefficients; } } ArrayRef ModulusPoly::getCoefficients() { return coefficients_; } /** * @return degree of this polynomial */ int ModulusPoly::getDegree() { return coefficients_->size() - 1; } /** * @return true iff this polynomial is the monomial "0" */ bool ModulusPoly::isZero() { return coefficients_[0] == 0; } /** * @return coefficient of x^degree term in this polynomial */ int ModulusPoly::getCoefficient(int degree) { return coefficients_[coefficients_->size() - 1 - degree]; } /** * @return evaluation of this polynomial at a given point */ int ModulusPoly::evaluateAt(int a) { int i; if (a == 0) { // Just return the x^0 coefficient return getCoefficient(0); } int size = coefficients_->size(); if (a == 1) { // Just the sum of the coefficients int result = 0; for (i = 0; i < size; i++) { result = field_.add(result, coefficients_[i]); } return result; } int result = coefficients_[0]; for (i = 1; i < size; i++) { result = field_.add(field_.multiply(a, result), coefficients_[i]); } return result; } Ref ModulusPoly::add(Ref other) { if (&field_ != &other->field_) { throw IllegalArgumentException("ModulusPolys do not have same ModulusGF field"); } if (isZero()) { return other; } if (other->isZero()) { return Ref(this); } ArrayRef smallerCoefficients = coefficients_; ArrayRef largerCoefficients = other->coefficients_; if (smallerCoefficients->size() > largerCoefficients->size()) { ArrayRef temp(smallerCoefficients); smallerCoefficients = largerCoefficients; largerCoefficients = temp; } ArrayRef sumDiff (new Array(largerCoefficients->size())); int lengthDiff = largerCoefficients->size() - smallerCoefficients->size(); // Copy high-order terms only found in higher-degree polynomial's coefficients for (int i = 0; i < lengthDiff; i++) { sumDiff[i] = largerCoefficients[i]; } for (int i = lengthDiff; i < largerCoefficients->size(); i++) { sumDiff[i] = field_.add(smallerCoefficients[i - lengthDiff], largerCoefficients[i]); } return Ref(new ModulusPoly(field_, sumDiff)); } Ref ModulusPoly::subtract(Ref other) { if (&field_ != &other->field_) { throw new IllegalArgumentException("ModulusPolys do not have same ModulusGF field"); } if (other->isZero()) { return Ref(this); } return add(other->negative()); } Ref ModulusPoly::multiply(Ref other) { if (&field_ != &other->field_) { throw new IllegalArgumentException("ModulusPolys do not have same ModulusGF field"); } if (isZero() || other->isZero()) { return field_.getZero(); } int i,j; ArrayRef aCoefficients = coefficients_; int aLength = aCoefficients->size(); ArrayRef bCoefficients = other->coefficients_; int bLength = bCoefficients->size(); ArrayRef product (new Array(aLength + bLength - 1)); for (i = 0; i < aLength; i++) { int aCoeff = aCoefficients[i]; for (j = 0; j < bLength; j++) { product[i + j] = field_.add(product[i + j], field_.multiply(aCoeff, bCoefficients[j])); } } return Ref(new ModulusPoly(field_, product)); } Ref ModulusPoly::negative() { int size = coefficients_->size(); ArrayRef negativeCoefficients (new Array(size)); for (int i = 0; i < size; i++) { negativeCoefficients[i] = field_.subtract(0, coefficients_[i]); } return Ref(new ModulusPoly(field_, negativeCoefficients)); } Ref ModulusPoly::multiply(int scalar) { if (scalar == 0) { return field_.getZero(); } if (scalar == 1) { return Ref(this); } int size = coefficients_->size(); ArrayRef product( new Array(size)); for (int i = 0; i < size; i++) { product[i] = field_.multiply(coefficients_[i], scalar); } return Ref(new ModulusPoly(field_, product)); } Ref ModulusPoly::multiplyByMonomial(int degree, int coefficient) { if (degree < 0) { throw new IllegalArgumentException("negative degree!"); } if (coefficient == 0) { return field_.getZero(); } int size = coefficients_->size(); ArrayRef product (new Array(size + degree)); for (int i = 0; i < size; i++) { product[i] = field_.multiply(coefficients_[i], coefficient); } return Ref(new ModulusPoly(field_, product)); } std::vector > ModulusPoly::divide(Ref other) { if (&field_ != &other->field_) { throw new IllegalArgumentException("ModulusPolys do not have same ModulusGF field"); } if (other->isZero()) { throw new IllegalArgumentException("Divide by 0"); } Ref quotient (field_.getZero()); Ref 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); Ref term (other->multiplyByMonomial(degreeDifference, scale)); Ref iterationQuotient (field_.buildMonomial(degreeDifference, scale)); quotient = quotient->add(iterationQuotient); remainder = remainder->subtract(term); } std::vector > result(2); result[0] = quotient; result[1] = remainder; return result; } #if 0 @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) { result.append(" - "); coefficient = -coefficient; } else { if (result.length() > 0) { result.append(" + "); } } if (degree == 0 || coefficient != 1) { result.append(coefficient); } if (degree != 0) { if (degree == 1) { result.append('x'); } else { result.append("x^"); result.append(degree); } } } } return result.toString(); } #endif ModulusPoly::~ModulusPoly() {}