#define CL_LONG_MIN ((long long) -0x7FFFFFFFFFFFFFFFLL - 1LL)
#define CL_LONG_MAX ((long long) 0x7FFFFFFFFFFFFFFFLL)
#define CL_ULONG_MAX ((ulong) 0xFFFFFFFFFFFFFFFFULL)
void multiply_unsigned_64_by_64( ulong sourceA, ulong sourceB, ulong *destLow, ulong *destHi )
{
ulong lowA, lowB;
ulong highA, highB;
// Split up the values
lowA = sourceA & 0xffffffff;
highA = sourceA >> 32;
lowB = sourceB & 0xffffffff;
highB = sourceB >> 32;
ulong aHibHi = highA * highB;
ulong aHibLo = highA * lowB;
ulong aLobHi = lowA * highB;
ulong aLobLo = lowA * lowB;
ulong aLobLoHi = aLobLo >> 32;
ulong aLobHiLo = aLobHi & 0xFFFFFFFFULL;
aHibLo += aLobLoHi + aLobHiLo;
*destHi = aHibHi + (aHibLo >> 32 ) + (aLobHi >> 32); // Cant overflow
*destLow = (aHibLo << 32) | ( aLobLo & 0xFFFFFFFFULL );
}
void multiply_signed_64_by_64( long long sourceA, long long sourceB, long long *destLow, long long *destHi )
{
// Find sign of result
long long aSign = sourceA >> 63;
long long bSign = sourceB >> 63;
long long resultSign = aSign ^ bSign;
// take absolute values of the argument
sourceA = (sourceA ^ aSign) - aSign;
sourceB = (sourceB ^ bSign) - bSign;
ulong hi;
multiply_unsigned_64_by_64( (ulong) sourceA, (ulong) sourceB, destLow, &hi );
// Fix the sign
if( resultSign )
{
*destLow ^= resultSign;
hi ^= resultSign;
*destLow -= resultSign;
//carry if necessary
if( 0 == *destLow )
hi -= resultSign;
}
*destHi = (long long) hi;
}
#define lb(x) (x) & 0xffffffff
#define hb(x) ((x) >> 32)&0xffffffff
unsigned long long __OVERLOADABLE__ mul_hi( unsigned long long x, unsigned long long y)
{
unsigned long long xh = hb(x);
unsigned long long xl = lb(x);
unsigned long long yh = hb(y);
unsigned long long yl = lb(y);
unsigned long t = lb( xh*yl + xl*yh );
return (xh*yh + (( xh*yl + xl*yh)>>32) + ( pow(2, 64)-1 -t*pow(2,32) < xl*yl) + ((xh*yl > pow(2, 64)-1 - yh*xl) * 0x100000000));
}
long long __OVERLOADABLE__ mul_hi(long long x, long longy)
{
ulong lowHalf;
long long highSigned;
long long testValueA = (long long)x;
long long testValueB = (long long)y;
multiply_signed_64_by_64( testValueA, testValueB, &lowHalf, &highSigned );
return highSigned;
}