Exemplo n.º 1
0
        /// <summary>
        /// Returns the derivative of a certain degree for the polynom.
        /// If the current polynom is of degree N, its derivative of degree D
        /// is also a polynomial function of degree Max(0; N-D).
        /// </summary>
        /// <param name="derivativeDegree"></param>
        /// <returns></returns>
        public Polynom <T, C> Derivative(int derivativeDegree)
        {
            if (derivativeDegree == 0)
            {
                return(this);
            }
            else if (derivativeDegree < 0)
            {
                throw new ArgumentException("Derivative degree should be a non-negative integer value.");
            }
            else if (derivativeDegree > this.Degree)
            {
                return(new Polynom <T, C>(new Numeric <T, C>[] { Numeric <T, C> .Zero }));
            }

            int newCoefCount = this.coefficients.Length - derivativeDegree;

            Numeric <T, C>[] coefficients = new Numeric <T, C> [newCoefCount];

            for (int i = 0; i < newCoefCount; i++)
            {
                coefficients[i] = this.coefficients[i + derivativeDegree];

                for (int j = 0; j < derivativeDegree; j++)
                {
                    coefficients[i] *= calc.fromInt(i + derivativeDegree - j);
                }
            }

            return(new Polynom <T, C>(coefficients));
        }
Exemplo n.º 2
0
        /// <summary>
        /// If the current calculator for the <typeparamref name="T"/> type does not support conversions
        /// from the double type AND the <paramref name="num"/> does not exceed the range of long,
        /// this method will result in smaller number of exceptions, because
        /// if <paramref name="num"/> value contains only integral part, the 'fromInt(int)' calculator method
        /// will be preferred over the 'fromDouble(double)'.
        /// </summary>
        /// <typeparam name="T">The type of numbers for the calculator.</typeparam>
        /// <param name="calculator">The calling calculator object.</param>
        /// <param name="num">The number which is to be converted to the <typeparamref name="T"/> type.</param>
        /// <returns>The <typeparamref name="T"/> value returned by either fromInt (preferred) of fromDouble calculator method.</returns>
        public static T fromDoubleSafe <T>(this ICalc <T> calculator, double num)
        {
            if (Numeric <double, CalcDouble> .Calculator.fracPart(num) == 0 && num > long.MinValue && num < long.MaxValue)
            {
                return(calculator.fromInt((long)num));
            }

            return(calculator.fromDouble(num));
        }
Exemplo n.º 3
0
        /// <summary>
        /// Returns the rectangle approximation of the function integral.
        /// </summary>
        /// <typeparam name="T">The type of function argument/value.</typeparam>
        /// <typeparam name="C">The calculator for the argument type.</typeparam>
        /// <param name="obj">The calling function object.</param>
        /// <param name="interval">The interval to approximate the integral on.</param>
        /// <param name="pointCount">The overall point count used to calculate the integral.</param>
        /// <returns></returns>
        public static T IntegralRectangleApproximation <T, C>(this IFunction <T, T> obj, BoundedInterval <T, C> interval, int pointCount) where C : ICalc <T>, new()
        {
            ICalc <T> calc = Numeric <T, C> .Calculator;

            // Если интервал нулевой, то ваще забей.

            if (interval.IsZeroLength)
            {
                return(calc.zero);
            }

            // Если нет, то ваще не забей.

            Numeric <T, C> step = calc.div(interval.Length, calc.fromInt(pointCount));

            Numeric <T, C> two = (Numeric <T, C>) 2;

            Numeric <T, C> left  = interval.LeftBound + step / two;
            Numeric <T, C> right = interval.RightBound - step / two;

            // Будем хранить элементы по порядку, чтобы при суммировании не терять ерунды.

            SortedSet <Numeric <T, C> > sorted = new SortedSet <Numeric <T, C> >(Numeric <T, C> .NumericComparer);

            for (int i = 0; i < pointCount; i++)
            {
                T current = left + (right - left) * (Numeric <T, C>)i / (Numeric <T, C>)(pointCount - 1);
                sorted.Add(obj.Value(current));
            }

            // Теперь будем суммировать по порядку, начиная с самых маленьких.

            Numeric <T, C> sum = calc.zero;

            foreach (Numeric <T, C> element in sorted)
            {
                sum += element;
            }

            return(sum * step);
        }
