質問

私が欲しいのは、double をハーフアップメソッドを使用して丸める文字列に変換するメソッドです。四捨五入される小数が 5 の場合、常に前の数値に切り上げられます。これは、ほとんどの人がほとんどの状況で期待する標準的な丸め方法です。

また、有効数字のみを表示したいと考えています。末尾にゼロがあってはなりません。

これを行う 1 つの方法は、 String.format 方法:

String.format("%.5g%n", 0.912385);

戻り値:

0.91239

これは素晴らしいことですが、数値が重要でない場合でも常に小数点以下 5 桁で表示されます。

String.format("%.5g%n", 0.912300);

戻り値:

0.91230

別の方法は、 DecimalFormatter:

DecimalFormat df = new DecimalFormat("#.#####");
df.format(0.912385);

戻り値:

0.91238

ただし、ご覧のとおり、これは半偶数丸めを使用しています。つまり、前の桁が偶数の場合は切り捨てられます。私が欲しいのはこれです:

0.912385 -> 0.91239
0.912300 -> 0.9123

Java でこれを実現する最善の方法は何でしょうか?

役に立ちましたか?

解決

を使用します。 setRoundingMode RoundingMode を明示的に使用して、半偶数ラウンドで問題を処理し、必要な出力にフォーマットパターンを使用します。

例:

DecimalFormat df = new DecimalFormat("#.####");
df.setRoundingMode(RoundingMode.CEILING);
for (Number n : Arrays.asList(12, 123.12345, 0.23, 0.1, 2341234.212431324)) {
    Double d = n.doubleValue();
    System.out.println(df.format(d));
}

出力を提供します:

12
123.1235
0.23
0.1
2341234.2125

他のヒント

value double であると仮定すると、次のことができます:

(double)Math.round(value * 100000d) / 100000d

これは5桁の精度です。ゼロの数は小数の数を示します。

new BigDecimal(String.valueOf(double)).setScale(yourScale, BigDecimal.ROUND_HALF_UP);

BigDecimal を取得します。文字列を取得するには、その BigDecimal toString メソッドを呼び出すか、Java 5+の toPlainString メソッドを呼び出して単純な形式にします。文字列。

サンプルプログラム:

package trials;
import java.math.BigDecimal;

public class Trials {

    public static void main(String[] args) {
        int yourScale = 10;
        System.out.println(BigDecimal.valueOf(0.42344534534553453453-0.42324534524553453453).setScale(yourScale, BigDecimal.ROUND_HALF_UP));
    }

使用することもできます

DecimalFormat df = new DecimalFormat("#.00000");
df.format(0.912385);

末尾の0があることを確認します。

他の人が指摘しているように、正しい答えは DecimalFormat または BigDecimal を使用することです。浮動小数点は小数点以下 を持たないため、最初に特定の数に丸めたり切り捨てたりすることはできません。 10進数で作業する必要があり、それがこれらの2つのクラスが行うことです。

このスレッド内のすべての回答に対する反例として、実際にはStackOverflow(および他の場所)全体で乗算、切り捨て、除算を推奨する次のコードを投稿しています。次のコードが92%以上のケースで間違った出力を生成する理由を説明するのは、この手法の支持者に任されています。

public class RoundingCounterExample
{

    static float roundOff(float x, int position)
    {
        float a = x;
        double temp = Math.pow(10.0, position);
        a *= temp;
        a = Math.round(a);
        return (a / (float)temp);
    }

