Esempio n. 1
0
        /// <summary>
        /// Uses the Simpson formula to calculate the approximate integral area
        /// on the interval using an even number of points.
        /// </summary>
        /// <typeparam name="T">The type of function argument/value.</typeparam>
        /// <typeparam name="C">The calculator for function argument.</typeparam>
        /// <param name="obj">The calling function object.</param>
        /// <param name="interval">The interval on which the integral should be approximated. No matter if bounds are exclusive, they ARE COUNTED AS INCLUSIVE.</param>
        /// <param name="pointCount">The number of points that should be used to calculate the method.</param>
        /// <returns>The approximate value of the integral calculated by Simpson method.</returns>
        public static T IntegralSimpsonMethod <T, C>(this IFunction <T, T> obj, BoundedInterval <T, C> interval, int pointCount) where C : ICalc <T>, new()
        {
            if (pointCount % 2 > 0)
            {
                throw new ArgumentException("The number of points for this function should be even.");
            }
            else if (pointCount < 4)
            {
                throw new ArgumentException("The number of points is too low for this method. It should be >= 4.");
            }

            Point <T>[] table = obj.GetFunctionTable(interval, pointCount);

            Numeric <T, C> sum1 = table[1].Y;
            Numeric <T, C> sum2 = table[2].Y;

            for (int i = 2; i <= pointCount - 2; i += 2)
            {
                sum1 += table[i].Y;
                sum2 += table[i + 1].Y;
            }

            Numeric <T, C> result = (Numeric <T, C> .Calculator.sum(table[0].Y, table[table.Length - 1].Y) + (Numeric <T, C>) 2 * sum2 + (Numeric <T, C>) 4 * sum1) * (interval.RightBound - interval.LeftBound) / (Numeric <T, C>)(3 * pointCount);

            return(result);
        }
Esempio n. 2
0
        /// <summary>
        /// Returns the maximum error for the Simpson integral approximation method
        /// depending on the interval on which the calculation is performed,
        /// the maximum absolute value of the function's fourth derivative and the point count (should be even).
        /// </summary>
        /// <typeparam name="T">The type of function argument/value.</typeparam>
        /// <typeparam name="C">The calculator for the function argument.</typeparam>
        /// <param name="obj">The calling function object. Is not actually used.</param>
        /// <param name="interval">The interval on which the calculation is performed. No matter if bounds are exclusive, they are considered INCLUSIVE.</param>
        /// <param name="pointCount">The point count on the interval.</param>
        /// <param name="maxFourthDerivative">The maximum absolute value of the function's fourth derivative.</param>
        /// <returns>The maximum error of the simpson method.</returns>
        public static T IntegralSimpsonMethodError <T, C>(this IFunction <T, T> obj, BoundedInterval <T, C> interval, int pointCount, T maxFourthDerivative) where C : ICalc <T>, new()
        {
            Numeric <T, C> big     = (Numeric <T, C>) 2880;
            Numeric <T, C> hFourth = WhiteMath <T, C> .PowerInteger((interval.RightBound - interval.LeftBound) / (Numeric <T, C>)(pointCount / 2), 4);

            return((interval.RightBound - interval.LeftBound) * hFourth * maxFourthDerivative / big);
        }
Esempio n. 3
0
        /// <summary>
        /// The constructor designed to create a pseudo-random LongExp
        /// number, using an integer amount of decimal digits specified by the user.
        /// </summary>
        /// <param name="powerInterval">An interval in which the exponent of the number can be presented.</param>
        /// <param name="generator">A random generator for the digits.</param>
        /// <param name="digitCount">The digit length of the number. Cannot be more than specified by IPrecision precision class.</param>
        public LongExp(int digitCount, BoundedInterval <int, CalcInt> powerInterval, Random generator)
        {
            this.Negative = (generator.Next(0, 2) == 0 ? false : true);

            // Randomize the explonent
            // -
            this.Exponent = generator.Next((powerInterval.IsLeftInclusive ? powerInterval.LeftBound : powerInterval.LeftBound + 1), (powerInterval.IsRightInclusive ? powerInterval.RightBound + 1 : powerInterval.RightBound));

            // Now to the mantiss.
            // -
            this.Mantiss = new List <int>(digitCount);
            this.Mantiss.Add(generator.Next(1, BASE));

            // ...Because the first digit should be significant.

            int i = 1;

            for ( ; i < digitCount - 1; i++)
            {
                this.Mantiss.Add(generator.Next(0, BASE));
            }

            if (i < digitCount)
            {
                this.Mantiss.Add(generator.Next(1, BASE));
            }
        }
