// ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== /*============================================================ ** ** Class: Math ** ** ** Purpose: Some floating-point math operations ** ** Date: July 8, 1998 ** ===========================================================*/ namespace System { using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; //| [CCtorIsRunDuringStartup] public sealed class Math { // Prevent from begin created private Math() {} //| public const double PI = 3.14159265358979323846; //| public const double E = 2.7182818284590452354; //| [MethodImpl(MethodImplOptions.InternalCall)] [GCAnnotation(GCOption.NOGC)] [StackBound(128)] [AccessedByRuntime("output to header : defined in Math.cpp")] public static extern double Acos(double d); //| [MethodImpl(MethodImplOptions.InternalCall)] [GCAnnotation(GCOption.NOGC)] [StackBound(128)] [AccessedByRuntime("output to header : defined in Math.cpp")] public static extern double Asin(double d); //| [MethodImpl(MethodImplOptions.InternalCall)] [GCAnnotation(GCOption.NOGC)] [StackBound(128)] [AccessedByRuntime("output to header : defined in Math.cpp")] public static extern double Atan(double d); //| [MethodImpl(MethodImplOptions.InternalCall)] [GCAnnotation(GCOption.NOGC)] [StackBound(128)] [AccessedByRuntime("output to header : defined in Math.cpp")] public static extern double Atan2(double y, double x); //| [MethodImpl(MethodImplOptions.InternalCall)] [StackBound(128)] [AccessedByRuntime("output to header : defined in Math.cpp")] public static extern double Cos(double d); //| [MethodImpl(MethodImplOptions.InternalCall)] [StackBound(128)] [AccessedByRuntime("output to header : defined in Math.cpp")] public static extern double Sin(double a); //| [MethodImpl(MethodImplOptions.InternalCall)] [GCAnnotation(GCOption.NOGC)] [StackBound(128)] [AccessedByRuntime("output to header : defined in Math.cpp")] public static extern double Tan(double a); //| [MethodImpl(MethodImplOptions.InternalCall)] [GCAnnotation(GCOption.NOGC)] [StackBound(512)] [AccessedByRuntime("output to header : defined in Math.cpp")] public static extern double Cosh(double value); //| [MethodImpl(MethodImplOptions.InternalCall)] [GCAnnotation(GCOption.NOGC)] [StackBound(512)] [AccessedByRuntime("output to header : defined in Math.cpp")] public static extern double Sinh(double value); //| [MethodImpl(MethodImplOptions.InternalCall)] [GCAnnotation(GCOption.NOGC)] [StackBound(256)] [AccessedByRuntime("output to header : defined in Math.cpp")] public static extern double Tanh(double value); //| [MethodImpl(MethodImplOptions.InternalCall)] [GCAnnotation(GCOption.NOGC)] [StackBound(128)] [AccessedByRuntime("output to header : defined in Math.cpp")] public static extern double Round(double a); private static double NegativeZero = BitConverter.UInt64BitsToDouble(0x8000000000000000); private const int maxRoundingDigits = 15; //| public static double Round(double value, int digits) { if ((digits < 0) || (digits > maxRoundingDigits)) { throw new ArgumentOutOfRangeException("ArgumentOutOfRange_RoundingDigits"); } return InternalRound(value,digits); } private static double InternalRound(double d, int digits) { // rusa: see also Lightning\Src\ClassLibNative\Float\COMFloat.cpp::RoundDigits // Managed code ensures that (digits >= 0 && digits <= 15) if (Abs(d) < 1E16) { d *= dblPower10[digits]; // There is a short x86 code sequence for the Round operation // __asm { // fld d; // frndint // fstp d; // } d = Round(d); d /= dblPower10[digits]; } return d; } private static readonly double[] dblPower10 = new double[16] { 1E0, 1E1, 1E2, 1E3, 1E4, 1E5, 1E6, 1E7, 1E8, 1E9, 1E10, 1E11, 1E12, 1E13, 1E14, 1E15 }; //| public static Decimal Round(Decimal d) { return Decimal.Round(d,0); } //| public static Decimal Round(Decimal d, int decimals) { return Decimal.Round(d,decimals); } //| [MethodImpl(MethodImplOptions.InternalCall)] [GCAnnotation(GCOption.NOGC)] [StackBound(128)] [AccessedByRuntime("output to header : defined in Math.cpp")] public static extern double Ceiling(double a); //| [MethodImpl(MethodImplOptions.InternalCall)] [GCAnnotation(GCOption.NOGC)] [StackBound(128)] [AccessedByRuntime("output to header : defined in Math.cpp")] public static extern double Floor(double d); //| [MethodImpl(MethodImplOptions.InternalCall)] [StackBound(128)] [AccessedByRuntime("output to header : defined in Math.cpp")] public static extern double Sqrt(double d); //| [MethodImpl(MethodImplOptions.InternalCall)] [GCAnnotation(GCOption.NOGC)] [StackBound(128)] [AccessedByRuntime("output to header : defined in Math.cpp")] public static extern double Log(double d); //| [MethodImpl(MethodImplOptions.InternalCall)] [GCAnnotation(GCOption.NOGC)] [StackBound(128)] [AccessedByRuntime("output to header : defined in Math.cpp")] public static extern double Log10(double d); //| [MethodImpl(MethodImplOptions.InternalCall)] [GCAnnotation(GCOption.NOGC)] [StackBound(128)] [AccessedByRuntime("output to header : defined in Math.cpp")] public static extern double Exp(double d); //| [MethodImpl(MethodImplOptions.InternalCall)] [GCAnnotation(GCOption.NOGC)] [StackBound(128)] [AccessedByRuntime("output to header : defined in Math.cpp")] public static extern double Pow(double x, double y); //| [MethodImpl(MethodImplOptions.InternalCall)] [GCAnnotation(GCOption.NOGC)] [StackBound(128)] [AccessedByRuntime("output to header : defined in Math.cpp")] public static extern double Mod(double x, double y); //| [GCAnnotation(GCOption.NOGC)] public static double IEEERemainder(double x, double y) { double val = (x - (y * (Math.Round(x / y)))); if (val == 0) { if (x < 0) { return NegativeZero; // this can be turned into a static if people like } } return val; } /*================================Abs========================================= **Returns the absolute value of its argument. ============================================================================*/ //| [CLSCompliant(false)] public static sbyte Abs(sbyte value) { if (value >= 0) { return value; } else { return AbsHelper(value); } } private static sbyte AbsHelper(sbyte value) { if (value < 0) { if (value == SByte.MinValue) { throw new OverflowException("Overflow_NegateTwosCompNum"); } return ((sbyte)(-value)); } return value; } //| public static short Abs(short value) { if (value >= 0) { return value; } else { return AbsHelper(value); } } private static short AbsHelper(short value) { if (value < 0) { if (value == Int16.MinValue) { throw new OverflowException("Overflow_NegateTwosCompNum"); } return (short) -value; } return value; } //| public static int Abs(int value) { if (value >= 0) { return value; } else { return AbsHelper(value); } } private static int AbsHelper(int value) { if (value < 0) { if (value == Int32.MinValue) { throw new OverflowException("Overflow_NegateTwosCompNum"); } return -value; } return value; } //| public static long Abs(long value) { if (value >= 0) { return value; } else { return AbsHelper(value); } } private static long AbsHelper(long value) { if (value < 0) { if (value == Int64.MinValue) { throw new OverflowException("Overflow_NegateTwosCompNum"); } return -value; } return value; } //| [Intrinsic] extern public static float Abs(float value); // This is special code to handle NaN (We need to make sure NaN's aren't // negated). In Cool, the else clause here should always be taken if // value is NaN, since the normal case is taken if and only if value < 0. // To illustrate this completely, a compiler has translated this into: // "load value; load 0; bge; ret -value ; ret value". // The bge command branches for comparisons with the unordered NaN. So // it runs the else case, which returns +value instead of negating it. // return (value < 0) ? -value : value; //| [MethodImpl(MethodImplOptions.InternalCall)] [StackBound(128)] [AccessedByRuntime("output to header : defined in Math.cpp")] extern public static double Abs(double value); // This is special code to handle NaN (We need to make sure NaN's aren't // negated). In Cool, the else clause here should always be taken if // value is NaN, since the normal case is taken if and only if value < 0. // To illustrate this completely, a compiler has translated this into: // "load value; load 0; bge; ret -value ; ret value". // The bge command branches for comparisons with the unordered NaN. So // it runs the else case, which returns +value instead of negating it. // return (value < 0) ? -value : value; //| public static Decimal Abs(Decimal value) { return Decimal.Abs(value); } /*================================MAX========================================= **Returns the larger of val1 and val2 ============================================================================*/ //| [CLSCompliant(false)] public static sbyte Max(sbyte val1, sbyte val2) { return (val1 >= val2) ? val1 : val2; } //| public static byte Max(byte val1, byte val2) { return (val1 >= val2) ? val1 : val2; } //| public static short Max(short val1, short val2) { return (val1 >= val2) ? val1 : val2; } //| [CLSCompliant(false)] public static ushort Max(ushort val1, ushort val2) { return (val1 >= val2) ? val1 : val2; } //| public static int Max(int val1, int val2) { return (val1 >= val2) ? val1 : val2; } //| [CLSCompliant(false)] public static uint Max(uint val1, uint val2) { return (val1 >= val2) ? val1 : val2; } //| public static long Max(long val1, long val2) { return (val1 >= val2) ? val1 : val2; } //| [CLSCompliant(false)] public static ulong Max(ulong val1, ulong val2) { return (val1 >= val2) ? val1 : val2; } //| public static float Max(float val1, float val2) { if (val1 > val2) { return val1; } if (Single.IsNaN(val1)) { return val1; } return val2; } //| public static double Max(double val1, double val2) { if (val1 > val2) { return val1; } if (Double.IsNaN(val1)) { return val1; } return val2; } //| public static Decimal Max(Decimal val1, Decimal val2) { return Decimal.Max(val1, val2); } /*================================MIN========================================= **Returns the smaller of val1 and val2. ============================================================================*/ //| [CLSCompliant(false)] public static sbyte Min(sbyte val1, sbyte val2) { return (val1 <= val2) ? val1 : val2; } //| public static byte Min(byte val1, byte val2) { return (val1 <= val2) ? val1 : val2; } //| public static short Min(short val1, short val2) { return (val1 <= val2) ? val1 : val2; } //| [CLSCompliant(false)] public static ushort Min(ushort val1, ushort val2) { return (val1 <= val2) ? val1 : val2; } //| public static int Min(int val1, int val2) { return (val1 <= val2) ? val1 : val2; } //| [CLSCompliant(false)] public static uint Min(uint val1, uint val2) { return (val1 <= val2) ? val1 : val2; } //| public static long Min(long val1, long val2) { return (val1 <= val2) ? val1 : val2; } //| [CLSCompliant(false)] public static ulong Min(ulong val1, ulong val2) { return (val1 <= val2) ? val1 : val2; } //| public static float Min(float val1, float val2) { if (val1 < val2) { return val1; } if (Single.IsNaN(val1)) { return val1; } return val2; } //| public static double Min(double val1, double val2) { if (val1 < val2) { return val1; } if (Double.IsNaN(val1)) { return val1; } return val2; } //| public static Decimal Min(Decimal val1, Decimal val2) { return Decimal.Min(val1, val2); } /*=====================================Log====================================== ** ==============================================================================*/ //| public static double Log(double a, double newBase) { return (Log(a) / Log(newBase)); } // Sign function for VB. Returns -1, 0, or 1 if the sign of the number // is negative, 0, or positive. Throws for floating point NaN's. //| [CLSCompliant(false)] public static int Sign(sbyte value) { if (value < 0) { return -1; } else if (value > 0) { return 1; } else { return 0; } } // Sign function for VB. Returns -1, 0, or 1 if the sign of the number // is negative, 0, or positive. Throws for floating point NaN's. //| public static int Sign(short value) { if (value < 0) { return -1; } else if (value > 0) { return 1; } else { return 0; } } // Sign function for VB. Returns -1, 0, or 1 if the sign of the number // is negative, 0, or positive. Throws for floating point NaN's. //| public static int Sign(int value) { if (value < 0) { return -1; } else if (value > 0) { return 1; } else { return 0; } } //| public static int Sign(long value) { if (value < 0) { return -1; } else if (value > 0) { return 1; } else { return 0; } } //| public static int Sign(float value) { if (value < 0) { return -1; } else if (value > 0) { return 1; } else if (value == 0) { return 0; } throw new ArithmeticException("Arithmetic_NaN"); } //| public static int Sign(double value) { if (value < 0) { return -1; } else if (value > 0) { return 1; } else if (value == 0) { return 0; } throw new ArithmeticException("Arithmetic_NaN"); } //| public static int Sign(Decimal value) { if (value < 0) { return -1; } else if (value > 0) { return 1; } else { return 0; } } //| public static long BigMul(int a, int b) { return ((long)a) * b; } //| public static int DivRem(int a, int b, out int result) { result = a % b; return a / b; } //| public static long DivRem(long a, long b, out long result) { result = a % b; return a / b; } } }