0

重複の可能性:
小数点以下の桁数を2倍に移動

アイスクリームとサプリメントを主題として使用して、デコレータパターンの基本的な実装を作成しています。ポップアップした奇妙な出力動作を除いて、すべてが正常に機能します。

一見ランダムな場所では、コストはドットの後ろの16番目の要素を丸めて出力されます。これは、使用する数値が1.00(Vanilla)、1.10(Chocolate)、0.30(Sprinkles)、0.40(WhippedCream)、0.35(Nuts)であるため奇妙です。

これを再現するには、次のクラスとインターフェイスが必要です。

public interface Icecream {
    public double getCost();
    public String getDescription();
}

public class Vanilla implements Icecream {
    @Override
    public double getCost() {
        return 1.00;
    }

    @Override
    public String getDescription() {
        return "Vanilla ice";
    }
}

public class Chocolate implements Icecream {
    @Override
    public double getCost() {
        return 1.10;
    }

    @Override
    public String getDescription() {
        return "Chocolate ice";
    }
}

public abstract class Decorator implements Icecream{
    protected Icecream decoratedIcecream;

    public Decorator(Icecream decoratedIcecream) {
        this.decoratedIcecream = decoratedIcecream;
    }

    public abstract double getCost();
    public abstract String getDescription();
}

public class Sprinkles extends Decorator {
    public Sprinkles(Icecream decoratedIcecream) {
        super(decoratedIcecream);
    }

    @Override
    public double getCost() {
        return decoratedIcecream.getCost() + 0.30;
    }

    @Override
    public String getDescription() {
        return decoratedIcecream.getDescription() + ", Sprinkles";
    }
}

public class WhippedCream extends Decorator {
    public WhippedCream(Icecream decoratedIcecream) {
        super(decoratedIcecream);
    }

    @Override
    public double getCost() {
        return decoratedIcecream.getCost() + 0.40;
    }

    @Override
    public String getDescription() {
        return decoratedIcecream.getDescription() + ", Whipped cream";
    }
}

public class Nuts extends Decorator {
    public Nuts(Icecream decoratedIcecream) {
        super(decoratedIcecream);
    }

    @Override
    public double getCost() {
        return decoratedIcecream.getCost() + 0.35;
    }

    @Override
    public String getDescription() {
        return decoratedIcecream.getDescription() + ", Nuts";
    }
}


public class StartUp {
    public static void main(String[] args) {
        Icecream icecream = new Vanilla();
        showDetails(icecream);

        icecream = new Sprinkles(icecream);
        showDetails(icecream);

        icecream = new WhippedCream(icecream);
        showDetails(icecream);

        Icecream icecream2 = new Nuts(new Chocolate());
        showDetails(icecream2);

        icecream2 = new Sprinkles(icecream2);
        showDetails(icecream2);

        Icecream icecream3 = new Vanilla();
        showDetails(icecream3);

        icecream3 = new Nuts(icecream3);
        showDetails(icecream3);

        icecream3 = new Sprinkles(icecream3);
        showDetails(icecream3);
    }

    private static void showDetails(Icecream icecream){
        System.out.println("Cost: " + icecream.getCost() + "\t" + "Description: " + icecream.getDescription());
    }
}

その結果、次の出力が得られます。

Cost: 1.0   Description: Vanilla ice
Cost: 1.3   Description: Vanilla ice, Sprinkles
Cost: 1.7000000000000002    Description: Vanilla ice, Sprinkles, Whipped cream
Cost: 1.4500000000000002    Description: Chocolate ice, Nuts
Cost: 1.7500000000000002    Description: Chocolate ice, Nuts, Sprinkles
Cost: 1.0   Description: Vanilla ice
Cost: 1.35  Description: Vanilla ice, Nuts
Cost: 1.6500000000000001    Description: Vanilla ice, Nuts, Sprinkles

これだけのコードを追加するのは気が進まなかったのですが、エラーがランダムにポップアップするようです(ホイップクリームを追加したとき、チョコレートとナッツを作成したとき、スプリンクルを追加したときに2回)、自分のどの部分を正確に特定することはできませんコードは関連性があり、そうでないものは何ですか。

どこでもdoubleとして宣言され、常にドットの後ろに2桁の数字がある場合、なぜそれが丸められるのですか?

4

2 に答える 2

4

これが浮動小数点数(doubleおよびfloat)の現実です。彼らは数式を使用してデータを保存しているため(詳細には触れません)、一部の値は期待どおりではありません(これが、銀行や他の通貨システムが他のようなもののBigDecimal代わりに使用する理由ですdouble)。

あなたの場合、あなたはかなり小さな測定単位を扱っているので、私はおそらくそれを小数点以下の桁数に丸めるでしょう。

小数点以下第2位を四捨五入して出力するコードを次に示します。

String dblOutput = new DecimalFormat("#.##").format(icecream.getCost());
System.out.println("Cost: " + dblOutput + "\t" + "Description: " + icecream.getDescription());
于 2013-01-12T17:42:04.587 に答える
1

これは、浮動小数点の丸めの結果にすぎません。基数2では、0.1のような適切な終了小数が無限の循環小数である可能性があることに注意してください。その小数が丸められると、これらの奇妙な丸め誤差が発生します。

解決策は、浮動小数点値を直接出力しないことです。Java.textでDecimalFormatを使用するか、通貨インスタンスを取得して出力をフォーマット(および丸め)します

于 2013-01-12T17:45:48.493 に答える