Esempio n. 4
0
        // -------------------------
        // ------ checker-----------
        // -------------------------

        /// <summary>
        /// Checks that intervals do not intersect.
        /// </summary>
        private void selfCheck()
        {
            HashSet <T> exclusiveLefts  = new HashSet <T>();
            HashSet <T> inclusiveLefts  = new HashSet <T>();
            HashSet <T> exclusiveRights = new HashSet <T>();
            HashSet <T> inclusiveRights = new HashSet <T>();

            ArgumentException ex = new ArgumentException("The intervals passed to the constructor intersect, but they shouldn't. Please check.");

            for (int i = 0; i < this.pieces.Length; i++)
            {
                BoundedInterval <T, C> interval = this.pieces[i].Key;

                if (!interval.IsLeftInclusive && exclusiveLefts.Contains(interval.LeftBound))
                {
                    throw ex;
                }
                else
                {
                    exclusiveLefts.Add(interval.LeftBound);
                }

                if (interval.IsLeftInclusive && inclusiveLefts.Contains(interval.LeftBound))
                {
                    throw ex;
                }
                else
                {
                    inclusiveLefts.Add(interval.LeftBound);
                }

                if (!interval.IsRightInclusive && exclusiveRights.Contains(interval.RightBound))
                {
                    throw ex;
                }
                else
                {
                    inclusiveLefts.Add(interval.LeftBound);
                }

                if (interval.IsRightInclusive && inclusiveRights.Contains(interval.RightBound))
                {
                    throw ex;
                }
                else
                {
                    inclusiveLefts.Add(interval.LeftBound);
                }

                // проверяем на пересечение, чтобы включающие границы не пересекались

                if (inclusiveLefts.Intersect(inclusiveRights).Count() > 0)
                {
                    throw ex;
                }
            }
        }
Esempio n. 5
0
        /// <summary>
        /// Returns the amount of hits registered for
        /// the specified interval.
        /// </summary>
        /// <param name="interval">The interval to test for amount of hits.</param>
        /// <returns>
        /// A non-negative amount of hits if the <c>Equals()</c>-equivalent interval
        /// is registered in the tester; a negative value otherwise.</returns>
        public int HitCount(BoundedInterval <T, C> interval)
        {
            int index = this.intervalList.WhiteBinarySearch(interval, BoundedInterval <T, C> .IntervalComparisons.LeftBoundComparison.CreateComparer());

            Contract.Assume(index >= 0 && index < this.intervalHits.Count && index < this.intervalList.Count);

            if (this.intervalList[index].Equals(interval))
            {
                return(this.intervalHits[index]);
            }

            return(-1);
        }
Esempio n. 6
0
        /// <summary>
        /// Creates the function table on a certain interval with a specified amount of table points.
        /// </summary>
        /// <typeparam name="T">The type of function argument and value.</typeparam>
        /// <typeparam name="C">The calculator for the function argument/value type.</typeparam>
        /// <param name="obj">The calling function object.</param>
        /// <param name="interval">The interval on which the table is created. Warning! Both of the interval bounds are counted INCLUSIVE!</param>
        /// <param name="pointCount">The overall point count of the function table</param>
        /// <returns>The function table in the format of point array.</returns>
        public static Point <T>[] GetFunctionTable <T, C>(this IFunction <T, T> obj, BoundedInterval <T, C> interval, int pointCount) where C : ICalc <T>, new()
        {
            Point <T>[] arr = new Point <T> [pointCount];

            Numeric <T, C> current;

            for (int i = 0; i < pointCount; i++)
            {
                current = interval.LeftBound + (interval.RightBound - interval.LeftBound) * (Numeric <T, C>)i / (Numeric <T, C>)(pointCount - 1);
                arr[i]  = new Point <T>(current, obj.Value(current));
            }

            return(arr);
        }
Esempio n. 7
0
        /// <summary>
        /// Creates a continuous piece-linear function from the points list.
        /// The user should also specify a default value to return
        /// when the function argument is out of the interpolation area bounds.
        /// </summary>
        /// <param name="points"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static PieceFunction <T, C> CreatePieceLinearFunction(IList <Point <T> > points, T defaultValue)
        {
            BoundedInterval <T, C>[] intervals = new BoundedInterval <T, C> [points.Count - 1];
            IFunction <T, T>[]       functions = new IFunction <T, T> [points.Count - 1];

            for (int i = 0; i < points.Count - 1; i++)
            {
                intervals[i] = new BoundedInterval <T, C>(points[i].X, points[i + 1].X, true, false);
                functions[i] = new LinearFunction <T, C>(points[i], points[i + 1]);
            }

            PieceFunction <T, C> fun = new PieceFunction <T, C>(intervals, functions, defaultValue);

            fun.Type = PieceFunctionType.PieceLinearFunction;

            return(fun);
        }
