Dil.
Dil.

Reputation: 2076

How to convert decimal to fractions?

What I need to convert decimal to fractions. It is easy to convert to 10's feet.

1.5 => 15/10

This can do via this code:

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

But what I want is

1.5 => 3/2

and I don't get how to proceed. My question is not a duplication. Because other related question is C#. This is java.

Upvotes: 12

Views: 47345

Answers (11)

user29028183
user29028183

Reputation: 1

Following is a solution using BigDecimal, which is in the JRE (no additional lib needed). Mind that it is not precise, for example with a value like 99999999.99999999.

public static long[] toFraction(double number) {
    final BigDecimal bigDecimal = BigDecimal.valueOf(number);
    final int decimalPlaces = bigDecimal.scale();
    final BigDecimal divisor = BigDecimal.TEN.pow(decimalPlaces);
    final BigDecimal dividend = bigDecimal.movePointRight(decimalPlaces);
    final BigInteger divisorInt = BigInteger.valueOf(divisor.longValue());
    final BigInteger dividendInt = BigInteger.valueOf(dividend.longValue());
    final BigInteger greatestCommonDivisor = divisorInt.gcd(dividendInt);
    return new long[] {
            dividendInt.divide(greatestCommonDivisor).longValue(), 
            divisorInt.divide(greatestCommonDivisor).longValue(), 
    };
}

Upvotes: 0

Hasan Shadi
Hasan Shadi

Reputation: 381

First of all, if you want to convert a decimal number, you need to know the state of the situation before you convert it, let us say you have 0.333333, number 3 is being repeated infinitely. We all know that 0.333333 is 1/3 . Some people think that multiplying by the number of digits after the decimal point will convert it. That is in some cases is false, and the other is true. It is something related to mathematics. Another situation is 0.25, take the numbers after the decimal point and divide them by 100 and simplify them, which equals to 1/4. states have been covered, one more to go, but I am not going to explain it because it is long.

However, in mathematics we have 3 states for converting a decimal number into a fraction, I am not going to explain them because It will take a lot of space and time, I have already written a program for this problem. This is the code:

import java.math.BigDecimal;
import java.math.BigInteger;

public class Main {
    static BigDecimal finalResult = new BigDecimal("0");
    
