The QBasic Forum      Other Subforums, Links and Downloads
  << Previous Topic | Next Topic >>Return to Index  

Decimal to fraction converter

March 10 2009 at 6:56 PM
Anonymous  (no login)

Write a program that converts a number entered in decimal format to a fraction that most closely approximates the entered number. The fraction must be in lowest terms and must equal the entered number when rounded back.

For example if 1.23456 is entered, the program should respond with the fraction 1879/1522.

Evaluate the fraction and you get 1.23455978... which equals the entered number when rounded back to 5 decimal places.

 
 Respond to this message   
AuthorReply
lawgin
(no login)

*lawgin forgot to log in!

March 10 2009, 6:59 PM 


 
 Respond to this message   
David
(no login)

A solution

March 11 2009, 8:33 AM 

DIM N(25)
X = 1.23456
N(0) = INT(X)
A = X - N(0)
w1$ = LTRIM$(STR$(A))
DP = LEN(w1$) - 1
WHILE w1$ <> w2$
J = J + 1
b = 1 / A
N(J) = INT(b)
A = (b - N(J))
L = 0: K = 0
L = N(J) * N(J - 1) + 1
K = N(J)
FOR m = J - 2 TO 1 STEP -1
kk = L
L = L * N(m) + K
K = kk
NEXT m
x1 = INT(((K / L) * 10 ^ DP) + .5)
w2$ = "." + LTRIM$(STR$(x1))
WEND
PRINT X; " = "; L * N(0) + K; "/"; L

 
 Respond to this message   
lawgin
(no login)

OK, but doesn't work for general case

March 11 2009, 11:18 AM 

Your code works for the example I provided but not for some others:

.00123 = subscript out of range
3.1 = subscript out of range
5 = division by zero
12.3456789 = 581321 / 47087

The answers I get for these are, respectively: 1/813, 31/10, 5/1, 1355679/109810

Also, I did a poor job of defining the challenge. I neglected to say that the fraction should be as close as possible to the decimal without going over. Otherwise there would be 2 answers, one slightly above, and one slightly below. (This is known in the US as The Price Is Right Principle).

 
 Respond to this message   

(Login burger2227)
R

* This sounds like a "fixed" challenge. Just "Lawg In" and show us your answer.

March 11 2009, 4:29 PM 



    
This message has been edited by burger2227 on Mar 11, 2009 4:30 PM


 
 Respond to this message   
David
(no login)

It is using the method of continued fractions

March 12 2009, 5:31 AM 

