| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "FloatingPointParser.h" |
| #include <decaf/lang/Math.h> |
| #include <decaf/lang/Integer.h> |
| #include <decaf/lang/Long.h> |
| #include <decaf/lang/Float.h> |
| #include <decaf/lang/Double.h> |
| #include <decaf/lang/Character.h> |
| #include <decaf/internal/util/HexStringParser.h> |
| #include <decaf/internal/util/BigInt.h> |
| #include <decaf/internal/util/BitOps.h> |
| #include <decaf/lang/exceptions/NumberFormatException.h> |
| #include <apr_lib.h> |
| #include <errno.h> |
| |
| using namespace std; |
| using namespace decaf; |
| using namespace decaf::lang; |
| using namespace decaf::internal; |
| using namespace decaf::internal::util; |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| const int FloatingPointParser::tens[11] = { |
| 0x3f800000, |
| 0x41200000, |
| 0x42c80000, |
| 0x447a0000, |
| 0x461c4000, |
| 0x47c35000, |
| 0x49742400, |
| 0x4b189680, |
| 0x4cbebc20, |
| 0x4e6e6b28, |
| 0x501502f9 /* 10 ^ 10 in float */ |
| }; |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| double FloatingPointParser::parseDblImpl( const std::string& value, int exp ) |
| throw ( exceptions::NumberFormatException ) { |
| |
| // assumes s is a null terminated string with at least one |
| // character in it |
| unsigned long long def[17] = {0}; |
| unsigned long long defBackup[17] = {0}; |
| unsigned long long* f = def; |
| unsigned long long* fNoOverflow = defBackup; |
| unsigned long long* tempBackup = NULL; |
| unsigned int overflow = 0; |
| unsigned long long result = 0; |
| int index = 1; |
| int unprocessedDigits = 0; |
| std::string::const_iterator valItr = value.begin(); |
| |
| do { |
| |
| if( Character::isDigit( *valItr ) ) { |
| |
| // Make a back up of f before appending, so that we can |
| // back out of it if there is no more room, i.e. index > |
| // MAX_ACCURACY_WIDTH. |
| |
| memcpy( fNoOverflow, f, sizeof(unsigned long long) * index ); |
| overflow = BigInt::simpleAppendDecimalDigitHighPrecision( |
| f, index, *valItr - '0' ); |
| |
| if( overflow ) { |
| f[index++] = overflow; |
| /* There is an overflow, but there is no more room |
| * to store the result. We really only need the top 52 |
| * bits anyway, so we must back out of the overflow, |
| * and ignore the rest of the string. |
| */ |
| if( index >= MAX_ACCURACY_WIDTH ) { |
| index--; |
| memcpy( f, fNoOverflow, sizeof(unsigned long long) * index); |
| break; |
| } |
| |
| if( tempBackup ) { |
| fNoOverflow = tempBackup; |
| } |
| } |
| } else { |
| // Bad chars in the string |
| BitOps::LOW_I32_FROM_LONG64( result ) = -1; |
| BitOps::HIGH_I32_FROM_LONG64( result ) = -1; |
| return Double::longBitsToDouble( result ); |
| } |
| |
| } while( ++valItr != value.end() ); |
| |
| // We've broken out of the parse loop either because we've reached |
| // the end of the string or we've overflowed the maximum accuracy |
| // limit of a double. If we still have unprocessed digits in the |
| // given string, then there are three possible results: |
| // 1. (unprocessed digits + e) == 0, in which case we simply |
| // convert the existing bits that are already parsed |
| // 2. (unprocessed digits + e) < 0, in which case we simply |
| // convert the existing bits that are already parsed along |
| // with the given e |
| // 3. (unprocessed digits + e) > 0 indicates that the value is |
| // simply too big to be stored as a double, so return Infinity |
| if( ( unprocessedDigits = value.length() ) > 0 ) { |
| |
| exp += unprocessedDigits; |
| if( exp == 0 ) { |
| return BigInt::toDoubleHighPrecision( f, index ); |
| } else if( exp < 0 ) { |
| return BitOps::CREATE_DOUBLE_BITS( f, index, exp ); |
| } else { |
| result = BitOps::INFINITE_LONGBITS; |
| } |
| |
| } else { |
| |
| if( exp == 0 ) { |
| return BigInt::toDoubleHighPrecision( f, index ); |
| } else { |
| return BitOps::CREATE_DOUBLE_BITS( f, index, exp ); |
| } |
| } |
| |
| return Double::longBitsToDouble( result ); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| float FloatingPointParser::parseFltImpl( const std::string& value, int exp ) |
| throw ( exceptions::NumberFormatException ) { |
| |
| float result = FloatingPointParser::createFloat( value, exp ); |
| |
| std::cout << std::endl |
| << "DEBUG - FloatingPointParser::parseFltImpl - " |
| << "createFloat returned = " << result << std::endl; |
| |
| if( Float::floatToIntBits( result ) >= 0 ) { |
| return result; |
| } else if( Float::floatToIntBits( result ) == -1 ) { |
| throw exceptions::NumberFormatException( |
| __FILE__, __LINE__, |
| "FloatingPointParser::parseFltImpl - Not a valid float string", |
| value.c_str() ); |
| } |
| |
| return result; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| FloatingPointParser::StringExponentPair FloatingPointParser::initialParse( |
| const std::string& value, int length ) throw ( exceptions::NumberFormatException ){ |
| |
| std::string newValue = value; |
| bool negative = false; |
| char c; |
| int start = 0; |
| int end = 0; |
| int decimal = 0; |
| int e = 0; |
| |
| if( length == 0 ) { |
| throw exceptions::NumberFormatException( |
| __FILE__, __LINE__, |
| "FloatingPointParser::initialParse - Invalid zero length string"); |
| } |
| |
| c = newValue[length - 1]; |
| if( c == 'D' || c == 'd' || c == 'F' || c == 'f') { |
| length--; |
| if( length == 0 ) { |
| throw exceptions::NumberFormatException( |
| __FILE__, __LINE__, |
| "FloatingPointParser::initialParse - Invalid zero length string"); |
| } |
| } |
| |
| end = Math::max( (int)newValue.find_first_of( 'E' ), |
| (int)newValue.find_first_of( 'e' ) ); |
| |
| if( (std::size_t)end != string::npos ) { |
| |
| if( end + 1 == length ) { |
| if( length == 0 ) { |
| throw exceptions::NumberFormatException( |
| __FILE__, __LINE__, |
| "FloatingPointParser::initialParse - Invalid no data after e", |
| newValue.c_str() ); |
| } |
| } |
| |
| int exponent_offset = end + 1; |
| |
| if( newValue[exponent_offset] == '+' ) { |
| if( newValue[exponent_offset + 1] == '-' ) { |
| if( length == 0 ) { |
| throw exceptions::NumberFormatException( |
| __FILE__, __LINE__, |
| "FloatingPointParser::initialParse - " |
| "Invalid length string"); |
| } |
| } |
| exponent_offset++; // skip the plus sign |
| } |
| |
| try { |
| e = Integer::parseInt( newValue.substr( exponent_offset, length ) ); |
| } catch( exceptions::NumberFormatException ex ) { |
| // ex contains the exponent substring only so throw a |
| // new exception with the correct string |
| throw exceptions::NumberFormatException( |
| __FILE__, __LINE__, |
| "FloatingPointParser::initialParse - " |
| "exponent string is not valid" ); |
| } |
| |
| } else { |
| end = length; |
| } |
| |
| if( length == 0 ) { |
| throw exceptions::NumberFormatException( |
| __FILE__, __LINE__, |
| "FloatingPointParser::initialParse - " |
| "invalid length string", newValue.c_str() ); |
| } |
| |
| c = newValue[start]; |
| |
| if( c == '-') { |
| ++start; |
| --length; |
| negative = true; |
| } else if( c == '+' ) { |
| ++start; |
| --length; |
| } |
| |
| if( length == 0 ) { |
| throw exceptions::NumberFormatException( |
| __FILE__, __LINE__, |
| "FloatingPointParser::initialParse - " |
| "invalid length string", newValue.c_str() ); |
| } |
| |
| decimal = newValue.find_first_of( '.' ); |
| if( decimal > -1 ) { |
| e -= end - decimal - 1; |
| newValue = newValue.substr( start, decimal ) + newValue.substr( decimal + 1, end ); |
| } else { |
| newValue = newValue.substr( start, end ); |
| } |
| |
| if( ( length = newValue.length() ) == 0 ) { |
| throw exceptions::NumberFormatException( |
| __FILE__, __LINE__, |
| "FloatingPointParser::initialParse - " |
| "invalid length string", newValue.c_str() ); |
| } |
| |
| end = length; |
| while( end > 1 && newValue[end - 1] == '0' ) { |
| --end; |
| } |
| |
| start = 0; |
| while( start < end - 1 && newValue[start] == '0' ) { |
| start++; |
| } |
| |
| if( end != length || start != 0 ) { |
| e += length - end; |
| newValue = newValue.substr( start, end ); |
| } |
| |
| return StringExponentPair( newValue, e, negative ); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| double FloatingPointParser::parseDblName( |
| const std::string& namedDouble, int length ) |
| throw( exceptions::NumberFormatException ) { |
| |
| // Valid strings are only +Nan, NaN, -Nan, +Infinity, Infinity, |
| // -Infinity. |
| if( (length != 3) && ( length != 4) && ( length != 8) && ( length != 9 ) ) { |
| throw exceptions::NumberFormatException( |
| __FILE__, __LINE__, |
| "FloatingPointParser::parseDblName - " |
| "invalid name string", namedDouble.c_str() ); |
| } |
| |
| bool negative = namedDouble.at(0) == '-' ? true : false; |
| |
| if( namedDouble.find( "Infinity" ) != string::npos ) { |
| return negative ? Double::NEGATIVE_INFINITY : Float::POSITIVE_INFINITY; |
| } |
| |
| if( namedDouble.find( "NaN" ) != string::npos ) { |
| return Double::NaN; |
| } |
| |
| throw exceptions::NumberFormatException( |
| __FILE__, __LINE__, |
| "FloatingPointParser::parseDblName - " |
| "invalid name string", namedDouble.c_str() ); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| float FloatingPointParser::parseFltName( |
| const std::string& namedFloat, int length ) |
| throw( exceptions::NumberFormatException ) { |
| |
| // Valid strings are only +Nan, NaN, -Nan, +Infinity, Infinity, |
| // -Infinity. |
| if( ( length != 3 ) && ( length != 4 ) && ( length != 8 ) && ( length != 9 ) ) { |
| throw exceptions::NumberFormatException( |
| __FILE__, __LINE__, |
| "FloatingPointParser::parseFltName - " |
| "invalid name string", namedFloat.c_str() ); |
| } |
| |
| bool negative = namedFloat.at(0) == '-' ? true : false; |
| |
| if( namedFloat.find( "Infinitiy" ) != string::npos ) { |
| return negative ? Float::NEGATIVE_INFINITY : Float::POSITIVE_INFINITY; |
| } |
| |
| if( namedFloat.find( "NaN" ) != string::npos ) { |
| return Float::NaN; |
| } |
| |
| throw exceptions::NumberFormatException( |
| __FILE__, __LINE__, |
| "FloatingPointParser::parseFltName - " |
| "invalid name string", namedFloat.c_str() ); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| double FloatingPointParser::parseDouble( const std::string& value ) |
| throw( exceptions::NumberFormatException ) { |
| |
| std::string newValue = value; |
| FloatingPointParser::trim( newValue ); |
| int length = newValue.length(); |
| |
| if( length == 0 ) { |
| throw exceptions::NumberFormatException( |
| __FILE__, __LINE__, |
| "FloatingPointParser::parseDouble - " |
| "invalid length string", value.c_str() ); |
| } |
| |
| // See if this could be a named double |
| char last = newValue[length - 1]; |
| |
| if( (last == 'y') || (last == 'N') ) { |
| return parseDblName( newValue, length ); |
| } |
| |
| // See if it could be a hexadecimal representation |
| if( toLowerCase( newValue ).find( "0x" ) != string::npos ) { |
| return HexStringParser::parseDouble(value); |
| } |
| |
| StringExponentPair info = initialParse(value, length); |
| |
| double result = parseDblImpl( info.value, info.exp ); |
| |
| if( info.negative ) { |
| result = -result; |
| } |
| |
| return result; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| float FloatingPointParser::parseFloat( const std::string& value ) |
| throw( exceptions::NumberFormatException ) { |
| |
| std::string newValue = value; |
| FloatingPointParser::trim( newValue ); |
| |
| int length = newValue.length(); |
| |
| if( length == 0 ) { |
| throw exceptions::NumberFormatException( |
| __FILE__, __LINE__, |
| "FloatingPointParser::parseFloat - " |
| "invalid length string", value.c_str() ); |
| } |
| |
| // See if this could be a named float |
| char last = newValue[length - 1]; |
| if( (last == 'y') || (last == 'N') ) { |
| return parseFltName( value, length ); |
| } |
| |
| // See if it could be a hexadecimal representation |
| if( toLowerCase( newValue ).find( "0x" ) != string::npos ) { |
| return HexStringParser::parseFloat( newValue ); |
| } |
| |
| StringExponentPair info = initialParse( newValue, length ); |
| |
| std::cout << std::endl |
| << "DEBUG - FloatingPointParser::parseFloat - " |
| << "newValue = " << newValue << ", length = " << length; |
| |
| float result = parseFltImpl( info.value, info.exp ); |
| if( info.negative ) { |
| result = -result; |
| } |
| |
| return result; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| std::string& FloatingPointParser::trim( std::string& value ) { |
| |
| // trim leading whitespace |
| string::size_type notwhite = value.find_first_not_of( " \t\r\n" ); |
| value.erase( 0, notwhite ); |
| |
| // trim trailing whitespace |
| notwhite = value.find_last_not_of( " \t\r\n" ); |
| value.erase( notwhite+1 ); |
| |
| return value; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| std::string& FloatingPointParser::toLowerCase( std::string& value ) { |
| |
| string::size_type index = 0; |
| |
| for( ; index < value.size(); ++index ) { |
| if( Character::isLetter( value[index] ) ) { |
| value[index] = apr_tolower( value[index] ); |
| } |
| } |
| |
| return value; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| float FloatingPointParser::createFloat( const std::string&s, int exp ) { |
| |
| // assumes s is a null terminated string with at least one |
| // character in it |
| unsigned long long def[DEFAULT_WIDTH] = {0}; |
| unsigned long long defBackup[DEFAULT_WIDTH] = {0}; |
| unsigned long long* f = def; |
| unsigned long long* fNoOverflow = defBackup; |
| unsigned long long* tempBackup = NULL; |
| unsigned int overflow = 0; |
| unsigned int result = 0; |
| int index = 1; |
| int unprocessedDigits = 0; |
| std::string::const_iterator sIter = s.begin(); |
| |
| do { |
| |
| if( Character::isDigit( *sIter ) ) { |
| |
| std::cout << std::endl |
| << "DEBUG - FloatingPointParser::createFloat - " |
| << "current digint ASCII = " << *sIter |
| << ", value = " << *sIter - '0'; |
| |
| // Make a back up of f before appending, so that we can |
| // back out of it if there is no more room, i.e. index > |
| // MAX_ACCURACY_WIDTH. |
| memcpy( fNoOverflow, f, sizeof(unsigned long long) * index ); |
| overflow = BigInt::simpleAppendDecimalDigitHighPrecision( |
| f, index, *sIter - '0' ); |
| |
| std::cout << std::endl |
| << "DEBUG - FloatingPointParser::createFloat - " |
| << "f[index] = " << f[index] |
| << ", overflow ? = " << overflow; |
| |
| if( overflow ) { |
| |
| f[index++] = overflow; |
| |
| // There is an overflow, but there is no more room |
| // to store the result. We really only need the top 52 |
| // bits anyway, so we must back out of the overflow, |
| // and ignore the rest of the string. |
| if( index >= MAX_ACCURACY_WIDTH ) { |
| index--; |
| memcpy( f, fNoOverflow, sizeof(unsigned long long)* index ); |
| break; |
| } |
| |
| if( tempBackup ) { |
| fNoOverflow = tempBackup; |
| } |
| } |
| } else { |
| // String contained invalid characters |
| return -1; |
| } |
| } while( ++sIter != s.end() ); |
| |
| // We've broken out of the parse loop either because we've reached |
| // the end of the string or we've overflowed the maximum accuracy |
| // limit of a double. If we still have unprocessed digits in the |
| // given string, then there are three possible results: |
| // 1. (unprocessed digits + e) == 0, in which case we simply |
| // convert the existing bits that are already parsed |
| // 2. (unprocessed digits + e) < 0, in which case we simply |
| // convert the existing bits that are already parsed along |
| // with the given e |
| // 3. (unprocessed digits + e) > 0 indicates that the value is |
| // simply too big to be stored as a double, so return Infinity |
| if( ( unprocessedDigits = std::distance( sIter, s.end() ) ) > 0 ) { |
| |
| exp += unprocessedDigits; |
| |
| if( exp <= 0 ) { |
| return createFloat1( f, index, exp ); |
| } else { |
| result = BitOps::INFINITE_INTBITS; |
| } |
| |
| } else { |
| return createFloat1( f, index, exp ); |
| } |
| |
| return Float::intBitsToFloat( result ); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| float FloatingPointParser::createFloat1( unsigned long long* f, int length, int exp ) { |
| |
| int numBits = BigInt::highestSetBitHighPrecision( f, length ) + 1; |
| double dresult = 0.0; |
| int result = 0; |
| |
| numBits -= BigInt::lowestSetBitHighPrecision( f, length ); |
| |
| if( numBits < 25 && exp >= 0 && exp < LOG5_OF_TWO_TO_THE_N ) { |
| return Float::intBitsToFloat( BitOps::LOW_I32_FROM_LONG64_PTR( f ) ) * |
| Float::intBitsToFloat( tenToTheE( exp ) ); |
| } else if( numBits < 25 && exp < 0 && (-exp) < LOG5_OF_TWO_TO_THE_N ) { |
| return Float::intBitsToFloat( BitOps::LOW_I32_FROM_LONG64_PTR( f ) ) * |
| Float::intBitsToFloat( tenToTheE( -exp ) ); |
| } else if (exp >= 0 && exp < 39) { |
| result = Float::floatToIntBits( |
| (float)( BigInt::toDoubleHighPrecision( f, length ) * Math::pow( 10.0, exp ) ) ); |
| } else if( exp >= 39 ) { |
| // Convert the partial result to make sure that the |
| // non-exponential part is not zero. This check fixes the case |
| // where the user enters 0.0e309! |
| dresult = BigInt::toDoubleHighPrecision( f, length ); |
| |
| if( dresult == 0.0 ) { |
| result = BitOps::MINIMUM_INTBITS; |
| } else { |
| result = BitOps::INFINITE_INTBITS; |
| } |
| |
| } else if( exp > -309 ) { |
| |
| int dexp; |
| unsigned int fmant, fovfl; |
| unsigned long long dmant; |
| dresult = BigInt::toDoubleHighPrecision( f, length ) / Math::pow( 10.0, -exp ); |
| |
| if( BitOps::IS_DENORMAL_DBL( dresult ) ) { |
| return 0.0f; |
| } |
| |
| dexp = BigInt::doubleExponent( dresult ) + 51; |
| dmant = BigInt::doubleMantissa( dresult ); |
| |
| // Is it too small to be represented by a single-precision |
| // float? |
| if( dexp <= -155 ) { |
| return 0.0f; |
| } |
| |
| // Is it a denormalized single-precision float? |
| if( (dexp <= -127) && (dexp > -155) ) { |
| |
| // Only interested in 24 msb bits of the 53-bit double mantissa |
| fmant = (unsigned int) (dmant >> 29); |
| fovfl = ((unsigned int) (dmant & 0x1FFFFFFF)) << 3; |
| |
| while( (dexp < -127) && ((fmant | fovfl) != 0) ) { |
| if( (fmant & 1) != 0 ) { |
| fovfl |= 0x80000000; |
| } |
| fovfl >>= 1; |
| fmant >>= 1; |
| dexp++; |
| } |
| |
| if( (fovfl & 0x80000000) != 0) { |
| if( (fovfl & 0x7FFFFFFC) != 0 ) { |
| fmant++; |
| } else if( (fmant & 1) != 0 ) { |
| fmant++; |
| } |
| } else if( (fovfl & 0x40000000) != 0 ) { |
| |
| if( (fovfl & 0x3FFFFFFC) != 0 ) { |
| fmant++; |
| } |
| } |
| |
| result = fmant; |
| } else { |
| result = Float::floatToIntBits( (float)dresult ); |
| } |
| } |
| |
| // Don't go straight to zero as the fact that x*0 = 0 independent |
| // of x might cause the algorithm to produce an incorrect result. |
| // Instead try the min value first and let it fall to zero if need be. |
| if( exp <= -309 || result == 0 ) { |
| result = BitOps::MINIMUM_INTBITS; |
| } |
| |
| return floatAlgorithm( f, length, exp, Float::intBitsToFloat( result ) ); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| float FloatingPointParser::floatAlgorithm( |
| unsigned long long* f, int length, int exp, float z ) { |
| |
| unsigned long long m = 0; |
| int k = 0; |
| int comparison = 0; |
| int comparison2 = 0; |
| unsigned long long* x = NULL; |
| unsigned long long* y = NULL; |
| unsigned long long* D = NULL; |
| unsigned long long* D2 = NULL; |
| int xLength = 0; |
| int yLength = 0; |
| int DLength = 0; |
| int D2Length = 0; |
| int decApproxCount = 0; |
| int incApproxCount = 0; |
| int result = Float::floatToIntBits( z ); |
| |
| do { |
| |
| m = BigInt::floatMantissa( z ); |
| k = BigInt::floatExponent( z ); |
| |
| if( exp >= 0 && k >= 0 ) { |
| |
| xLength = sizeOfTenToTheE( exp ) + length; |
| x = new unsigned long long[xLength]; |
| memset( x + length, 0, sizeof(unsigned long long) * (xLength - length) ); |
| memcpy( x, f, sizeof(unsigned long long) * length ); |
| BigInt::timesTenToTheEHighPrecision( x, xLength, exp ); |
| |
| yLength = (k >> 6) + 2; |
| y = new unsigned long long[yLength]; |
| memset( y + 1, 0, sizeof(unsigned long long) * (yLength - 1) ); |
| *y = m; |
| BigInt::simpleShiftLeftHighPrecision (y, yLength, k); |
| |
| } else if( exp >= 0 ) { |
| |
| xLength = sizeOfTenToTheE (exp) + length + ((-k) >> 6) + 1; |
| x = new unsigned long long[xLength]; |
| memset( x + length, 0, sizeof(unsigned long long) * (xLength - length) ); |
| memcpy( x, f, sizeof(unsigned long long) * length ); |
| BigInt::timesTenToTheEHighPrecision( x, xLength, exp ); |
| BigInt::simpleShiftLeftHighPrecision( x, xLength, -k ); |
| |
| yLength = 1; |
| y = new unsigned long long[yLength]; |
| *y = m; |
| |
| } else if( k >= 0 ) { |
| |
| xLength = length; |
| x = f; |
| |
| yLength = sizeOfTenToTheE( -exp ) + 2 + ( k >> 6 ); |
| y = new unsigned long long[yLength]; |
| memset( y + 1, 0, sizeof(unsigned long long) * (yLength - 1)) ; |
| *y = m; |
| BigInt::timesTenToTheEHighPrecision( y, yLength, -exp ); |
| BigInt::simpleShiftLeftHighPrecision( y, yLength, k ); |
| |
| } else { |
| |
| xLength = length + ((-k) >> 6) + 1; |
| x = new unsigned long long[xLength]; |
| memset( x + length, 0, sizeof(unsigned long long) * (xLength - length) ); |
| memcpy( x, f, sizeof(unsigned long long) * length ); |
| BigInt::simpleShiftLeftHighPrecision( x, xLength, -k ); |
| |
| yLength = sizeOfTenToTheE( -exp ) + 1; |
| y = new unsigned long long[yLength]; |
| memset( y + 1, 0, sizeof(unsigned long long) * (yLength - 1) ); |
| *y = m; |
| BigInt::timesTenToTheEHighPrecision( y, yLength, -exp ); |
| } |
| |
| comparison = BigInt::compareHighPrecision( x, xLength, y, yLength ); |
| if( comparison > 0 ) { |
| // x > y |
| DLength = xLength; |
| D = new unsigned long long[DLength]; |
| memcpy( D, x, DLength * sizeof(unsigned long long) ); |
| BigInt::subtractHighPrecision( D, DLength, y, yLength ); |
| } else if( comparison ) { |
| // y > x |
| DLength = yLength; |
| D = new unsigned long long[DLength]; |
| memcpy (D, y, DLength * sizeof (unsigned long long)); |
| BigInt::subtractHighPrecision( D, DLength, x, xLength ); |
| } else { |
| /* y == x */ |
| DLength = 1; |
| D = new unsigned long long[DLength]; |
| *D = 0; |
| } |
| |
| D2Length = DLength + 1; |
| D = new unsigned long long[DLength]; |
| m <<= 1; |
| BigInt::multiplyHighPrecision( D, DLength, &m, 1, D2, D2Length ); |
| m >>= 1; |
| |
| comparison2 = BigInt::compareHighPrecision( D2, D2Length, y, yLength ); |
| if( comparison2 < 0 ) { |
| if( comparison < 0 && m == BitOps::NORMAL_MASK ) { |
| |
| BigInt::simpleShiftLeftHighPrecision( D2, D2Length, 1 ); |
| if( BigInt::compareHighPrecision( D2, D2Length, y, yLength) > 0 ) { |
| --result; |
| decApproxCount++; |
| if( ( incApproxCount > 2 ) && ( decApproxCount > 2 ) ) { |
| if( decApproxCount > incApproxCount ) { |
| result += decApproxCount - incApproxCount; |
| } else if( incApproxCount > decApproxCount ) { |
| result -= incApproxCount - decApproxCount; |
| } |
| break; |
| } |
| } else { |
| break; |
| } |
| } else { |
| break; |
| } |
| } else if( comparison2 == 0 ) { |
| |
| if( (m & 1) == 0 ) { |
| if( comparison < 0 && m == BitOps::NORMAL_MASK ) { |
| --result; |
| decApproxCount++; |
| if( ( incApproxCount > 2 ) && ( decApproxCount > 2 ) ) { |
| if( decApproxCount > incApproxCount ) { |
| result += decApproxCount - incApproxCount; |
| } else if( incApproxCount > decApproxCount ) { |
| result -= incApproxCount - decApproxCount; |
| } |
| break; |
| } |
| } else { |
| break; |
| } |
| } else if( comparison < 0 ) { |
| --result; |
| decApproxCount++; |
| if( ( incApproxCount > 2 ) && ( decApproxCount > 2 ) ) { |
| if( decApproxCount > incApproxCount ) { |
| result += decApproxCount - incApproxCount; |
| } else if( incApproxCount > decApproxCount ) { |
| result -= incApproxCount - decApproxCount; |
| } |
| break; |
| } |
| break; |
| } else { |
| ++result; |
| incApproxCount++; |
| if( ( incApproxCount > 2 ) && ( decApproxCount > 2 ) ) { |
| if( decApproxCount > incApproxCount ) { |
| result += decApproxCount - incApproxCount; |
| } else if( incApproxCount > decApproxCount ) { |
| result -= incApproxCount - decApproxCount; |
| } |
| } |
| break; |
| } |
| } else if( comparison < 0 ) { |
| --result; |
| decApproxCount++; |
| if( ( incApproxCount > 2 ) && ( decApproxCount > 2 ) ) { |
| if( decApproxCount > incApproxCount ) { |
| result += decApproxCount - incApproxCount; |
| } else if( incApproxCount > decApproxCount ) { |
| result -= incApproxCount - decApproxCount; |
| } |
| break; |
| } |
| } else { |
| if( (unsigned int)result == BitOps::FLOAT_EXPONENT_MASK ) { |
| break; |
| } |
| |
| if( ( incApproxCount > 2 ) && ( decApproxCount > 2 ) ) { |
| if( decApproxCount > incApproxCount ) { |
| result += decApproxCount - incApproxCount; |
| } else if( incApproxCount > decApproxCount ) { |
| result -= incApproxCount - decApproxCount; |
| } |
| break; |
| } |
| } |
| } |
| while( true ); |
| |
| delete x; |
| delete y; |
| delete D; |
| delete D2; |
| |
| return Float::intBitsToFloat( result ); |
| } |