Reputation: 2076
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
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
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
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
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
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
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
Reputation: 109547
Given double x >= 0, int p, int q, find p/q as closest approximation:
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
Reputation: 1461
Not only for the decimal number 1.5
, for all you can use the following steps:
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
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
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
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
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
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
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