/*
* FPInstructionUtils.java
*
* 6th may, 2007
* (c) 2006 EduMips64 project - Trubia Massimo
*
* This file is part of the EduMIPS64 project, and is released under the GNU
* General Public License.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.edumips64.core.fpu;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.MathContext;
import java.math.RoundingMode;
import org.edumips64.core.CPU;
import org.edumips64.core.FCSRRegister;
import org.edumips64.utils.Converter;
import org.edumips64.utils.IrregularStringOfBitsException;
/** Group of functions used in the Floating point unit
*/
public class FPInstructionUtils {
private FCSRRegister fcsr;
/** The fcsr parameter is used to get/set flags relative to the state of FPU exceptions.
*
* Classes that don't need to work with the "real" state of the CPU (for example, Parser or unit tests), can just pass
* any instance of FCSRRegister to this constructor.
*/
public FPInstructionUtils(FCSRRegister fcsr) {
this.fcsr = fcsr;
}
private final static String PLUSINFINITY = "0111111111110000000000000000000000000000000000000000000000000000";
private final static String MINUSINFINITY = "1111111111110000000000000000000000000000000000000000000000000000";
private final static String PLUSZERO = "0000000000000000000000000000000000000000000000000000000000000000";
private final static String MINUSZERO = "1000000000000000000000000000000000000000000000000000000000000000";
private final static String BIGGEST = "1.797693134862315708145274237317E308";
private final static String SMALLEST = "-1.797693134862315708145274237317E308";
private final static String MINUSZERO_DEC = "-4.9406564584124654417656879286822E-324";
private final static String PLUSZERO_DEC = "4.9406564584124654417656879286822E-324";
/*
snan
0x7fffffffffffffff (value used in MIPS64 to generate a new snan)
0 11111111111 1111111111111111111111111111111111111111111111111111 (bynary equivalent)
X 11111111111 1XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX (pattern for snans values)*/
private final static String SNAN_NEW = "0111111111111111111111111111111111111111111111111111111111111111";
private final static String SNAN_PATTERN = "X111111111111XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; //XX..XX cannot be equal to zero at the same time
/*qnan
0x7ff7ffffffffffff (value used in MIPS64 to generate a new qnan)
0 11111111111 0111111111111111111111111111111111111111111111111111 (bynary equivalent)
X 11111111111 0XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX (pattern for qnans values) */
private final static String QNAN_NEW = "0111111111110111111111111111111111111111111111111111111111111111";
private final static String QNAN_PATTERN = "X111111111110XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; //XX..XX cannot be equal to zero at the same time
/**
* Converts a double value passed as string to a 64 bit binary string according with IEEE754 standard for double precision floating point numbers
*
* @param value the double value in the format "123.213" or "1.23213E2"
* value belongs to [-1.797693134862315708145274237317E308,-4.9406564584124654417656879286822E-324] U [4.9406564584124654417656879286822E-324, 1.797693134862315708145274237317E308]
* @return the binary string
* @throws FPOverflowException,FPUnderflowException,IrregularStringOfBitsException
*/
public String doubleToBin(String value) throws FPOverflowException, FPUnderflowException, IrregularStringOfBitsException {
//if a special value is passed then the proper binary string is returned
String old_value = value;
value = parseKeywords(value);
if (old_value.compareToIgnoreCase(value) != 0) {
return value;
}
// Check if the value can be treated as a valid double.
try {
Double.parseDouble(value);
} catch (NumberFormatException e) {
throw new IrregularStringOfBitsException();
}
// Constants to be used for the comparisons.
final BigDecimal theBiggest = new BigDecimal(BIGGEST);
final BigDecimal theSmallest = new BigDecimal(SMALLEST);
final BigDecimal theZeroMinus = new BigDecimal(MINUSZERO_DEC);
final BigDecimal theZeroPlus = new BigDecimal(PLUSZERO_DEC);
final BigDecimal zero = new BigDecimal(0.0);
final BigDecimal minuszero = new BigDecimal(-0.0);
try { //Check if the exponent is not in signed 32 bit, in this case the NumberFormatException occurs
BigDecimal value_bd = new BigDecimal(value);
// Check for overflow.
if (value_bd.compareTo(theBiggest) == 1 || value_bd.compareTo(theSmallest) == -1) {
fcsr.setFlagsOrRaiseException(CPU.FPExceptions.OVERFLOW);
if (value_bd.compareTo(theBiggest) == 1) {
return PLUSINFINITY;
}
if (value_bd.compareTo(theSmallest) == -1) {
return MINUSINFINITY;
}
}
// Check for underflow.
if ((value_bd.compareTo(theZeroMinus) == 1 && value_bd.compareTo(theZeroPlus) == -1) && (value_bd.compareTo(zero) != 0 && value_bd.compareTo(minuszero) != 0)) {
fcsr.setFlagsOrRaiseException(CPU.FPExceptions.UNDERFLOW);
if (value_bd.compareTo(zero) == 1) {
return PLUSZERO;
}
if (value_bd.compareTo(zero) == -1) {
return MINUSZERO;
}
}
String output = Long.toBinaryString(Double.doubleToLongBits(value_bd.doubleValue()));
return padding64(output);
} catch (NumberFormatException e) {
if (fcsr.getFPExceptions(CPU.FPExceptions.OVERFLOW)) {
fcsr.setFCSRCause("O", 1);
throw new FPOverflowException();
} else {
fcsr.setFCSRFlags("V", 1);
}
return PLUSZERO;
} catch (FPDivideByZeroException | FPInvalidOperationException e) {
// Can't really happen.
e.printStackTrace();
return "";
}
}
/**
* determines if the passed string contains the keywords for special values
*
* @param value a binary string or a string containing POSITIVEINFINITY,NEGATIVEINFINITY,POSITIVEZERO,NEGATIVEZERO,QNAN,SNAN
* @return the proper binary string if value contains special values, or value itself if the string is not special
*/
private static String parseKeywords(String value) {
if (value.compareToIgnoreCase("POSITIVEINFINITY") == 0) {
return PLUSINFINITY;
} else if (value.compareToIgnoreCase("NEGATIVEINFINITY") == 0) {
return MINUSINFINITY;
} else if (value.compareToIgnoreCase("POSITIVEZERO") == 0) {
return PLUSZERO;
} else if (value.compareToIgnoreCase("NEGATIVEZERO") == 0) {
return MINUSZERO;
} else if (value.compareToIgnoreCase("QNAN") == 0) {
return QNAN_NEW;
} else if (value.compareToIgnoreCase("SNAN") == 0) {
return SNAN_NEW;
}
return value;
}
/**
* In order to create a 64 bit binary string, the zero-padding on the left of the value is carried out
*
* @param value the string to pad
* @return Padded string
*/
private static String padding64(String value) {
StringBuilder sb = new StringBuilder();
sb.append(value);
for (int i = 0; i < 64 - value.length(); i++) {
sb.insert(0, "0");
}
return sb.toString();
}
/**
* This method performs the sum between two double values, if the passed values are Snan or Qnan
* and the invalid operation exception is not enabled the result of the operation is a Qnan else an InvalidOperation exception occurs,
* if the passed values are infinities and their signs agree, an infinity (positive or negative is returned),
* if signs don't agree then an invalid operation exception occurs if this trap is enabled.
* After the addition, if the result is too large in absolute value a right signed infinity is returned, else
* if the FP overflow or underflow are enabled an exception occurs.
*
* @param value1 the binary string representing the double value
* @param value2 the binary string representing the double value
* @return the result value (if trap are disabled, special values are returned as binary string)
* @throws FPInvalidOperationException,FPUnderflowException,FPOverflowException
*/
public String doubleSum(String value1, String value2) throws FPInvalidOperationException, FPUnderflowException, FPOverflowException, IrregularStringOfBitsException {
if (is64BinaryString(value1) && is64BinaryString(value2)) {
// QNaN check:
// 1. any NaN
boolean isNan = isQNaN(value1) || isQNaN(value2) || isSNaN(value1) || isSNaN(value2);
// 2. signs that make it impossible to determine the final result
boolean wrongOperands = isPositiveInfinity(value1) && isNegativeInfinity(value2);
wrongOperands = wrongOperands || (isNegativeInfinity(value1) && isPositiveInfinity(value2));
if (isNan || wrongOperands) {
try {
fcsr.setFlagsOrRaiseException(CPU.FPExceptions.INVALID_OPERATION);
} catch (FPDivideByZeroException e) {
// Should never happen.
e.printStackTrace();
}
return QNAN_NEW;
}
// Return +Inf if:
// 1. +Inf + Inf
boolean plusInf = isPositiveInfinity(value1) && isPositiveInfinity(value2);
// 2. +Inf + (any)
plusInf = plusInf || (isPositiveInfinity(value1) && !isInfinity(value2));
// 3. (any) + +Inf
plusInf = plusInf || !isInfinity(value1) && isPositiveInfinity(value2);
if (plusInf) {
return PLUSINFINITY;
}
// Return -Inf if:
// 1. -Inf + -Inf
boolean minusInf = isNegativeInfinity(value1) && isNegativeInfinity(value2);
// 2. -Inf + (any)
minusInf = minusInf || (isNegativeInfinity(value1) && !isInfinity(value2));
// 3. (any) + -Inf
minusInf = minusInf || !isInfinity(value1) && isNegativeInfinity(value2);
if (minusInf) {
return MINUSINFINITY;
}
// At this point operands can be added and if an overflow or an underflow occurs
// and if exceptions are activated then trap else results are returned
MathContext mc = new MathContext(1000, RoundingMode.HALF_EVEN);
BigDecimal operand1 = new BigDecimal(Double.longBitsToDouble(Converter.binToLong(value1, false)));
BigDecimal operand2 = new BigDecimal(Double.longBitsToDouble(Converter.binToLong(value2, false)));
BigDecimal result = operand1.add(operand2, mc);
//checking for underflows or overflows are performed inside the doubleToBin method (if relative traps are disabled output is returned)
//if an underflow or overflow occur and they are activated (trap enabled) this point is never reached
return doubleToBin(result.toString());
}
return null;
}
/**
* This method performs the subtraction between two double values, if the passed values are Snan or Qnan
* and the invalid operation exception is not enabled the result of the operation is a Qnan else an InvalidOperation exception occurs,
* if the passed values are infinities and their signs agree, an infinity (positive or negative is returned),
* if signs don't agree then an invalid operation exception occurs if this trap is enabled.
* After the addition, if the result is too large in absolute value a right signed infinity is returned, else
* if the FP overflow or underflow are enabled an exception occurs.
*/
public String doubleSubtraction(String value1, String value2) throws FPInvalidOperationException, FPUnderflowException, FPOverflowException, IrregularStringOfBitsException {
if (!(is64BinaryString(value1) && is64BinaryString(value2))) {
return null;
}
// QNaN check:
// 1. any NaN
boolean isNan = isQNaN(value1) || isQNaN(value2) || isSNaN(value1) || isSNaN(value2);
// 2. signs that make it impossible to determine the final result
boolean wrongOperands = isPositiveInfinity(value1) && isPositiveInfinity(value2);
wrongOperands = wrongOperands || (isNegativeInfinity(value1) && isNegativeInfinity(value2));
if (isNan || wrongOperands) {
try {
fcsr.setFlagsOrRaiseException(CPU.FPExceptions.INVALID_OPERATION);
} catch (FPDivideByZeroException e) {
// Should never happen.
e.printStackTrace();
}
return QNAN_NEW;
}
// Return +Inf if:
// 1. +Inf - -Inf
boolean plusInf = isPositiveInfinity(value1) && isNegativeInfinity(value2);
// 2. +Inf - (any)
plusInf = plusInf || (isPositiveInfinity(value1) && !isInfinity(value2));
// 3. (any) - -Inf
plusInf = plusInf || !isInfinity(value1) && isNegativeInfinity(value2);
if (plusInf) {
return PLUSINFINITY;
}
// Return -Inf if:
// 1. -Inf - +Inf
boolean minusInf = isNegativeInfinity(value1) && isPositiveInfinity(value2);
// 2. -Inf - (any)
minusInf = minusInf || (isNegativeInfinity(value1) && !isInfinity(value2));
// 3. (any) - +Inf
minusInf = minusInf || !isInfinity(value1) && isPositiveInfinity(value2);
if (minusInf) {
return MINUSINFINITY;
}
//at this point operands can be subtracted and if an overflow or an underflow occurs
//and if exceptions are activated then a trap happens else results are returned
MathContext mc = new MathContext(1000, RoundingMode.HALF_EVEN);
BigDecimal operand1 = new BigDecimal(Double.longBitsToDouble(Converter.binToLong(value1, false)));
BigDecimal operand2 = new BigDecimal(Double.longBitsToDouble(Converter.binToLong(value2, false)));
BigDecimal result = operand1.subtract(operand2, mc);
//checking for underflows or overflows are performed inside the doubleToBin method (if the relative traps are disabled the output is returned)
//if an underflow or overflow occur and they are activated (trap enabled) this point is never reached
return doubleToBin(result.toString());
}
/**
* This method performs the multiplication between two double values, if the passed values are Snan or Qnan
* and the invalid operation exception is not enabled the result of the operation is a Qnan else an InvalidOperation exception occurs,
* if the passed values are infinities a positive or negative infinity is returned depending of the signs product,
* Only if we attempt to perform (sign)0 X (sign)Infinity and the Invalid operation exception is not enabled NAN is returned,
* else a trap occur. After the multiplication, if the result is too large in absolute value a right signed infinity is returned, else
* if the FP overflow or underflow are enabled an exception occurs.
*/
public String doubleMultiplication(String value1, String value2) throws FPInvalidOperationException, FPUnderflowException, FPOverflowException, IrregularStringOfBitsException {
if (!(is64BinaryString(value1) && is64BinaryString(value2))) {
return null;
}
// QNaN check:
// 1. any NaN
boolean isNan = isQNaN(value1) || isQNaN(value2) || isSNaN(value1) || isSNaN(value2);
// 2. zero x Inf or Inf x zero
boolean wrongOperands = isZero(value1) && isInfinity(value2);
wrongOperands = wrongOperands || (isInfinity(value1) && isZero(value2));
if (isNan || wrongOperands) {
try {
fcsr.setFlagsOrRaiseException(CPU.FPExceptions.INVALID_OPERATION);
} catch (FPDivideByZeroException e) {
// Should never happen.
e.printStackTrace();
}
return QNAN_NEW;
}
// Get signs of value1 and value2, and the resulting sign.
int sign1 = getDoubleSign(value1);
int sign2 = getDoubleSign(value2);
int res_sign = sign1 * sign2;
// Return a signed infinity when infinity is involved. Zeros and NaNs won't be
// operands because of the previous checks.
boolean returnInf = isInfinity(value1) && isInfinity(value2);
returnInf = returnInf || (isInfinity(value1) && !isInfinity(value2));
// any X (sign)Infinity
returnInf = returnInf || (!isInfinity(value1) && isInfinity(value2));
//(sign)Infinity X (sign)Infinity
if (returnInf) {
return getSignedInfinity(res_sign);
}
//(sign)zero X (sign)zero
if (isZero(value1) && isZero(value2)) {
return getSignedZero(res_sign);
}
//at this point operands can be multiplied and if an overflow or an underflow occurs
//and if exceptions are activated then a trap happens else results are returned
MathContext mc = new MathContext(1000, RoundingMode.HALF_EVEN);
BigDecimal operand1 = new BigDecimal(Double.longBitsToDouble(Converter.binToLong(value1, false)));
BigDecimal operand2 = new BigDecimal(Double.longBitsToDouble(Converter.binToLong(value2, false)));
BigDecimal result = operand1.multiply(operand2, mc);
//checking for underflows or overflows are performed inside the doubleToBin method (if the relative traps are disabled the output is returned)
//if an underflow or overflow occur and they are activated (trap enabled) this point is never reached
return doubleToBin(result.toString());
}
private static String getSignedInfinity(int sign) {
if (sign == -1) {
return MINUSINFINITY;
}
return PLUSINFINITY;
}
private static String getSignedZero(int sign) {
if (sign == -1) {
return MINUSZERO;
}
return PLUSZERO;
}
/**
* This method performs the division between two double values, if the passed values are Snan or Qnan
* and the invalid operation exception is not enabled the result of the operation is a Qnan else an InvalidOperation exception occurs,
* Only if the passed values are both infinities or zeros a Qnan is returned if the InvalidOperation exception is not enabled else a trap occurs,
* If value2 (not also value1) is Zero a DivisionByZero Exception occurs if it is enabled else a right infinity is returned depending on the product's signs
* After the operation, if the result is too small in absolute value a right signed infinity is returned, else
* if the FP underflow is enabled an exception occurs.
*/
public String doubleDivision(String value1, String value2) throws FPInvalidOperationException, FPUnderflowException, FPOverflowException, FPDivideByZeroException, IrregularStringOfBitsException {
if (!(is64BinaryString(value1) && is64BinaryString(value2))) {
return null;
}
// QNaN check:
// 1. any NaN
boolean isNan = isQNaN(value1) || isQNaN(value2) || isSNaN(value1) || isSNaN(value2);
// 2. Inf / Inf or zero / zero
boolean wrongOperands = isInfinity(value1) && isInfinity(value2);
wrongOperands = wrongOperands || (isZero(value1) && isZero(value2));
if (isNan || wrongOperands) {
fcsr.setFlagsOrRaiseException(CPU.FPExceptions.INVALID_OPERATION);
return QNAN_NEW;
}
// Get signs of value1 and value2, and the resulting sign.
int sign1 = getDoubleSign(value1);
int sign2 = getDoubleSign(value2);
int res_sign = sign1 * sign2;
// (sign)Zero / any
if (isZero(value1) && !isZero(value2)) {
return getSignedZero(res_sign);
}
if (!isZero(value1) && isZero(value2)) {
fcsr.setFlagsOrRaiseException(CPU.FPExceptions.DIVIDE_BY_ZERO);
return getSignedInfinity(res_sign);
}
// (sign)infinity / any(different from infinity and zero)
if (isInfinity(value1)) {
return getSignedInfinity(res_sign);
}
//at this point operands can be divided and if an underflow occurs
//and if exceptions are activated then a trap happens else results are returned
MathContext mc = new MathContext(1000, RoundingMode.HALF_EVEN);
BigDecimal operand1 = new BigDecimal(Double.longBitsToDouble(Converter.binToLong(value1, false)));
BigDecimal operand2 = new BigDecimal(Double.longBitsToDouble(Converter.binToLong(value2, false)));
BigDecimal result = operand1.divide(operand2, mc);
//checking for underflows is performed inside the doubleToBin method (if the relative traps are disabled the output is returned)
return doubleToBin(result.toString());
}
/**
* Returns a string with a double value or the name of a special value
* it is recommended the use of this method only for the visualisation of the double value because it may return an alphanumeric value
*
* @param value the 64 bit binary string in the IEEE754 format to convert
* @return the double value or the special values "Quiet NaN","Signaling NaN", "Positive infinity", "Negative infinity","Positive zero","Negative zero"
*/
public static String binToDouble(String value) {
if (is64BinaryString(value)) {
String new_value = getSpecialValues(value);
//the value wasn't changed
if (new_value.compareTo(value) == 0) {
Double new_value_d = null;
try {
new_value_d = Double.longBitsToDouble(Converter.binToLong(value, false));
} catch (IrregularStringOfBitsException ex) {
ex.printStackTrace();
}
return new_value_d.toString();
}
return new_value;
}
return null;
}
/**
* Returns the name of a special value (+-infinity, qnan, snan ) or "value" itself if it isn't a special value
*/
private static String getSpecialValues(String value) {
if (isQNaN(value)) {
return "Quiet NaN";
} else if (isSNaN(value)) {
return "Signaling NaN";
} else if (isPositiveInfinity(value)) {
return "Positive infinity";
} else if (isNegativeInfinity(value)) {
return "Negative infinity";
} else if (isPositiveZero(value)) {
return "Positive zero";
} else if (isNegativeZero(value)) {
return "Negative zero";
} else {
return value;
}
}
/*Determines if the passed binary string is a Nan value, in other words if
* it has got the QNAN_PATTERN
* @param value the binary string of 64 bits
* return true if the condition is true
*/
public static boolean isQNaN(String value) {
return value.matches("[01]111111111110[01]{51}") && !value.matches("[01]111111111110[0]{51}");
}
/*Determines if the passed binary string is an SNan value, in other words if
* it has got the SNAN_PATTERN for MIPS64
* @param value the binary string of 64 bits
* return true if the condition is true
*/
public static boolean isSNaN(String value) {
return value.matches("[01]111111111111[01]{51}") && !value.matches("[01]111111111110[0]{51}");
}
/*Determines if the passed binary string is an infinity value according to the IEEE754 standard
* @param value the binary string of 64 bits
* @return true if the value is positive infinity
*/
private static boolean isPositiveInfinity(String value) {
if (is64BinaryString(value)) {
if (value.compareTo(PLUSINFINITY) == 0) {
return true;
}
}
return false;
}
/**
* Determines if value is a negative infinity according to the IEEE754 standard
*
* @param value the binary string of 64 bits
* @return true if the value is negative infinity
*/
private static boolean isNegativeInfinity(String value) {
if (is64BinaryString(value)) {
if (value.compareTo(MINUSINFINITY) == 0) {
return true;
}
}
return false;
}
/**
* Determines if value is an infinity according to the IEEE754 standard
*
* @param value the binary string of 64 bits
* @return true if the value is infinity
*/
private static boolean isInfinity(String value) {
if (is64BinaryString(value)) {
if (isPositiveInfinity(value) || isNegativeInfinity(value)) {
return true;
}
}
return false;
}
/**
* Returns -1 if "value" is a negative double binary string,+1 if it is positive, 0 if "value" is not a well formed 64 binary string according to IEEE754 standard
*/
private static int getDoubleSign(String value) {
if (is64BinaryString(value)) {
switch (value.charAt(0)) {
case '0':
return 1;
case '1':
return -1;
}
}
return 0;
}
/**
* Determines if value is a positive zero according to the IEEE754 standard
*
* @param value the binary string of 64 bits
* @return true if the value is positive zero
*/
private static boolean isPositiveZero(String value) {
if (is64BinaryString(value)) {
if (value.compareTo(PLUSZERO) == 0) {
return true;
}
}
return false;
}
/*Determines if the passed binary string is a negative zero
* @param value the binary string of 64 bits
* @return true if the value is a positive zero
*/
private static boolean isNegativeZero(String value) {
if (is64BinaryString(value)) {
if (value.compareTo(MINUSZERO) == 0) {
return true;
}
}
return false;
}
/**
* Determines if value is a zero according to the IEEE754 standard
*
* @param value the binary string of 64 bits
* @return true if the value is infinity
*/
private static boolean isZero(String value) {
if (is64BinaryString(value)) {
if (isPositiveZero(value) || isNegativeZero(value)) {
return true;
}
}
return false;
}
/**
* Determines if the passed value is a binary string of 64 bits
*
* @param value the binary string
* @return a boolean value
*/
private static boolean is64BinaryString(String value) {
return value.length() == 64 && value.matches("[01]{64}");
}
/**
* Returns the long fixed point format with the passed rounding mode, or null if an XNan or Infinity is passed to this function
*
* @param value a binary string representing a double value according to the IEEE754 standard
* @param rm the rounding mode to use for the conversion
**/
public static BigInteger doubleToBigInteger(String value, CPU.FPRoundingMode rm) throws IrregularStringOfBitsException {
//we have to check if a XNan o Infinity was passed to this function
if (isQNaN(value) || isSNaN(value) || isInfinity(value) || !is64BinaryString(value)) {
return null;
}
final int INT_PART = 0;
final int DEC_PART = 1;
BigDecimal bd = new BigDecimal(Double.longBitsToDouble(Converter.binToLong(value, false)));
String plainValue = bd.toPlainString();
//removing the sign
plainValue = plainValue.replaceFirst("-", "");
//if the decimal part contains only zeros we must remove it
if (plainValue.matches("[0123456789]+.[0]+")) {
plainValue = plainValue.substring(0, plainValue.indexOf("."));
}
//we now split the integer part and the decimal one
String[] splittedParts = plainValue.split("\\.");
long int_part_value = Long.valueOf(splittedParts[INT_PART]);
//if the decimal part of the plain value exists, we must round to the passed rounding mode
if (splittedParts.length == 2)
switch (rm) {
case TO_NEAREST:
//ex. 1.6-->2 1.8-->2
if (splittedParts[DEC_PART].matches("[6789][0123456789]*")) {
int_part_value++;
}
//1.5-->2 2.5-->2(we must round to the nearest even)
else if (splittedParts[DEC_PART].matches("[5][0123456789]*"))
if (splittedParts[INT_PART].matches("[0123456789]*[13579]")) {
int_part_value++;
}
break;
case TOWARD_ZERO:
//it is a truncation +-4.X -->+-4
break;
case TOWARDS_PLUS_INFINITY:
if (bd.doubleValue() > 0) {
int_part_value++;
}
break;
case TOWARDS_MINUS_INFINITY:
if (bd.doubleValue() < 0) {
int_part_value++;
}
break;
}
if (bd.doubleValue() < 0) {
int_part_value *= (-1);
}
return new BigInteger(String.valueOf(int_part_value));
}
/**
* Returns the double value of the 64 bit fixed point number , or null if an XNan or Infinity is passed to this function
*
* @param value a binary string representing a long value
**/
public static BigDecimal longToDouble(String value) throws IrregularStringOfBitsException {
//we have to check if a XNan o Infinity was passed to this function
if (isQNaN(value) || isSNaN(value) || isInfinity(value) || !is64BinaryString(value)) {
return null;
}
long toConvertValue = Converter.binToLong(value, false);
return new BigDecimal(toConvertValue);
}
/**
* Returns the double value of the 64 bit fixed point number, or null if an if an XNan or Infinity is passed to this function
**/
public static BigDecimal intToDouble(String value) throws IrregularStringOfBitsException {
//we have to check if a XNan o Infinity was passed to this function
if (isQNaN(value) || isSNaN(value) || isInfinity(value) || !is64BinaryString(value)) {
return null;
}
long toConvertValue = Converter.binToInt(value.substring(32, value.length()), false);
return new BigDecimal(toConvertValue);
}
}