    public static void main(String[] args)
    {
        float a = roundOff(0.0009434f,3);
        System.out.println("a="+a+" (a % .001)="+(a % 0.001));
        int count = 0, errors = 0;
        for (double x = 0.0; x < 1; x += 0.0001)
        {
            count++;
            double d = x;
            int scale = 2;
            double factor = Math.pow(10, scale);
            d = Math.round(d * factor) / factor;
            if ((d % 0.01) != 0.0)
            {
                System.out.println(d + " " + (d % 0.01));
                errors++;
            }
        }
        System.out.println(count + " trials " + errors + " errors");
    }
}

このプログラムの出力:

10001 trials 9251 errors

編集:以下のコメントに対処するために、 BigDecimal および new MathContext(16)を使用してテストループのモジュラス部分を再編集しましたモジュラス操作は次のとおりです。

public static void main(String[] args)
{
    int count = 0, errors = 0;
    int scale = 2;
    double factor = Math.pow(10, scale);
    MathContext mc = new MathContext(16, RoundingMode.DOWN);
    for (double x = 0.0; x < 1; x += 0.0001)
    {
        count++;
        double d = x;
        d = Math.round(d * factor) / factor;
        BigDecimal bd = new BigDecimal(d, mc);
        bd = bd.remainder(new BigDecimal("0.01"), mc);
        if (bd.multiply(BigDecimal.valueOf(100)).remainder(BigDecimal.ONE, mc).compareTo(BigDecimal.ZERO) != 0)
        {
            System.out.println(d + " " + bd);
            errors++;
        }
    }
    System.out.println(count + " trials " + errors + " errors");
}

結果:

10001 trials 4401 errors

あなたが持っていると仮定

double d = 9232.129394d;

BigDecimal

BigDecimal bd = new BigDecimal(d).setScale(2, RoundingMode.HALF_EVEN);
d = bd.doubleValue();

またはBigDecimalなし

d = Math.round(d*100)/100.0d;

両方のソリューション d == 9232.13

DecimalFormatクラスを使用できます。

double d = 3.76628729;

DecimalFormat newFormat = new DecimalFormat("#.##");
double twoDecimal =  Double.valueOf(newFormat.format(d));

RealのJavaハウツー投稿 Java 1.6より前のバージョン。

BigDecimal bd = new BigDecimal(Double.toString(d));
bd = bd.setScale(decimalPlace, BigDecimal.ROUND_HALF_UP);
return bd.doubleValue();
double myNum = .912385;
int precision = 10000; //keep 4 digits
myNum= Math.floor(myNum * precision +.5)/precision;

@Milhous:丸めの10進形式は優れています:

  

使用することもできます

DecimalFormat df = new DecimalFormat("#.00000");
df.format(0.912385);
     

末尾の0を確認します。

この方法は、実際の 数値の丸めメカニズム-視覚的にだけでなく、処理時も。

仮説:丸めメカニズムをGUIに実装する必要があります プログラム。結果出力の精度/精度を簡単に変更するには キャレットの形式を変更します(括弧内)。そのため:

DecimalFormat df = new DecimalFormat("#0.######");
df.format(0.912385);

出力として返されます: 0.912385

DecimalFormat df = new DecimalFormat("#0.#####");
df.format(0.912385);

出力として戻る: 0.91239

DecimalFormat df = new DecimalFormat("#0.####");
df.format(0.912385);

出力として戻る: 0.9124

[編集:キャレットの形式がそのような場合(&quot;#0。############&quot;)と 小数点を入力します。 3.1415926、引数のため、DecimalFormat ガベージ(たとえば、末尾のゼロ)を生成せず、以下を返します: 3.1415926 ..そのような傾向がある場合。確かに、それは少し冗長です いくつかの開発者の好みのために-しかし、ちょっと、それは低いメモリフットプリントを持っています 処理中に非常に簡単に実装できます。]

本質的に、DecimalFormatの利点は、文字列を同時に処理できることです 外観-丸め精度セットのレベル。エルゴ:あなた 1つのコード実装の価格で2つのメリットが得られます。 ;)

次のユーティリティメソッドを使用できます-

public static double round(double valueToRound, int numberOfDecimalPlaces)
{
    double multipicationFactor = Math.pow(10, numberOfDecimalPlaces);
    double interestedInZeroDPs = valueToRound * multipicationFactor;
    return Math.round(interestedInZeroDPs) / multipicationFactor;
}

文字列として結果が必要な場合に使用できるものの概要は次のとおりです。

  1. DecimalFormat#setRoundingMode()

    DecimalFormat df = new DecimalFormat("#.#####");
    df.setRoundingMode(RoundingMode.HALF_UP);
    String str1 = df.format(0.912385)); // 0.91239
    
  2. BigDecimal#setScale()

