4

JavaScript から Java にアルゴリズムを移植する際に、JavaScript の toPrecision() を置き換える必要があるという問題に遭遇しました。問題は、数値がどのくらい小さいか大きいかがわからないため、正しい形式で単純な NumberFormat を使用できないことです。

同様の機能を提供する標準クラスはありますか?

編集これが私が思いついたものです:

   double toPrecision(double n, double p) {
        if (n==0) return 0;

        double e = Math.floor(Math.log10(Math.abs(n)));
        double f = Math.exp((e-p+1)*Math.log(10));

        return Math.round(n/f)*f;
    }

原則として、正しいことを行いますが、丸め誤差によって完全に台無しになります。たとえば、 toPrecision(12.34567, 3)返品12.299999999999997

編集 2 このバージョンは、12 個のテスト ケースのうち 11 個で完全に機能します...

   double toPrecision(double n, double p) {
        if (n==0) return 0;

        double e = Math.floor(Math.log10(Math.abs(n)));
        double f = Math.round(Math.exp((Math.abs(e-p+1))*Math.log(10)));
        if (e-p+1<0) {
            f = 1/f;
        }

        return Math.round(n/f)*f;
    }

しかし、それでも代わりにtoPrecision(0.00001234567, 3)戻ります1.2299999999999999E-51.23E-5

4

6 に答える 6

12

精度を設定する用途BigDecimalと方法setScale()

BigDecimal bd = new BigDecimal("1.23456789");
System.out.println(bd.setScale(3,BigDecimal.ROUND_HALF_UP));

出力

1.235

見る

于 2012-08-21T11:41:12.670 に答える
3

これに対して私が思いついた最も簡単な解決策は、との組み合わせを使用しjava.math.BigDecimalますjava.math.MathContext

String toPrecision(double number, int precision) {
    return new BigDecimal(number, new MathContext(precision)).toString();
}

Number.prototype.toPrecisionのdynjs 実装でこれを使用しています。

于 2012-11-13T17:11:59.767 に答える
2

String.format を使用した Java ソリューションを次に示します。

public static String toPrecision(double d, int digits) {
    s = String.format("%."+((digits>0)?digits:16)+"g",d).replace("e+0","e+").replace("e-0","e-");
    return s;
}

.replace は、指数に先行ゼロがない JavaScript を模倣する場合にのみ必要です。丸めに使用するだけの場合は、値を次のように返します

return Double.parseDouble(s);

単体テスト コードを次に示します。

public void testToPrecision() {
    String s = NumberFormat.toPrecision(1234567.0,5);
    assertEquals("1.2346e+6",s);
    s = NumberFormat.toPrecision(12.34567,5);
    assertEquals("12.346",s);
    s = NumberFormat.toPrecision(0.1234567,5);
    assertEquals("0.12346",s);
    s = NumberFormat.toPrecision(0.1234567e20,5);
    assertEquals("1.2346e+19",s);
    s = NumberFormat.toPrecision(-0.1234567e-8,5);
    assertEquals("-1.2346e-9",s);
    s = NumberFormat.toPrecision(1.0/3.0,5);
    assertEquals("0.33333",s);
    s = NumberFormat.toPrecision(1.0/3.0,0);
    assertEquals("0.3333333333333333",s);
}
于 2012-11-20T18:14:28.840 に答える
1

これはついに機能します...

double toPrecision(double n, double p) {
    if (n==0) return 0;

    double e = Math.floor(Math.log10(Math.abs(n)));
    double f = Math.round(Math.exp((Math.abs(e-p+1))*Math.log(10)));

    if (e-p+1<0) {
        return Math.round(n*f)/f;
    }

    return Math.round(n/f)*f;
}
于 2012-08-21T12:44:41.110 に答える
1

doubleで使用できます

double d = 1.23456789;
System.out.println(Math.round(d * 1e3) / 1e3);

プリント

1.235

また

System.out.printf("%.3f%n", d);

同じことをします。


public static void main(String... args) {
    System.out.println(round3significant(12345678.9));
    System.out.println(round3significant(0.0000012345));
}

public static double round3significant(double d) {
    if (d < 100) {
        double divide = 1;
        while(d < 100) {
            d *= 10;
            divide *= 10;
        }
        return Math.round(d) / divide;
    } else {
        double multi = 1;
        while(d > 1000) {
            d /= 10;
            multi *= 10;
        }
        return Math.round(d) * multi;
    }
}

プリント

1.23E7
1.23E-6

NumberFormatを使用して、小数としてのみ表示できます。

于 2012-08-21T11:51:07.003 に答える
0
    import java.text.*;  
Class Decimals
{  
    public static void main(String[] args)
    {  
        float f = 125.069f;  
        DecimalFormat form = new DecimalFormat("#.##");  
        System.out.println(form.format(f));  
    }
}

.## は、必要な小数点以下の桁数を表します。これが要件に合っていることを願っています。

于 2012-08-21T12:09:27.673 に答える