
import numbers.floats.*;
import math.*;

//Constants
public alias M_E	    = 2.7182818284590452353602874713526625;  /* e */
public alias M_LOG2E	= 1.4426950408889634073599246810018921;  /* log_2 e */
public alias M_LOG10E	= 0.4342944819032518276511289189166051;  /* log_10 e */
public alias M_LN2	    = 0.6931471805599453094172321214581766;  /* log_e 2 */
public alias M_LN10     = 2.3025850929940456840179914546843642;  /* log_e 10 */
public alias M_PI		= 3.1415926535897932384626433832795029;  /* pi */
public alias M_TWOPI    = 6.2831853071795864769252867665590058;   /* 2*pi */
public alias M_1_TWOPI  = 0.1591549430918953357688837633725143620344596457405; /* 1/(2*pi) */
public alias M_PI_2	    = 1.570796326794896619231321691639751442098584699687;  /* pi/2 */
public alias M_PI_4	    = 0.7853981633974483096156608458198757;  /* pi/4 */
public alias M_1_PI	    = 0.3183098861837906715377675267450287;  /* 1/pi */
public alias M_2_PI	    = 0.6366197723675813430755350534900574;  /* 2/pi */
public alias M_2_SQRTPI = 1.1283791670955125738961589031215452;  /* 2/sqrt(pi) */
public alias M_SQRT2	= 1.4142135623730950488016887242096981;  /* sqrt(2) */
public alias M_SQRT1_2  = 0.7071067811865475244008443621048490;  /* 1/sqrt(2) */
public alias M_COS_PI_4 = 0.707106781186547524400844362104849039284835937688; /* cos(M_PI_4) */
public alias M_COS_PI_8 = 0.923879532511286756128183189396788286822416625863; /* cos(M_PI_4*0.5) */
public alias M_SIN_PI_8 = 0.382683432365089771728459984030398866761344562485; /* sin(M_PI_4*0.5) */


[T | Numeric?(T)]
inline overload max(x:T,y:T) = if(x<y) y else x;

[T | Numeric?(T)]
inline overload min(x:T,y:T) = if(y<x) y else x;

[T] inline overload fma(a:T,b:T,c:T) = (a * b) + c;


[T | Float?(T)]
overload recip(x:T) = T(1)/x;

[T,U | Float?(T,U)]
overload hypot(m:T,n:U) {
    var a = toBiggerNumericType(T,U,m);
    var b = toBiggerNumericType(T,U,n);
    alias T = Type(a);
    alias ZERO = T(0);
    alias ONE = T(1);
    var r = ZERO;
    if (a == ZERO)
        r = abs(b);
    else if (b == ZERO)
        r = abs(a);
    else {
        var x,y = abs(a),abs(b);
        if (x > y){
            var temp = y / x;
            r = x * sqrt(ONE + temp * temp);
        }
        else{
            var temp = x / y;
            r = y * sqrt(ONE + temp * temp);
        }
    }
    return r;
}


[I | Integer?(I)]
inline overload abs(x:I) = if(x >= 0) x else -x;


inline overload sign(x:Long) = bitor(bitshr(x,63),Long(bitshr(ULong(-x),63)));
inline overload sign(x:Int) = bitor(bitshr(x,31),Int(bitshr(UInt(-x),31)));
inline overload sign(x:Short) = bitor(bitshr(x,15),Short(bitshr(UShort(-x),15)));
inline overload sign(x:Byte) = bitor(bitshr(x,7),Byte(bitshr(UByte(-x),7)));



overload llround(x:Float) {
    var result = 0l;
    var i = floatBits(x);
    var j0 = bitand(bitshr(i,23),0xff) - 0x7f;
    var sign = if(bitand(i,0x80000000u) != 0) -1l else 1l;
    i = bitor(bitand(i,0x7fffff),0x800000);
    if (j0 < Int(8 * TypeSize(Long)) - 1){
        if (j0 < 0)
            return if(j0 < -1) 0l else sign;
        else if (j0 >= 23)
            result = Long(bitshl(i, (j0 - 23)));
        else {
            i += bitshr(0x400000,j0);
            result = Long(bitshr(i,23 - j0));
        }
    }
    else {
        // The number is too large.  Return implementation default.
        result = Long(x);
    }
    return sign * result;
}

overload llround (x:Double ) {
    var result = 0l;
    var xdb = db_number(x);
    var j0 = bitand(bitshr(xdb.0[1] , 20) , 0x7ff) - 0x3ff;
    var sign = if(bitand(xdb.0[1] , 0x80000000u) != 0) -1l else 1l;
    xdb.0[1] = bitor(bitand(xdb.0[1],0xfffff) ,0x100000);
    if (j0 < 20){
        if (j0 < 0)
            return if(j0 < -1) 0l else sign;
        else{
            xdb.0[1] += bitshr(0x80000 , j0);
            result = Long(bitshr(xdb.0[1] , 20 - j0));
        }
    }
    else if (j0 <  Int(8 * TypeSize(Long)) - 1){
        if (j0 >= 52)
            result = bitshl(bitor(bitshl( Long(xdb.0[1]) , 32) , xdb.0[0]) , j0 - 52);
        else{
            var j = xdb.0[0] + bitshr(0x80000000u ,j0 - 20);
            if (j < xdb.0[0])
                inc(xdb.0[1]);
            if (j0 == 20)
                result = Long(xdb.0[1]);
            else
                result = bitor(bitshl(Long(xdb.0[1]) , j0 - 20) , bitshr(j , 52 - j0));
        }
    }
    else{
        // The number is too large.  Return implementation default.
        return Long(x);
    }
    return sign * result;
}



