如何在Java中增加固定有效位?

如何在Java中增加固定有效位?,java,double,digit,significant-digits,Java,Double,Digit,Significant Digits,我不确定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 ->

我不确定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
对于固定有效数字的递增/递减,是否有任何解决方案

编辑:
不准确的算术是可以的。也就是说,如果我们将12.5转为12.50100000000041,就可以了。
最小输入值为0.00001。最大输入值为100000.0。
递增/递减的最大有效位为5。
即增量后最小输出值为0.000010001
从最高有效位到最低有效位的长度不超过10

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

希望这能帮助您:

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+", "$1");
    String rightPart = String.valueOf(number).replaceAll("^\\d+\\.(\\d+)", "$1");
    int left = leftPart.length();
    int right = rightPart.length();
    if (Integer.parseInt(leftPart) == 0) {
        position = 6 + rightPart.replaceAll("^([0]*).*", "$1").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..................................");
}


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

  • 计算给定数字的克拉数,例如:
    1->1152->3123.65899->8
  • 您现在有两个案例,
    size>5或5,然后从您的号码中删除“逗号”,并以10**大小的格式保存“逗号”后的号码大小,例如:
    12345.67=1234567 x 10**-2,0.1234567=1234567 x 10**-7
  • 删除“逗号”后在数字上加1:
    12345.67=(1234567+1)x10**-2=12345.68,0.99999=(99999+1)x10**-5=1.00000
  • 第二种情况:如果尺寸为(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);
    }
    
    public静态final DecimalFormat DF=(DecimalFormat)NumberFormat.getNumberInstance(Locale.ENGLISH);
    静止的{
    DF.setMaximumFractionDigits(16);
    DF.setGroupingUsed(假);
    }
    公共静态双固定有效数字增量(双输入,整数有效数字){
    返回输入+固定有效数字量(输入,有效数字);
    }
    公共静态双固定有效数字递减(双输入,整数有效数字){
    返回输入固定有效数字量(输入,有效数字);
    }
    公共静态双固定有效数字量(双输入,整数有效数字){
    字符串inputStr=DF.format(输入);
    int pointIndex=inputStr.indexOf('.');
    int-digitsBeforePoint;
    如果(点索引==-1){
    pointIndex=inputStr.length();
    digitsBeforePoint=inputStr.length();
    }否则{
    digitsBeforePoint=点索引;
    如果(digitsBeforePoint==1&&inputStr.charAt(0)==0')digitsBeforePoint=0;
    }
    
    如果(significtdigitno,浮点运算无论如何都是不准确的。为什么你认为你需要这样做?这是可行的,但在IEEE754二进制浮点中会非常非常棘手。我的建议是通过BigDecimal路径。我有一个特殊的计算,需要增加/减少nu中的有效数字成员数。预期的“数字”为十进制,双精度实现为二进制。FP计算不仅存在精度问题(如@kayaman say),但表示法也有问题:并非每个值都存在于双域中。这不能四舍五入,或者不能通过四舍五入来实现。@YCF_L:除了使用正则表达式计算数量级之外,这很好。但是它显示了错误的值…0.12345必须是0.12346,依此类推。有些值是正确的,有些则不是。请检查r输出与问题的输出OK@Alexandr我们接近了,我将很快编辑我的答案我忘记了这个案例;)@Alexandr那么像0.123这样的案例中的0不算?抱歉,它仍然不起作用。检查答案中的输出值。与您的解决方案不起作用的案例:
    0.0012345->0.0012346
    0.000123456789->0.000123466789
    @Alexandr立即检查抱歉,您的解决方案不起作用。请使用
    0.01234567->>0.01测试您的解决方案234667
    。请在编辑有问题的输出值之前检查您的解决方案。
    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);
    }