using System;
using System.Collections.Generic;
using System.Text;
namespace System
{
///
/// Contains various extensions to .
///
public static class MathExtensions
{
#region Internal things
private const ulong QuadhighestBit = 1UL << 63;
private static int Quadnlz(ulong x)
{
//Future work: might be faster with a huge, explicit nested if tree, or use of an 256-element per-byte array.
int n;
if (x == 0) return (64);
n = 0;
if (x <= 0x00000000FFFFFFFF) { n = n + 32; x = x << 32; }
if (x <= 0x0000FFFFFFFFFFFF) { n = n + 16; x = x << 16; }
if (x <= 0x00FFFFFFFFFFFFFF) { n = n + 8; x = x << 8; }
if (x <= 0x0FFFFFFFFFFFFFFF) { n = n + 4; x = x << 4; }
if (x <= 0x3FFFFFFFFFFFFFFF) { n = n + 2; x = x << 2; }
if (x <= 0x7FFFFFFFFFFFFFFF) { n = n + 1; }
return n;
}
#endregion
///
/// Removes any fractional part of the provided value (rounding down for positive numbers, and rounding up for negative numbers)
///
///
///
public static Quad Truncate(Quad value)
{
if (value.Exponent <= -64)
return Quad.Zero;
else if (value.Exponent >= 0)
return value;
else
{
//clear least significant "-value.exponent" bits that come after the binary point by shifting
return new Quad((value.SignificandBits >> (int)(-value.Exponent)) << (int)(-value.Exponent), value.Exponent);
}
}
///
/// Returns only the fractional part of the provided value. Equivalent to value % 1.
///
///
///
public static Quad Fraction(Quad value)
{
if (value.Exponent >= 0) return Quad.Zero; //no fraction
else if (value.Exponent <= -64) return value; //all fraction (or zero)
else
{
//clear most significant 64+value.exponent bits before the binary point
ulong bits = (value.SignificandBits << (int)(64 + value.Exponent)) >> (int)(64 + value.Exponent);
if (bits == 0) return Quad.Zero; //value is an integer
int shift = Quadnlz(bits); //renormalize
return new Quad((~QuadhighestBit & (bits << shift)) | (QuadhighestBit & value.SignificandBits), value.Exponent - shift);
}
}
///
/// Calculates the log (base 2) of a Quad.
///
///
///
public static double Log2(Quad value)
{
if (value.SignificandBits >= QuadhighestBit) return double.NaN;
if (value.Exponent == long.MinValue) return double.NegativeInfinity; //Log(0)
return Math.Log(value.SignificandBits | QuadhighestBit, 2) + value.Exponent;
}
///
/// Calculates the natural log (base e) of a Quad.
///
///
///
public static double Log(Quad value)
{
if (value.SignificandBits >= QuadhighestBit)
return double.NaN;
if (value.Exponent == long.MinValue)
return double.NegativeInfinity; //Log(0)
return Math.Log(value.SignificandBits | QuadhighestBit) + value.Exponent * 0.69314718055994530941723212145818;
}
///
/// Raise a Quad to a given exponent. Pow returns 1 for x^0 for all x >= 0. An exception is thrown
/// if 0 is raised to a negative exponent (implying division by 0), or if a negative value is raised
/// by a non-integer exponent (yielding an imaginary number).
///
///
///
///
/// Internally, Pow uses Math.Pow. This effectively limits the precision of the output to a double's 53 bits.
public static Quad Pow(Quad value, double exponent)
{
if (value.Exponent == long.MinValue)
{
if (exponent > 0)
return Quad.Zero;
else if (exponent == 0)
return Quad.One;
else
throw new ArgumentOutOfRangeException("Cannot raise 0 to a negative exponent, as this implies division by zero.");
}
if (value.SignificandBits >= QuadhighestBit && exponent % 1 != 0)
throw new ArgumentOutOfRangeException("Cannot raise a negative number to a non-integer exponent, as this yields an imaginary number.");
double resultSignificand = Math.Pow((double)new Quad(value.SignificandBits, -63), exponent);
double resultExponent = (value.Exponent + 63) * exponent; //exponents multiply
resultSignificand *= Math.Pow(2, resultExponent % 1); //push the fractional exponent into the significand
Quad result = (Quad)resultSignificand;
result.Exponent += (long)Math.Truncate(resultExponent);
return result;
}
///
/// Returns the larger of the 2 values.
///
///
///
///
public static Quad Max(Quad qd1, Quad qd2)
{
return qd1 > qd2 ? qd1 : qd2;
}
///
/// Returns the smaller of the 2 values.
///
///
///
///
public static Quad Min(Quad qd1, Quad qd2)
{
return qd1 < qd2 ? qd1 : qd2;
}
///
/// Returns the absolute value of the specified .
///
///
///
public static Quad Abs(Quad qd)
{
return new Quad(qd.SignificandBits & ~QuadhighestBit, qd.Exponent); //clear the sign bit
}
///
/// Returns a value indicating the sign of a half-precision floating-point number.
///
/// A signed number.
///
/// A number indicating the sign of value. Number Description -1 value is less
/// than zero. 0 value is equal to zero. 1 value is greater than zero.
///
/// value is equal to System.Half.NaN.
public static int Sign(Half value)
{
if (value < 0)
{
return -1;
}
else if (value > 0)
{
return 1;
}
else
{
if (value != 0)
{
throw new ArithmeticException("Function does not accept floating point Not-a-Number values.");
}
}
return 0;
}
///
/// Returns the absolute value of a half-precision floating-point number.
///
/// A number in the range System.Half.MinValue ≤ value ≤ System.Half.MaxValue.
/// A half-precision floating-point number, x, such that 0 ≤ x ≤System.Half.MaxValue.
public static Half Abs(Half value)
{
return Half.ToHalf((ushort)(value.value & 0x7fff));
}
///
/// Returns the larger of two half-precision floating-point numbers.
///
/// The first of two half-precision floating-point numbers to compare.
/// The second of two half-precision floating-point numbers to compare.
///
/// Parameter value1 or value2, whichever is larger. If value1, or value2, or both val1
/// and value2 are equal to System.Half.NaN, System.Half.NaN is returned.
///
public static Half Max(Half value1, Half value2)
{
return (value1 < value2) ? value2 : value1;
}
///
/// Returns the smaller of two half-precision floating-point numbers.
///
/// The first of two half-precision floating-point numbers to compare.
/// The second of two half-precision floating-point numbers to compare.
///
/// Parameter value1 or value2, whichever is smaller. If value1, or value2, or both val1
/// and value2 are equal to System.Half.NaN, System.Half.NaN is returned.
///
public static Half Min(Half value1, Half value2)
{
return (value1 < value2) ? value1 : value2;
}
}
}