Esempio n. 8
0
        /// <summary>
        /// Returns the value of the piece function.
        /// Searches through the intervals mapping to the functions,
        /// when the argument is within the interval, the value of the
        /// respective function is returned.
        /// </summary>
        /// <param name="x">The argument of the function.</param>
        /// <returns>The value of the piece function in the specified point.</returns>
        public T Value(T x)
        {
            int index = Array.BinarySearch(intervalLefts, x);

            if (index < 0)
            {
                index = ~index;

                if (index > intervalLefts.Length || index == 0)
                {
                    return(this.defaultValue);
                }
                else
                {
                    index--;
                }
            }

            BoundedInterval <T, C> needed = pieces[index].Key;

            if (needed.Contains(x))
            {
                return(pieces[index].Value.Value(x));
            }

            // граничный случай - попали в исключенную границу интервала. Ищем [3; 3], а попали в needed на (3; 6].
            // надо поискать в прошлом интервале.

            else if (index > 0 && pieces[index - 1].Key.Contains(x))
            {
                return(pieces[index - 1].Value.Value(x));
            }

            // если нет - ничего не поделаешь.

            else
            {
                return(this.defaultValue);
            }
        }
Esempio n. 9
0
        /// <summary>
        /// Searches for the function maximum/minimum. using the ternary search method.
        ///
        /// Conditions:
        /// 1a. If one searches for the maximum, f(x) should be STRICTLY increasing before the maximum and STRICTLY decreasing after the maximum.
        /// 1b. If one searches for the minimum, f(x) should be STRICTLY decreasing before the minimum and STRICTLY increasing after the minimum.
        /// 1*. Only one maximum/minimum should exist on the interval.
        /// </summary>
        /// <typeparam name="T">The type of function argument/value.</typeparam>
        /// <typeparam name="C">The calculator for the function argument.</typeparam>
        /// <param name="obj">The calling function object.</param>
        /// <param name="interval">The interval on which the maximum lies.</param>
        /// <param name="absolutePrecision">The desired precision of the argument value.</param>
        /// <param name="what">What to search for, maximum or minimum. Should be of 'SearchFor' enum type.</param>
        /// <returns>The 'x0' value such that f(x0) ~= max f(x) on the interval.</returns>
        public static T MaximumSearchTernaryMethod <T, C>(this IFunction <T, T> obj, BoundedInterval <T, C> interval, T absolutePrecision, SearchFor what) where C : ICalc <T>, new()
        {
            Numeric <T, C> left  = interval.LeftBound;
            Numeric <T, C> right = interval.RightBound;

            Numeric <T, C> leftThird;
            Numeric <T, C> rightThird;

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

            Numeric <T, C> funcValLT, funcValRT;

            ICalc <T>         calc = Numeric <T, C> .Calculator;
            Func <T, T, bool> test = (what == SearchFor.Maximum ? (Func <T, T, bool>) delegate(T a, T b) { return(calc.mor(b, a)); } : calc.mor);

            while (true)
            {
                if (right - left < absolutePrecision)
                {
                    return((left + right) / two);
                }

                leftThird  = (left * two + right) / three;
                rightThird = (left + two * right) / three;

                funcValLT = obj.Value(leftThird);
                funcValRT = obj.Value(rightThird);

                if (test(funcValLT, funcValRT))
                {
                    left = leftThird;
                }
                else
                {
                    right = rightThird;
                }
            }
        }
Esempio n. 10
0
        /// <summary>
        /// TODO: write description
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="C"></typeparam>
        /// <param name="obj"></param>
        /// <param name="interval"></param>
        /// <param name="maxError"></param>
        /// <param name="maxFourthDerivative"></param>
        /// <returns></returns>
        public static T IntegralSimpsonNeededPointCount <T, C>(this IFunction <T, T> obj, BoundedInterval <T, C> interval, T maxError, T maxFourthDerivative) where C : ICalc <T>, new()
        {
            // N^4 степени.
            Numeric <T, C> nFourth = (Numeric <T, C>)maxFourthDerivative * WhiteMath <T, C> .PowerInteger(interval.RightBound - interval.LeftBound, 5) / (maxError * (Numeric <T, C>) 2880);

            // TODO: почему 100 членов в ряде тейлора?
            // надо вычислять точность.

            Numeric <T, C> power = (Numeric <T, C>) 0.25;
            Numeric <T, C> n     = WhiteMath <T, C> .SquareRootHeron(WhiteMath <T, C> .SquareRootHeron(nFourth, maxError), maxError);

            return(Numeric <T, C> ._2 * WhiteMath <T, C> .Ceiling(n));
        }