    static boolean check(short[] checks) {
        boolean isContinues = true;
        int index = -1;
        for (short ind : checks) {
            index++;
            if (ind==1) {
                
            }
            else if (ind==0) {
                isContinues = false;
                break;
            }
            else if (ind==-1) {
                if (index==0) {
                    isContinues = false;
                }
                break;
            }
        }
        
        return isContinues;
    }
    static int[] analyzeDecimal() { // will return int[3]
        int[] analysis = new int[3];
        int dot = finalResult.toString().indexOf(".");
        String num = finalResult.toString();
        int state = -1;
        int firstPart = 0; // first part will be compared with each secondPart!
        int secondPart = 0; 
        String part = ""; // without the dot
        int index = 0; // index for every loop!
        int loop = 6;
        int originalLoop = loop;
        int size = 0; // until six!
        int ps = -1;
        short[] checks = new short[] {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; // 10 compares for each part!
        // length of checks is 10!
        int continues = -1; // -1 means there is no continues part!
        boolean stop = false;
        while (true) { // while for size!
            if (size!=6) {
            while (true) { // we need to compare a part with a part!
                // while for loop
                // 6 loops, every loop will increase the compared part by 1!
                if (loop!=-1) { // TODO : check every part with the increasing pos
                    firstPart = dot+1+(originalLoop-loop); // changed
                    try {
                        part = num.substring(firstPart, firstPart+(size+1));
                    }
                    catch (StringIndexOutOfBoundsException ex) {
                        break;
                    }
                    int partSize = part.length();
                    int afterDecimal = num.length()-(dot+1);
                    while (index!=checks.length && 
                        firstPart+partSize+index*partSize-(dot+1)<=afterDecimal) { // while for index!
                        secondPart = firstPart+partSize+index*partSize;
                        String comparedPart;
                        try {
                            comparedPart = num.substring(secondPart, secondPart+partSize);
                        }
                        catch (StringIndexOutOfBoundsException ex) {
                            break;
                        }
                        if (part.equals(comparedPart)) {
                            checks[index] = 1;
                        }
                        else {
                            checks[index] = 0;
                        }
                        index++;
                    }
                    index = 0;
                    if (check(checks)) {
                        stop = true;
                        continues = firstPart;
                        ps = partSize;
                    }
                    for (int i = 0 ; i!=10 ; i++) {
                        checks[i] = -1;
                    }
                }
                else { // finished!
                    break;
                }
                loop--;
                if (stop) {
                    break;
                }
            }
            loop = originalLoop;
            size++;
            if (stop) {
                break;
            }
            }
            else {
                break;
            }
        }
        if (continues==-1) {
            state = 2;
        }
        else {
            if (dot+1==continues) {
                state = 1;
            }
            else {
                state = 0;
            }
        }
        analysis[0] = state;
        analysis[1] = continues;
        analysis[2] = ps;
        
        return analysis;
    }
    static String convertToStandard() {
        // determine the state first : 
        int[] analysis = analyzeDecimal();
        int dot = finalResult.toString().indexOf('.')+1;
        int continues = analysis[1];
        int partSize = analysis[2]; // how many steps after the continues part
        if (analysis[0]==0) { // constant + continues
            String number = finalResult.toString().substring(0, continues+partSize);
            int numOfConst = continues-dot;
            int numOfDecimals = continues+partSize-dot;
            int den = (int)(Math.pow(10, numOfDecimals)-Math.pow(10, numOfConst)); // (10^numOfDecimals)-(10^numOfConst);
            int num;
            int toSubtract = Integer.parseInt(number.substring(0, dot-1)+number.substring(dot, dot+numOfConst));
            if (number.charAt(0)==0) {
                num = Integer.parseInt(number.substring(dot));
            }
            else {
                num = Integer.parseInt(number.replace(".", ""));
            }
            num -= toSubtract;
            return simplify(num, den);
        }
        
        else if (analysis[0]==1) { // continues 
            int num, den;
            // we always have  to subtract by only one x!
            String n = finalResult.toString().substring(0, dot+partSize).replace(".", "");
            num = Integer.parseInt(n);
            den = nines(partSize);
            int toSubtract = Integer.parseInt(finalResult.toString().substring(0, dot-1));
            num -= toSubtract;
            return simplify(num, den);
        }
        else if (analysis[0]==2) { // constant
            partSize = finalResult.toString().length()-dot;
            int num = Integer.parseInt(finalResult.toString().replace(".", ""));
            int den = (int)Math.pow(10, partSize);
            return simplify(num, den);
        }
        else {
            System.out.println("[Error] State is not determined!");
        }
        
        return "STATE NOT DETERMINED!";
    }
    static String simplify(int num, int den) {
        BigInteger n1 = new BigInteger(Integer.toString(num));
        BigInteger n2 = new BigInteger(Integer.toString(den));
        BigInteger GCD = n1.gcd(n2);
        String number = Integer.toString(num/GCD.intValue())+"/"+Integer.toString(den/GCD.intValue());
        
        return number;
    }
    static int nines(int n) {
        StringBuilder result = new StringBuilder();
        while (n!=0) {
            n--;
            result.append("9");
        }
        return Integer.parseInt(result.toString());
    }
    public static void main(String[] args) {
        finalResult = new BigDecimal("1.222222");
        System.out.println(convertToStandard());
    }
}

The program above will give you an optimal result with high precision. All you have to do is change the finalResult variable in the main function.

Upvotes: 1

Utkarsh Raj
Utkarsh Raj

Reputation: 1

Well check this simple implementation, I have not used any GCD or something, instead, I have put the logic for the numerator and keep on incrementing till the logic is not fulfilled.

public static void main(String[] args) {
    Scanner scan = new Scanner(System.in);
    
    System.out.println("Enter the decimal number:");
    double d = scan.nextDouble();
    
    int denom = 1;
    boolean b = true;
    while(b) {
        String[] s = String.valueOf(d * denom).split("\\.");
        if(s[0].equals(String.valueOf((int)(d * denom))) && s[1].equals("0")) {
            break;
        }
        denom++;
    }
    
    if(denom == 1) {
        System.out.println("Input a decimal number");
    }
    else {
        System.out.print("Fraction: ");
        System.out.print((int)(d*denom)+"/"+denom);
    }
}

Upvotes: 0

Orhan
Orhan

Reputation: 21

I prepared a solution for this question. Maybe it's look like primitive but working. I tested many decimal number. At least it can converting 1.5 to 3/2 :)

public String kesirliYap(Double sayi){
    String[] a=payPaydaVer(sayi);
    return a[0]+"/"+a[1];
}
public String[] payPaydaVer(Double sayi){
long pay;
long payda;

  DecimalFormat df=new DecimalFormat("#");
    df.setRoundingMode(RoundingMode.FLOOR);
    String metin=sayi.toString();        
    int virguldenSonra=(metin.length() -metin.indexOf("."))-1;
    double payyda=Math.pow(10,virguldenSonra);
    double payy=payyda*sayi;
    String pays=df.format(payy);
    String paydas=df.format(payyda);
    pay=Long.valueOf(pays);
    payda=Long.valueOf(paydas);


   String[] kesir=sadelestir(pay,payda).split(",");

   return kesir;
}

private String sadelestir(Long pay,Long payda){
    DecimalFormat df=new DecimalFormat("#");
    df.setRoundingMode(RoundingMode.FLOOR);
    Long a=pay<payda ? pay : payda;
    String b = "",c = "";
    int sayac=0;
    for(double i = a;i>1;i--){
      double payy=pay/i;
      double paydaa=payda/i;
      String spay=df.format(payy);
      String spayda=df.format(paydaa);
      Long lpay=Long.valueOf(spay);
      Long lpayda=Long.valueOf(spayda);
      if((payy-lpay)==0&&(paydaa-lpayda)==0){
          b=df.format(pay/i);
          c=df.format(payda/i);
          sayac++;
          break;
      }

    }

    return sayac>0 ?  b+","+c:pay+","+payda;
}

Upvotes: 1

John R Perry
John R Perry

Reputation: 4192

I tried adding this as an edit, but it was denied. This answer builds off of @Hristo93's answer but finishes the gcd method:

public class DecimalToFraction {