    String str2 = new BigDecimal(0.912385)
        .setScale(5, BigDecimal.ROUND_HALF_UP)
        .toString();
    

結果として double が必要な場合に使用できるライブラリの提案を次に示します。ただし、文字列の変換にはお勧めしません。doubleは必要なものを正確に表現できない可能性があるためです(例:こちら):

  1. Apache Commons Mathの精度

    double rounded = Precision.round(0.912385, 5, BigDecimal.ROUND_HALF_UP);
    
  2. 関数コルト

    double rounded = Functions.round(0.00001).apply(0.912385)
    
  3. Utils Wekaから

    double rounded = Utils.roundDouble(0.912385, 5)
    

簡潔な解決策:

   public static double round(double value, int precision) {
      int scale = (int) Math.pow(10, precision);
      return (double) Math.round(value * scale) / scale;
  }

こちらも参照してください。 https://stackoverflow.com/a/22186845/212950おかげで ジェーディモンド これを提供してくれて。

BigDecimalを使用できます

BigDecimal value = new BigDecimal("2.3");
value = value.setScale(0, RoundingMode.UP);
BigDecimal value1 = new BigDecimal("-2.3");
value1 = value1.setScale(0, RoundingMode.UP);
System.out.println(value + "n" + value1);

参照: http://www.javabeat.net/precise-丸めモードを使用した小数点以下の丸め/

これを試してください:org.apache.commons.math3.util.Precision.round(double x、int scale)

参照: http://commons.apache .org / proper / commons-math / apidocs / org / apache / commons / math3 / util / Precision.html

Apache Commons Mathematics Libraryホームページ: http://commons.apache.org/proper/commons- math / index.html

このメソッドの内部実装は次のとおりです。

public static double round(double x, int scale) {
    return round(x, scale, BigDecimal.ROUND_HALF_UP);
}

public static double round(double x, int scale, int roundingMethod) {
    try {
        return (new BigDecimal
               (Double.toString(x))
               .setScale(scale, roundingMethod))
               .doubleValue();
    } catch (NumberFormatException ex) {
        if (Double.isInfinite(x)) {
            return x;
        } else {
            return Double.NaN;
        }
    }
}

(出力だけでなく)計算に本当に10進数が必要な場合は、doubleなどのバイナリベースの浮動小数点形式を使用しないでください。

Use BigDecimal or any other decimal-based format.

BigDecimalは計算に使用しますが、サイズに依存することに注意してください あなたが扱っている番号。ほとんどの実装では、doubleまたは 非常に大きな数の計算には、整数からLongで十分です。

実際、私は (16進数の結果とは対照的に)正確に表現するために最近解析されて使用された #################################文字と同じくらい大きな数字のGUIで( 例)。

このテーマについて完全な答えが見つからなかったため、以下をサポートして、これを適切に処理するクラスを作成しました。

  • フォーマット:特定の小数点以下の桁数を持つdouble型を文字列に簡単にフォーマットします
  • 解析:フォーマットされた値を解析してdoubleに戻します
  • ロケール:デフォルトのロケールを使用してフォーマットおよび解析します
  • 指数表記:特定のしきい値の後に指数表記の使用を開始します

使用法は非常に簡単です

(この例では、カスタムロケールを使用しています)

public static final int DECIMAL_PLACES = 2;

NumberFormatter formatter = new NumberFormatter(DECIMAL_PLACES);

String value = formatter.format(9.319); // "9,32"
String value2 = formatter.format(0.0000005); // "5,00E-7"
String value3 = formatter.format(1324134123); // "1,32E9"

double parsedValue1 = formatter.parse("0,4E-2", 0); // 0.004
double parsedValue2 = formatter.parse("0,002", 0); // 0.002
double parsedValue3 = formatter.parse("3423,12345", 0); // 3423.12345

クラスは次のとおりです

import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.ParseException;
import java.util.Locale;

public class NumberFormatter {

    private static final String SYMBOL_INFINITE           = "\u221e";
    private static final char   SYMBOL_MINUS              = '-';
    private static final char   SYMBOL_ZERO               = '0';
    private static final int    DECIMAL_LEADING_GROUPS    = 10;
    private static final int    EXPONENTIAL_INT_THRESHOLD = 1000000000; // After this value switch to exponential notation
    private static final double EXPONENTIAL_DEC_THRESHOLD = 0.0001; // Below this value switch to exponential notation

