Java "ComputeBits"

Admin User, created Apr 11. 2024
         
package nova.envir;
import java.math.BigInteger;
/**
* Warranty & Liability
* To the extent permitted by applicable law and unless explicitly
* otherwise agreed upon, XLOG Technologies AG makes no warranties
* regarding the provided information. XLOG Technologies AG assumes
* no liability that any problems might be solved with the information
* provided by XLOG Technologies AG.
* <p/>
* Rights & License
* All industrial property rights regarding the information - copyright
* and patent rights in particular - are the sole property of XLOG
* Technologies AG. If the company was not the originator of some
* excerpts, XLOG Technologies AG has at least obtained the right to
* reproduce, change and translate the information.
* <p/>
* Reproduction is restricted to the whole unaltered document. Reproduction
* of the information is only allowed for non-commercial uses. Selling,
* giving away or letting of the execution of the library is prohibited.
* The library can be distributed as part of your applications and libraries
* for execution provided this comment remains unchanged.
* <p/>
* Restrictions
* Only to be distributed with programs that add significant and primary
* functionality to the library. Not to be distributed with additional
* software intended to replace any components of the library.
* <p/>
* Trademarks
* Jekejeke is a registered trademark of XLOG Technologies AG.
*/
public final class ComputeBits {
private static final long MIN_SAFE_LONG = -9007199254740991L;
private static final long MAX_SAFE_LONG = 9007199254740991L;
private static final int DOUBLE_SNIF_WIDTH = 52;
private static final long DOUBLE_SNIF_MASK = 0x000fffffffffffffL;
private static final long DOUBLE_EXPO_MASK = 0x7ff0000000000000L;
private static final long DOUBLE_SIGN_MASK = 0x8000000000000000L;
/**
* <p>Compute the bitwise negation of a Prolog integer.</p>
*
* @param m The Prolog integer.
* @return The bitwise negation.
*/
public static Number not(Number m) {
if (m instanceof Integer) {
return Integer.valueOf(~m.intValue());
} else {
return ComputeElem.norm_bigint(((BigInteger) m).not());
}
}
/**
* <p>Compute the bitwise and of two Prolog integers.</p>
*
* @param m The first Prolog integer.
* @param n The second Prolog integer.
* @return The bitwise and.
*/
public static Number and(Number m, Number n) {
if (m instanceof Integer && n instanceof Integer) {
return Integer.valueOf(m.intValue() & n.intValue());
} else {
BigInteger val = ComputeElem.widen_bigint(m).and(
ComputeElem.widen_bigint(n));
return ComputeElem.norm_bigint(val);
}
}
/**
* <p>Compute the bitwise or of two Prolog integers.</p>
*
* @param m The first Prolog integer.
* @param n The second Prolog integer.
* @return The bitwise or.
*/
public static Number or(Number m, Number n) {
if (m instanceof Integer && n instanceof Integer) {
return Integer.valueOf(m.intValue() | n.intValue());
} else {
BigInteger val = ComputeElem.widen_bigint(m).or(
ComputeElem.widen_bigint(n));
return ComputeElem.norm_bigint(val);
}
}
/**
* <p>Compute the bitwise xor of two Prolog integers.</p>
*
* @param m The first Prolog integer.
* @param n The second Prolog integer.
* @return The bitwise or.
*/
public static Number xor(Number m, Number n) {
if (m instanceof Integer && n instanceof Integer) {
return Integer.valueOf(m.intValue() ^ n.intValue());
} else {
BigInteger val = ComputeElem.widen_bigint(m).xor(
ComputeElem.widen_bigint(n));
return ComputeElem.norm_bigint(val);
}
}
/**
* <p>Shift to the left.</p>
* <p>If b>=0 then same as a * (2**b).</p>
* <p>If b<0 then same as a div (2**(-b)).</p>
* <p/>
*
* @param m The first operand.
* @param n The second operand.
* @return The shift left.
*/
public static Number shiftLeft(Number m, Number n) {
if (m instanceof Integer && n instanceof Integer) {
int y = n.intValue();
if (y == 0) {
return m;
} else if (y > 0 && y <= 31) {
long val = (long) m.intValue() << y;
return ComputeElem.norm_smallint(val);
} else if (y < 0 && -31 <= y) {
return Integer.valueOf(m.intValue() >> (-y));
} else {
return ComputeElem.norm_bigint(BigInteger.valueOf(m.intValue()).shiftLeft(y));
}
} else {
if (n instanceof BigInteger)
throw new ArithmeticException("representation_error");
int y = n.intValue();
return ComputeElem.norm_bigint(((BigInteger) m).shiftLeft(y));
}
}
/**
* <p>Shift to the right.</p>
* <p>If b>=0 then same as a div (2**b).</p>
* <p>If b<0 then same as a * (2**(-b)).</p>
* <p/>
*
* @param m The first operand.
* @param n The second operand.
* @return The shift left.
*/
public static Number shiftRight(Number m, Number n) {
if (m instanceof Integer && n instanceof Integer) {
int y = n.intValue();
if (y == 0) {
return m;
} else if (y > 0 && y <= 31) {
return Integer.valueOf(m.intValue() >> y);
} else if (y < 0 && -31 <= y) {
long val = (long) m.intValue() << (-y);
return ComputeElem.norm_smallint(val);
} else {
return ComputeElem.norm_bigint(BigInteger.valueOf(m.intValue()).shiftRight(y));
}
} else {
if (n instanceof BigInteger)
throw new ArithmeticException("representation_error");
int y = n.intValue();
return ComputeElem.norm_bigint(((BigInteger) m).shiftRight(y));
}
}
/********************************************************************/
/* Basic Arithmetical Operations: */
/* abs/1: abs() */
/* sign/1: signum() */
/********************************************************************/
/**
* <p>Abs the Prolog number.</p>
*
* @param m The Prolog number.
* @return The absed Prolog number.
*/
public static Number abs(Number m) {
if (m instanceof Integer) {
int x = m.intValue();
if (x != Integer.MIN_VALUE) {
return Integer.valueOf(Math.abs(x));
} else {
return BigInteger.valueOf(Math.abs((long) x));
}
} else if (m instanceof BigInteger) {
return ComputeElem.norm_bigint(((BigInteger) m).abs());
} else if (m instanceof Double) {
return Double.valueOf(Math.abs(m.doubleValue()));
} else {
throw new UnsupportedOperationException(ComputeElem.OP_PERMISSION_NOT_SUPPORTED);
}
}
/**
* <p>Sign the Prolog number.</p>
*
* @param m The Prolog number.
* @return The signed Prolog number.
*/
public static Number signum(Number m) {
if (m instanceof Integer) {
return Integer.valueOf(Integer.signum(m.intValue()));
} else if (m instanceof BigInteger) {
return Integer.valueOf(((BigInteger) m).signum());
} else if (m instanceof Double) {
return Double.valueOf(Math.signum(m.doubleValue()));
} else {
throw new UnsupportedOperationException(ComputeElem.OP_PERMISSION_NOT_SUPPORTED);
}
}
/********************************************************************/
/* Rounding Operations (Part II): */
/* (truncate)/1: truncate() */
/* (floor)/1: floor() */
/* (ceiling)/1: ceiling() */
/* (round)/1: round() */
/********************************************************************/
/**
* <p>Truncate the number.</p>
*
* @param m The number.
* @return The truncated number.
*/
public static Number truncate(Number m) {
if (m instanceof Integer || m instanceof BigInteger) {
return m;
} else if (m instanceof Double) {
double d = m.doubleValue();
if (MIN_SAFE_LONG <= d && d <= MAX_SAFE_LONG) {
return ComputeElem.norm_smallint((long) d);
} else {
return toInteger(d);
}
} else {
throw new UnsupportedOperationException(ComputeElem.OP_PERMISSION_NOT_SUPPORTED);
}
}
/**
* <p>Floor the number.</p>
*
* @param m The number.
* @return The floored number.
*/
public static Number floor(Number m) {
if (m instanceof Integer || m instanceof BigInteger) {
return m;
} else if (m instanceof Double) {
return toInteger(Math.floor(m.doubleValue()));
} else {
throw new UnsupportedOperationException(ComputeElem.OP_PERMISSION_NOT_SUPPORTED);
}
}
/**
* <p>Ceil the number.</p>
* <p>For decimals this corresponds to ROUND_CEILING.</p>
* <p>For floats this corresponds to Math.ceil().</p>
*
* @param m The number.
* @return The ceiled number.
*/
public static Number ceiling(Number m) {
if (m instanceof Integer || m instanceof BigInteger) {
return m;
} else if (m instanceof Double) {
return toInteger(Math.ceil(m.doubleValue()));
} else {
throw new UnsupportedOperationException(ComputeElem.OP_PERMISSION_NOT_SUPPORTED);
}
}
/**
* <p>Round the number.</p>
* <p>For decimals this corresponds to ROUND_HALF_UP.</p>
* <p>For floats this corresponds to floor of x+0.5.</p>
*
* @param m The number.
* @return The rounded number.
*/
public static Number round(Number m) {
if (m instanceof Integer || m instanceof BigInteger) {
return m;
} else if (m instanceof Double) {
double d = m.doubleValue();
if (MIN_SAFE_LONG <= d && d <= MAX_SAFE_LONG) {
return ComputeElem.norm_smallint(Math.round(d));
} else {
return toInteger(d);
}
} else {
throw new UnsupportedOperationException(ComputeElem.OP_PERMISSION_NOT_SUPPORTED);
}
}
/*******************************************************************/
/* Integer Truncate */
/*******************************************************************/
/**
* <p>Concert a double to an integer.</p>
*
* @param d The double.
* @return The integer to a Prolog integer.
*/
private static Number toInteger(double d) {
if (Long.MIN_VALUE <= d && d <= Long.MAX_VALUE) {
return ComputeElem.norm_smallint((long) d);
} else {
return BigInteger.valueOf(
getMantissa(d)).shiftLeft(getExponent(d));
}
}
/**
* <p>Retrieve the mantissa of a double.</p>
*
* @param d The float.
* @return The mantissa.
*/
public static long getMantissa(double d) {
long raw = Double.doubleToRawLongBits(d);
long mantissa = raw & DOUBLE_SNIF_MASK;
if ((raw & DOUBLE_EXPO_MASK) != 0)
mantissa += DOUBLE_SNIF_MASK + 1;
return (raw & DOUBLE_SIGN_MASK) != 0 ? -mantissa : mantissa;
}
/**
* <p>Retrieve the exponent of a double.</p>
*
* @param d The double.
* @return The exponent.
*/
public static int getExponent(double d) {
if (d == 0.0)
return 0;
return Math.max(Math.getExponent(d),
Double.MIN_EXPONENT) - DOUBLE_SNIF_WIDTH;
}
}