Search code examples
javadoubledigitsignificant-digits

How to increment fixed significant digit in Java?


I am not sure that Java has tools for it but if there is a solution in Java it would be awesome. For example, I need to increment fifth significant digit in Double / Decimal / BigDecimal or similar variable.

// 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

Is there any solution to increment / decrement fixed significant digits?

EDIT:
Inaccurate arithmetic is OK. I.e. if we turn 12.5 to 12.50100000000041 its OK.
Min input value is 0.00001. Max input value is 100000.0.
Max significant digit to increment/decrement is 5.
I.e. min output value after increment is 0.000010001
Length from highest significant digit to least significant digit is no more than 10

P.S. Please, test your solution at least with all example numbers listed in this question before posting an answer. I will check all answers to find the most effective solution. The fastest method will be marked as a correct one.


Solution

  • Here is my solution till now. It's not nice as I need to work with a string but it is pretty fast. At least I don't know how to make it faster.

    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);
    }