0

we're told to convert strings to double without using parse double or any math,int, or double function. I'm having a hard time converting the numbers using exponents.

public class Convert {

    public static void main(String args[]) {
        String num = "1223.230";
        int d = 0, g = 0, c = 0, fnl = 0;
        int exp = (num.indexOf(".") - 1);
        while (num.charAt(d) != '.') {
            g = num.charAt(d) - 48;
            int k = 1;
            for (int f = 0; f < exp; f++) {
                k = (k * 10) * g;
            }
            fnl += k;
            d++;
            exp--;
            System.out.println(fnl);                
        }   
    }

}

These codes only convert the int part of the given string and it prints the wrong answer.

3
  • 3
    Look at the source code for parseDouble and get an idea. Commented Sep 13, 2013 at 13:48
  • 1
    What kind of an exercise is this? Commented Sep 13, 2013 at 13:49
  • review your algorithm. hint: you do not need to explicitly identify exponents (unless you have to parse a full-fledged lexicalization of doubles [eg. 1.23E-4). Commented Sep 13, 2013 at 13:53

5 Answers 5

2

You could split on the '.', then loop through the left side, grab the next char digit, if the existing value > 0, multiply it by 10, then add the read digit (use a switch/case). You would end up growing the number out to the left.

Then process the right side of the '.' by going right-to-left and doing the same thing, except this time divide by 10 and add digit/10. You will grow the decimal to the right.

Finally, take the left side and add it to the right side.

Sign up to request clarification or add additional context in comments.

Comments

1

I suggest you step through the code in your debugger to see what it is really doing. However I can see that

k=(k*10)*g;

should be

k=k*10 + g;

And k should be a long which is outside the loop.

You also don't need to use indexOf.

You need to write a loop which reads the whole number. You don't need to split the String on . or do anything special, just remember where it was. When you finish you divide by 10^count.

Here is a method I wrote

@Override
public double parseDouble() {
    long value = 0;
    int exp = 0;
    boolean negative = false;
    int decimalPlaces = Integer.MIN_VALUE;
    while (true) {
        byte ch = readByte();
        if (ch >= '0' && ch <= '9') {
            while (value >= MAX_VALUE_DIVIDE_10) {
                value >>>= 1;
                exp++;
            }
            value = value * 10 + (ch - '0');
            decimalPlaces++;
        } else if (ch == '-') {
            negative = true;
        } else if (ch == '.') {
            decimalPlaces = 0;
        } else {
            break;
        }
    }

    return asDouble(value, exp, negative, decimalPlaces);
}

for this class https://github.com/OpenHFT/Java-Lang/blob/master/lang/src/main/java/net/openhft/lang/io/AbstractBytes.java

Note: this doesn't handle e or hexidecimal p notation.

Comments

0

This is how oracle does it :)

http://docs.oracle.com/javase/6/docs/api/java/lang/Double.html#valueOf(java.lang.String)

final String Digits     = "(\\p{Digit}+)";
final String HexDigits  = "(\\p{XDigit}+)";
// an exponent is 'e' or 'E' followed by an optionally 
// signed decimal integer.
final String Exp        = "[eE][+-]?"+Digits;
final String fpRegex    =
            ("[\\x00-\\x20]*"+  // Optional leading "whitespace"
             "[+-]?(" + // Optional sign character
             "NaN|" +           // "NaN" string
             "Infinity|" +      // "Infinity" string

// A decimal floating-point string representing a finite positive
// number without a leading sign has at most five basic pieces:
// Digits . Digits ExponentPart FloatTypeSuffix
// 
// Since this method allows integer-only strings as input
// in addition to strings of floating-point literals, the
// two sub-patterns below are simplifications of the grammar
// productions from the Java Language Specification, 2nd 
// edition, section 3.10.2.

// Digits ._opt Digits_opt ExponentPart_opt FloatTypeSuffix_opt
             "((("+Digits+"(\\.)?("+Digits+"?)("+Exp+")?)|"+

// . Digits ExponentPart_opt FloatTypeSuffix_opt
             "(\\.("+Digits+")("+Exp+")?)|"+

// Hexadecimal strings
       "((" +
// 0[xX] HexDigits ._opt BinaryExponent FloatTypeSuffix_opt
        "(0[xX]" + HexDigits + "(\\.)?)|" +

// 0[xX] HexDigits_opt . HexDigits BinaryExponent FloatTypeSuffix_opt
        "(0[xX]" + HexDigits + "?(\\.)" + HexDigits + ")" +

        ")[pP][+-]?" + Digits + "))" +
             "[fFdD]?))" +
             "[\\x00-\\x20]*");// Optional trailing "whitespace"

