Java Number Value Of valueOfHexDoubleLiteral(char[] source)

Here you can find the source of valueOfHexDoubleLiteral(char[] source)

Description

Returns the double value corresponding to the given hexadecimal floating-point double precision literal.

License

Open Source License

Parameter

Parameter Description
source source string containing double precision hexadecimal floating-point literal

Return

the double value, including Double.POSITIVE_INFINITY if the non-zero value is too large to be represented, and Double.NaN if the non-zero value is too small to be represented

Declaration

public static double valueOfHexDoubleLiteral(char[] source) 

Method Source Code

//package com.java2s;
/*******************************************************************************
 * Copyright (c) 2004, 2007 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors://w  ww .j  a  va 2 s. com
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/

public class Main {
    private static final int DOUBLE_FRACTION_WIDTH = 52;
    private static final int DOUBLE_PRECISION = 53;
    private static final int MAX_DOUBLE_EXPONENT = +1023;
    private static final int MIN_NORMALIZED_DOUBLE_EXPONENT = -1022;
    private static final int MIN_UNNORMALIZED_DOUBLE_EXPONENT = MIN_NORMALIZED_DOUBLE_EXPONENT - DOUBLE_PRECISION;
    private static final int DOUBLE_EXPONENT_BIAS = +1023;
    private static final int DOUBLE_EXPONENT_SHIFT = 52;
    private static final int SINGLE_FRACTION_WIDTH = 23;
    private static final int SINGLE_PRECISION = 24;
    private static final int MAX_SINGLE_EXPONENT = +127;
    private static final int MIN_NORMALIZED_SINGLE_EXPONENT = -126;
    private static final int MIN_UNNORMALIZED_SINGLE_EXPONENT = MIN_NORMALIZED_SINGLE_EXPONENT - SINGLE_PRECISION;
    private static final int SINGLE_EXPONENT_BIAS = +127;
    private static final int SINGLE_EXPONENT_SHIFT = 23;

    /**
     * Returns the double value corresponding to the given
     * hexadecimal floating-point double precision literal.
     * The literal must be syntactially correct, and must be
     * a double literal (end in an optional 'd' or 'D').
     * It must not include either leading or trailing whitespace or
     * a sign.
     * <p>
     * This method returns the same answer as
     * Double.parseDouble(new String(source)) does in JDK 1.5,
     * except that this method throw NumberFormatException in
     * the case of overflow to infinity or underflow to 0.
     * The method handles all the tricky cases, including
     * fraction rounding to 53 bits and gradual underflow.
     * </p>
     *
     * @param source source string containing double precision
     * hexadecimal floating-point literal
     * @return the double value, including Double.POSITIVE_INFINITY
     * if the non-zero value is too large to be represented, and
     * Double.NaN if the non-zero value is too small to be represented
     */
    public static double valueOfHexDoubleLiteral(char[] source) {
        long bits = convertHexFloatingPointLiteralToBits(source);
        return Double.longBitsToDouble(bits);
    }

    /**
     * Returns the given hexadecimal floating-point literal as
     * the bits for a single-precision  (float) or a
     * double-precision (double) IEEE floating point number.
     * The literal must be syntactially correct.  It must not
     * include either leading or trailing whitespace or a sign.
     *
     * @param source source string containing hexadecimal floating-point literal
     * @return for double precision literals, bits suitable
     * for passing to Double.longBitsToDouble; for single precision literals,
     * bits suitable for passing to Single.intBitsToDouble in the bottom
     * 32 bits of the result
     * @throws NumberFormatException if the number cannot be parsed
     */
    private static long convertHexFloatingPointLiteralToBits(char[] source) {
        int length = source.length;
        long mantissa = 0;

        // Step 1: process the '0x' lead-in
        int next = 0;
        char nextChar = source[next];
        nextChar = source[next];
        if (nextChar == '0') {
            next++;
        } else {
            throw new NumberFormatException();
        }
        nextChar = source[next];
        if (nextChar == 'X' || nextChar == 'x') {
            next++;
        } else {
            throw new NumberFormatException();
        }

        // Step 2: process leading '0's either before or after the '.'
        int binaryPointPosition = -1;
        loop: while (true) {
            nextChar = source[next];
            switch (nextChar) {
            case '0':
                next++;
                continue loop;
            case '.':
                binaryPointPosition = next;
                next++;
                continue loop;
            default:
                break loop;
            }
        }

        // Step 3: process the mantissa
        // leading zeros have been trimmed
        int mantissaBits = 0;
        int leadingDigitPosition = -1;
        loop: while (true) {
            nextChar = source[next];
            int hexdigit;
            switch (nextChar) {
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
                hexdigit = nextChar - '0';
                break;
            case 'a':
            case 'b':
            case 'c':
            case 'd':
            case 'e':
            case 'f':
                hexdigit = (nextChar - 'a') + 10;
                break;
            case 'A':
            case 'B':
            case 'C':
            case 'D':
            case 'E':
            case 'F':
                hexdigit = (nextChar - 'A') + 10;
                break;
            case '.':
                binaryPointPosition = next;
                next++;
                continue loop;
            default:
                if (binaryPointPosition < 0) {
                    // record virtual '.' as being to right of all digits
                    binaryPointPosition = next;
                }
                break loop;
            }
            if (mantissaBits == 0) {
                // this is the first non-zero hex digit
                // ignore leading binary 0's in hex digit
                leadingDigitPosition = next;
                mantissa = hexdigit;
                mantissaBits = 4;
            } else if (mantissaBits < 60) {
                // middle hex digits
                mantissa <<= 4;
                mantissa |= hexdigit;
                mantissaBits += 4;
            } else {
                // more mantissa bits than we can handle
                // drop this hex digit on the ground
            }
            next++;
            continue loop;
        }

        // Step 4: process the 'P'
        nextChar = source[next];
        if (nextChar == 'P' || nextChar == 'p') {
            next++;
        } else {
            throw new NumberFormatException();
        }

        // Step 5: process the exponent
        int exponent = 0;
        int exponentSign = +1;
        loop: while (next < length) {
            nextChar = source[next];
            switch (nextChar) {
            case '+':
                exponentSign = +1;
                next++;
                continue loop;
            case '-':
                exponentSign = -1;
                next++;
                continue loop;
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
                int digit = nextChar - '0';
                exponent = (exponent * 10) + digit;
                next++;
                continue loop;
            default:
                break loop;
            }
        }

        // Step 6: process the optional 'f' or 'd'
        boolean doublePrecision = true;
        if (next < length) {
            nextChar = source[next];
            switch (nextChar) {
            case 'f':
            case 'F':
                doublePrecision = false;
                next++;
                break;
            case 'd':
            case 'D':
                doublePrecision = true;
                next++;
                break;
            default:
                throw new NumberFormatException();
            }
        }

        // at this point, all the parsing is done
        // Step 7: handle mantissa of zero
        if (mantissa == 0) {
            return 0L;
        }

        // Step 8: normalize non-zero mantissa
        // mantissa is in right-hand mantissaBits
        // ensure that top bit (as opposed to hex digit) is 1
        int scaleFactorCompensation = 0;
        long top = (mantissa >>> (mantissaBits - 4));
        if ((top & 0x8) == 0) {
            mantissaBits--;
            scaleFactorCompensation++;
            if ((top & 0x4) == 0) {
                mantissaBits--;
                scaleFactorCompensation++;
                if ((top & 0x2) == 0) {
                    mantissaBits--;
                    scaleFactorCompensation++;
                }
            }
        }

        // Step 9: convert double literals to IEEE double
        long result = 0L;
        if (doublePrecision) {
            long fraction;
            if (mantissaBits > DOUBLE_PRECISION) {
                // more bits than we can keep
                int extraBits = mantissaBits - DOUBLE_PRECISION;
                // round to DOUBLE_PRECISION bits
                fraction = mantissa >>> (extraBits - 1);
                long lowBit = fraction & 0x1;
                fraction += lowBit;
                fraction = fraction >>> 1;
                if ((fraction & (1L << DOUBLE_PRECISION)) != 0) {
                    fraction = fraction >>> 1;
                    scaleFactorCompensation -= 1;
                }
            } else {
                // less bits than the faction can hold - pad on right with 0s
                fraction = mantissa << (DOUBLE_PRECISION - mantissaBits);
            }

            int scaleFactor = 0; // how many bits to move '.' to before leading hex digit
            if (mantissaBits > 0) {
                if (leadingDigitPosition < binaryPointPosition) {
                    // e.g., 0x80.0p0 has scaleFactor == +8
                    scaleFactor = 4 * (binaryPointPosition - leadingDigitPosition);
                    // e.g., 0x10.0p0 has scaleFactorCompensation == +3
                    scaleFactor -= scaleFactorCompensation;
                } else {
                    // e.g., 0x0.08p0 has scaleFactor == -4
                    scaleFactor = -4 * (leadingDigitPosition - binaryPointPosition - 1);
                    // e.g., 0x0.01p0 has scaleFactorCompensation == +3
                    scaleFactor -= scaleFactorCompensation;
                }
            }

            int e = (exponentSign * exponent) + scaleFactor;
            if (e - 1 > MAX_DOUBLE_EXPONENT) {
                // overflow to +infinity
                result = Double.doubleToLongBits(Double.POSITIVE_INFINITY);
            } else if (e - 1 >= MIN_NORMALIZED_DOUBLE_EXPONENT) {
                // can be represented as a normalized double
                // the left most bit must be discarded (it's always a 1)
                long biasedExponent = e - 1 + DOUBLE_EXPONENT_BIAS;
                result = fraction & ~(1L << DOUBLE_FRACTION_WIDTH);
                result |= (biasedExponent << DOUBLE_EXPONENT_SHIFT);
            } else if (e - 1 > MIN_UNNORMALIZED_DOUBLE_EXPONENT) {
                // can be represented as an unnormalized double
                long biasedExponent = 0;
                result = fraction >>> (MIN_NORMALIZED_DOUBLE_EXPONENT - e + 1);
                result |= (biasedExponent << DOUBLE_EXPONENT_SHIFT);
            } else {
                // underflow - return Double.NaN
                result = Double.doubleToLongBits(Double.NaN);
            }
            return result;
        }

        // Step 10: convert float literals to IEEE single
        long fraction;
        if (mantissaBits > SINGLE_PRECISION) {
            // more bits than we can keep
            int extraBits = mantissaBits - SINGLE_PRECISION;
            // round to DOUBLE_PRECISION bits
            fraction = mantissa >>> (extraBits - 1);
            long lowBit = fraction & 0x1;
            fraction += lowBit;
            fraction = fraction >>> 1;
            if ((fraction & (1L << SINGLE_PRECISION)) != 0) {
                fraction = fraction >>> 1;
                scaleFactorCompensation -= 1;
            }
        } else {
            // less bits than the faction can hold - pad on right with 0s
            fraction = mantissa << (SINGLE_PRECISION - mantissaBits);
        }

        int scaleFactor = 0; // how many bits to move '.' to before leading hex digit
        if (mantissaBits > 0) {
            if (leadingDigitPosition < binaryPointPosition) {
                // e.g., 0x80.0p0 has scaleFactor == +8
                scaleFactor = 4 * (binaryPointPosition - leadingDigitPosition);
                // e.g., 0x10.0p0 has scaleFactorCompensation == +3
                scaleFactor -= scaleFactorCompensation;
            } else {
                // e.g., 0x0.08p0 has scaleFactor == -4
                scaleFactor = -4 * (leadingDigitPosition - binaryPointPosition - 1);
                // e.g., 0x0.01p0 has scaleFactorCompensation == +3
                scaleFactor -= scaleFactorCompensation;
            }
        }

        int e = (exponentSign * exponent) + scaleFactor;
        if (e - 1 > MAX_SINGLE_EXPONENT) {
            // overflow to +infinity
            result = Float.floatToIntBits(Float.POSITIVE_INFINITY);
        } else if (e - 1 >= MIN_NORMALIZED_SINGLE_EXPONENT) {
            // can be represented as a normalized single
            // the left most bit must be discarded (it's always a 1)
            long biasedExponent = e - 1 + SINGLE_EXPONENT_BIAS;
            result = fraction & ~(1L << SINGLE_FRACTION_WIDTH);
            result |= (biasedExponent << SINGLE_EXPONENT_SHIFT);
        } else if (e - 1 > MIN_UNNORMALIZED_SINGLE_EXPONENT) {
            // can be represented as an unnormalized single
            long biasedExponent = 0;
            result = fraction >>> (MIN_NORMALIZED_SINGLE_EXPONENT - e + 1);
            result |= (biasedExponent << SINGLE_EXPONENT_SHIFT);
        } else {
            // underflow - return Float.NaN
            result = Float.floatToIntBits(Float.NaN);
        }
        return result;
    }
}

Related

  1. valueOf(Integer value)
  2. valueOf(Short value)
  3. valueOf(T v)
  4. valueOfHexDigit(char digit)
  5. valueOfHexDoubleLiteral(char[] source)