    private int numerator, denominator;

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

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

        int numerator = (int) Math.round(decimal);
        int gcd = gcd(numerator, denominator); 

        this.numerator = numerator / gcd;
        this.denominator = denominator /gcd;
    }

    public static int gcd(int numerator, int denom) {
        return denominator == 0 ? numerator : gcm(denominator, numerator % denominator);
    }

    public String toString() {
        return String.valueOf(numerator) + "/" + String.valueOf(denominator);
    }

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

Upvotes: 1

Matthew556
Matthew556

Reputation: 713

static private String convertDecimalToFraction(double x){
    if (x < 0){
        return "-" + convertDecimalToFraction(-x);
    }
    double tolerance = 1.0E-6;
    double h1=1; double h2=0;
    double k1=0; double k2=1;
    double b = x;
    do {
        double a = Math.floor(b);
        double aux = h1; h1 = a*h1+h2; h2 = aux;
        aux = k1; k1 = a*k1+k2; k2 = aux;
        b = 1/(b-a);
    } while (Math.abs(x-h1/k1) > x*tolerance);

    return h1+"/"+k1;
}

I got this answer from here. All I had to do is convert his answer to java.

Upvotes: 22

Joop Eggen
Joop Eggen

Reputation: 109547

Given double x >= 0, int p, int q, find p/q as closest approximation:

