1

I am trying to calculate the value a field which represent Interest rate for that I have to round up the value to 3 digits.

Below is code which I am using :

double bigAmt1 = Double.parseDouble(amount);
            bigAmt = (intsign*bigAmt1)/div;
            
        bigAmt=Math.round(bigAmt*1000d)/1000d;

amount = 4048500
intsign = 1
div = 6

it returns = 4.048 I need it return = 4.049

if I change the value of amount to 4048600 then it return 4.049 so I think it is rounding up values where last digit after division is greater than 5 but It should be if last digit equal or greater than 5 then It should round up to next digit.

Below is my test class --

package test;

import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.text.DecimalFormat;

public class Test {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        System.out.println(divideAndConvertToString1("4048100","6","1"));
        //System.out.println("---> 3 places  "+Math.round(3.5));
        //Math.round(3.7)
        /*double value = 12.3457652133;
        value =Double.parseDouble(new DecimalFormat("##.####").format(value));
        System.out.println("---> 3 places  "+value);*/
    }
    
    public static String divideAndConvertToString(String amount, String decml, String sign) {

        double bigAmt = 0.00;
        
        int div = 0;
        
        double d =0;
        
        if (!isStringEmpty(decml)) {
          d = Double.parseDouble(decml);
        }
        
        double d1 = Math.pow(10, d);
        div = (int)d1;              
        
        int intsign = Integer.parseInt(sign);
        
        if (amount != null && !"".equalsIgnoreCase(amount)) {
            //BigDecimal bigAmt1 = new BigDecimal(amount);
            
            double bigAmt1 = Double.parseDouble(amount);
            bigAmt = (intsign*bigAmt1)/div;         
            bigAmt=Math.ceil(bigAmt*1000d)/1000d;
            
            //bigAmt = new BigDecimal((intsign*bigAmt1.doubleValue())/div);
            
            return  String.valueOf(bigAmt);
                        
        }
        else {
            bigAmt = bigAmt;
        }
        System.out.println("inside divideAndConvertToString");
        return String.valueOf(bigAmt);
        
    }
    
    
     public static String divideAndConvertToString1(String amount, String decml, String sign) {

         BigDecimal bigAmt = null;
            
            int div = 0;
            
            double d =0;
            
            if (!Util.isStringEmpty(decml)) {
              d = Double.parseDouble(decml);
            }
            
            double d1 = Math.pow(10, d);
            div = (int)d1;              
            
            int intsign = Integer.parseInt(sign);
            
            if (amount != null && !"".equalsIgnoreCase(amount)) {
                BigDecimal bigAmt1 = new BigDecimal(amount);

                bigAmt = new BigDecimal((intsign*bigAmt1.doubleValue())/div);
            }
            else {
                bigAmt = new BigDecimal("0");
            }
            System.out.println("inside divideAndConvertToString1");

            return String.valueOf(bigAmt.setScale(3, RoundingMode.CEILING));
            
            //System.out.println(b.setScale(0, RoundingMode.CEILING)); 
            
        }
     
     public static boolean isStringEmpty(String input) {
            if (input == null || input.trim().length() == 0 || "".equalsIgnoreCase(input)) {
                return true;
            }
            return false;
        }

}
mradul
  • 509
  • 4
  • 12
  • 28
  • Does this answer your question? [rounding .5 down in java](https://stackoverflow.com/questions/27450766/rounding-5-down-in-java) – Amongalen Dec 03 '20 at 08:17
  • @Amongalen -- Thanks for reply but unfortunately that i have checked already it is not rounding up values which are equal to 5 to next digit. – mradul Dec 03 '20 at 08:26
  • Indeed a case for BigDecimal even though the usage is more verbose (`.add`, .`multiply`); use String constructors like `new BigDecimal("4.048500"). The problem is that Math,round(calculated 4048.5) might round 4048.4999998. – Joop Eggen Dec 03 '20 at 08:26
  • try BigDecimal; BigDecimal b = new BigDecimal(amount); System.out.println(b.setScale(0, RoundingMode.CEILING)); – brijesh Dec 03 '20 at 08:37
  • @brijesh -- i tried this way as well but it is rounding up values where last is less than 5 to next digit like amount = 4048300 then it is giving 4.049 whereas it should give 4.048 in this case – mradul Dec 03 '20 at 09:24
  • @mradul Then use a different rounding mode than CEILING, eg HALF_UP. – Mark Rotteveel Dec 05 '20 at 09:57

2 Answers2

1

Math.round should work however I usual do this like this:

bigAmt=Math.floor((bigAmt*1000d)+0.5d)/1000d;

Your problem however lies elsewhere:

bigAmt1 = Double.parseDouble(amount);
bigAmt = (intsign*bigAmt1)/div;
bigAmt=Math.round(bigAmt*1000d)/1000d;

So using your values:

amount = 4048500
intsign = 1
div = 6

bigAmt1 = 4048500;
bigAmt = (1*4048500)/6 = 674750;
bigAmt=   round(674750*1000)/1000 = round(674750000)/1000 = 674750;

However in your example You wrote: it returns = 4.048 I need it return = 4.049 So do you have the same div value? If the div is 1000000 instead then:

bigAmt1 = 4048500;
bigAmt = (1*4048500)/1000000 = 4.048500;
bigAmt=   round(4.048500*1000)/1000 = round(4048.500)/1000 = 4.049;

However there is a big problem because floating point might round your 4.048500 number to something like 4.048499999999. It is safer to use integer rounding directly:

1000* ((amount+500)/1000)
1000* ((4048500+500)/1000)
1000* ((4049000    )/1000)
1000* (4049)
       4049000

So you add half of the rounding value, divide by rounding value and then multiply by rounding value. All done on integers

Spektre
  • 49,595
  • 11
  • 110
  • 380
0

Why won't you use Math.ceil(), instead of Math.round(), I think that's what it's for.

  • I tried using math.ceil() but it is rounding even if last value is less than 5 to next digit like amount = 4048300 then it is giving 4.049 whereas it should give 4.048 in this case – mradul Dec 03 '20 at 09:18
  • @mradul round/ceil/floor is not the problem... problem is floating point rounding, you need to round on integer arithmetics and store the result to double ... – Spektre Dec 03 '20 at 12:00
  • The main problem is that there is `1.5` but there is no `1.05` or `1.005` ,... number in floating point ... and only the closest (slightly less) binary representable number is used ... – Spektre Dec 03 '20 at 12:04
  • Oh, i see, sorry misunderstood your question, i will let you know when i find it out – user14302571 Dec 03 '20 at 12:13