Как преобразовать десятичные дроби в дроби?

Что мне нужно, чтобы преобразовать десятичные числа в дроби. Это легко преобразовать в 10 футов.

1.5 => 15/10

Это можно сделать с помощью этого кода:

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

Но я хочу

1.5 => 3/2

и я не понимаю, как поступить. Мой вопрос не является дублированием. Потому что другой связанный с этим вопрос - С#. Это джава.


person Dil.    schedule 23.07.2015    source источник
comment
Вы, конечно, имели в виду от 1.5 до 3/2?   -  person Michał Szydłowski    schedule 23.07.2015
comment
возможный дубликат алгоритма упрощения десятичных дробей   -  person Jure    schedule 23.07.2015
comment
Как насчет того, чтобы продублировать свой конструктор на тот, который также принимает желаемый знаменатель, и просто разделить на него?   -  person Diego Martinoia    schedule 23.07.2015
comment
@ Михал, да: D, глупый я. исправлено сейчас.   -  person Dil.    schedule 23.07.2015
comment
@diego, можешь объяснить подробнее, пожалуйста?   -  person Dil.    schedule 23.07.2015
comment
Поскольку вы можете сделать 1,5 -> 15/10, просто возьмите 15 и 10, найдите наибольший общий делитель и используйте его.   -  person Nadir    schedule 23.07.2015
comment
@nadir.. рад, что ты это понял. Проблема в том, что я не знаю, как это сделать :)   -  person Dil.    schedule 23.07.2015
comment
Вам нужна минимальная дробь (то есть та, которую нельзя упростить дальше) или дробь с определенным знаменателем?   -  person Diego Martinoia    schedule 23.07.2015
comment
Это непросто, в основном из-за неточности с плавающей запятой. Смотрите дубликат.   -  person Bathsheba    schedule 23.07.2015
comment
@ Диего, извини за поздний ответ .. Я хочу этого. Пожалуйста, помогите мне с этим..   -  person Dil.    schedule 24.07.2015
comment
@ Вирсавия, ты прав. Из-за неточности с плавающей запятой это сложно. Поэтому нужно использовать int или long. Проверьте мой ответ. В любом случае будет ограничение, когда количество десятичных цифр велико.   -  person Krishanthy Mohanachandran    schedule 24.07.2015
comment
Это неплохой ответ, но правильный способ решения этой проблемы использует дерево Stern Brocot. И один из ответов в обмане показывает вам, как это сделать.   -  person Bathsheba    schedule 24.07.2015


Ответы (10)


Нужно найти наибольший общий делитель полученных чисел и разделить на него числитель и знаменатель.

Вот один из способов сделать это:

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));
    }
}
person Hristo93    schedule 23.07.2015
comment
что такое НОД()? Я не могу понять этот метод? - person Dil.; 24.07.2015
comment
@pippilongstocking наибольший общий делитель, возможно, в вашем языке существует такая же аббревиатура. Таким образом, 2/4 уменьшается до 1/2. Очень помогает. Если вы сделаете поля final, у вас будет неизменный класс, а умножение и тому подобное создадут новый, уменьшенный, дробный. - person Joop Eggen; 24.07.2015

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

Я получил этот ответ от здесь. Все, что мне нужно было сделать, это преобразовать его ответ в java.

person Matthew556    schedule 02.01.2017
comment
Работает, но не могли бы вы немного объяснить - person Paras Sidhu; 25.07.2017
comment
Посмотрите на ссылку. Это все объясняет. - person Matthew556; 26.07.2017
comment
Это действительно опрятно!! - person Animesh Sahu; 29.11.2020

Учитывая double x >= 0, int p, int q, найдите p/q в качестве ближайшего приближения:

  • итерация по q от 1 вверх, определение p выше и ниже; проверить отклонения

Итак (не проверено):

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

Вы можете попробовать это для Math.PI и E.

person Joop Eggen    schedule 23.07.2015
comment
Это, безусловно, лучший ответ! - person Akash Jain; 26.08.2020

Вот простой алгоритм:

numerato = 1.5
denominator = 1;

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

return numerator*denominator + '/' + denominator


// => 3/2

Вам просто нужно реализовать его в java + реализовать isInteger(i), где i - это float.

person Rémi Becheras    schedule 23.07.2015
comment
Я не уверен, что это работает? Числитель не меняется во время итерации цикла, поэтому isInteger никогда не вернет true? Я также думаю, что будет более эффективный алгоритм, чем линейный поиск. - person ; 23.07.2015
comment
Да, это опечатка: я редактировал while (!isInterger(numerator*denominator)) - person Rémi Becheras; 23.07.2015
comment
Это немного сбивает с толку. Вы можете объяснить это больше? пожалуйста? - person Dil.; 24.07.2015

Я полагаю, что включение метода поиска наибольшего общего фактора и изменение метода toString решает ваш вопрос.

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);
    }
person Abhiram Kulkarni    schedule 23.07.2015

Не только для десятичного числа 1.5, для всех вы можете использовать следующие шаги:

  1. Найти количество десятичных цифр:

    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. Затем преобразуйте в целое число:

    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. Затем найдите наибольший общий делитель

    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. Наконец, распечатайте результаты:

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

Здесь вы можете найти:

  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);
    }
person Krishanthy Mohanachandran    schedule 23.07.2015

Я пытался добавить это как редактирование, но мне было отказано. Этот ответ основан на ответе @Hristo93, но завершает метод gcd:

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));
    }
}
person John R Perry    schedule 18.04.2018

Я подготовил решение для этого вопроса. Может быть, это выглядит примитивно, но работает. Я проверил много десятичных чисел. По крайней мере, он может конвертировать 1,5 в 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;
}
person Orhan    schedule 08.01.2019
comment
Всегда пожалуйста - person Orhan; 10.01.2019

Прежде всего, если вы хотите преобразовать десятичное число, вам нужно знать состояние ситуации, прежде чем преобразовать его, скажем, у вас есть 0,333333, число 3 повторяется бесконечно. Все мы знаем, что 0,333333 равно 1/3. Некоторые люди думают, что умножение на количество цифр после запятой преобразует его. То есть в одних случаях ложно, а в других верно. Это что-то связанное с математикой. Другая ситуация 0,25, берем числа после запятой и делим их на 100 и упрощаем, что равно 1/4. состояния пройдены, осталось еще одно, но я не буду объяснять это, потому что это долго.

Однако в математике у нас есть 3 состояния для преобразования десятичного числа в дробь, я не буду их объяснять, т.к. это займет много места и времени, я уже написал программу для этой задачи. Это код:

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

Приведенная выше программа даст вам оптимальный результат с высокой точностью. Все, что вам нужно сделать, это изменить переменную finalResult в основной функции.

person Hasan Shadi    schedule 22.11.2019

Что ж, проверьте эту простую реализацию, я не использовал GCD или что-то в этом роде, вместо этого я поставил логику для числителя и продолжаю увеличивать до тех пор, пока логика не будет выполнена.

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);
    }
}
person Utkarsh Raj    schedule 25.08.2020