  • iterate on q from 1 upwards, determine p above and below; check deviations

So (not tested):

public static Rational toFraction(double x) {
    // Approximate x with p/q.
    final double eps = 0.000_001;
    int pfound = (int) Math.round(x);
    int qfound = 1;
    double errorfound = Math.abs(x - pfound);
    for (int q = 2; q < 100 && error > eps; ++q) {
        int p = (int) (x * q);
        for (int i = 0; i < 2; ++i) { // below and above x
            double error = Math.abs(x - ((double) p / q));
            if (error < errorfound) {
                pfound = p;
                qfound = q;
                errorfound = error;
            }
            ++p;
        }
    }
    return new Rational(pfound, qfound);
}

You could try it for Math.PI and E.

Upvotes: 3

Estimate
Estimate

Reputation: 1461

Not only for the decimal number 1.5, for all you can use the following steps:

  1. Find Number of decimal digits:

    double d = 1.5050;//Example I used

    double d1 = 1;

    String text = Double.toString(Math.abs(d));

    int integerPlaces = text.indexOf('.');

    int decimalPlaces = text.length() - integerPlaces - 1;

    System.out.println(decimalPlaces);//4

  2. Then convert to integer:

    static int ipower(int base, int exp) {

        int result = 1;
        for (int i = 1; i <= exp; i++) {
            result *= base;           
        }            
        return result;
    }
    

    //using the method

    int i = (int) (d*ipower(10, decimalPlaces));

    int i1 = (int) (d1*ipower(10, decimalPlaces));

    System.out.println("i=" + i + " i1 =" +i1);//i=1505 i1 =1000

  3. Then find highest common factor

    private static int commonFactor(int num, int divisor) {

        if (divisor == 0) {
            return num;
        }
    
        return commonFactor(divisor, num % divisor);
    }
    

//using common factor

int commonfactor = commonFactor(i, i1);

System.out.println(commonfactor);//5

  1. Finally print results:

    System.out.println(i/commonfactor + "/" + i1/commonfactor);//301/200

Here you can find:

  public static void main(String[] args) {

        double d = 1.5050;
        double d1 = 1;

        String text = Double.toString(Math.abs(d));
        int integerPlaces = text.indexOf('.');
        int decimalPlaces = text.length() - integerPlaces - 1;

        System.out.println(decimalPlaces);
        System.out.println(ipower(10, decimalPlaces));

        int i = (int) (d*ipower(10, decimalPlaces));
        int i1 = (int) (d1*ipower(10, decimalPlaces));      

        System.out.println("i=" + i + " i1 =" +i1);

        int commonfactor = commonFactor(i, i1);
        System.out.println(commonfactor);

        System.out.println(i/commonfactor + "/" + i1/commonfactor);


    }

    static int ipower(int base, int exp) {
        int result = 1;
        for (int i = 1; i <= exp; i++) {
            result *= base;           
        }

        return result;
    }

    private static int commonFactor(int num, int divisor) {
        if (divisor == 0) {
            return num;
        }
        return commonFactor(divisor, num % divisor);
    }

Upvotes: 1

Hristo93
Hristo93

Reputation: 197

You should find the greatest common divisor of the resulted numbers and divide the numerator and denominator by it.

Here is one way to do it:

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);
        int g = gcd(num, denom);
        this.num = num / g;
        this.denom = denom /g;
    }

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

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

    public static int gcd(int num, int denom) {
          ....
    }

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

Upvotes: 10

Abhiram Kulkarni
Abhiram Kulkarni

Reputation: 53

Including the method to find highest common factor and modifying toString method, solves your question i suppose.

public String toString() {
        int hcf = findHighestCommonFactor(num, denom);
        return (String.valueOf(num/hcf) + "/" + String.valueOf(denom/hcf));

    }

    private int findHighestCommonFactor(int num, int denom) {
        if (denom == 0) {
            return num;
        }
        return findHighestCommonFactor(denom, num % denom);
    }

Upvotes: 1

R&#233;mi Becheras
R&#233;mi Becheras

Reputation: 15222

Here is a simple algorythme :

numerato = 1.5
denominator = 1;

while (!isInterger(numerator*denominator))
do
    denominator++;
done

return numerator*denominator + '/' + denominator


// => 3/2

You just have to implement it in java + implement the isInteger(i) where i is a float.

Upvotes: 1

Related Questions