Android calculator 默认计算器 计算错误 bug fix


Android默认的计算器计算错误 : 5.04-4.99= 0.0499999

其实这是一个正常的结果,其产生的原因就是:

计算机计算时使用的是2进制,而我们输入的是10进制。10进制的小数转2进制就有可能产生精度丢失的问题.

Android这个calculator采用的是arity框架封装的,而arity并没有正确处理这些精度问题。


下面算是个workaround,代码不好请多见谅。

  1. Index: src/com/android/calculator2/Logic.java  
  2. ===================================================================  
  3. --- src/com/android/calculator2/Logic.java  (revision 600)  
  4. +++ src/com/android/calculator2/Logic.java  (revision 604)  
  5.   
  6. +      
  7. +    /** 
  8. +     * function to truncate decimal 
  9. +     * @author jacky yang 
  10. +     *  
  11. +     * @param number 
  12. +     * @param length 
  13. +     * @return the exact number in decimal 
  14. +     */  
  15. +    private String getPrecisionNumber(double number, int length) {  
  16. +         
  17. +       //1.get formatted string from double   
  18. +       String formatString = new String("%"+mLineLength+"."+length+"g");  
  19. +       String value = String.format(Locale.US, formatString, Double.valueOf(number)).trim();  
  20. +       if(DBG) Log.d(TAG, "value="+value+"\nnumber="+number+"\nlength="+length);  
  21. +       //2.if it's NaN 00 -00, just return string   
  22. +       if(NAN.equals(value)||INFINITY.equals(value)||("-"+INFINITY).equals(value)) {  
  23. +           mIsError = true;  
  24. +            return mErrorString;  
  25. +       }  
  26. +       //3.split science value to two part   
  27. +       int indexOfE = value.indexOf('e');  
  28. +       String prePart = null;  
  29. +       String postPart = null;  
  30. +       if(indexOfE != -1) {  
  31. +           prePart = value.substring(0, indexOfE);  
  32. +           postPart = value.substring(indexOfE+1);  
  33. +           if(postPart.startsWith("+")) {  
  34. +               postPart = postPart.substring(1);  
  35. +           }  
  36. +           if(DBG) Log.d(TAG, "pre : "+ prePart +"   back : "+ postPart);  
  37. +       } else {  
  38. +           prePart = value;  
  39. +       }  
  40. +       //4.round the decimal in the prePart   
  41. +       while (true) {  
  42. +           int m = prePart.indexOf('.');  
  43. +           if(m == -1) {  
  44. +               m = prePart.indexOf(',');  
  45. +               if(m == -1) {  
  46. +                   break;  
  47. +               }  
  48. +           }  
  49. +           while(true) {  
  50. +               if(prePart.length()>0 && prePart.endsWith("0")) {  
  51. +                   prePart = prePart.substring(0, prePart.length()-1);  
  52. +                   continue;  
  53. +               } else {  
  54. +                   break;  
  55. +               }  
  56. +           }  
  57. +           if((m+1) != prePart.length()) {  
  58. +               break;  
  59. +           } else {  
  60. +               prePart = prePart.substring(0, prePart.length()-1);  
  61. +           }  
  62. +             
  63. +       }  
  64. +       //5.append the postPart   
  65. +       if(postPart != null) {  
  66. +           prePart = prePart + "E" + postPart;  
  67. +       }  
  68. +       return prePart;  
  69. +    }  
  70. +      
  71. +//    private static final int ROUND_DIGITS = 1; commented by jacky.yang 2011.08.26   
  72.      String evaluate(String input) throws SyntaxException {  
  73.          if (input.trim().equals("")) {  
  74.              return "";  
  75. @@ -181,18 +255,33 @@  
  76.              input = input.substring(0, size - 1);  
  77.              --size;  
  78.          }  
  79. -  
  80. -        String result = Util.doubleToString(mSymbols.eval(input), mLineLength, ROUND_DIGITS);  
  81. -        if (result.equals(NAN)) { // treat NaN as Error   
  82. -            mIsError = true;  
  83. -            return mErrorString;  
  84. -        } else if (result.equals(INFINITY)) {// add by pxy   
  85. -            mIsError = true;  
  86. -            return mErrorString;  
  87. -        } else if (result.equals('-' + INFINITY)) {// add by pxy   
  88. -            mIsError = true;  
  89. -            return mErrorString;  
  90. -        }  
  91. +        //added by jacky.yang 2011.08.26   
  92. +        String result = "";  
  93. +        double d = mSymbols.eval(input);  
  94. +        int m = mLineLength;  
  95. +        while(true) {  
  96. +           if(m>6) {  
  97. +               result = getPrecisionNumber(d, m);  
  98. +               if(DBG) Log.d(TAG, result);  
  99. +           } else {  
  100. +               break;  
  101. +           }  
  102. +           m--;  
  103. +        }//end   
  104. +          
  105. +        /* commented by jacky yang 2011.08.26 
  106. +//        String result = Util.doubleToString(mSymbols.eval(input), mLineLength, ROUND_DIGITS); 
  107. +//        if (result.equals(NAN)) { // treat NaN as Error 
  108. +//            mIsError = true; 
  109. +//            return mErrorString; 
  110. +//        } else if (result.equals(INFINITY)) {// add by pxy 
  111. +//            mIsError = true; 
  112. +//            return mErrorString; 
  113. +//        } else if (result.equals('-' + INFINITY)) {// add by pxy 
  114. +//            mIsError = true; 
  115. +//            return mErrorString; 
  116. +//        } 
  117. +        */  
  118.          //modify by pxy   
  119.  //        return result.replace('-', MINUS).replace(INFINITY, INFINITY_UNICODE);   
  120.          return result.replace('-', MINUS);  

相关内容