    private DecimalFormat decimalFormat;
    private DecimalFormat decimalFormatLong;
    private DecimalFormat exponentialFormat;

    private char groupSeparator;

    public NumberFormatter(int decimalPlaces) {
        configureDecimalPlaces(decimalPlaces);
    }

    public void configureDecimalPlaces(int decimalPlaces) {
        if (decimalPlaces <= 0) {
            throw new IllegalArgumentException("Invalid decimal places");
        }

        DecimalFormatSymbols separators = new DecimalFormatSymbols(Locale.getDefault());
        separators.setMinusSign(SYMBOL_MINUS);
        separators.setZeroDigit(SYMBOL_ZERO);

        groupSeparator = separators.getGroupingSeparator();

        StringBuilder decimal = new StringBuilder();
        StringBuilder exponential = new StringBuilder("0.");

        for (int i = 0; i < DECIMAL_LEADING_GROUPS; i++) {
            decimal.append("###").append(i == DECIMAL_LEADING_GROUPS - 1 ? "." : ",");
        }

        for (int i = 0; i < decimalPlaces; i++) {
            decimal.append("#");
            exponential.append("0");
        }

        exponential.append("E0");

        decimalFormat = new DecimalFormat(decimal.toString(), separators);
        decimalFormatLong = new DecimalFormat(decimal.append("####").toString(), separators);
        exponentialFormat = new DecimalFormat(exponential.toString(), separators);

        decimalFormat.setRoundingMode(RoundingMode.HALF_UP);
        decimalFormatLong.setRoundingMode(RoundingMode.HALF_UP);
        exponentialFormat.setRoundingMode(RoundingMode.HALF_UP);
    }

    public String format(double value) {
        String result;
        if (Double.isNaN(value)) {
            result = "";
        } else if (Double.isInfinite(value)) {
            result = String.valueOf(SYMBOL_INFINITE);
        } else {
            double absValue = Math.abs(value);
            if (absValue >= 1) {
                if (absValue >= EXPONENTIAL_INT_THRESHOLD) {
                    value = Math.floor(value);
                    result = exponentialFormat.format(value);
                } else {
                    result = decimalFormat.format(value);
                }
            } else if (absValue < 1 && absValue > 0) {
                if (absValue >= EXPONENTIAL_DEC_THRESHOLD) {
                    result = decimalFormat.format(value);
                    if (result.equalsIgnoreCase("0")) {
                        result = decimalFormatLong.format(value);
                    }
                } else {
                    result = exponentialFormat.format(value);
                }
            } else {
                result = "0";
            }
        }
        return result;
    }

    public String formatWithoutGroupSeparators(double value) {
        return removeGroupSeparators(format(value));
    }

