|
|
|
@@ -17,350 +17,352 @@
|
|
|
|
|
|
|
|
|
|
package konan.internal
|
|
|
|
|
|
|
|
|
|
// TODO: Enable as soon as regexes are supported.
|
|
|
|
|
import kotlin.text.regex.*
|
|
|
|
|
|
|
|
|
|
@SymbolName("Konan_int_bits_to_float")
|
|
|
|
|
private external fun intBitsToFloat(x: Int): Float
|
|
|
|
|
|
|
|
|
|
@SymbolName("Konan_long_bits_to_double")
|
|
|
|
|
private external fun longBitsToDouble(x: Long): Double
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Parses hex string to a single or double precision floating point number.
|
|
|
|
|
*/
|
|
|
|
|
//internal class HexStringParser(private val EXPONENT_WIDTH: Int, private val MANTISSA_WIDTH: Int) {
|
|
|
|
|
//
|
|
|
|
|
// private val EXPONENT_BASE: Long
|
|
|
|
|
//
|
|
|
|
|
// private val MAX_EXPONENT: Long
|
|
|
|
|
//
|
|
|
|
|
// private val MIN_EXPONENT: Long
|
|
|
|
|
//
|
|
|
|
|
// private val MANTISSA_MASK: Long
|
|
|
|
|
//
|
|
|
|
|
// private var sign: Long = 0
|
|
|
|
|
//
|
|
|
|
|
// private var exponent: Long = 0
|
|
|
|
|
//
|
|
|
|
|
// private var mantissa: Long = 0
|
|
|
|
|
//
|
|
|
|
|
// private var abandonedNumber = "" //$NON-NLS-1$
|
|
|
|
|
//
|
|
|
|
|
// init {
|
|
|
|
|
//
|
|
|
|
|
// this.EXPONENT_BASE = (-1L shl EXPONENT_WIDTH - 1).inv()
|
|
|
|
|
// this.MAX_EXPONENT = (-1L shl EXPONENT_WIDTH).inv()
|
|
|
|
|
// this.MIN_EXPONENT = (-(MANTISSA_WIDTH + 1)).toLong()
|
|
|
|
|
// this.MANTISSA_MASK = (-1L shl MANTISSA_WIDTH).inv()
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// private fun parse(hexString: String): Long {
|
|
|
|
|
// val hexSegments = getSegmentsFromHexString(hexString)
|
|
|
|
|
// val signStr = hexSegments[0]
|
|
|
|
|
// val significantStr = hexSegments[1]
|
|
|
|
|
// val exponentStr = hexSegments[2]
|
|
|
|
|
//
|
|
|
|
|
// parseHexSign(signStr)
|
|
|
|
|
// parseExponent(exponentStr)
|
|
|
|
|
// parseMantissa(significantStr)
|
|
|
|
|
//
|
|
|
|
|
// sign = sign shl (MANTISSA_WIDTH + EXPONENT_WIDTH)
|
|
|
|
|
// exponent = exponent shl MANTISSA_WIDTH
|
|
|
|
|
// return sign or exponent or mantissa
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// /*
|
|
|
|
|
// * Parses the sign field.
|
|
|
|
|
// */
|
|
|
|
|
// private fun parseHexSign(signStr: String) {
|
|
|
|
|
// this.sign = (if (signStr == "-") 1 else 0).toLong() //$NON-NLS-1$
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// /*
|
|
|
|
|
// * Parses the exponent field.
|
|
|
|
|
// */
|
|
|
|
|
// private fun parseExponent(exponentStr: String) {
|
|
|
|
|
// var exponentStr = exponentStr
|
|
|
|
|
// val leadingChar = exponentStr[0]
|
|
|
|
|
// val expSign = if (leadingChar == '-') -1 else 1
|
|
|
|
|
// if (!Character.isDigit(leadingChar)) {
|
|
|
|
|
// exponentStr = exponentStr.substring(1)
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// try {
|
|
|
|
|
// exponent = expSign * exponentStr.toLong()
|
|
|
|
|
// checkedAddExponent(EXPONENT_BASE)
|
|
|
|
|
// } catch (e: NumberFormatException) {
|
|
|
|
|
// exponent = expSign * Long.MAX_VALUE
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// /*
|
|
|
|
|
// * Parses the mantissa field.
|
|
|
|
|
// */
|
|
|
|
|
// private fun parseMantissa(significantStr: String) {
|
|
|
|
|
// val strings = significantStr.split("\\.".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() //$NON-NLS-1$
|
|
|
|
|
// val strIntegerPart = strings[0]
|
|
|
|
|
// val strDecimalPart = if (strings.size > 1) strings[1] else "" //$NON-NLS-1$
|
|
|
|
|
//
|
|
|
|
|
// var significand = getNormalizedSignificand(strIntegerPart, strDecimalPart)
|
|
|
|
|
// if (significand == "0") { //$NON-NLS-1$
|
|
|
|
|
// setZero()
|
|
|
|
|
// return
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// val offset = getOffset(strIntegerPart, strDecimalPart)
|
|
|
|
|
// checkedAddExponent(offset.toLong())
|
|
|
|
|
//
|
|
|
|
|
// if (exponent >= MAX_EXPONENT) {
|
|
|
|
|
// setInfinite()
|
|
|
|
|
// return
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// if (exponent <= MIN_EXPONENT) {
|
|
|
|
|
// setZero()
|
|
|
|
|
// return
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// if (significand.length > MAX_SIGNIFICANT_LENGTH) {
|
|
|
|
|
// abandonedNumber = significand.substring(MAX_SIGNIFICANT_LENGTH)
|
|
|
|
|
// significand = significand.substring(0, MAX_SIGNIFICANT_LENGTH)
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// mantissa = significand.toLong(HEX_RADIX)
|
|
|
|
|
//
|
|
|
|
|
// if (exponent >= 1) {
|
|
|
|
|
// processNormalNumber()
|
|
|
|
|
// } else {
|
|
|
|
|
// processSubNormalNumber()
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// private fun setInfinite() {
|
|
|
|
|
// exponent = MAX_EXPONENT
|
|
|
|
|
// mantissa = 0
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// private fun setZero() {
|
|
|
|
|
// exponent = 0
|
|
|
|
|
// mantissa = 0
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// private fun signum(x: Long) = when {
|
|
|
|
|
// x == 0L -> 0
|
|
|
|
|
// x > 0L -> 1
|
|
|
|
|
// else -> -1
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// /*
|
|
|
|
|
// * Sets the exponent variable to Long.MAX_VALUE or -Long.MAX_VALUE if
|
|
|
|
|
// * overflow or underflow happens.
|
|
|
|
|
// */
|
|
|
|
|
// private fun checkedAddExponent(offset: Long) {
|
|
|
|
|
// val result = exponent + offset
|
|
|
|
|
// val expSign = signum(exponent)
|
|
|
|
|
// if (expSign * signum(offset) > 0 && expSign * signum(result) < 0) {
|
|
|
|
|
// exponent = expSign * Long.MAX_VALUE
|
|
|
|
|
// } else {
|
|
|
|
|
// exponent = result
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// private fun processNormalNumber() {
|
|
|
|
|
// val desiredWidth = MANTISSA_WIDTH + 2
|
|
|
|
|
// fitMantissaInDesiredWidth(desiredWidth)
|
|
|
|
|
// round()
|
|
|
|
|
// mantissa = mantissa and MANTISSA_MASK
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// private fun processSubNormalNumber() {
|
|
|
|
|
// var desiredWidth = MANTISSA_WIDTH + 1
|
|
|
|
|
// desiredWidth += exponent.toInt()//lends bit from mantissa to exponent
|
|
|
|
|
// exponent = 0
|
|
|
|
|
// fitMantissaInDesiredWidth(desiredWidth)
|
|
|
|
|
// round()
|
|
|
|
|
// mantissa = mantissa and MANTISSA_MASK
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// /*
|
|
|
|
|
// * Adjusts the mantissa to desired width for further analysis.
|
|
|
|
|
// */
|
|
|
|
|
// private fun fitMantissaInDesiredWidth(desiredWidth: Int) {
|
|
|
|
|
// val bitLength = countBitsLength(mantissa)
|
|
|
|
|
// if (bitLength > desiredWidth) {
|
|
|
|
|
// discardTrailingBits((bitLength - desiredWidth).toLong())
|
|
|
|
|
// } else {
|
|
|
|
|
// mantissa = mantissa shl (desiredWidth - bitLength)
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// /*
|
|
|
|
|
// * Stores the discarded bits to abandonedNumber.
|
|
|
|
|
// */
|
|
|
|
|
// private fun discardTrailingBits(num: Long) {
|
|
|
|
|
// val mask = (-1L shl num.toInt()).inv()
|
|
|
|
|
// abandonedNumber += mantissa and mask
|
|
|
|
|
// mantissa = mantissa shr num.toInt()
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// /*
|
|
|
|
|
// * The value is rounded up or down to the nearest infinitely precise result.
|
|
|
|
|
// * If the value is exactly halfway between two infinitely precise results,
|
|
|
|
|
// * then it should be rounded up to the nearest infinitely precise even.
|
|
|
|
|
// */
|
|
|
|
|
// private fun round() {
|
|
|
|
|
// val result = abandonedNumber.replace("0+".toRegex(), "") //$NON-NLS-1$ //$NON-NLS-2$
|
|
|
|
|
// val moreThanZero = result.length > 0
|
|
|
|
|
//
|
|
|
|
|
// val lastDiscardedBit = (mantissa and 1L).toInt()
|
|
|
|
|
// mantissa = mantissa shr 1
|
|
|
|
|
// val tailBitInMantissa = (mantissa and 1L).toInt()
|
|
|
|
|
//
|
|
|
|
|
// if (lastDiscardedBit == 1 && (moreThanZero || tailBitInMantissa == 1)) {
|
|
|
|
|
// val oldLength = countBitsLength(mantissa)
|
|
|
|
|
// mantissa += 1L
|
|
|
|
|
// val newLength = countBitsLength(mantissa)
|
|
|
|
|
//
|
|
|
|
|
// //Rounds up to exponent when whole bits of mantissa are one-bits.
|
|
|
|
|
// if (oldLength >= MANTISSA_WIDTH && newLength > oldLength) {
|
|
|
|
|
// checkedAddExponent(1)
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// /*
|
|
|
|
|
// * Returns the normalized significand after removing the leading zeros.
|
|
|
|
|
// */
|
|
|
|
|
// private fun getNormalizedSignificand(strIntegerPart: String, strDecimalPart: String): String {
|
|
|
|
|
// var significand = strIntegerPart + strDecimalPart
|
|
|
|
|
// significand = significand.replaceFirst("^0+".toRegex(), "") //$NON-NLS-1$//$NON-NLS-2$
|
|
|
|
|
// if (significand.length == 0) {
|
|
|
|
|
// significand = "0" //$NON-NLS-1$
|
|
|
|
|
// }
|
|
|
|
|
// return significand
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// /*
|
|
|
|
|
// * Calculates the offset between the normalized number and unnormalized
|
|
|
|
|
// * number. In a normalized representation, significand is represented by the
|
|
|
|
|
// * characters "0x1." followed by a lowercase hexadecimal representation of
|
|
|
|
|
// * the rest of the significand as a fraction.
|
|
|
|
|
// */
|
|
|
|
|
// private fun getOffset(strIntegerPart: String, strDecimalPart: String): Int {
|
|
|
|
|
// var strIntegerPart = strIntegerPart
|
|
|
|
|
// strIntegerPart = strIntegerPart.replaceFirst("^0+".toRegex(), "") //$NON-NLS-1$ //$NON-NLS-2$
|
|
|
|
|
//
|
|
|
|
|
// // If the Integer part is a nonzero number.
|
|
|
|
|
// if (strIntegerPart.length != 0) {
|
|
|
|
|
// val leadingNumber = strIntegerPart.substring(0, 1)
|
|
|
|
|
// return (strIntegerPart.length - 1) * 4 + countBitsLength(leadingNumber.toLong(HEX_RADIX)) - 1
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// // If the Integer part is a zero number.
|
|
|
|
|
// var i = 0
|
|
|
|
|
// while (i < strDecimalPart.length && strDecimalPart[i] == '0') {
|
|
|
|
|
// i++
|
|
|
|
|
// }
|
|
|
|
|
// if (i == strDecimalPart.length) {
|
|
|
|
|
// return 0
|
|
|
|
|
// }
|
|
|
|
|
// val leadingNumber = strDecimalPart.substring(i, i + 1)
|
|
|
|
|
// return (-i - 1) * 4 + countBitsLength(leadingNumber.toLong(HEX_RADIX)) - 1
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// fun numberOfLeadingZeros(i: Long): Int {
|
|
|
|
|
// // HD, Figure 5-6
|
|
|
|
|
// if (i == 0L)
|
|
|
|
|
// return 64
|
|
|
|
|
// var n = 1
|
|
|
|
|
// var x = (i ushr 32).toInt()
|
|
|
|
|
// if (x == 0) {
|
|
|
|
|
// n += 32
|
|
|
|
|
// x = i.toInt()
|
|
|
|
|
// }
|
|
|
|
|
// if (x ushr 16 == 0) {
|
|
|
|
|
// n += 16
|
|
|
|
|
// x = x shl 16
|
|
|
|
|
// }
|
|
|
|
|
// if (x ushr 24 == 0) {
|
|
|
|
|
// n += 8
|
|
|
|
|
// x = x shl 8
|
|
|
|
|
// }
|
|
|
|
|
// if (x ushr 28 == 0) {
|
|
|
|
|
// n += 4
|
|
|
|
|
// x = x shl 4
|
|
|
|
|
// }
|
|
|
|
|
// if (x ushr 30 == 0) {
|
|
|
|
|
// n += 2
|
|
|
|
|
// x = x shl 2
|
|
|
|
|
// }
|
|
|
|
|
// n -= x ushr 31
|
|
|
|
|
// return n
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// private fun countBitsLength(value: Long): Int {
|
|
|
|
|
// val leadingZeros = numberOfLeadingZeros(value)
|
|
|
|
|
// return java.lang.Long.SIZE - leadingZeros
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// companion object {
|
|
|
|
|
//
|
|
|
|
|
// private val DOUBLE_EXPONENT_WIDTH = 11
|
|
|
|
|
//
|
|
|
|
|
// private val DOUBLE_MANTISSA_WIDTH = 52
|
|
|
|
|
//
|
|
|
|
|
// private val FLOAT_EXPONENT_WIDTH = 8
|
|
|
|
|
//
|
|
|
|
|
// private val FLOAT_MANTISSA_WIDTH = 23
|
|
|
|
|
//
|
|
|
|
|
// private val HEX_RADIX = 16
|
|
|
|
|
//
|
|
|
|
|
// private val MAX_SIGNIFICANT_LENGTH = 15
|
|
|
|
|
//
|
|
|
|
|
// private val HEX_SIGNIFICANT = "0[xX](\\p{XDigit}+\\.?|\\p{XDigit}*\\.\\p{XDigit}+)" //$NON-NLS-1$
|
|
|
|
|
//
|
|
|
|
|
// private val BINARY_EXPONENT = "[pP]([+-]?\\d+)" //$NON-NLS-1$
|
|
|
|
|
//
|
|
|
|
|
// private val FLOAT_TYPE_SUFFIX = "[fFdD]?" //$NON-NLS-1$
|
|
|
|
|
//
|
|
|
|
|
// private val HEX_PATTERN = "[\\x00-\\x20]*([+-]?)$HEX_SIGNIFICANT" + //$NON-NLS-1$
|
|
|
|
|
//
|
|
|
|
|
// BINARY_EXPONENT + FLOAT_TYPE_SUFFIX + "[\\x00-\\x20]*" //$NON-NLS-1$
|
|
|
|
|
//
|
|
|
|
|
// private val PATTERN = Pattern.compile(HEX_PATTERN)
|
|
|
|
|
//
|
|
|
|
|
// /*
|
|
|
|
|
// * Parses the hex string to a double number.
|
|
|
|
|
// */
|
|
|
|
|
// fun parseDouble(hexString: String): Double {
|
|
|
|
|
// val parser = HexStringParser(DOUBLE_EXPONENT_WIDTH,
|
|
|
|
|
// DOUBLE_MANTISSA_WIDTH)
|
|
|
|
|
// val result = parser.parse(hexString)
|
|
|
|
|
// return java.lang.Double.longBitsToDouble(result)
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// /*
|
|
|
|
|
// * Parses the hex string to a float number.
|
|
|
|
|
// */
|
|
|
|
|
// fun parseFloat(hexString: String): Float {
|
|
|
|
|
// val parser = HexStringParser(FLOAT_EXPONENT_WIDTH,
|
|
|
|
|
// FLOAT_MANTISSA_WIDTH)
|
|
|
|
|
// val result = parser.parse(hexString).toInt()
|
|
|
|
|
// return java.lang.Float.intBitsToFloat(result)
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// /*
|
|
|
|
|
// * Analyzes the hex string and extracts the sign and digit segments.
|
|
|
|
|
// */
|
|
|
|
|
// private fun getSegmentsFromHexString(hexString: String): Array<String> {
|
|
|
|
|
// val matcher = PATTERN.matcher(hexString)
|
|
|
|
|
// if (!matcher.matches()) {
|
|
|
|
|
// throw NumberFormatException()
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// val hexSegments = arrayOf(
|
|
|
|
|
// matcher.group(1),
|
|
|
|
|
// matcher.group(2),
|
|
|
|
|
// matcher.group(3)
|
|
|
|
|
// )
|
|
|
|
|
//
|
|
|
|
|
// return hexSegments
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
//}
|
|
|
|
|
internal class HexStringParser(private val EXPONENT_WIDTH: Int, private val MANTISSA_WIDTH: Int) {
|
|
|
|
|
|
|
|
|
|
private val EXPONENT_BASE: Long
|
|
|
|
|
|
|
|
|
|
private val MAX_EXPONENT: Long
|
|
|
|
|
|
|
|
|
|
private val MIN_EXPONENT: Long
|
|
|
|
|
|
|
|
|
|
private val MANTISSA_MASK: Long
|
|
|
|
|
|
|
|
|
|
private var sign: Long = 0
|
|
|
|
|
|
|
|
|
|
private var exponent: Long = 0
|
|
|
|
|
|
|
|
|
|
private var mantissa: Long = 0
|
|
|
|
|
|
|
|
|
|
private var abandonedNumber = "" //$NON-NLS-1$
|
|
|
|
|
|
|
|
|
|
init {
|
|
|
|
|
this.EXPONENT_BASE = (-1L shl (EXPONENT_WIDTH - 1)).inv()
|
|
|
|
|
this.MAX_EXPONENT = (-1L shl EXPONENT_WIDTH).inv()
|
|
|
|
|
this.MIN_EXPONENT = (-(MANTISSA_WIDTH + 1)).toLong()
|
|
|
|
|
this.MANTISSA_MASK = (-1L shl MANTISSA_WIDTH).inv()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun parse(hexString: String): Long {
|
|
|
|
|
val hexSegments = getSegmentsFromHexString(hexString)
|
|
|
|
|
val signStr = hexSegments[0]
|
|
|
|
|
val significantStr = hexSegments[1]
|
|
|
|
|
val exponentStr = hexSegments[2]
|
|
|
|
|
|
|
|
|
|
parseHexSign(signStr)
|
|
|
|
|
parseExponent(exponentStr)
|
|
|
|
|
parseMantissa(significantStr)
|
|
|
|
|
|
|
|
|
|
sign = sign shl (MANTISSA_WIDTH + EXPONENT_WIDTH)
|
|
|
|
|
exponent = exponent shl MANTISSA_WIDTH
|
|
|
|
|
return sign or exponent or mantissa
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Parses the sign field.
|
|
|
|
|
*/
|
|
|
|
|
private fun parseHexSign(signStr: String) {
|
|
|
|
|
this.sign = (if (signStr == "-") 1 else 0).toLong() //$NON-NLS-1$
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Parses the exponent field.
|
|
|
|
|
*/
|
|
|
|
|
private fun parseExponent(exponentStr: String) {
|
|
|
|
|
var exponentStr = exponentStr
|
|
|
|
|
val leadingChar = exponentStr[0]
|
|
|
|
|
val expSign = if (leadingChar == '-') -1 else 1
|
|
|
|
|
if (!leadingChar.isDigit()) {
|
|
|
|
|
exponentStr = exponentStr.substring(1)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
exponent = expSign * exponentStr.toLong()
|
|
|
|
|
checkedAddExponent(EXPONENT_BASE)
|
|
|
|
|
} catch (e: NumberFormatException) {
|
|
|
|
|
exponent = expSign * Long.MAX_VALUE
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Parses the mantissa field.
|
|
|
|
|
*/
|
|
|
|
|
private fun parseMantissa(significantStr: String) {
|
|
|
|
|
val strings = significantStr.split("\\.".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() //$NON-NLS-1$
|
|
|
|
|
val strIntegerPart = strings[0]
|
|
|
|
|
val strDecimalPart = if (strings.size > 1) strings[1] else "" //$NON-NLS-1$
|
|
|
|
|
|
|
|
|
|
var significand = getNormalizedSignificand(strIntegerPart, strDecimalPart)
|
|
|
|
|
if (significand == "0") { //$NON-NLS-1$
|
|
|
|
|
setZero()
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
val offset = getOffset(strIntegerPart, strDecimalPart)
|
|
|
|
|
checkedAddExponent(offset.toLong())
|
|
|
|
|
|
|
|
|
|
if (exponent >= MAX_EXPONENT) {
|
|
|
|
|
setInfinite()
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (exponent <= MIN_EXPONENT) {
|
|
|
|
|
setZero()
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (significand.length > MAX_SIGNIFICANT_LENGTH) {
|
|
|
|
|
abandonedNumber = significand.substring(MAX_SIGNIFICANT_LENGTH)
|
|
|
|
|
significand = significand.substring(0, MAX_SIGNIFICANT_LENGTH)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mantissa = significand.toLong(HEX_RADIX)
|
|
|
|
|
|
|
|
|
|
if (exponent >= 1) {
|
|
|
|
|
processNormalNumber()
|
|
|
|
|
} else {
|
|
|
|
|
processSubNormalNumber()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun setInfinite() {
|
|
|
|
|
exponent = MAX_EXPONENT
|
|
|
|
|
mantissa = 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun setZero() {
|
|
|
|
|
exponent = 0
|
|
|
|
|
mantissa = 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun signum(x: Long) = when {
|
|
|
|
|
x == 0L -> 0
|
|
|
|
|
x > 0L -> 1
|
|
|
|
|
else -> -1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Sets the exponent variable to Long.MAX_VALUE or -Long.MAX_VALUE if
|
|
|
|
|
* overflow or underflow happens.
|
|
|
|
|
*/
|
|
|
|
|
private fun checkedAddExponent(offset: Long) {
|
|
|
|
|
val result = exponent + offset
|
|
|
|
|
val expSign = signum(exponent)
|
|
|
|
|
if (expSign * signum(offset) > 0 && expSign * signum(result) < 0) {
|
|
|
|
|
exponent = expSign * Long.MAX_VALUE
|
|
|
|
|
} else {
|
|
|
|
|
exponent = result
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun processNormalNumber() {
|
|
|
|
|
val desiredWidth = MANTISSA_WIDTH + 2
|
|
|
|
|
fitMantissaInDesiredWidth(desiredWidth)
|
|
|
|
|
round()
|
|
|
|
|
mantissa = mantissa and MANTISSA_MASK
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun processSubNormalNumber() {
|
|
|
|
|
var desiredWidth = MANTISSA_WIDTH + 1
|
|
|
|
|
desiredWidth += exponent.toInt()//lends bit from mantissa to exponent
|
|
|
|
|
exponent = 0
|
|
|
|
|
fitMantissaInDesiredWidth(desiredWidth)
|
|
|
|
|
round()
|
|
|
|
|
mantissa = mantissa and MANTISSA_MASK
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Adjusts the mantissa to desired width for further analysis.
|
|
|
|
|
*/
|
|
|
|
|
private fun fitMantissaInDesiredWidth(desiredWidth: Int) {
|
|
|
|
|
val bitLength = countBitsLength(mantissa)
|
|
|
|
|
if (bitLength > desiredWidth) {
|
|
|
|
|
discardTrailingBits((bitLength - desiredWidth).toLong())
|
|
|
|
|
} else {
|
|
|
|
|
mantissa = mantissa shl (desiredWidth - bitLength)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Stores the discarded bits to abandonedNumber.
|
|
|
|
|
*/
|
|
|
|
|
private fun discardTrailingBits(num: Long) {
|
|
|
|
|
val mask = (-1L shl num.toInt()).inv()
|
|
|
|
|
abandonedNumber += mantissa and mask
|
|
|
|
|
mantissa = mantissa shr num.toInt()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The value is rounded up or down to the nearest infinitely precise result.
|
|
|
|
|
* If the value is exactly halfway between two infinitely precise results,
|
|
|
|
|
* then it should be rounded up to the nearest infinitely precise even.
|
|
|
|
|
*/
|
|
|
|
|
private fun round() {
|
|
|
|
|
val result = abandonedNumber.replace("0+".toRegex(), "") //$NON-NLS-1$ //$NON-NLS-2$
|
|
|
|
|
val moreThanZero = result.length > 0
|
|
|
|
|
|
|
|
|
|
val lastDiscardedBit = (mantissa and 1L).toInt()
|
|
|
|
|
mantissa = mantissa shr 1
|
|
|
|
|
val tailBitInMantissa = (mantissa and 1L).toInt()
|
|
|
|
|
|
|
|
|
|
if (lastDiscardedBit == 1 && (moreThanZero || tailBitInMantissa == 1)) {
|
|
|
|
|
val oldLength = countBitsLength(mantissa)
|
|
|
|
|
mantissa += 1L
|
|
|
|
|
val newLength = countBitsLength(mantissa)
|
|
|
|
|
|
|
|
|
|
//Rounds up to exponent when whole bits of mantissa are one-bits.
|
|
|
|
|
if (oldLength >= MANTISSA_WIDTH && newLength > oldLength) {
|
|
|
|
|
checkedAddExponent(1)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Returns the normalized significand after removing the leading zeros.
|
|
|
|
|
*/
|
|
|
|
|
private fun getNormalizedSignificand(strIntegerPart: String, strDecimalPart: String): String {
|
|
|
|
|
var significand = strIntegerPart + strDecimalPart
|
|
|
|
|
significand = significand.replaceFirst("^0+".toRegex(), "") //$NON-NLS-1$//$NON-NLS-2$
|
|
|
|
|
if (significand.length == 0) {
|
|
|
|
|
significand = "0" //$NON-NLS-1$
|
|
|
|
|
}
|
|
|
|
|
return significand
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Calculates the offset between the normalized number and unnormalized
|
|
|
|
|
* number. In a normalized representation, significand is represented by the
|
|
|
|
|
* characters "0x1." followed by a lowercase hexadecimal representation of
|
|
|
|
|
* the rest of the significand as a fraction.
|
|
|
|
|
*/
|
|
|
|
|
private fun getOffset(strIntegerPart: String, strDecimalPart: String): Int {
|
|
|
|
|
var strIntegerPart = strIntegerPart
|
|
|
|
|
strIntegerPart = strIntegerPart.replaceFirst("^0+".toRegex(), "") //$NON-NLS-1$ //$NON-NLS-2$
|
|
|
|
|
|
|
|
|
|
// If the Integer part is a nonzero number.
|
|
|
|
|
if (strIntegerPart.length != 0) {
|
|
|
|
|
val leadingNumber = strIntegerPart.substring(0, 1)
|
|
|
|
|
return (strIntegerPart.length - 1) * 4 + countBitsLength(leadingNumber.toLong(HEX_RADIX)) - 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the Integer part is a zero number.
|
|
|
|
|
var i = 0
|
|
|
|
|
while (i < strDecimalPart.length && strDecimalPart[i] == '0') {
|
|
|
|
|
i++
|
|
|
|
|
}
|
|
|
|
|
if (i == strDecimalPart.length) {
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
val leadingNumber = strDecimalPart.substring(i, i + 1)
|
|
|
|
|
return (-i - 1) * 4 + countBitsLength(leadingNumber.toLong(HEX_RADIX)) - 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun numberOfLeadingZeros(i: Long): Int {
|
|
|
|
|
// HD, Figure 5-6
|
|
|
|
|
if (i == 0L)
|
|
|
|
|
return 64
|
|
|
|
|
var n = 1
|
|
|
|
|
var x = (i ushr 32).toInt()
|
|
|
|
|
if (x == 0) {
|
|
|
|
|
n += 32
|
|
|
|
|
x = i.toInt()
|
|
|
|
|
}
|
|
|
|
|
if (x ushr 16 == 0) {
|
|
|
|
|
n += 16
|
|
|
|
|
x = x shl 16
|
|
|
|
|
}
|
|
|
|
|
if (x ushr 24 == 0) {
|
|
|
|
|
n += 8
|
|
|
|
|
x = x shl 8
|
|
|
|
|
}
|
|
|
|
|
if (x ushr 28 == 0) {
|
|
|
|
|
n += 4
|
|
|
|
|
x = x shl 4
|
|
|
|
|
}
|
|
|
|
|
if (x ushr 30 == 0) {
|
|
|
|
|
n += 2
|
|
|
|
|
x = x shl 2
|
|
|
|
|
}
|
|
|
|
|
n -= x ushr 31
|
|
|
|
|
return n
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun countBitsLength(value: Long) = 64 - numberOfLeadingZeros(value)
|
|
|
|
|
|
|
|
|
|
companion object {
|
|
|
|
|
|
|
|
|
|
private val DOUBLE_EXPONENT_WIDTH = 11
|
|
|
|
|
|
|
|
|
|
private val DOUBLE_MANTISSA_WIDTH = 52
|
|
|
|
|
|
|
|
|
|
private val FLOAT_EXPONENT_WIDTH = 8
|
|
|
|
|
|
|
|
|
|
private val FLOAT_MANTISSA_WIDTH = 23
|
|
|
|
|
|
|
|
|
|
private val HEX_RADIX = 16
|
|
|
|
|
|
|
|
|
|
private val MAX_SIGNIFICANT_LENGTH = 15
|
|
|
|
|
|
|
|
|
|
private val HEX_SIGNIFICANT = "0[xX](\\p{XDigit}+\\.?|\\p{XDigit}*\\.\\p{XDigit}+)" //$NON-NLS-1$
|
|
|
|
|
|
|
|
|
|
private val BINARY_EXPONENT = "[pP]([+-]?\\d+)" //$NON-NLS-1$
|
|
|
|
|
|
|
|
|
|
private val FLOAT_TYPE_SUFFIX = "[fFdD]?" //$NON-NLS-1$
|
|
|
|
|
|
|
|
|
|
private val HEX_PATTERN = "[\\x00-\\x20]*([+-]?)$HEX_SIGNIFICANT" + //$NON-NLS-1$
|
|
|
|
|
|
|
|
|
|
BINARY_EXPONENT + FLOAT_TYPE_SUFFIX + "[\\x00-\\x20]*" //$NON-NLS-1$
|
|
|
|
|
|
|
|
|
|
private val PATTERN = Regex(HEX_PATTERN)
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Parses the hex string to a double number.
|
|
|
|
|
*/
|
|
|
|
|
fun parseDouble(hexString: String): Double {
|
|
|
|
|
val parser = HexStringParser(DOUBLE_EXPONENT_WIDTH,
|
|
|
|
|
DOUBLE_MANTISSA_WIDTH)
|
|
|
|
|
val result = parser.parse(hexString)
|
|
|
|
|
return longBitsToDouble(result)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Parses the hex string to a float number.
|
|
|
|
|
*/
|
|
|
|
|
fun parseFloat(hexString: String): Float {
|
|
|
|
|
val parser = HexStringParser(FLOAT_EXPONENT_WIDTH,
|
|
|
|
|
FLOAT_MANTISSA_WIDTH)
|
|
|
|
|
val result = parser.parse(hexString).toInt()
|
|
|
|
|
return intBitsToFloat(result)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Analyzes the hex string and extracts the sign and digit segments.
|
|
|
|
|
*/
|
|
|
|
|
private fun getSegmentsFromHexString(hexString: String): Array<String> {
|
|
|
|
|
val matchResult = PATTERN.matchEntire(hexString)
|
|
|
|
|
if (matchResult == null) {
|
|
|
|
|
throw NumberFormatException()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
val hexSegments = arrayOf(
|
|
|
|
|
matchResult.groupValues[1],
|
|
|
|
|
matchResult.groupValues[2],
|
|
|
|
|
matchResult.groupValues[3]
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
return hexSegments
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|