How to convert decimal to fractions?
Asked Answered
J

10

12

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.

Jobie answered 23/7, 2015 at 11:23 Comment(12)
Surely you meant 1.5 to 3/2 ?Homophonic
possible duplicate of Algorithm for simplifying decimal to fractionsExplanatory
How about you duplicate your constructor to one that takes also the desired denominator and simply divide by it?Pantaloon
@Michal yeah :D silly me. corrected now.Jobie
@diego can u explain more please?Jobie
Since you can do a 1.5 -> 15/10, just take the 15 and 10, find greatest common divisor, and use it.Unfasten
@nadir.. glad you understood it. Problem is I don't know how to do it :)Jobie
Do you want the minimal fraction (i.e. the one that can't be simplified any further) or one with a specific denominator?Pantaloon
It's not easy, mainly due to floating point imprecision. See the duplicate.Francesfrancesca
@Diego sorry for the late reply.. I want that. Please help me with that..Jobie
@Bathsheba, you are correct. Due to floating point imprecision it's difficult. So need to use int or long. Check my answer. Anyway there will be a limitation when the number of decimal digits are high.Rogation
It's not a bad answer but the proper way of solving this uses a Stern Brocot tree. And one of the answers in the dupe shows you how.Francesfrancesca
W
10

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));
    }
}
Witter answered 23/7, 2015 at 11:44 Comment(3)
what is gcd()? I can't understand that method?Jobie
@pippilongstocking greatest-common-divisor there exists probably a same abbreviation in your language. So 2/4 is reduced to 1/2. Helps much. If you make the fields final you have an immutable class, and multiplication and such create a new, reduced, fractional.Centimeter
what is in gsd() ?Sauls
S
22
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.

Shortlived answered 2/1, 2017 at 23:25 Comment(4)
Working but can you explain a bitAnthemion
Look at the link. It explains everything.Shortlived
This is really neat!!Pangermanism
but its returning 1.0/2.0 for 0.5. how to remove those zeros. probably int xx=(int) h1; int yy=(int) k1; return xx+"/"+k1;Sauls
W
10

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));
    }
}
Witter answered 23/7, 2015 at 11:44 Comment(3)
what is gcd()? I can't understand that method?Jobie
@pippilongstocking greatest-common-divisor there exists probably a same abbreviation in your language. So 2/4 is reduced to 1/2. Helps much. If you make the fields final you have an immutable class, and multiplication and such create a new, reduced, fractional.Centimeter
what is in gsd() ?Sauls
C
3

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.

Centimeter answered 23/7, 2015 at 11:49 Comment(1)
This is by far the best answer!Saltire
C
1

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.

Chinese answered 23/7, 2015 at 11:34 Comment(3)
I am not sure that this works? The numerator does not change during the loop iteration and so isInteger will never return true? I also think there will be a more efficient algorithm than a linear search.Duckbill
Yes its a typo : I edited while (!isInterger(numerator*denominator))Administer
This is little bit confusing. can you explain this more? please?Jobie
C
1

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);
    }
Cultus answered 23/7, 2015 at 11:51 Comment(0)
R
1

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);
    }
Rogation answered 23/7, 2015 at 12:24 Comment(0)
U
1

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));
    }
}
Une answered 18/4, 2018 at 6:8 Comment(0)
F
1

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;
}
Forecourse answered 8/1, 2019 at 12:9 Comment(1)
You're wellcomeForecourse
F
1

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.

Foolish answered 22/11, 2019 at 7:2 Comment(0)
B
0

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);
    }
}
Barytone answered 25/8, 2020 at 8:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.