将双精度数字舍入为 3 位有效数字

发布于 2024-12-06 13:41:27 字数 204 浏览 3 评论 0原文

有谁知道我如何将双精度值舍入为 3 位有效数字,如本网站上的示例

http: //www.purplemath.com/modules/rounding2.htm

注意:有效数字与小数位不同

Does anybody know how I can round a double value to 3 significant figures like the examples on this website

http://www.purplemath.com/modules/rounding2.htm

Note: significant figures are not the same as decimal places

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

唔猫 2024-12-13 13:41:27
double d = ...;
BigDecimal bd = new BigDecimal(d);
bd = bd.round(new MathContext(3));
double rounded = bd.doubleValue();
double d = ...;
BigDecimal bd = new BigDecimal(d);
bd = bd.round(new MathContext(3));
double rounded = bd.doubleValue();
守望孤独 2024-12-13 13:41:27

如果您想手动执行此操作:

import java.lang.Math;

public class SigDig {

  public static void main(String[] args) {
    System.out.println("   -123.456   rounded up   to 2 sig figures is " + sigDigRounder(-123.456, 2,  1));
    System.out.println("     -0.03394 rounded down to 3 sig figures is " + sigDigRounder(-0.03394, 3, -1));
    System.out.println("    474       rounded up   to 2 sig figures is " + sigDigRounder(474, 2,  1));
    System.out.println("3004001       rounded down to 4 sig figures is " + sigDigRounder(3004001, 4, -1));
  }

  public static double sigDigRounder(double value, int nSigDig, int dir) {

    double intermediate = value/Math.pow(10,Math.floor(Math.log10(Math.abs(value)))-(nSigDig-1));

    if(dir > 0)      intermediate = Math.ceil(intermediate);
    else if (dir< 0) intermediate = Math.floor(intermediate);
    else             intermediate = Math.round(intermediate);

    double result = intermediate * Math.pow(10,Math.floor(Math.log10(Math.abs(value)))-(nSigDig-1));

    return(result);

  }
}

上述方法将双精度数舍入为所需的有效数字数,处理负数,并且可以明确告知向上或向下舍入

If you want to do it by hand:

import java.lang.Math;

public class SigDig {

  public static void main(String[] args) {
    System.out.println("   -123.456   rounded up   to 2 sig figures is " + sigDigRounder(-123.456, 2,  1));
    System.out.println("     -0.03394 rounded down to 3 sig figures is " + sigDigRounder(-0.03394, 3, -1));
    System.out.println("    474       rounded up   to 2 sig figures is " + sigDigRounder(474, 2,  1));
    System.out.println("3004001       rounded down to 4 sig figures is " + sigDigRounder(3004001, 4, -1));
  }

  public static double sigDigRounder(double value, int nSigDig, int dir) {

    double intermediate = value/Math.pow(10,Math.floor(Math.log10(Math.abs(value)))-(nSigDig-1));

    if(dir > 0)      intermediate = Math.ceil(intermediate);
    else if (dir< 0) intermediate = Math.floor(intermediate);
    else             intermediate = Math.round(intermediate);

    double result = intermediate * Math.pow(10,Math.floor(Math.log10(Math.abs(value)))-(nSigDig-1));

    return(result);

  }
}

The above method rounds a double to a desired number of significant figures, handles negative numbers, and can be explicitly told to round up or down

别忘他 2024-12-13 13:41:27

