Vla_DOS

Untitled

Apr 27th, 2022
67
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 15.95 KB | None | 0 0
  1. using System;
  2. namespace lametsy_server.Servises
  3. {
  4.  
  5.     // ReSharper disable once IdentifierTypo
  6.     /// <summary>
  7.     /// Analogy of Syatem.Math class for decimal types
  8.     /// </summary>
  9.     public static class DecimalMath
  10.     {
  11.         /// <summary>
  12.         /// represents PI
  13.         /// </summary>
  14.         public const decimal Pi = 3.14159265358979323846264338327950288419716939937510M;
  15.  
  16.         /// <summary>
  17.         /// represents PI
  18.         /// </summary>
  19.         public const decimal Epsilon = 0.0000000000000000001M;
  20.  
  21.         /// <summary>
  22.         /// represents 2*PI
  23.         /// </summary>
  24.         private const decimal PIx2 = 6.28318530717958647692528676655900576839433879875021M;
  25.  
  26.         /// <summary>
  27.         /// represents E
  28.         /// </summary>
  29.         public const decimal E = 2.7182818284590452353602874713526624977572470936999595749M;
  30.  
  31.         /// <summary>
  32.         /// represents PI/2
  33.         /// </summary>
  34.         private const decimal PIdiv2 = 1.570796326794896619231321691639751442098584699687552910487M;
  35.  
  36.         /// <summary>
  37.         /// represents PI/4
  38.         /// </summary>
  39.         private const decimal PIdiv4 = 0.785398163397448309615660845819875721049292349843776455243M;
  40.  
  41.         /// <summary>
  42.         /// represents 1.0/E
  43.         /// </summary>
  44.         private const decimal Einv = 0.3678794411714423215955237701614608674458111310317678M;
  45.  
  46.         /// <summary>
  47.         /// log(10,E) factor
  48.         /// </summary>
  49.         private const decimal Log10Inv = 0.434294481903251827651128918916605082294397005803666566114M;
  50.  
  51.         /// <summary>
  52.         /// Zero
  53.         /// </summary>
  54.         public const decimal Zero = 0.0M;
  55.  
  56.         /// <summary>
  57.         /// One
  58.         /// </summary>
  59.         public const decimal One = 1.0M;
  60.  
  61.         /// <summary>
  62.         /// Represents 0.5M
  63.         /// </summary>
  64.         private const decimal Half = 0.5M;
  65.  
  66.         /// <summary>
  67.         /// Max iterations count in Taylor series
  68.         /// </summary>
  69.         private const int MaxIteration = 100;
  70.  
  71.         /// <summary>
  72.         /// Analogy of Math.Exp method
  73.         /// </summary>
  74.         /// <param name="x"></param>
  75.         /// <returns></returns>
  76.         public static decimal Exp(decimal x)
  77.         {
  78.             var count = 0;
  79.  
  80.             if (x > One)
  81.             {
  82.                 count = decimal.ToInt32(decimal.Truncate(x));
  83.                 x -= decimal.Truncate(x);
  84.             }
  85.  
  86.             if (x < Zero)
  87.             {
  88.                 count = decimal.ToInt32(decimal.Truncate(x) - 1);
  89.                 x = One + (x - decimal.Truncate(x));
  90.             }
  91.  
  92.             var iteration = 1;
  93.             var result = One;
  94.             var factorial = One;
  95.             decimal cachedResult;
  96.             do
  97.             {
  98.                 cachedResult = result;
  99.                 factorial *= x / iteration++;
  100.                 result += factorial;
  101.             } while (cachedResult != result);
  102.  
  103.             if (count == 0)
  104.                 return result;
  105.             return result * PowerN(E, count);
  106.         }
  107.  
  108.         /// <summary>
  109.         /// Analogy of Math.Pow method
  110.         /// </summary>
  111.         /// <param name="value"></param>
  112.         /// <param name="pow"></param>
  113.         /// <returns></returns>
  114.         public static decimal Power(decimal value, decimal pow)
  115.         {
  116.             if (pow == Zero) return One;
  117.             if (pow == One) return value;
  118.             if (value == One) return One;
  119.  
  120.             if (value == Zero)
  121.             {
  122.                 if (pow > Zero)
  123.                 {
  124.                     return Zero;
  125.                 }
  126.  
  127.                 throw new Exception("Invalid Operation: zero base and negative power");
  128.             }
  129.  
  130.             if (pow == -One) return One / value;
  131.  
  132.             var isPowerInteger = IsInteger(pow);
  133.             if (value < Zero && !isPowerInteger)
  134.             {
  135.                 throw new Exception("Invalid Operation: negative base and non-integer power");
  136.             }
  137.  
  138.             if (isPowerInteger && value > Zero)
  139.             {
  140.                 int powerInt = (int)pow;
  141.                 return PowerN(value, powerInt);
  142.             }
  143.  
  144.             if (isPowerInteger && value < Zero)
  145.             {
  146.                 int powerInt = (int)pow;
  147.                 if (powerInt % 2 == 0)
  148.                 {
  149.                     return Exp(pow * Log(-value));
  150.                 }
  151.  
  152.                 return -Exp(pow * Log(-value));
  153.             }
  154.  
  155.             return Exp(pow * Log(value));
  156.         }
  157.  
  158.         private static bool IsInteger(decimal value)
  159.         {
  160.             var longValue = (long)value;
  161.             return Abs(value - longValue) <= Epsilon;
  162.         }
  163.  
  164.         /// <summary>
  165.         /// Power to the integer value
  166.         /// </summary>
  167.         /// <param name="value"></param>
  168.         /// <param name="power"></param>
  169.         /// <returns></returns>
  170.         public static decimal PowerN(decimal value, int power)
  171.         {
  172.             while (true)
  173.             {
  174.                 if (power == Zero) return One;
  175.                 if (power < Zero)
  176.                 {
  177.                     value = One / value;
  178.                     power = -power;
  179.                     continue;
  180.                 }
  181.  
  182.                 var q = power;
  183.                 var prod = One;
  184.                 var current = value;
  185.                 while (q > 0)
  186.                 {
  187.                     if (q % 2 == 1)
  188.                     {
  189.                         // detects the 1s in the binary expression of power
  190.                         prod = current * prod; // picks up the relevant power
  191.                         q--;
  192.                     }
  193.  
  194.                     current *= current; // value^i -> value^(2*i)
  195.                     q >>= 1;
  196.                 }
  197.  
  198.                 return prod;
  199.             }
  200.         }
  201.  
  202.         /// <summary>
  203.         /// Analogy of Math.Log10
  204.         /// </summary>
  205.         /// <param name="x"></param>
  206.         /// <returns></returns>
  207.         public static decimal Log10(decimal x)
  208.         {
  209.             return Log(x) * Log10Inv;
  210.         }
  211.  
  212.         /// <summary>
  213.         /// Analogy of Math.Log
  214.         /// </summary>
  215.         /// <param name="x"></param>
  216.         /// <returns></returns>
  217.         public static decimal Log(decimal x)
  218.         {
  219.             if (x <= Zero)
  220.             {
  221.                 throw new ArgumentException("x must be greater than zero");
  222.             }
  223.             var count = 0;
  224.             while (x >= One)
  225.             {
  226.                 x *= Einv;
  227.                 count++;
  228.             }
  229.             while (x <= Einv)
  230.             {
  231.                 x *= E;
  232.                 count--;
  233.             }
  234.             x--;
  235.             if (x == Zero) return count;
  236.             var result = Zero;
  237.             var iteration = 0;
  238.             var y = One;
  239.             var cacheResult = result - One;
  240.             while (cacheResult != result && iteration < MaxIteration)
  241.             {
  242.                 iteration++;
  243.                 cacheResult = result;
  244.                 y *= -x;
  245.                 result += y / iteration;
  246.             }
  247.             return count - result;
  248.         }
  249.  
  250.         /// <summary>
  251.         /// Analogy of Math.Cos
  252.         /// </summary>
  253.         /// <param name="x"></param>
  254.         /// <returns></returns>
  255.         public static decimal Cos(decimal x)
  256.         {
  257.             //truncating to  [-2*PI;2*PI]
  258.             TruncateToPeriodicInterval(ref x);
  259.  
  260.             // now x in (-2pi,2pi)
  261.             if (x >= Pi && x <= PIx2)
  262.             {
  263.                 return -Cos(x - Pi);
  264.             }
  265.             if (x >= -PIx2 && x <= -Pi)
  266.             {
  267.                 return -Cos(x + Pi);
  268.             }
  269.  
  270.             x *= x;
  271.             //y=1-x/2!+x^2/4!-x^3/6!...
  272.             var xx = -x * Half;
  273.             var y = One + xx;
  274.             var cachedY = y - One;//init cache  with different value
  275.             for (var i = 1; cachedY != y && i < MaxIteration; i++)
  276.             {
  277.                 cachedY = y;
  278.                 decimal factor = i * ((i << 1) + 3) + 1; //2i^2+2i+i+1=2i^2+3i+1
  279.                 factor = -Half / factor;
  280.                 xx *= x * factor;
  281.                 y += xx;
  282.             }
  283.             return y;
  284.         }
  285.  
  286.         /// <summary>
  287.         /// Analogy of Math.Tan
  288.         /// </summary>
  289.         /// <param name="x"></param>
  290.         /// <returns></returns>
  291.         public static decimal Tan(decimal x)
  292.         {
  293.             var cos = Cos(x);
  294.             if (cos == Zero) throw new ArgumentException(nameof(x));
  295.             //calculate sin using cos
  296.             var sin = CalculateSinFromCos(x, cos);
  297.             return sin / cos;
  298.         }
  299.         /// <summary>
  300.         /// Helper function for calculating sin(x) from cos(x)
  301.         /// </summary>
  302.         /// <param name="x"></param>
  303.         /// <param name="cos"></param>
  304.         /// <returns></returns>
  305.         private static decimal CalculateSinFromCos(decimal x, decimal cos)
  306.         {
  307.             var moduleOfSin = Sqrt(One - (cos * cos));
  308.             var sineIsPositive = IsSignOfSinePositive(x);
  309.             if (sineIsPositive) return moduleOfSin;
  310.             return -moduleOfSin;
  311.         }
  312.         /// <summary>
  313.         /// Analogy of Math.Sin
  314.         /// </summary>
  315.         /// <param name="x"></param>
  316.         /// <returns></returns>
  317.         public static decimal Sin(decimal x)
  318.         {
  319.             var cos = Cos(x);
  320.             return CalculateSinFromCos(x, cos);
  321.         }
  322.  
  323.  
  324.         /// <summary>
  325.         /// Truncates to  [-2*PI;2*PI]
  326.         /// </summary>
  327.         /// <param name="x"></param>
  328.         private static void TruncateToPeriodicInterval(ref decimal x)
  329.         {
  330.             while (x >= PIx2)
  331.             {
  332.                 var divide = Math.Abs(decimal.ToInt32(x / PIx2));
  333.                 x -= divide * PIx2;
  334.             }
  335.  
  336.             while (x <= -PIx2)
  337.             {
  338.                 var divide = Math.Abs(decimal.ToInt32(x / PIx2));
  339.                 x += divide * PIx2;
  340.             }
  341.         }
  342.  
  343.  
  344.         private static bool IsSignOfSinePositive(decimal x)
  345.         {
  346.             //truncating to  [-2*PI;2*PI]
  347.             TruncateToPeriodicInterval(ref x);
  348.  
  349.             //now x in [-2*PI;2*PI]
  350.             if (x >= -PIx2 && x <= -Pi) return true;
  351.             if (x >= -Pi && x <= Zero) return false;
  352.             if (x >= Zero && x <= Pi) return true;
  353.             if (x >= Pi && x <= PIx2) return false;
  354.  
  355.             //will not be reached
  356.             throw new ArgumentException(nameof(x));
  357.         }
  358.  
  359.         /// <summary>
  360.         /// Analogy of Math.Sqrt
  361.         /// </summary>
  362.         /// <param name="x"></param>
  363.         /// <param name="epsilon">lasts iteration while error less than this epsilon</param>
  364.         /// <returns></returns>
  365.         public static decimal Sqrt(decimal x, decimal epsilon = Zero)
  366.         {
  367.             if (x < Zero) throw new OverflowException("Cannot calculate square root from a negative number");
  368.             //initial approximation
  369.             decimal current = (decimal)Math.Sqrt((double)x), previous;
  370.             do
  371.             {
  372.                 previous = current;
  373.                 if (previous == Zero) return Zero;
  374.                 current = (previous + x / previous) * Half;
  375.             } while (Abs(previous - current) > epsilon);
  376.             return current;
  377.         }
  378.         /// <summary>
  379.         /// Analogy of Math.Sinh
  380.         /// </summary>
  381.         /// <param name="x"></param>
  382.         /// <returns></returns>
  383.         public static decimal Sinh(decimal x)
  384.         {
  385.             var y = Exp(x);
  386.             var yy = One / y;
  387.             return (y - yy) * Half;
  388.         }
  389.  
  390.         /// <summary>
  391.         /// Analogy of Math.Cosh
  392.         /// </summary>
  393.         /// <param name="x"></param>
  394.         /// <returns></returns>
  395.         public static decimal Cosh(decimal x)
  396.         {
  397.             var y = Exp(x);
  398.             var yy = One / y;
  399.             return (y + yy) * Half;
  400.         }
  401.  
  402.         /// <summary>
  403.         /// Analogy of Math.Sign
  404.         /// </summary>
  405.         /// <param name="x"></param>
  406.         /// <returns></returns>
  407.         public static int Sign(decimal x)
  408.         {
  409.             return x < Zero ? -1 : (x > Zero ? 1 : 0);
  410.         }
  411.  
  412.         /// <summary>
  413.         /// Analogy of Math.Tanh
  414.         /// </summary>
  415.         /// <param name="x"></param>
  416.         /// <returns></returns>
  417.         public static decimal Tanh(decimal x)
  418.         {
  419.             var y = Exp(x);
  420.             var yy = One / y;
  421.             return (y - yy) / (y + yy);
  422.         }
  423.  
  424.         /// <summary>
  425.         /// Analogy of Math.Abs
  426.         /// </summary>
  427.         /// <param name="x"></param>
  428.         /// <returns></returns>
  429.         public static decimal Abs(decimal x)
  430.         {
  431.             if (x <= Zero)
  432.             {
  433.                 return -x;
  434.             }
  435.             return x;
  436.         }
  437.  
  438.         /// <summary>
  439.         /// Analogy of Math.Asin
  440.         /// </summary>
  441.         /// <param name="x"></param>
  442.         /// <returns></returns>
  443.         public static decimal Asin(decimal x)
  444.         {
  445.             if (x > One || x < -One)
  446.             {
  447.                 throw new ArgumentException("x must be in [-1,1]");
  448.             }
  449.             //known values
  450.             if (x == Zero) return Zero;
  451.             if (x == One) return PIdiv2;
  452.             //asin function is odd function
  453.             if (x < Zero) return -Asin(-x);
  454.  
  455.             //my optimize trick here
  456.  
  457.             // used a math formula to speed up :
  458.             // asin(x)=0.5*(pi/2-asin(1-2*x*x))
  459.             // if x>=0 is true
  460.  
  461.             var newX = One - 2 * x * x;
  462.  
  463.             //for calculating new value near to zero than current
  464.             //because we gain more speed with values near to zero
  465.             if (Abs(x) > Abs(newX))
  466.             {
  467.                 var t = Asin(newX);
  468.                 return Half * (PIdiv2 - t);
  469.             }
  470.             var y = Zero;
  471.             var result = x;
  472.             decimal cachedResult;
  473.             var i = 1;
  474.             y += result;
  475.             var xx = x * x;
  476.             do
  477.             {
  478.                 cachedResult = result;
  479.                 result *= xx * (One - Half / (i));
  480.                 y += result / ((i << 1) + 1);
  481.                 i++;
  482.             } while (cachedResult != result);
  483.             return y;
  484.         }
  485.  
  486.         /// <summary>
  487.         /// Analogy of Math.Atan
  488.         /// </summary>
  489.         /// <param name="x"></param>
  490.         /// <returns></returns>
  491.         public static decimal ATan(decimal x)
  492.         {
  493.             if (x == Zero) return Zero;
  494.             if (x == One) return PIdiv4;
  495.             return Asin(x / Sqrt(One + x * x));
  496.         }
  497.         /// <summary>
  498.         /// Analogy of Math.Acos
  499.         /// </summary>
  500.         /// <param name="x"></param>
  501.         /// <returns></returns>
  502.         public static decimal Acos(decimal x)
  503.         {
  504.             if (x == Zero) return PIdiv2;
  505.             if (x == One) return Zero;
  506.             if (x < Zero) return Pi - Acos(-x);
  507.             return PIdiv2 - Asin(x);
  508.         }
  509.  
  510.         /// <summary>
  511.         /// Analogy of Math.Atan2
  512.         /// for more see this
  513.         /// <seealso cref="http://i.imgur.com/TRLjs8R.png"/>
  514.         /// </summary>
  515.         /// <param name="y"></param>
  516.         /// <param name="x"></param>
  517.         /// <returns></returns>
  518.         public static decimal Atan2(decimal y, decimal x)
  519.         {
  520.             if (x > Zero)
  521.             {
  522.                 return ATan(y / x);
  523.             }
  524.             if (x < Zero && y >= Zero)
  525.             {
  526.                 return ATan(y / x) + Pi;
  527.             }
  528.             if (x < Zero && y < Zero)
  529.             {
  530.                 return ATan(y / x) - Pi;
  531.             }
  532.             if (x == Zero && y > Zero)
  533.             {
  534.                 return PIdiv2;
  535.             }
  536.             if (x == Zero && y < Zero)
  537.             {
  538.                 return -PIdiv2;
  539.             }
  540.             throw new ArgumentException("invalid atan2 arguments");
  541.         }
  542.     }
  543. }
  544.  
Advertisement
Add Comment
Please, Sign In to add comment