Unfortunately I coded it pretty badly.
decimal = a0+(1/(a1+(1/(a2....

 
 Respond to this message   
qbguy
(no login)

Why that answer and not the exact

March 11 2009, 4:57 PM 

1.23456 = 3858/3125

Is there supposed to be a rule that numerator+denominator must be minimized?

 
 Respond to this message   
lawgin
(no login)

I should have stayed anonymous

March 11 2009, 6:06 PM 

I am not brazen enough to try and change the rules again, so I have to accept your exact answer of 3858/3125 as the correct one. Here is my code which does minimize the numerator and denominator (I think).

INPUT "Enter Decimal"; d$
p = LEN(d$) - INSTR(d$, ".") + 1
d1 = VAL(d$)
wp = INT(d1)
dp = d1 - wp
DO
m = m + 1
x1 = m * dp
x2 = CLNG(x1)
dx = ABS(x1 - x2)
IF dx < min THEN min = dx: y = m: d2 = (CLNG(y * dp) + y * wp) / y
LOOP UNTIL ABS(d2 - d1) < 1 / 10 ^ p
PRINT d1; "="; CLNG(y * dp) + y * wp; "/"; y
END

 
 Respond to this message   

(Login burger2227)
R

Dunno.......I got nothing running it!

March 11 2009, 7:09 PM 

Got stuck in the loop? How long does it take for an answer?


    
This message has been edited by burger2227 on Mar 11, 2009 8:22 PM


 
 Respond to this message   
lawgin
(no login)

copy/paste error...sorry

March 11 2009, 9:03 PM 

It was missing the first 2 lines. Below is correct.

DEFDBL A-Z
min = 10
INPUT "Enter Decimal"; d$
p = LEN(d$) - INSTR(d$, ".") + 1
d1 = VAL(d$)
wp = INT(d1)
dp = d1 - wp
DO
m = m + 1
x1 = m * dp
x2 = CLNG(x1)
dx = ABS(x1 - x2)
IF dx < min THEN min = dx: y = m: d2 = (CLNG(y * dp) + y * wp) / y
LOOP UNTIL ABS(d2 - d1) < 1 / 10 ^ p
PRINT d1; "="; CLNG(y * dp) + y * wp; "/"; y
END

 
 Respond to this message   

(Login burger2227)
R

* Nice! Seems pretty accurate too.

March 11 2009, 9:43 PM 


 
 Respond to this message   

(Login The-Universe)
Admin

Errrr, close but no cigar...

March 11 2009, 9:45 PM 

Enter Decimal? .001
.001 = 1 / 1000
Enter Decimal? .0001
.0001 = 1 / 9999

The last answer should have been .0001 = 1 / 10000

Pete

- Darn binary system.

 
 Respond to this message   

(Login burger2227)
R

Fixed I hope.........

March 11 2009, 9:50 PM 

I changed min and dx to Single. I recall problems could be solved by rounding to singles first. Integers can use Single with no rounding errors. Doubles is troubles!

'converts decimal to fractions by Lawgin

DEFDBL A-Z
DIM min AS SINGLE, dx AS SINGLE 'for all 9 divisor errors
min = 10
INPUT "Enter Decimal"; d$
p = LEN(d$) - INSTR(d$, ".") + 1
d1 = VAL(d$)
wp = INT(d1)
dp = d1 - wp
DO
m = m + 1
x1 = m * dp
x2 = CLNG(x1)
dx = ABS(x1 - x2)
IF dx < min THEN min = dx: y = m: d2 = (CLNG(y * dp) + y * wp) / y
LOOP UNTIL ABS(d2 - d1) < 1 / 10 ^ p
PRINT d1; "="; CLNG(y * dp) + y * wp; "/"; y
END

Ted


    
This message has been edited by burger2227 on Mar 12, 2009 12:27 PM
This message has been edited by burger2227 on Mar 12, 2009 12:03 AM
This message has been edited by burger2227 on Mar 11, 2009 10:58 PM
This message has been edited by burger2227 on Mar 11, 2009 10:20 PM
This message has been edited by burger2227 on Mar 11, 2009 10:05 PM


 
 Respond to this message   
lawgin
(no login)

not quite

March 12 2009, 12:08 PM 

.0001 comes up correctly as 1/10000, but now .001 = 1/999.
Non-integer QBasic arithmetic sure is frustrating. It's not an exact science.

 
 Respond to this message   

(Login burger2227)
R

DIM dx AS SINGLE and it is fixed for that. But it may need more.

March 12 2009, 12:18 PM 

I think that attempting fractions beyond 6 decimal places will not work anyhow. I could get a fraction for .000001, but not beyond that. The loop just keeps running.

So, taking that into account, I would recommend trying to use SINGLE variables instead of Doubles. Doubles are always a problem when you amplify the slight difference in each multiplication!

It is similar to the problems with exponents. You have to convert the result into a Single rather than trying LONGs using CLNG.

Ted


    
This message has been edited by burger2227 on Mar 12, 2009 1:03 PM
This message has been edited by burger2227 on Mar 12, 2009 1:02 PM


 
 Respond to this message   
lawgin
(no login)

*I agree, see response to David below

March 12 2009, 1:47 PM 


 
 Respond to this message   

(Login burger2227)
R

Perhaps you over simplified?

March 12 2009, 10:34 PM 

The fractions are almost too accurate, but you can never get 1/3. The program needs to have some imagination to it! Like, if you enter .3 then you get 3/10, but if you enter .33333 you get 1/3. Some kind of rounding that still is mathmatically correct for the decimal places allowed.

1/3 is repetitive to many decimal point places beyond the progam's needs.

I dunno where to take this from here. Any ideas?

Ted


    
This message has been edited by burger2227 on Mar 13, 2009 1:47 AM
This message has been edited by burger2227 on Mar 12, 2009 11:41 PM


 
 Respond to this message   
lawgin
(no login)

I think this one has run it's course

March 13 2009, 11:40 AM 

Check out David's last solution. I think it has the kind of output you're looking for.

 
 Respond to this message   
David
(no login)

What about 1279/1036

March 12 2009, 12:30 PM 

It's curious that all the numerators that work end in 79.
And the numerators increase by 100 and the denominators by 81 between solutions.

1279/1036
1379/1117
1479/1198
1579/1279
1679/1360

 
 Respond to this message   
lawgin
(no login)

you're adding the same proportion

March 12 2009, 1:46 PM 

Since 100/81 = 1.23456, the value of the fraction doesn't change.

There is a trivial solution to the challenge: Given a decimal w.d, we need only to find a number n such that n*w+n*d is a whole number. Then the fractional equivalent is (n*w+n*d)/n. Single precision math provides a built-in approximation of the fraction.


INPUT "Enter Decimal"; d$
d = VAL(d$)
wp = INT(d1)
dp = d - wp
DO
m = m + 1
x = m * wp + m * dp
IF x - INT(x) = 0 THEN EXIT DO
LOOP
PRINT d; "="; INT(x); "/"; m
END

 
 Respond to this message   
David
(no login)

I think I know what is going on

March 13 2009, 4:57 AM 

Take 1.23456 as an example. The two nearest two digit fractions above and below are 79/64 and 100/81.
So using a graphical representation we are trying to construct a line that crosses a line of gradient 1.23456.
So start at a point (79,64) and form a line with gradient 100/81.
As the initial point is below the required gradient and 100/81 is larger than the required gradient then the constructed line will eventually cross the line of gradient 1.23456 and there is the solution.

so 1.23456 =(79+100*N)/(64+81*N) N=1,2,3,4,5....

Anyway here's another attempt at a program to do the hard work.

Remove the :END if you want all the solutions.

DEFLNG I-N
INPUT w$
x = VAL(w$)
dp = LEN(w$) - INSTR(w$, ".")
q$ = STRING$(dp + 2, "#")
FOR i = 1 TO 100000
FOR k = j TO 1 STEP -1
y = k / i
IF y - x < -.1 THEN 20
NEXT k
20 FOR j = k TO 100000
y = j / i
IF y - x > .1 THEN 10
y1 = INT(y * 10 ^ dp + .499) / (10 ^ dp)
IF y1 = x THEN
PRINT j; "/"; i; "=";
PRINT USING "###." + q$; y: END
END IF
NEXT j
10 NEXT i

 
 Respond to this message   
lawgin
(no login)

That about covers everything

March 13 2009, 11:38 AM 

I see that for the example 1.23456, the exact answer 3858/3125 is reached at about the 50th approximation. For many decimals, I like that you get the intuitive answer immediately:

.33=1/3
.667=2/3
.142857=1/7
3.14159=355/113

One minor bug---when there's only 1 decimal place, the results are erratic. Try .5 for example.

 
 Respond to this message   
Current Topic - Decimal to fraction converter
  << Previous Topic | Next Topic >>Return to Index