Double to fraction in Java

Neutrino picture Neutrino · Dec 23, 2012 · Viewed 23k times · Source

So what I'm trying to do is convert double to rational number. I check how many digits there is after decimal point and I want to save the number 123.456 as 123456 / 1000, for example.

public Rational(double d){      
    String s = String.valueOf(d);
    int digitsDec = s.length() - 1 - s.indexOf('.');        

    for(int i = 0; i < digitsDec; i++){
        d *= 10;
    }

    System.out.println((int)d); //checking purposes
}   

However, for the number 123.456 I get a round off error and the result is 123455. I guess it'd be possible to fix this with BigDecimal but I can't get it to work. Also, having calculated what rational number it would be, I would like to call another constructor with parameters (int numerator, int denominator) but I can't obviously call the constructor in the line where println is now. How should I do this?

Answer

ktm5124 picture ktm5124 · Dec 23, 2012

For the first part of the question, Java is storing .6 as .5999999 (repeating). See this output:

(after first multiply): d=1234.56
(after second multiply): d=12345.599999999999
(after third multiply): d=123455.99999999999

One fix is to use d = Math.round(d) immediately after your loop finishes.

public class Rational {

     private int num, denom;

     public Rational(double d) {
          String s = String.valueOf(d);
          int digitsDec = s.length() - 1 - s.indexOf('.');        

          int denom = 1;
          for(int i = 0; i < digitsDec; i++){
             d *= 10;
             denom *= 10;
          }
          int num = (int) Math.round(d);

          this.num = num; this.denom = denom;
     }

     public Rational(int num, int denom) {
          this.num = num; this.denom = denom;
     }

     public String toString() {
          return String.valueOf(num) + "/" + String.valueOf(denom);
     }

     public static void main(String[] args) {
          System.out.println(new Rational(123.456));
     }
}

It works - try it.

For the second part of your question...

In order to call the second constructor from the first, you can use the "this" keyword

this(num, denom)

But it has to be the very first line in the constructor... which doesn't make sense here (we have to do some calculations first). So I wouldn't bother trying to do that.