/// <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; }
/// <summary> /// 난수 발생 /// </summary> /// <returns>난수</returns> public override double Next() { if (_haveOne) { //if (IsDebugEnabled) // log.Debug(@"기존에 발급받은 Random 변수가 있으므로, 그 값을 반환합니다. return=" + _rndNumber); _haveOne = !_haveOne; return(_rndNumber); } double r1, r2; double s; do { r1 = 2.0 * RandomNumberFunc() - 1.0; r2 = 2.0 * RandomNumberFunc() - 1.0; s = MathTool.Norm(r1, r2); } while(s > 1.0 || Math.Abs(s - 0.0) < double.Epsilon); s = Math.Sqrt(-2.0 * Math.Log(s) / s); r1 *= s; r2 *= s; _rndNumber = _mean + r1 * _stdev; _haveOne = true; return(_mean + r2 * _stdev); }
/// <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] 구간에 대해, 근을 찾는다 (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); }
/// <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); }
/// <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); }