Ejemplo n.º 1
0
        /// <summary>
        /// 상하한 구간 설정
        /// </summary>
        /// <param name="lower"></param>
        /// <param name="upper"></param>
        /// <param name="m"></param>
        public void SetParameters(double lower, double upper, double m)
        {
            if (IsDebugEnabled)
            {
                log.Debug(@"Set parameters... lower=[{0}], upper=[{1}], m=[{2}]", lower, upper, m);
            }

            Guard.Assert(Math.Abs(lower - upper) > double.Epsilon &&
                         Math.Abs(upper - m) > double.Epsilon &&
                         Math.Abs(m - lower) > double.Epsilon,
                         "Parameter must not be equals. lower=[{0}], upper=[{1}], m=[{2}]", lower, upper, m);

            if (lower > upper)
            {
                MathTool.Swap(ref lower, ref upper);
            }

            Guard.Assert(m > lower && m < upper,
                         "Mode must in range (lower, upper) - 경계포함 안함(Opened). lower=[{0}], upper=[{1}], m=[{2}]",
                         lower, upper, m);

            _lowerBound = lower;
            _upperBound = upper;
            _mode       = m;
            _range      = _upperBound - _lowerBound;
            _modeStd    = (_mode - _lowerBound) / _range;
        }
Ejemplo n.º 2
0
        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="numBins">히스토그램의 막대 수</param>
        /// <param name="minValue">최소 값</param>
        /// <param name="maxValue">최대 값</param>
        public Histogram_Old(int numBins, double minValue, double maxValue)
        {
            if (IsDebugEnabled)
            {
                log.Debug("Histogram을 생성합니다... numBins=[{0}], minValue=[{1}], maxValue=[{2}]", numBins, minValue, maxValue);
            }

            numBins.ShouldBePositive("numBins");
            minValue.ShouldNotBeEquals(maxValue, "minValue");

            Counts = new int[numBins];

            if (minValue > maxValue)
            {
                MathTool.Swap(ref minValue, ref maxValue);
            }

            MakeBinBoundary(numBins, minValue, maxValue);
            CheckBinBoundary(BinBoundaries);
        }
        /// <summary>
        /// y = func(x) 함수의 [lower, upper] 구간에서 f(x)의 최소 값이 되는 x를 구합니다.
        /// </summary>
        /// <param name="func">함수</param>
        /// <param name="lower">구간의 하한</param>
        /// <param name="upper">구간의 상한</param>
        /// <param name="tryCount">시도횟수</param>
        /// <param name="tolerance">허용 오차</param>
        /// <returns>f(x)가 최소값이 되는 x 값, 검색 실패시에는 double.NaN을 반환한다</returns>
        public override double FindMiminum(Func <double, double> @func,
                                           double lower,
                                           double upper,
                                           int tryCount     = MathTool.DefaultTryCount,
                                           double tolerance = MathTool.Epsilon)
        {
            @func.ShouldNotBeNull("func");
            tolerance = Math.Abs(tolerance);

            if (IsDebugEnabled)
            {
                log.Debug("Find root by GoldenSectionMinimumFinder... " +
                          "func=[{0}], lower=[{1}], upper=[{2}], tryCount=[{3}], tolerance=[{4}]",
                          func, lower, upper, tryCount, tolerance);
            }

            if (tryCount < MathTool.DefaultTryCount)
            {
                tryCount = MathTool.DefaultTryCount;
            }

            if (lower > upper)
            {
                MathTool.Swap(ref lower, ref upper);
            }

            var t = GodenRatio * (upper - lower);
            var c = lower + t;
            var d = upper - t;

            var fc = @func(c);
            var fd = @func(d);

            for (var i = 0; i < tryCount; i++)
            {
                if (fc > fd)
                {
                    lower = c;
                    c     = d;
                    fc    = fd;
                    d     = upper - GodenRatio * (upper - lower);

                    if (Math.Abs(d - c) <= tolerance)
                    {
                        return(c);
                    }

                    fd = @func(d);
                }
                else
                {
                    upper = d;
                    d     = c;
                    fd    = fc;
                    c     = lower + GodenRatio * (upper - lower);

                    if (Math.Abs(d - c) <= tolerance)
                    {
                        return(d);
                    }

                    fc = @func(c);
                }
            }

            return(double.NaN);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// 이분법으로 y = func(x) 함수의 [lower, upper] 구간에 대해, 근을 찾는다 (y=0 이되는 x 값)
        /// </summary>
        /// <param name="func">근을 찾을 함수</param>
        /// <param name="lower">근을 찾을 구간의 하한</param>
        /// <param name="upper">근을 찾을 구간의 상한</param>
        /// <param name="tryCount">시도 횟수</param>
        /// <param name="tolerance">근의 오차허용범위</param>
        /// <returns>근에 해당하는 x 값. 해를 못찾으면 <see cref="double.NaN"/>을 반환한다.</returns>
        public override double FindRoot(Func <double, double> func,
                                        double lower,
                                        double upper,
                                        int tryCount     = MathTool.DefaultTryCount,
                                        double tolerance = MathTool.Epsilon)
        {
            func.ShouldNotBeNull("func");
            tolerance = Math.Abs(tolerance);

            if (IsDebugEnabled)
            {
                log.Debug("Bisection을 이용하여, root 값을 찾습니다... func=[{0}], lower=[{1}], upper=[{2}], tryCount=[{3}], tolerance=[{4}]",
                          func, lower, upper, tryCount, tolerance);
            }

            if (lower > upper)
            {
                MathTool.Swap(ref lower, ref upper);
            }

            var fa = func(lower);
            var fb = func(upper);

            if (Math.Abs(fa - RootY) < tolerance)
            {
                return(lower);
            }
            if (Math.Abs(fb - RootY) < tolerance)
            {
                return(upper);
            }

            Guard.Assert(Math.Abs(lower - upper) > tolerance, "상하한이 같은 값을 가지면 근을 구할 수 없습니다.");

            if (tryCount < DefaultTryCount)
            {
                tryCount = DefaultTryCount;
            }

            for (var k = 0; k < tryCount; k++)
            {
                var x = (lower + upper) / 2.0;

                if (Math.Abs(upper - x) < tolerance || Math.Abs(lower - x) < tolerance)
                {
                    return(x);
                }

                var y = func(x);

                if (IsDebugEnabled)
                {
                    log.Debug(@"Find root...  x=[{0}], y=[{1}]", x, y);
                }

                // 해를 만족하던가, upper-lower의 변화가 매우 작던가..
                if (Math.Abs(y - RootY) < tolerance)
                {
                    if (IsDebugEnabled)
                    {
                        log.Debug("Iteration count=[{0}]", k);
                    }

                    return(x);
                }

                if (fa * y > 0)
                {
                    lower = x;
                    fa    = y;
                }
                else
                {
                    upper = x;
                    fb    = y;
                }
            }

            return(double.NaN);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// y = func(x) 함수의 [lower, upper] 구간에 대해, 근을 찾는다 ( func(x) = 0 인 x 값 )
        /// </summary>
        /// <param name="func">근을 찾을 함수</param>
        /// <param name="lower">근을 찾을 구간의 하한</param>
        /// <param name="upper">근을 찾을 구간의 상한</param>
        /// <param name="tryCount">시도 횟수</param>
        /// <param name="tolerance">근의 오차허용범위</param>
        /// <returns>근에 해당하는 x 값. 해를 못찾으면 <see cref="double.NaN"/>을 반환한다.</returns>
        public override double FindRoot(Func <double, double> func,
                                        double lower,
                                        double upper,
                                        int tryCount     = MathTool.DefaultTryCount,
                                        double tolerance = MathTool.Epsilon)
        {
            func.ShouldNotBeNull("func");
            tolerance = Math.Abs(tolerance);

            if (IsDebugEnabled)
            {
                log.Debug(@"Find root by Secant... func=[{0}], lower=[{1}], upper=[{2}], tryCount=[{3}], tolerance=[{4}]",
                          func, lower, upper, tryCount, tolerance);
            }

            if (lower > upper)
            {
                MathTool.Swap(ref lower, ref upper);
            }

            if (Math.Abs(func(lower).Clamp(RootY, tolerance) - RootY) < double.Epsilon)
            {
                return(lower);
            }
            if (Math.Abs(func(upper).Clamp(RootY, tolerance) - RootY) < double.Epsilon)
            {
                return(upper);
            }

            if (tryCount < DefaultTryCount)
            {
                tryCount = DefaultTryCount;
            }

            double root, xt;
            var    y1 = func(lower);
            var    y2 = func(upper);

            if (Math.Abs(y1) < Math.Abs(y2))
            {
                root = lower;
                xt   = upper;

                MathTool.Swap(ref y1, ref y2);
            }
            else
            {
                xt   = lower;
                root = upper;
            }

            for (var i = 0; i < tryCount; i++)
            {
                var dx = (xt - root) * y2 / (y2 - y1);
                xt    = root;
                y1    = y2;
                root += dx;
                y2    = func(root);

                if (IsDebugEnabled)
                {
                    log.Debug(@"Secant root=[{0}]", root);
                }

                if ((Math.Abs(dx - RootY) < double.Epsilon) || (Math.Abs((y2 - y1) - RootY) < double.Epsilon))
                {
                    return(root);
                }
                // if(Math.Abs(Math.Abs(dx).Clamp(RootY, tolerance) - RootY) < double.Epsilon || Math.Abs(Math.Abs(y2 - y1).Clamp(RootY, tolerance) - RootY) < double.Epsilon)
                //		return root;
            }

            return(double.NaN);
        }