Sean Owen (https://stackoverflow.com/a/7548871/274677) 给出的答案没有任何问题。但是,根据您的用例,您可能希望获得字符串表示形式。在这种情况下,IMO 最好在仍在 BigDecimal 空间中时使用以下方法进行转换:

bd.toPlainString();

... 如果这是您的用例,那么您可能会感到沮丧,根据 Owen 的答案改编的代码将产生以下结果:

d = 0.99, significantDigits = 3 ==> 0.99

... 而不是严格的 more准确0.990

如果这些事情在您的用例中很重要,那么我建议对欧文的答案进行以下调整;显然,您也可以返回 BigDecimal 本身,而不是调用 toPlainString() - 我只是为了完整性而提供这种方式。

public static String setSignificanDigits(double value, int significantDigits) {
    if (significantDigits < 0) throw new IllegalArgumentException();

    // this is more precise than simply doing "new BigDecimal(value);"
    BigDecimal bd = new BigDecimal(value, MathContext.DECIMAL64);
    bd = bd.round(new MathContext(significantDigits, RoundingMode.HALF_UP));
    final int precision = bd.precision();
    if (precision < significantDigits)
    bd = bd.setScale(bd.scale() + (significantDigits-precision));
    return bd.toPlainString();
}    

There's nothing wrong with the answer given by Sean Owen (https://stackoverflow.com/a/7548871/274677). However depending on your use case you might want to arrive at a String representation. In that case, IMO it is best to convert while still in BigDecimal space using:

bd.toPlainString();

... if that's your use case then you might be frustrated that the code adapted from Owen's answer will produce the following:

d = 0.99, significantDigits = 3 ==> 0.99

... instead of the strictly more accurate 0.990.

If such things are important in your use case then I suggest the following adaptation to Owen's answer ; you can obviously also return the BigDecimal itself instead of calling toPlainString() — I just provide it this way for completeness.

public static String setSignificanDigits(double value, int significantDigits) {
    if (significantDigits < 0) throw new IllegalArgumentException();

    // this is more precise than simply doing "new BigDecimal(value);"
    BigDecimal bd = new BigDecimal(value, MathContext.DECIMAL64);
    bd = bd.round(new MathContext(significantDigits, RoundingMode.HALF_UP));
    final int precision = bd.precision();
    if (precision < significantDigits)
    bd = bd.setScale(bd.scale() + (significantDigits-precision));
    return bd.toPlainString();
}    
德意的啸 2024-12-13 13:41:27
    public String toSignificantFiguresString(BigDecimal bd, int significantFigures ){
    String test = String.format("%."+significantFigures+"G", bd);
    if (test.contains("E+")){
        test = String.format(Locale.US, "%.0f", Double.valueOf(String.format("%."+significantFigures+"G", bd)));
    }
    return test;
}
    public String toSignificantFiguresString(BigDecimal bd, int significantFigures ){
    String test = String.format("%."+significantFigures+"G", bd);
    if (test.contains("E+")){
        test = String.format(Locale.US, "%.0f", Double.valueOf(String.format("%."+significantFigures+"G", bd)));
    }
    return test;
}
紫竹語嫣☆ 2024-12-13 13:41:27

双 d=3.142568;
System.out.printf("答案:%.3f", d);

double d=3.142568;
System.out.printf("Answer : %.3f", d);

无边思念无边月 2024-12-13 13:41:27

如何将双精度值舍入为 3 位有效数字

你不能。双精度数以二进制表示。它们没有要四舍五入的小数位。获得特定小数位数的唯一方法是将其转换为小数基数并将其保留在那里。当您将其转换回双精度时,您再次失去了小数精度。

对于这里和其他地方的所有转换为其他基数和反向转换,或乘以和除以 10 的幂的粉丝,请显示结果双精度值 % 0.001 或所需精度规定的任何内容,并解释结果。

编辑:具体来说,这些技术的支持者需要解释以下代码的 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 % .0001)="+(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");
    }
}

how I can round a double value to 3 significant figures

You can't. Doubles are representing in binary. They do not have decimal places to be rounded to. The only way you can get a specific number of decimal places is to convert it to a decimal radix and leave it there. The moment you convert it back to double you have lost the decimal precision again.

For all the fans, here and elsewhere, of converting to other radixes and back, or multiplying and dividing by powers of ten, please display the resulting double value % 0.001 or whatever the required precision dictates, and explain the result.

EDIT: Specifically, the proponents of those techniques need to explain the 92% failure rate of the following code:

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 % .0001)="+(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");
    }
}
耀眼的星火 2024-12-13 13:41:27

我通常不会舍入数字本身,而是在需要显示数字时舍入数字的字符串表示形式,因为通常重要的是显示,需要舍入(尽管在情况,也许是你的情况,但如果是这样,你需要详细说明)。这样,我的号码就可以保持其准确性,但它的显示会被简化且更易于阅读。为此,可以使用 DecimalFormat 对象,例如用“0.000”字符串初始化 (new DecimalFormat("0.000")),或使用 String.format("%.3f" , myDouble),或其他几种方式。

例如:

// yeah, I know this is just Math.PI.
double myDouble = 3.141592653589793;
DecimalFormat myFormat = new DecimalFormat("0.000");
String myDoubleString = myFormat.format(myDouble);
System.out.println("My number is: " + myDoubleString);

// or you can use printf which works like String.format:
System.out.printf("My number is: %.3f%n", myDouble);

I usually don't round the number itself but round the String representation of the number when I need to display it because usually it's the display that matters, that needs the rounding (although this may not be true in situations, and perhaps yours, but you need to elaborate on this if so). This way, my number retains its accuracy, but it's display is simplified and easier to read. To do this, one can use a DecimalFormat object, say initialzed with a "0.000" String (new DecimalFormat("0.000")), or use String.format("%.3f", myDouble), or several other ways.

For example:

// yeah, I know this is just Math.PI.
double myDouble = 3.141592653589793;
DecimalFormat myFormat = new DecimalFormat("0.000");
String myDoubleString = myFormat.format(myDouble);
System.out.println("My number is: " + myDoubleString);

// or you can use printf which works like String.format:
System.out.printf("My number is: %.3f%n", myDouble);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文