如何增加 Java 中的固定有效数字?

How to increment fixed significant digit in Java?

我不确定 Java 是否有相应的工具,但如果 Java 中有解决方案那就太棒了。 例如,我需要在 Double / Decimal / BigDecimal 或类似变量中增加第五位有效数字。

// Left is what I have. Right is what I need to get
12345 -> 12346
1234567 -> 1234667
123 -> 123.01
0.12345 -> 0.12346
0.1 -> 0.10001
0.0012345 -> 0.0012346
123.5 -> 123.51
12.5 -> 12.501
0.000123456789 -> 0.000123466789

有没有固定有效数字递增/递减的解决方案?

编辑:
不准确的算术是可以的。 IE。如果我们将 12.5 变为 12.50100000000041 就可以了。
最小输入值为 0.00001。最大输入值为 100000.0.
increment/decrement 的最大有效数字为 5。
IE。增量后的最小输出值为 0.000010001
最高有效位到最低有效位的长度不超过10

P.S。在发布答案之前,请至少使用此问题中列出的所有示例编号测试您的解决方案。 我将检查所有答案以找到最有效的解决方案。最快的方法将被标记为正确方法。

希望对您有所帮助:

int position;
BigDecimal[] numbers = {new BigDecimal("12345.0"), new BigDecimal("1234567.0"),
    new BigDecimal("0.12345"), new BigDecimal("0.1"),
    new BigDecimal("0.0012345"), new BigDecimal("123.5"), new BigDecimal("12.5"),
    new BigDecimal("1234500000.0000000012345")};

for (BigDecimal number : numbers) {
    System.out.println(number);
    String leftPart = String.valueOf(number).replaceAll("^(\d+)\.\d+", "");
    String rightPart = String.valueOf(number).replaceAll("^\d+\.(\d+)", "");
    int left = leftPart.length();
    int right = rightPart.length();
    if (Integer.parseInt(leftPart) == 0) {
        position = 6 + rightPart.replaceAll("^([0]*).*", "").length();
    } else {
        position = 5;
    }
    if (left <= position) {
        number = number.add(new BigDecimal(Math.pow(0.1, position - left)));
    } else {
        number = number.add(new BigDecimal(Math.pow(10, left - position)));
    }
    System.out.println(number.setScale(right > 5 ? right : 5, RoundingMode.DOWN) + "\n..................................");
}

备注

如果递增

,可以将add改为subtract

输出

12345.0
12346.00000
..................................
1234567.0
1234667.00000
..................................
0.12345
0.12346
..................................
0.1
0.10001
..................................
0.0012345
0.0012346
..................................
123.5
123.51000
..................................
12.5
12.50100
..................................
1234500000.0000000012345
1234600000.0000000012345
..................................

ideone demo

我可以提出一个有效的方法:

  1. 计算给定数字的克拉数,例如:1 -> 1, 152 -> 3, 123.65899 -> 8
  2. 你现在有两个案例,size is >5 or <5
  3. 第一种情况:如果大小>5,则从您的号码中删除"comma"并将号码的大小保存在"comma"之后10**size 格式,例如:12345.67 = 1234567 x 10**-2 , 0.1234567 = 1234567 x 10**-7
  4. 去掉"comma"后数字加1:12345.67 = (1234567 + 1) x 10**-2 = 12345.68 , 0.99999 = (99999 + 1) x 10**-5 = 1.00000
  5. 第二种情况:如果大小小于 5,则添加零并将 10 的幂乘以负值,示例 5 = 50000 x 10**-4
  6. 与第一种情况相同加1并应用10**-x,示例:1234 = 12340 x 10**-1 -> (12340 + 1) x 10**-1 = 1234.1

注意:您可以将此解决方案应用于除 5 之外的任何其他数字。

到目前为止,这是我的解决方案。这不太好,因为我需要使用字符串,但速度非常快。至少我不知道如何让它更快。

public static final DecimalFormat DF = (DecimalFormat) NumberFormat.getNumberInstance(Locale.ENGLISH);

static {
    DF.setMaximumFractionDigits(16);
    DF.setGroupingUsed(false);
}

public static double fixedSignificantDigitIncrement(double input, int significantDigit){
    return input+fixedSignificantDigitAmount(input, significantDigit);
}

public static double fixedSignificantDigitDecrement(double input, int significantDigit){
    return input-fixedSignificantDigitAmount(input, significantDigit);
}

public static double fixedSignificantDigitAmount(double input, int significantDigit){
    String inputStr = DF.format(input);

    int pointIndex = inputStr.indexOf('.');

    int digitsBeforePoint;
    if(pointIndex==-1){
        pointIndex=inputStr.length();
        digitsBeforePoint=inputStr.length();
    } else {
        digitsBeforePoint = pointIndex;
        if(digitsBeforePoint==1 && inputStr.charAt(0)=='0') digitsBeforePoint=0;
    }

    if(significantDigit<=digitsBeforePoint){
        return Math.pow(10, digitsBeforePoint-significantDigit);
    }  else if(digitsBeforePoint==0){
        ++pointIndex;
        for(;pointIndex<inputStr.length();pointIndex++){
            if(inputStr.charAt(pointIndex)!='0') break;
        }

        return 1/Math.pow(10, significantDigit+(pointIndex-2));
    }

    return 1/Math.pow(10, significantDigit-digitsBeforePoint);
}