if (Pattern.matches(fpRegex, myString))
    Double.valueOf(myString); // Will not throw NumberFormatException
else
{
    // Perform suitable alternative action
}

If you want you can look at other regex patterns to do it, there are lots.

EDIT:

Prettier version of the pattern :)

private static final Pattern DOUBLE_PATTERN = Pattern
        .compile("[\\x00-\\x20]*[+-]?(NaN|Infinity|((((\\p{Digit}+)(\\.)?((\\p{Digit}+)?)([eE][+-]?(\\p{Digit}+))?)"
            + "|(\\.((\\p{Digit}+))([eE][+-]?(\\p{Digit}+))?)|(((0[xX](\\p{XDigit}+)(\\.)?)|(0[xX](\\p{XDigit}+)"
            + "?(\\.)(\\p{XDigit}+)))[pP][+-]?(\\p{Digit}+)))[fFdD]?))[\\x00-\\x20]*");

Comments

0

This is just a problem solving exercise as would not really do this manually. It's more likely to be asked in an interview situation. So as CodeChimp above explained as well, the best way is to use good old units, tens, hundreds and multiply on the integer side and divide on decimal side.

 public double convertStrToDouble(String doubleAsString) {
    final String[] split = doubleAsString.split("\\."); // 123.375
    int intPart = 0;
    final String intPartStr = split[0]; // 123
    final String decPartStr = split[1]; // 375
    // (1 * 3) + (2 * 10) + (3 * 100) = 123
    int units = 1;
    for(int i = intPartStr.length()-1; i >= 0; i--) {
        char nChar = intPartStr.charAt(i);
        int n = Character.getNumericValue(nChar);
        int toAdd =  n * units;
        intPart = intPart + toAdd;
        System.out.printf("int: n %,5d toAdd %,5d intPart %,5d units %,5d\n",n,toAdd,intPart,units);
        units =  units * 10;
    }
    System.out.println("");
    // double part 375
    // (1 / 10) * 3 + (1 / 100) * 7 + (1 /1000) * 5
    // 0.3 + 0.07 + 0.005 = 0.375
    double decPart = 0d;
    units = 10;
    for(final char character : decPartStr.toCharArray()) {
        int n = Character.getNumericValue(character);
        double toAdd = (1.0 / units) * n;
        decPart = decPart + toAdd;
        System.out.printf("dec: n %,5d toAdd %,5.4f decPart %,5.4f units 1/%d\n",n,toAdd,decPart,units);
        units =  units * 10;
    }
    System.out.printf("returning %,4d + %,4.4f\n\n",intPart,decPart);
    return  intPart  + decPart;
}

1 Comment

Fair enough but the solution above does not deal with negative number or overflow if you pass in a string which is min double etc! If you passi n a string containing a -ve number, you ll be surprised by the double you get!
0
  1. Check number format is valid.
  2. Create a map, where key - position, value - multiplier.
  3. Multiple each number by value and get a sum.

For example: "123.45" -> (1 * 100) + (2 * 10) + (3 * 1) + (4 * 0.1) + (5 * 0.01)

public static double toDouble(String num) {
    if (!Pattern.compile("-?[0-9]+.[0-9]+").matcher(num).matches()) {
        throw new NumberFormatException();
    }

    boolean isNegative = num.startsWith("-");
    if (isNegative) {
        num = num.replace("-", "");
    }

    // Map<SymbolsPosition, Multiplier>
    int n = 1_000_000_000;
    Map<Integer, Integer> map = new HashMap<>();
    for (int i = 10; i > 0; i--) {
        map.put(i, n);
        n /= 10;
    }
    double multiplier = map.get(num.indexOf("."));

    // Get number from char and multiplying accordingly position
    double result = 0;
    char[] chars = num.toCharArray();
    for (int i = 0; i < num.length(); i++) {
        if (chars[i] != '.') {
            double value = (chars[i] - '0') * multiplier;
            multiplier /= 10;
            result += value;
        }
    }

    return isNegative ? result * -1 : result;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.