/// <summary>
        /// Finds the error magnitudes by directly applying Forney's Formula
        /// </summary>
        /// <returns>The error magnitudes.</returns>
        /// <param name="errorEvaluator">Error evaluator.</param>
        /// <param name="errorLocator">Error locator.</param>
        /// <param name="errorLocations">Error locations.</param>
        private int[] FindErrorMagnitudes(ModulusPoly errorEvaluator,
                                          ModulusPoly errorLocator,
                                          int[] errorLocations)
        {
            int errorLocatorDegree = errorLocator.Degree;

            int[] formalDerivativeCoefficients = new int[errorLocatorDegree];
            for (int i = 1; i <= errorLocatorDegree; i++)
            {
                formalDerivativeCoefficients[errorLocatorDegree - i] =
                    field.Multiply(i, errorLocator.GetCoefficient(i));
            }
            ModulusPoly formalDerivative = new ModulusPoly(field, formalDerivativeCoefficients);

            // 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 numerator   = field.Subtract(0, errorEvaluator.EvaluateAt(xiInverse));
                int denominator = field.Inverse(formalDerivative.EvaluateAt(xiInverse));
                result[i] = field.Multiply(numerator, denominator);
            }
            return(result);
        }
        /// <summary>
        /// Finds the error locations as a direct application of Chien's search
        /// </summary>
        /// <returns>The error locations.</returns>
        /// <param name="errorLocator">Error locator.</param>
        private int[] FindErrorLocations(ModulusPoly errorLocator)
        {
            // This is a direct application of Chien's search
            int numErrors = errorLocator.Degree;

            int[] result = new int[numErrors];
            int   e      = 0;

            for (int i = 1; i < field.Size && e < numErrors; i++)
            {
                if (errorLocator.EvaluateAt(i) == 0)
                {
                    result[e] = field.Inverse(i);
                    e++;
                }
            }
            if (e != numErrors)
            {
                // return null;
                throw ReaderException.Instance;
            }
            return(result);
        }
        /// <summary>
        /// Decodes the specified received.
        /// </summary>
        /// <param name="received">The received.</param>
        /// <param name="numECCodewords">The num EC codewords.</param>
        /// <param name="erasures">The erasures.</param>
        /// <returns></returns>
        public int Decode(int[] received,
                          int numECCodewords,
                          int[] erasures)
        {
            
            ModulusPoly poly = new ModulusPoly(field, received);
            int[] S = new int[numECCodewords];
            bool error = false;
            for (int i = numECCodewords; i > 0; i--)
            {
                int eval = poly.EvaluateAt(field.Exp(i));
                S[numECCodewords - i] = eval;
                if (eval != 0)
                {
                    error = true;
                }
            }
            
            if (!error)
            {
                return 0;
            }
            
            ModulusPoly knownErrors = field.One;
            foreach (int erasure in erasures)
            {
                int b = field.Exp(received.Length - 1 - erasure);
                // Add (1 - bx) term:
                ModulusPoly term = new ModulusPoly(field, new int[]
                {
                    field.Subtract(0, b),
                    1
                });
                knownErrors = knownErrors.Multiply(term);
            }
            
            ModulusPoly syndrome = new ModulusPoly(field, S);
            //syndrome = syndrome.multiply(knownErrors);
            
            ModulusPoly[] sigmaOmega = RunEuclideanAlgorithm(field.BuildMonomial(numECCodewords, 1), syndrome, numECCodewords);

            if (sigmaOmega == null)
            {
                throw ReaderException.Instance;
            }

            ModulusPoly sigma = sigmaOmega[0];
            ModulusPoly omega = sigmaOmega[1];

            if (sigma == null || omega == null)
            {
                throw ReaderException.Instance;
            }

            //sigma = sigma.multiply(knownErrors);
            
            int[] errorLocations = FindErrorLocations(sigma);

            if (errorLocations == null)
            {
                throw ReaderException.Instance;
            }

            int[] errorMagnitudes = FindErrorMagnitudes(omega, sigma, errorLocations);
            
            for (int i = 0; i < errorLocations.Length; i++)
            {
                int position = received.Length - 1 - field.Log(errorLocations[i]);
                if (position < 0)
                {
                    throw ReaderException.Instance;
                    // return -3; // don't throw

                }
                received[position] = field.Subtract(received[position], errorMagnitudes[i]);
            }
            return errorLocations.Length;
        }
        /// <summary>
        /// Finds the error magnitudes by directly applying Forney's Formula
        /// </summary>
        /// <returns>The error magnitudes.</returns>
        /// <param name="errorEvaluator">Error evaluator.</param>
        /// <param name="errorLocator">Error locator.</param>
        /// <param name="errorLocations">Error locations.</param>
        private int[] FindErrorMagnitudes(ModulusPoly errorEvaluator,
                                        ModulusPoly errorLocator,
                                        int[] errorLocations)
        {
            int errorLocatorDegree = errorLocator.Degree;
            int[] formalDerivativeCoefficients = new int[errorLocatorDegree];
            for (int i = 1; i <= errorLocatorDegree; i++)
            {
                formalDerivativeCoefficients[errorLocatorDegree - i] =
                field.Multiply(i, errorLocator.GetCoefficient(i));
            }
            ModulusPoly formalDerivative = new ModulusPoly(field, formalDerivativeCoefficients);

            // 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 numerator = field.Subtract(0, errorEvaluator.EvaluateAt(xiInverse));
                int denominator = field.Inverse(formalDerivative.EvaluateAt(xiInverse));
                result[i] = field.Multiply(numerator, denominator);
            }
            return result;
        }
 /// <summary>
 /// Finds the error locations as a direct application of Chien's search
 /// </summary>
 /// <returns>The error locations.</returns>
 /// <param name="errorLocator">Error locator.</param>
 private int[] FindErrorLocations(ModulusPoly errorLocator)
 {
     // This is a direct application of Chien's search
     int numErrors = errorLocator.Degree;
     int[] result = new int[numErrors];
     int e = 0;
     for (int i = 1; i < field.Size && e < numErrors; i++)
     {
         if (errorLocator.EvaluateAt(i) == 0)
         {
             result[e] = field.Inverse(i);
             e++;
         }
     }
     if (e != numErrors)
     {
         // return null;
         throw ReaderException.Instance;
     }
     return result;
 }
        /// <summary>
        /// Decodes the specified received.
        /// </summary>
        /// <param name="received">The received.</param>
        /// <param name="numECCodewords">The num EC codewords.</param>
        /// <param name="erasures">The erasures.</param>
        /// <returns></returns>
        public int Decode(int[] received,
                          int numECCodewords,
                          int[] erasures)
        {
            ModulusPoly poly = new ModulusPoly(field, received);

            int[] S     = new int[numECCodewords];
            bool  error = false;

            for (int i = numECCodewords; i > 0; i--)
            {
                int eval = poly.EvaluateAt(field.Exp(i));
                S[numECCodewords - i] = eval;
                if (eval != 0)
                {
                    error = true;
                }
            }

            if (!error)
            {
                return(0);
            }

            ModulusPoly knownErrors = field.One;

            foreach (int erasure in erasures)
            {
                int b = field.Exp(received.Length - 1 - erasure);
                // Add (1 - bx) term:
                ModulusPoly term = new ModulusPoly(field, new int[]
                {
                    field.Subtract(0, b),
                    1
                });
                knownErrors = knownErrors.Multiply(term);
            }

            ModulusPoly syndrome = new ModulusPoly(field, S);

            //syndrome = syndrome.multiply(knownErrors);

            ModulusPoly[] sigmaOmega = RunEuclideanAlgorithm(field.BuildMonomial(numECCodewords, 1), syndrome, numECCodewords);

            if (sigmaOmega == null)
            {
                throw ReaderException.Instance;
            }

            ModulusPoly sigma = sigmaOmega[0];
            ModulusPoly omega = sigmaOmega[1];

            if (sigma == null || omega == null)
            {
                throw ReaderException.Instance;
            }

            //sigma = sigma.multiply(knownErrors);

            int[] errorLocations = FindErrorLocations(sigma);

            if (errorLocations == null)
            {
                throw ReaderException.Instance;
            }

            int[] errorMagnitudes = FindErrorMagnitudes(omega, sigma, errorLocations);

            for (int i = 0; i < errorLocations.Length; i++)
            {
                int position = received.Length - 1 - field.Log(errorLocations[i]);
                if (position < 0)
                {
                    throw ReaderException.Instance;
                    // return -3; // don't throw
                }
                received[position] = field.Subtract(received[position], errorMagnitudes[i]);
            }
            return(errorLocations.Length);
        }