0

「2+3」など、String 型のオペランドを評価するメソッド calculate(String) を作成しました。多くのオペランドを試してみましたが、メソッドはこれを除いて正常に動作します: calculate("2.002*1000) //returns 2001.9999999999 このエラーがどのように発生したのか非常に興味があります。コードを何度も調べましたが、できません問題がどこにあるかを把握します。

ここにコード:

private String calculate(String str)
    {
        String num = "";
        List<String> list = new ArrayList<String>();
        for(int i = 0; i < str.length(); i++) //Arrange str into list, elements are seperated by "+" or "-"
        {
            if(! checkPM(str.substring(i, i + 1)))
            {
                num = num + str.substring(i, i + 1);
            } else
            {
                list.add(num);
                list.add(str.substring(i, i + 1));
                num = "";
            }
        }
        list.add(num);//add the last num into list
        if(checkSign(list.get(list.size() - 1)))//remove last element if it is an operator
        {
        list.remove(list.get(list.size() - 1));
        }
        String numlistele = ""; //Elements of numlist
        List<String> numlist = new ArrayList<String>(); //List of numbers to be TD
        List<String> TDlist = new ArrayList<String>(); //List of times or divide
        for(int j = 0; j < list.size(); j++) //Check which of the elements of list contains "*" or "/"
        {
            String tdAns = ""; //Answer of numlistele timed or divided
            if(checkTD(list.get(j))) // When the elements of list contains "*" or "/"
            {
                for(int k = 0; k < list.get(j).length(); k++) //
                {
                    if(! checkSign(list.get(j).substring(k, k + 1)))
                    {
                        numlistele = numlistele + list.get(j).substring(k, k+1);
                    } else
                    {
                        numlist.add(numlistele);
                        TDlist.add(list.get(j).substring(k, k+1));
                        numlistele = "";
                    }
                }
                numlist.add(numlistele); //Adds the last number into numlist
                numlistele = ""; //Restore numlistele to "", to be used in next loop 
                tdAns = numlist.get(0); //Answer of numlistele timed or divided, firstly it is equals to the first elements of numlist
                for(int l = 0; l < TDlist.size(); l++)
                {
                    if(TDlist.get(l).equals("×"))
                    {
                        double tempdou = Double.parseDouble(tdAns) * //temporary double used to save to tdANS
                                Double.parseDouble(numlist.get(l+1));
                        tdAns = String.valueOf(tempdou);
                    } else //when TDlist.get(l).equals("/") is true
                    {
                        double tempdou = Double.parseDouble(tdAns) / 
                                Double.parseDouble(numlist.get(l+1));
                        tdAns = String.valueOf(tempdou);
                    }
                }
            list.set(j, tdAns);
            }               
            numlist.clear(); //Clear numlist for next loop
            TDlist.clear(); //Clear TDlist for next loop
        }
        String ans = list.get(0); //Will become final answer later, first it is assign to first element of list
        for(int m = 0; m < list.size(); m++)
        {
            if(list.get(m).equals("+"))
            {
                double tempdou = Double.parseDouble(ans) + //Temporary double used to save to ans
                        Double.parseDouble(list.get(m + 1));
                ans = String.valueOf(tempdou);
            } else if(list.get(m).equals("-"))
            {
                double tempdou = Double.parseDouble(ans) - 
                        Double.parseDouble(list.get(m + 1));
                ans = String.valueOf(tempdou);
            }
        }
        if(ans.length() > 2)
        {
            if(ans.substring(ans.length() - 2).equals(".0")) //To remove .0 of the answer
            {
                ans = ans.substring(0, ans.length() - 2);
            }

        }
        return ans;
    }

前もって感謝します。

4

3 に答える 3

6

浮動小数点表現は必ずしも正確ではありません。文字列「2.002」を解析すると、最も近い表現Double.parseDoubleが返されました。double

を掛ける1000と浮動小数点表現の誤差が大きくなり気付きました(2001.999999999999)。

これは、浮動小数点表現と発生する可能性のある事故に関する優れたオンライン記事です。

浮動小数点数を正確に表現するには、Java の組み込みBigDecimalクラスを使用できます。それほど高速ではないかもしれませんが、必要な精度はすべて保持されます。

于 2013-07-09T17:57:17.140 に答える
4

これは、IEEE 754 の丸め規則により double が丸められるために発生します。丸めたくない場合は、BigDecimal クラスを使用します。

http://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html

于 2013-07-09T17:59:01.313 に答える
2

これは、浮動小数点数学の教科書的なケースです。あなたが掛けたものは、実際には 2.002 * 1000 ではありませんでした。代わりに、それは reeeeeeeeally 2.002 に近い数に reeeeeeeeally に近い数を掛けたものでした。

絶対的な精度が必要な場合は、Java のBigDecimal型を使用する必要があります。C# では、decimal型を使用します。

http://en.wikipedia.org/wiki/Round-off_error

http://en.wikipedia.org/wiki/Floating_point

于 2013-07-09T17:57:11.417 に答える