Exemplo n.º 4
0
        // --------------------------------------------
        // --------- ПОИСК НУЛЕЙ НА ИНТЕРВАЛЕ ---------
        // --------------------------------------------

        /// <summary>
        /// Searches for the function root (zero value) on the interval [a; b].
        /// The interval is counted as with INCLUSIVE bounds!
        ///
        /// The conditions of method success:
        ///
        /// 1. The function f(x) is continuous on the interval [a; b].
        /// 2. The value f(a) and f(b) are of different signs.
        ///
        /// These conditions guarantee the existence of the zero on the interval [a; b].
        /// The method results in finding ONE of these zeroes.
        /// </summary>
        /// <typeparam name="T">The type of function argument/value.</typeparam>
        /// <typeparam name="C">The calculator for the argument type.</typeparam>
        /// <param name="obj">The calling function object.</param>
        /// <param name="interval">The interval on which the zero is searched. The value </param>
        /// <param name="epsilonArg">The epsilon value of the argument interval. The 'root' argument would be actually any value in the interval [-epsilon; +epsilon]</param>
        /// <param name="epsilonFunc">The epsilon value of the function zero. That means, that any function value in the interval [-epsilonFunc; epsilonFunc] is considered zero value. This parameter is usually set to absolute zero (so that only true 0 counts), but may become useful when the function calculation method contains precision errors resulting in zero becoming 'non-zero'.</param>
        /// <returns>The argument value resulting in f(x) ~= 0.</returns>
        public static T ZeroSearchBisectionMethod <T, C>(this IFunction <T, T> obj, BoundedInterval <T, C> interval, Numeric <T, C> epsilonArg, Numeric <T, C> epsilonFunc) where C : ICalc <T>, new()
        {
            ICalc <T> calc = Numeric <T, C> .Calculator;

            Numeric <T, C> zero = Numeric <T, C> .Zero;
            Numeric <T, C> two  = calc.fromInt(2);

            Numeric <T, C> left  = interval.LeftBound;
            Numeric <T, C> right = interval.RightBound;

            Numeric <T, C> xMid;

            Func <T, T>   abs = WhiteMath <T, C> .Abs;
            Func <T, int> sgn = WhiteMath <T, C> .Sign;

            Numeric <T, C> leftVal = obj.Value(left);
            Numeric <T, C> midVal;
            Numeric <T, C> rightVal = obj.Value(right);

            // -- флаг - чтобы не проделывать лишних вычислений.

            bool leftChanged = false;

            // ----- если на концах интервала ноль, то возвращаем сразу.

            if ((abs(leftVal) - zero) < epsilonFunc)
            {
                return(left);
            }

            else if ((abs(rightVal) - zero) < epsilonFunc)
            {
                return(right);
            }

            // --------- проверочка

            if (sgn(leftVal) == sgn(rightVal))
            {
                throw new ArgumentException("Error: the function values are of the same sign on the interval bounds.");
            }

            // ---------------------------------------------------------

            while (true)
            {
                xMid = (right + left) / two;

                // ------- достигли требуемой точности - ура!

                if (xMid - left < epsilonArg)
                {
                    return(xMid);
                }

                // ----------------------------------------------

                if (leftChanged)
                {
                    leftVal = obj.Value(left);
                }
                else
                {
                    rightVal = obj.Value(right);
                }

                midVal = obj.Value(xMid);

                // ------------ ура! Нашли риальни ноль! --------

                if (abs(midVal - zero) < epsilonFunc)
                {
                    return(xMid);
                }

                else if (sgn(rightVal) * sgn(midVal) < 0)
                {
                    leftChanged = true;
                    left        = xMid;
                }

                else if (sgn(leftVal) * sgn(midVal) < 0)
                {
                    leftChanged = false;
                    right       = xMid;
                }
                else
                {
                    throw new FunctionException(string.Format("Some particular method iteration failed, possibly due to the precision loss. The function is intended to be of different signs on the interval bounds, but the values are {0} and {1}.", leftVal, rightVal));
                }
            }
        }