【问题标题】:Manually convert string to double java without using parse double在不使用 parse double 的情况下手动将字符串转换为 double java
【发布时间】:2013-09-13 13:48:36
【问题描述】:

我们被告知在不使用 parse double 或任何 math、int 或 double 函数的情况下将字符串转换为 double。我很难使用指数转换数字。

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);                
        }   
    }

}

这些代码只转换给定字符串的 int 部分,并打印错误的答案。

【问题讨论】:

  • 查看parseDouble的源代码并得到一个想法。
  • 这是什么练习?
  • 查看您的算法。提示:您不需要显式识别指数(除非您必须解析双精度的成熟词汇[例如。1.23E-4)。

标签: java


【解决方案1】:

您可以拆分“。”,然后遍历左侧,获取下一个字符数字,如果现有值 > 0,将其乘以 10,然后添加读取的数字(使用开关/大小写)。你最终会增加左边的数字。

然后处理'.'的右边通过从右到左并做同样的事情,除了这次除以 10 并添加 digit/10。您将向右增加小数。

最后取左边,加到右边。

【讨论】:

    【解决方案2】:

    我建议您在调试器中单步调试代码,看看它到底在做什么。但是我可以看到

    k=(k*10)*g;
    

    应该是

    k=k*10 + g;
    

    k 应该是循环外的long

    你也不需要使用 indexOf。

    您需要编写一个读取整数的循环。您不需要在 .或者做任何特别的事情,只要记住它在哪里。完成后除以 10^count。

    这是我写的一个方法

    @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);
    }
    

    对于这个类https://github.com/OpenHFT/Java-Lang/blob/master/lang/src/main/java/net/openhft/lang/io/AbstractBytes.java

    注意:这不处理 e 或十六进制 p 表示法。

    【讨论】:

      【解决方案3】:

      oracle 就是这样做的 :)

      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
      }
      

      如果您愿意,可以查看其他正则表达式模式来执行此操作,有很多。

      编辑:

      模式的更漂亮的版本:)

      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]*");
      

      【讨论】:

        【解决方案4】:

        这只是一个解决问题的练习,不会真正手动执行此操作。在面试的情况下更有可能被问到。因此,正如上面的 CodeChimp 所解释的那样,最好的方法是使用良好的旧单位,十、百,并在整数侧乘以在小数侧除。

         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;
        }
        

        【讨论】:

        • 很公平,但是如果您传入一个最小双倍的字符串等,上述解决方案不会处理负数或溢出!如果你传递一个包含 -ve 数字的字符串,你会惊讶于你得到的双倍!
        猜你喜欢
        • 1970-01-01
        • 2022-01-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-07-13
        • 2011-06-30
        • 1970-01-01
        相关资源
        最近更新 更多