Java 如何将双精度长度四舍五入到n(不是小数点后n位)?

Java 如何将双精度长度四舍五入到n(不是小数点后n位)?,java,double,rounding,Java,Double,Rounding,我一直试图找到一种方法来确保双“值”的长度不大于10。然而,由于我没有将其四舍五入到小数点后的某个数字,因此编程变得越来越困难 例如,1234567.8912和12.345678912都大于10位,但它们必须四舍五入到不同的小数位数。我的逻辑是找到小数点的位置,并将双精度四舍五入到“小数点前的10位数” 我创建了两种不同的方法,但两种方法似乎都不能正常工作 if ((Double.toString(value)).length()> 10){ int counter

我一直试图找到一种方法来确保双“值”的长度不大于10。然而,由于我没有将其四舍五入到小数点后的某个数字,因此编程变得越来越困难

例如,1234567.8912和12.345678912都大于10位,但它们必须四舍五入到不同的小数位数。我的逻辑是找到小数点的位置,并将双精度四舍五入到“小数点前的10位数”

我创建了两种不同的方法,但两种方法似乎都不能正常工作

    if ((Double.toString(value)).length()> 10){
        int counter = 0;
        double no_of_dec = 1;
        double no_of_int = 1;
        double new_value = 0;
        for (int i = 0; i< (Double.toString(value)).length(); i++){
            if ( (Character.toString((Double.toString(value)).charAt(i))).equals(".") ){
                counter = 1;
            } if (counter == 1){
                no_of_dec = no_of_dec * 10;
            } else if (counter == 0){
                no_of_int = no_of_int * 10;
            }
        } 
        no_of_dec = no_of_dec / (no_of_int);
        new_value = (double)Math.round(value * 100d/100d);
        return Double.toString(new_value);
    } else {
        return Double.toString(value);
    }


    if ((Double.toString(value)).length()> 10){
        double no_of_dec = 0;
        double no_of_int = 0;
        double new_value = 0;
        for (int i = 0; i< (Double.toString(value)).length(); i++){
            while (!(Character.toString((Double.toString(value)).charAt(i))).equals(".")){
                no_of_int = no_of_int + 1;
            }
        }
        no_of_dec = (Double.toString(value)).length() - no_of_int;
        no_of_dec = no_of_dec * 10;
        new_value = (double)Math.round(value * no_of_dec/no_of_dec);
        return Double.toString(new_value);
    } else {
        return Double.toString(value);
    }
}
if((Double.toString(value)).length()>10){
int计数器=0;
双no_的_dec=1;
_int=1的双no_;
双新_值=0;
对于(int i=0;i<(Double.toString(value)).length();i++){
if((Character.toString((Double.toString(value)).charAt(i))等于(“.”){
计数器=1;
}如果(计数器==1){
12月的数量=12月的数量*10;
}else if(计数器==0){
非整数=非整数*10;
}
} 
无dec=无dec/(无int);
新的_值=(双)数学舍入(值*100d/100d);
返回Double.toString(新的_值);
}否则{
返回Double.toString(值);
}
if((Double.toString(value)).length()>10){
双no_的_dec=0;
双no_的_int=0;
双新_值=0;
对于(int i=0;i<(Double.toString(value)).length();i++){
而(!(Character.toString((Double.toString(value)).charAt(i))等于(“.”){
不含整数=不含整数+1;
}
}
no_of_dec=(Double.toString(value)).length()-no_of_int;
12月的数量=12月的数量*10;
新值=(双精度)数学四舍五入(值*数字编号/数字编号);
返回Double.toString(新的_值);
}否则{
返回Double.toString(值);
}
}
我是这样做的:

private static BigDecimal getRounded(double n, int totalDigits) {

    String nString = Double.toString(n); // transform to string to make the job easier

    if(nString.contains(".")) {
        int dotPos = nString.indexOf("."); // = number of digits before the decimal point

        int remainingDigits = totalDigits - dotPos; // = remaining digits after the decimal point

        return new BigDecimal(nString).setScale(remainingDigits, BigDecimal.ROUND_HALF_UP); // round
    }

    return new BigDecimal(n);
}
这是我的测试:

double n = 1234567.8912;
System.out.println(getRounded(n, 10));

n = 12.345678915;
System.out.println(getRounded(n, 10));
结果如下:

1234567.891
12.34567892
演示:

具有执行此操作的操作:

double truncate(double value) {
    BigDecimal b = new BigDecimal(String.valueOf(value));
    b = b.round(new MathContext(10));
    return b.doubleValue();
}
使用BigDecimal(String)构造函数而不是BigDecimal(double)构造函数是有原因的。double和float不是以10为基数的数字,因此它们并不完全代表我们在打印它们时看到的值;这本书很好地说明了这一点。这不是Java独有的,在大多数语言中也是如此

更新:

4CARS指出,对于不小于1的非零个数,这将不起作用,因为BigDePiple不认为零整数部分是一个有效的数字。你可以解决这个问题:

double truncate(double value) {
    int precision = 10;
    if (value != 0 && Math.abs(value) < 1) {
        precision--;
    }

    BigDecimal b = new BigDecimal(String.valueOf(value));
    b = b.round(new MathContext(precision));
    return b.doubleValue();
}
双截断(双值){
整数精度=10;
如果(值!=0&&Math.abs(值)<1){
精度--;
}
BigDecimal b=新的BigDecimal(String.valueOf(value));
b=b.round(新的MathContext(精度));
返回b.doubleValue();
}
更新2:

反斜杠指出,对于-1和1之间的非零数,它比上面的更复杂。我确信可以计算出所需的精确精度,但我认为更简单的方法是,为了四舍五入的目的,只需添加1即可消除该问题:

double truncate(double value) {
    BigDecimal b = new BigDecimal(String.valueOf(value));

    MathContext context = new MathContext(10);
    if (value > 0 && value < 1) {
        b = b.add(BigDecimal.ONE);
        b = b.round(context);
        b = b.subtract(BigDecimal.ONE);
    } else if (value < 0 && value > -1) {
        b = b.subtract(BigDecimal.ONE);
        b = b.round(context);
        b = b.add(BigDecimal.ONE);
    } else {
        b = b.round(context);
    }

    return b.doubleValue();
}
双截断(双值){
BigDecimal b=新的BigDecimal(String.valueOf(value));
MathContext=新的MathContext(10);
如果(值>0&&值<1){
b=b.add(BigDecimal.ONE);
b=b.圆形(上下文);
b=b.减法(大十进制1);
}else if(值<0&&value>-1){
b=b.减法(大十进制1);
b=b.圆形(上下文);
b=b.add(BigDecimal.ONE);
}否则{
b=b.圆形(上下文);
}
返回b.doubleValue();
}

如果数字为
0.1234567891
前导零是否算作数字?什么是“必须四舍五入到不同的小数位数”?但是,您能举一个例子作为输入和预期输出吗?@4castle yes itdoes@snr例如,1.3456789556和13456.789556都大于10位。但是,它们都有不同的小数位数。因此,对于第一个示例,您必须将其四舍五入到小数点后9位,而对于第二个示例,您必须将其四舍五入到小数点后5位,以使其长度为10位。double没有小数。它们有二进制数字,两个是不可通约的。你所要求的原则上是不可能的。如果您想要十进制数字,请使用十进制基数,例如
BigDecimal
。这绝对是最好的解决方案,但我发现前导零(见我上面的注释)不算作精度的一部分,因此,在这种情况下,它给出的数字太多了。将其变回
双精度
会破坏
BigDecimal
所做的一切。而且
BigDecimal
确实有一个来自
double
的构造函数。事实上,它不仅仅返回一个数字小于1的多个数字。它每前导零多返回一个数字。例如,我用
0.00034567089445515
尝试了这个方法:它返回14位长的
0.0003456708945
:10+4个前导零。如果输入try with
0.00000000 34567089445515
,则返回
0.00000000 3456708945
,长度为19位:10+9个前导零@EJPI解释了为什么应该避免使用BigDecimal(double)构造函数;javadoc很好地解释了这一点。你能举一个输入值被转换破坏的例子吗?我尝试的每个输入值都有效。@反斜杠正确。更新。