    public double parse(String value, double defValue) {
        try {
            return decimalFormat.parse(value).doubleValue();
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return defValue;
    }

    private String removeGroupSeparators(String number) {
        return number.replace(String.valueOf(groupSeparator), "");
    }

}

誰かがまだこれで助けを必要とする場合に備えて。このソリューションは私にとって完璧に機能します。

private String withNoTrailingZeros(final double value, final int nrOfDecimals) {
return new BigDecimal(String.valueOf(value)).setScale(nrOfDecimals,  BigDecimal.ROUND_HALF_UP).stripTrailingZeros().toPlainString();

}

目的の出力で文字列を返します。

以下のコードスニペットは、n桁の表示方法を示しています。秘Theは、変数ppに1を設定し、その後にn個のゼロを設定することです。以下の例では、変数pp値にはゼロが5つあるため、5桁が表示されます。

double pp = 10000;

double myVal = 22.268699999999967;
String needVal = "22.2687";

double i = (5.0/pp);

String format = "%10.4f";
String getVal = String.format(format,(Math.round((myVal +i)*pp)/pp)-i).trim();

DecimalFormat を使用して double String に変換している場合、非常に簡単です:

DecimalFormat formatter = new DecimalFormat("0.0##");
formatter.setRoundingMode(RoundingMode.HALF_UP);

double num = 1.234567;
return formatter.format(num);

必要な動作に応じて、選択できる RoundingMode 列挙値がいくつかあります。

私はここに来て、数字の丸め方に関する簡単な答えを求めました。これは、それを提供する補足的な回答です。

Javaで数値を丸める方法

最も一般的なケースは、 Math.round()を使用することです。

Math.round(3.7) // 4

数字は最も近い整数に丸められます。 .5 値は切り上げられます。それとは異なる丸め動作が必要な場合は、他の数学関数。以下の比較を参照してください。

ラウンド

上記のように、これは最も近い整数に丸めます。 .5 小数点以下を切り上げます。このメソッドは、 int を返します。

Math.round(3.0); // 3
Math.round(3.1); // 3
Math.round(3.5); // 4
Math.round(3.9); // 4

Math.round(-3.0); // -3
Math.round(-3.1); // -3
Math.round(-3.5); // -3 *** careful here ***
Math.round(-3.9); // -4

ceil

10進数値は、次の整数に切り上げられます。それは天井に行きます。このメソッドは double を返します。

Math.ceil(3.0); // 3.0
Math.ceil(3.1); // 4.0
Math.ceil(3.5); // 4.0
Math.ceil(3.9); // 4.0

Math.ceil(-3.0); // -3.0
Math.ceil(-3.1); // -3.0
Math.ceil(-3.5); // -3.0
Math.ceil(-3.9); // -3.0

フロア

10進数の値は、次の整数に切り捨てられます。このメソッドは double を返します。

Math.floor(3.0); // 3.0
Math.floor(3.1); // 3.0
Math.floor(3.5); // 3.0
Math.floor(3.9); // 3.0

Math.floor(-3.0); // -3.0
Math.floor(-3.1); // -4.0
Math.floor(-3.5); // -4.0
Math.floor(-3.9); // -4.0

rint

これは、10進数値が最も近い整数に丸められるという点で丸めに似ています。ただし、 round とは異なり、 .5 値は偶数の整数に丸められます。このメソッドは double を返します。

Math.rint(3.0); // 3.0
Math.rint(3.1); // 3.0
Math.rint(3.5); // 4.0 ***
Math.rint(3.9); // 4.0
Math.rint(4.5); // 4.0 ***
Math.rint(5.5); // 6.0 ***

Math.rint(-3.0); // -3.0
Math.rint(-3.1); // -3.0
Math.rint(-3.5); // -4.0 ***
Math.rint(-3.9); // -4.0
Math.rint(-4.5); // -4.0 ***
Math.rint(-5.5); // -6.0 ***

これを実現するために、このフォーマッタを使用できます:

 DecimalFormat df = new DecimalFormat("#.00");
 String resultado = df.format(valor)

または:

DecimalFormat df = new DecimalFormat("0.00"); :

常に2つの小数を取得するには、このメソッドを使用します。

   private static String getTwoDecimals(double value){
      DecimalFormat df = new DecimalFormat("0.00"); 
      return df.format(value);
    }

この値の定義:

91.32
5.22
11.5
1.2
2.6

メソッドを使用すると、次の結果を取得できます。

91.32
5.22
11.50
1.20
2.60

オンラインデモ

DecimalFormat を使用するか、または BigDecimal を使用するかを選択した回答に同意します。

最初に以下の更新をお読みください!

ただし、double値を四捨五入して double 値の結果を取得する場合は、 org.apache.commons.math3を使用できます上記の.util.Precision.round(..)。実装では BigDecimal を使用しますが、処理速度が遅く、ゴミが作成されます。

decimal4jライブラリの DoubleRounder ユーティリティにより、同様であるが高速でゴミのない方法が提供されます。

 double a = DoubleRounder.round(2.0/3.0, 3);
 double b = DoubleRounder.round(2.0/3.0, 3, RoundingMode.DOWN);
 double c = DoubleRounder.round(1000.0d, 17);
 double d = DoubleRounder.round(90080070060.1d, 9);
 System.out.println(a);
 System.out.println(b);
 System.out.println(c);
 System.out.println(d);

出力します