Esempio n. 11
0
        /// <summary>
        /// Warning! Works correctly only for the MONOTONOUS (on the interval specified) function!
        /// Returns the bounded approximation of monotonous function's Riman 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 approximate the integral value. The more this value is, the more precise is the calculation.</param>
        /// <returns>The interval in which the integral's value lies.</returns>
        public static BoundedInterval <T, C> IntegralRectangleBoundedApproximation <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(new BoundedInterval <T, C>(calc.zero, calc.zero, true, true));
            }

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

            Point <T>[] table = obj.GetFunctionTable <T, C>(interval, pointCount + 1);

            Numeric <T, C> step = calc.dif(table[2].X, table[0].X);

            Numeric <T, C> sumOne = calc.zero;
            Numeric <T, C> sumTwo = calc.zero;

            for (int i = 0; i < pointCount; i++)
            {
                if (i < pointCount - 1)
                {
                    sumOne += table[i].Y;
                }
                if (i > 0)
                {
                    sumTwo += table[i].Y;
                }
            }

            Numeric <T, C> res1 = sumOne * step;
            Numeric <T, C> res2 = sumTwo * step;

            return(new BoundedInterval <T, C>(WhiteMath <T, C> .Min(res1, res2), WhiteMath <T, C> .Max(res1, res2), true, true));
        }
Esempio n. 12
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);
        }
Esempio n. 13
0
        // --------------------------------------------
        // --------- ЧИСЛЕННОЕ ИНТЕГРИРОВАНИЕ ---------
        // --------------------------------------------

        /// <summary>
        /// Returns the Monte-Carlo stochastic approximation of the function integral.
        ///
        /// Requirements: calculator for the function argument/value should provide
        /// reasonable implementation of the 'fromDouble()' method.
        /// </summary>
        /// <typeparam name="T">The type of the function's argument/value.</typeparam>
        /// <typeparam name="C">The calculator for the function argument.</typeparam>
        /// <param name="obj">The calling function object.</param>
        /// <param name="generator">The uniform distribution (pseudo)random generator.</param>
        /// <param name="interval">The interval on which the integral will be approximated.</param>
        /// <param name="rectangleHeight">The height of the testing rectangle. Should be more than the function's absolute maximum on the interval tested, otherwise the method would return wrong results. On the other side, the difference between the height and the function's absolute maximum should not be very large as it will reduce the accuracy of the method. The ideal case is equality of the max f(x) on [a; b] and the rectangle height.</param>
        /// <param name="throwsCount">A positive integer value of overall tests.</param>
        /// <returns>The value approximating the function integral on the interval specified.</returns>
        public static T IntegralMonteCarloApproximation <T, C>(this IFunction <T, T> obj, IRandomBounded <T> generator, BoundedInterval <T, C> interval, T rectangleHeight, T throwsCount) where C : ICalc <T>, new()
        {
            ICalc <T> calc = Numeric <T, C> .Calculator;

            T         hits = calc.zero; // overall hits.
            Point <T> randomPoint;      // random point.

            if (!calc.mor(throwsCount, calc.zero))
            {
                throw new ArgumentException("The amount of point throws count should be a positive integer value.");
            }

            for (T i = calc.zero; calc.mor(throwsCount, i); i = calc.increment(i))
            {
                randomPoint = new Point <T>(generator.Next(interval.LeftBound, interval.RightBound), generator.Next(calc.zero, rectangleHeight));

                // Если попали под функцию - увеличиваем количество хитов.

                if (!calc.mor(randomPoint.Y, obj.Value(randomPoint.X)))
                {
                    hits = calc.increment(hits);
                }
            }

            T result = calc.div(calc.mul(calc.mul(interval.Length, rectangleHeight), hits), throwsCount);

            return(result);
        }
Esempio n. 14
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));
                }
            }
        }
Esempio n. 15
0
        private void __init(IEnumerable<Color> colorSequence)
        {
            Contract.Assume(colorSequence != null);
            Contract.Assume(colorSequence.Count () > 1);

            int colorCount = colorSequence.Count();

            this.intervals = new BoundedInterval<double,CalcDouble>[colorCount - 1];
            this.colors = colorSequence.ToArray();

            double intervalLength = (double)1 / (colorCount - 1);

            double leftBound;
            double rightBound = 0;

            for (int i = 0; i < colorCount - 2; i++)
            {
                leftBound = rightBound;
                rightBound = (i + 1) * intervalLength;

                this.intervals[i] = new BoundedInterval<double, CalcDouble>(leftBound, rightBound, true, false);
            }

            leftBound = rightBound;
            rightBound = 1;

            this.intervals[colorCount - 2] = new BoundedInterval<double, CalcDouble>(leftBound, rightBound, true, true);
        }