Uncommented hex floating point parser

This commit is contained in:
Igor Chevdar
2017-06-20 14:35:30 +03:00
parent 501a40501e
commit ed0c78167b
4 changed files with 370 additions and 349 deletions
+11
View File
@@ -53,6 +53,17 @@ KDouble Konan_NumberConverter_ceil(KDouble x) {
}
void Kotlin_IntArray_set(KRef thiz, KInt index, KInt value);
KDouble Konan_long_bits_to_double(KLong x);
}
KDouble Konan_long_bits_to_double(KLong x) {
union {
int64_t x;
double d;
} tmp;
tmp.x = x;
return tmp.d;
}
KDouble createDouble (const char *s, KInt e);
+12 -2
View File
@@ -39,8 +39,18 @@
#define DEFAULT_WIDTH MAX_ACCURACY_WIDTH
extern "C" {
KFloat
Konan_FloatingPointParser_parseFloatImpl (KString s, KInt e);
KFloat Konan_FloatingPointParser_parseFloatImpl (KString s, KInt e);
KFloat Konan_int_bits_to_float(KInt x);
}
KFloat Konan_int_bits_to_float(KInt x) {
union {
int32_t x;
float f;
} tmp;
tmp.x = x;
return tmp.f;
}
KFloat createFloat1 (U_64 * f, IDATA length, KInt e);
@@ -336,8 +336,7 @@ object FloatingPointParser {
// See if it could be a hexadecimal representation.
if (parseAsHex(s)) {
TODO("Hex format is not supported")
//return HexStringParser.parseDouble(s)
return HexStringParser.parseDouble(s)
}
val info = initialParse(s, length)
@@ -389,8 +388,7 @@ object FloatingPointParser {
// See if it could be a hexadecimal representation.
if (parseAsHex(s)) {
TODO("Hex format is not supported")
//return HexStringParser.parseFloat(s)
return HexStringParser.parseFloat(s)
}
val info = initialParse(s, length)
@@ -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
}
}
}