 0.667
 0.666
 1000.0
 9.00800700601E10

参照 https://github.com/tools4j/decimal4j/wiki/DoubleRounder-Utility

免責事項: decimal4jプロジェクトに関与しています。

更新: @iaforekが指摘したように、DoubleRounderは直観に反する結果を返すことがあります。理由は、数学的に正しい丸めを実行するためです。たとえば、 DoubleRounder.round(256.025d、2)は256.02に切り捨てられます。256.025dとして表されるdouble値は、合理的な値256.025よりもやや小さく、したがって切り捨てられるためです。

注:

  • この動作は、 BigDecimal(double)コンストラクターの動作と非常によく似ています(ただし、文字列コンストラクターを使用する valueOf(double)とは異なります)。
  • 最初に高精度の二重丸めステップで問題を回避できますが、それは複雑であり、ここでは詳細を説明しません

これらの理由と、この投稿で前述したすべてのことから、 DoubleRounderの使用をお勧めできません

JDKが最小限のテクノロジーを使用している場合。 Javaライブラリを使用しない方法を次に示します。

double scale = 100000;    
double myVal = 0.912385;
double rounded = (int)((myVal * scale) + 0.5d) / scale;

DecimalFormatは出力する最良の方法ですが、私はそれを好みません。 double値を返すため、常にこれを実行します。したがって、単なる出力以上に使用できます。

Math.round(selfEvaluate*100000d.0)/100000d.0;

または

Math.round(selfEvaluate*100000d.0)*0.00000d1;

大きな小数点以下の桁数の値が必要な場合は、代わりにBigDecimalを使用できます。とにかく .0 が重要です。 0.33333d5の丸めでは0.33333が返され、9桁のみが許可されます。 .0 のない2番目の関数には、0.30000が0.30000000000000004を返すという問題があります。

Where dp =小数点以下の桁数、 value はdoubleです。

    double p = Math.pow(10d, dp);

    double result = Math.round(value * p)/p;

String.format()およびDecimalFormatは、デフォルトのロケールを使用して文字列を生成することに注意してください。そのため、整数部分と小数部分の間の区切り文字としてドットまたはコンマを使用して、フォーマットされた数値を書き込む場合があります。丸みを帯びた文字列が希望する形式になっていることを確認するには、java.text.NumberFormatを次のように使用します。

  Locale locale = Locale.ENGLISH;
  NumberFormat nf = NumberFormat.getNumberInstance(locale);
  // for trailing zeros:
  nf.setMinimumFractionDigits(2);
  // round to 2 digits:
  nf.setMaximumFractionDigits(2);

  System.out.println(nf.format(.99));
  System.out.println(nf.format(123.567));
  System.out.println(nf.format(123.0));

英語のロケールで印刷されます(ロケールが何であれ):   0.99   123.57   123.00

例はFarendaからのものです- doubleをどのように変換するか正しく

5桁またはn桁の小数を考慮する場合。 この答えがあなたの問題を解決するかもしれません。

    double a = 123.00449;
    double roundOff1 = Math.round(a*10000)/10000.00;
    double roundOff2 = Math.round(roundOff1*1000)/1000.00;
    double roundOff = Math.round(roundOff2*100)/100.00;

    System.out.println("result:"+roundOff);

出力は次のとおりです。 123.0 1
これはループと再帰関数で解決できます。

一般に、丸めはスケーリングによって行われます: round(num / p)* p

/**
 * MidpointRounding away from zero ('arithmetic' rounding)
 * Uses a half-epsilon for correction. (This offsets IEEE-754
 * half-to-even rounding that was applied at the edge cases).
 */
double RoundCorrect(double num, int precision) {
    double c = 0.5 * EPSILON * num;
//  double p = Math.pow(10, precision); //slow
    double p = 1; while (precision--> 0) p *= 10;
    if (num < 0)
        p *= -1;
    return Math.round((num + c) * p) / p;
}

// testing edge cases
RoundCorrect(1.005, 2);   // 1.01 correct
RoundCorrect(2.175, 2);   // 2.18 correct
RoundCorrect(5.015, 2);   // 5.02 correct

RoundCorrect(-1.005, 2);  // -1.01 correct
RoundCorrect(-2.175, 2);  // -2.18 correct
RoundCorrect(-5.015, 2);  // -5.02 correct
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top