Author Topic: Convert Decimal to Fraction  (Read 10361 times)

0 Members and 1 Guest are viewing this topic.

Offline Jack002

  • Forum Regular
  • Posts: 123
  • Boss, l wanna talk about arrays
    • View Profile
Re: Convert Decimal to Fraction
« Reply #30 on: April 27, 2019, 09:22:01 am »
After some more experimenting I see it also fails for 1/60. GCD is given two numbers, one is negative. It seems to always happen when one or both numbers given GCD are negative
{1/56 also fails for the same reason, both numbers given to GCD are negative}
 
crash2.jpg
« Last Edit: April 27, 2019, 09:24:06 am by Jack002 »
QB64 is the best!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Convert Decimal to Fraction
« Reply #31 on: April 27, 2019, 09:37:27 am »
Ok so vd1 is larger than vd2. You multiply both by adj and take a difference. Won't that number be positive? If so, why is this negative?
 

Yes why are your numerator and denominator negative? The only time I see that is when the number exceeds it's TYPE limit.

And why is your adj 1000000 when mine is 10? That might make VD1 and VD2 too big even for _INTEGER64 limit.

So the crux of our difference might begin here with the calculation of adj&&
Code: QB64: [Select]
  1.     adj&& = 1 'convert to whole numbers
  2.     WHILE n## <> INT(n##)
  3.         adj&& = adj&& * 10
  4.         n## = n## * 10
  5.     WEND
  6.  
adj&& is the multiplier needed to get VD1-VD2 (which becomes the numerator of the fraction) into a whole number.

We are using the same code. Is there a version 1.3 difference in handling the variable types?




Has anyone else tried 1/62? What do you get with what version of QB64?


OK I am still getting good results with Jack002 code on an older version of QB64.
 
1 over 62 with old version of QB64.PNG
 

Jack002 are you using 32 bit of even X86 versions of QB64?
« Last Edit: April 27, 2019, 10:01:09 am by bplus »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Convert Decimal to Fraction
« Reply #32 on: April 27, 2019, 10:23:57 am »
After some more experimenting I see it also fails for 1/60. GCD is given two numbers, one is negative. It seems to always happen when one or both numbers given GCD are negative
{1/56 also fails for the same reason, both numbers given to GCD are negative}
 
crash2.jpg


The 3rd number from left of the 2nd line from bottom adj&& is supposed to be a simple power of 10, eg 10, 100, 1000, 10000...
Code: QB64: [Select]
  1.     adj&& = 1 'convert to whole numbers
  2.     WHILE n## <> INT(n##)
  3.         adj&& = adj&& * 10
  4.         n## = n## * 10
  5.     WEND

So there is a type limit problem.
« Last Edit: April 27, 2019, 10:53:22 am by bplus »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Convert Decimal to Fraction
« Reply #33 on: April 27, 2019, 10:39:58 am »
1/56 works perfectly:
 
1 over 56.PNG


1/60 has a suspiciously high adj&&
 
1 over 60 adj&& too high but works.PNG
« Last Edit: April 27, 2019, 10:45:36 am by bplus »

Offline Jack002

  • Forum Regular
  • Posts: 123
  • Boss, l wanna talk about arrays
    • View Profile
Re: Convert Decimal to Fraction
« Reply #34 on: April 27, 2019, 05:32:17 pm »
The while loop that makes ADJ has issues. I ran this test script and its not seeing it's done?! Hello? McFly!?
I don't know why this is failing. The number and the INT are the same.
Code: QB64: [Select]
  1. vd1## = .166
  2. vd2## = .016
  3.  
  4. n## = vd1## - vd2## 'subtract dec2$ from dec1$
  5.  
  6. PRINT "vd1"; vd1##
  7. PRINT "vd2"; vd2##
  8. PRINT "n##"; n##
  9.  
  10. adj&& = 1 'convert to whole numbers
  11. WHILE n## <> INT(n##)
  12.     adj&& = adj&& * 10
  13.     PRINT "adj"; adj&&
  14.     n## = n## * 10
  15.     PRINT "test, is "; n##; " = "; INT(n##); "?"
  16.     SLEEP
  17.  
while fail.jpg

I see it keeps going till ADJ is 1.5D+19!!

« Last Edit: April 27, 2019, 05:34:57 pm by Jack002 »
QB64 is the best!

Offline Jack002

  • Forum Regular
  • Posts: 123
  • Boss, l wanna talk about arrays
    • View Profile
Re: Convert Decimal to Fraction
« Reply #35 on: April 27, 2019, 05:39:00 pm »
I see some kind of rounding error here. I added a difference between n## and int(n##)  and things get funny
Code: QB64: [Select]
  1. vd1## = .166
  2. vd2## = .016
  3.  
  4. n## = vd1## - vd2## 'subtract dec2$ from dec1$
  5.  
  6. PRINT "vd1"; vd1##
  7. PRINT "vd2"; vd2##
  8. PRINT "n##"; n##
  9.  
  10. adj&& = 1 'convert to whole numbers
  11. WHILE n## <> INT(n##)
  12.     adj&& = adj&& * 10
  13.     PRINT "adj"; adj&&
  14.     n## = n## * 10
  15.     PRINT "test, is "; n##; " = "; INT(n##); "?"
  16.     PRINT n## - INT(n##)
  17.     SLEEP
  18.  
while fail2.jpg


EDIT

I made two changes to the while loop. Now it seems to work

Code: QB64: [Select]
  1.     WHILE (n## - INT(n##)) > 1.0D-15
  2.         adj&& = adj&& * 10
  3.         n## = n## * 10 + 1.0D+15
  4.         PRINT n##; INT(n##); (n## - INT(n##)); adj&&
  5.         SLEEP
  6.     WEND
  7.  
I have to add 1.0D-15 to n## so it won't keep drifting.
« Last Edit: April 27, 2019, 05:59:19 pm by Jack002 »
QB64 is the best!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Convert Decimal to Fraction
« Reply #36 on: April 27, 2019, 08:46:33 pm »
Hi Jack002,

Yep! I was convinced something was screwy when I saw the adj&& for 1/60.

Here is another way around adj&& calc:
Code: QB64: [Select]
  1.     'adj&& = 1 'convert to whole numbers
  2.     'WHILE n## <> INT(n##)
  3.     '    adj&& = adj&& * 10
  4.     '    n## = n## * 10
  5.     'WEND
  6.  
  7.     ns$ = STR$(n##)
  8.     dot = INSTR(ns$, ".")
  9.     p2 = LEN(ns$) - dot
  10.     adj&& = 10 ^ p2
  11.  

I also had to reduce max length of the repeat section below 13 because 1/79 was getting negative numerator and denominator like you were getting, which means the type limit was exceeded.

Modified code:
Code: QB64: [Select]
  1. _TITLE "n slash d to R notation and back again" '2019-04-24
  2. ' from:"Decimal Expansion of Division without Dividing  by bplus 2017-12-03"
  3. ' dove tailing Adrians and my recent dividing programs
  4.  
  5. ' 2019-04-24
  6. ' I want to isolate the repeated section immediately not write the fraction out and then repeat the repeated section
  7. ' not 1/6 = .16R6 >>> but .1R6
  8.  
  9. 'hmm... look like have to cycle through twice to get the length of the repeat section
  10. ' but before returning backup to start of repeat section insert the R where it starts the first time
  11. ' and end it where " repeat " starts.
  12.  
  13. '2019-04-24
  14. ' just for kicks, convert the R notation back to fraction if possible.
  15. ' Had to revert back to the redundant " repeat " form of R notation.
  16.  
  17. '2019-04-27 Thanks to Jack002's comments and replies this code to calculate adj&& may have been improved.
  18.  
  19. DEFLNG A-Z
  20.     PRINT: PRINT "Enter 2 integers < 3200, numerator / denominator, 0's quit, don't forget / "
  21.     INPUT nd$
  22.     slash = INSTR(nd$, "/")
  23.     IF slash THEN
  24.         dvsr = VAL(MID$(nd$, slash + 1))
  25.         IF dvsr = 0 THEN PRINT "Divisor is 0, bye.": END
  26.         numerator = VAL(MID$(nd$, 1, slash - 1))
  27.         IF numerator = 0 THEN PRINT "Numerator is 0, bye.": END
  28.     ELSE
  29.         PRINT "No slash found, bye.": END
  30.     END IF
  31.     CLS
  32.     d$ = divide$(numerator, dvsr)
  33.     PRINT numerator; " / "; dvsr; " = "; d$
  34.  
  35.     'and now arttemp"t to convert back to fraction
  36.     PRINT: PRINT "Check if can convert back to fraction:"
  37.     result$ = convertRnotation2Fraction$(d$)
  38.     IF result$ <> "" THEN PRINT result$
  39.  
  40. FUNCTION convertRnotation2Fraction$ (rNotedDecimal$)
  41.     'check if R in the decimal
  42.     dotPos = INSTR(rNotedDecimal$, ".")
  43.     IF dotPos = 0 THEN convertRnotation2Fraction$ = rNotedDecimal$: EXIT FUNCTION
  44.     RPos = INSTR(rNotedDecimal$, " repeat ")
  45.     IF RPos = 0 THEN convertRnotation2Fraction$ = convert2Fraction$(rNotedDecimal$): EXIT FUNCTION
  46.  
  47.     'still here? we have an R and a decimal
  48.     whole$ = MID$(rNotedDecimal$, 1, dotPos - 1)
  49.     IF VAL(whole$) = 0 THEN whole$ = ""
  50.  
  51.     p = LEN(rNotedDecimal$) - RPos - LEN(" repeat ") + 1
  52.     PRINT "Debug: repeat length ="; p
  53.     IF p > 12 THEN
  54.         PRINT "The length of the repeat section of: "
  55.         PRINT rNotedDecimal$
  56.         PRINT " is too long to convert back to fraction."
  57.         EXIT FUNCTION
  58.     END IF
  59.  
  60.     dec$ = MID$(rNotedDecimal$, dotPos)
  61.     PRINT "Debug: converting dec$ "; dec$
  62.  
  63.     'remove " repeat "
  64.     RPos = INSTR(dec$, " repeat ")
  65.     dec1$ = MID$(dec$, 1, RPos - 1) + MID$(dec$, RPos + LEN(" repeat "))
  66.     dec2$ = MID$(dec$, 1, RPos - 1)
  67.     PRINT "Debug: dec1$ (double repeat), dec2$ (single repeat) = "; dec1$; ", "; dec2$
  68.  
  69.     'mult by 10^p to get the 2nd repeat part in dec1$ aligned to 1st repeat part  in dec2$
  70.     vd1## = VAL(dec1$) * 10 ^ p
  71.     vd2## = VAL(dec2$)
  72.     n## = vd1## - vd2## 'subtract dec2$ from dec1$
  73.  
  74.     'adj&& = 1 'convert to whole numbers
  75.     'WHILE n## <> INT(n##)
  76.     '    adj&& = adj&& * 10
  77.     '    n## = n## * 10
  78.     'WEND
  79.  
  80.     'calculate adj&& from length of decimal
  81.     ns$ = STR$(n##)
  82.     dot = INSTR(ns$, ".")
  83.     p2 = LEN(ns$) - dot
  84.     adj&& = 10 ^ p2
  85.  
  86.     'reevaluate to avoid rounding errors from crazy floating point math
  87.     n1&& = vd1## * adj&& - vd2## * adj&&
  88.     PRINT "Debug values: vd1, vd2, adj&&, n1&& (difference * adj&& for whole number):"
  89.     PRINT vd1##; ", "; vd2##; ", "; adj&&; ", "; n1&&
  90.  
  91.     d&& = (10 ^ p - 1) * adj&&
  92.     PRINT "Debug: Giant numerator, denominator "; n1&&; ", "; d&& 'giant numbers
  93.  
  94.     'reduce giant numbers by Gretaest Common Divisor between them
  95.     g&& = gcd&&(n1&&, d&&): sn&& = n1&& / g&&: sd&& = d&& / g&&
  96.  
  97.     convertRnotation2Fraction$ = whole$ + " " + _TRIM$(STR$(sn&&)) + "/" + _TRIM$(STR$(sd&&))
  98.  
  99. FUNCTION convert2Fraction$ (decimal$)
  100.     dot%% = INSTR(decimal$, ".")
  101.     IF dot%% > 0 THEN
  102.         whole$ = MID$(decimal$, 1, dot%% - 1)
  103.         IF VAL(whole$) = 0 THEN whole$ = ""
  104.         p%% = LEN(decimal$) - dot%%
  105.         n&& = VAL(MID$(decimal$, dot%% + 1))
  106.         d&& = 10 ^ p%%
  107.         g&& = gcd&&(n&&, d&&): sn&& = n&& / g&&: sd&& = d&& / g&&
  108.         convert2Fraction$ = whole$ + " " + _TRIM$(STR$(sn&&)) + "/" + _TRIM$(STR$(sd&&))
  109.     ELSE
  110.         convert2Fraction$ = decimal$
  111.     END IF
  112.  
  113. FUNCTION gcd&& (a&&, b&&)
  114.     'a and b will be changed unless make copies
  115.     c&& = a&&: d&& = b&&
  116.     WHILE c&& <> 0 AND d&& <> 0
  117.         IF c&& > d&& THEN c&& = c&& MOD d&& ELSE d&& = d&& MOD c&&
  118.     WEND
  119.     gcd&& = c&& + d&&
  120.  
  121.  
  122. FUNCTION divide$ (n, d)
  123.     'n = original product or numerator (preserve value of n)
  124.     'd = divisor  (also preserve value)
  125.     c = n 'copy of n to be reduced until <= d, c will be the remainder part of division
  126.     a = 0 'a is for answer or accumulate, the integer part of the division result
  127.  
  128.     'find lowest power of 10 such that: d * 10^p > n
  129.     p = 0 'power of 10
  130.     WHILE d * (10 ^ p) < n
  131.         p = p + 1
  132.     WEND
  133.     WHILE c >= d
  134.         IF c = d THEN a = a + 1: c = 0: EXIT WHILE
  135.         p = p - 1
  136.         IF p >= 0 THEN
  137.             m = 0
  138.             WHILE d * m * 10 ^ p < c
  139.                 m = m + 1
  140.             WEND
  141.             m = m - 1
  142.             c = c - d * m * 10 ^ p
  143.             a = a + m * 10 ^ p
  144.         END IF
  145.     WEND
  146.  
  147.     'Now for the decimal expansion isolating the repeating part if one
  148.     IF c <> 0 THEN
  149.         DIM b(d)
  150.         b$ = "."
  151.         WHILE c <> 0
  152.  
  153.             'emergency bug out!
  154.             loopct = loopct + 1 'loop count should not exceed 1000 for numbers I am testing
  155.             IF loopct > 1000 THEN PRINT "Error: loop too long, bugging out! ": GOTO skip
  156.  
  157.             'track repeats  b() tracks been here once, b2() tracks been here twice
  158.             IF b(c) = 1 THEN 'been here!
  159.                 IF rFlag = 1 THEN 'been here twice!
  160.                     IF b2(c) = 1 THEN EXIT WHILE 'strike 3, we're out of here
  161.                     b2(c) = 1
  162.                 ELSE
  163.                     rFlag = 1
  164.                     DIM b2(d)
  165.                     b$ = b$ + " repeat "
  166.                     b2(c) = 1
  167.                 END IF
  168.             ELSE
  169.                 b(c) = 1
  170.             END IF
  171.  
  172.             'c was last remainder, mult by 10 and see if some m * d > can reduce it
  173.             tc = 10 * c
  174.             flag = 0
  175.             FOR m = 0 TO 9
  176.                 IF ((tc - m * d) >= 0) AND ((tc - (m + 1) * d) < 0) THEN
  177.                     flag = 1: b$ = b$ + LTRIM$(STR$(m))
  178.                     EXIT FOR
  179.                 END IF
  180.             NEXT
  181.             IF flag = 0 THEN b$ = b$ + "0": m = 0
  182.             c = tc - d * m
  183.         WEND
  184.     END IF
  185.  
  186.     'OK either d divided n eventually or there is a repeated pattern recorded in b$
  187.     skip: '< needed for debugging
  188.     r$ = STR$(a)
  189.     IF b$ <> "" THEN r$ = r$ + b$
  190.     divide$ = r$
  191.  
313 over 150.PNG
* 313 over 150.PNG (Filesize: 10.49 KB, Dimensions: 641x244, Views: 275)

Offline Jack002

  • Forum Regular
  • Posts: 123
  • Boss, l wanna talk about arrays
    • View Profile
Re: Convert Decimal to Fraction
« Reply #37 on: April 28, 2019, 12:19:01 am »
I was proud to hack some kind of solution. I had my doubts. I have written one like your first part that does the dec equivalent, but never thought to make it go back again. Well done (in spite of any problems)

Why do you suppose there is so much rounding error between the versions? This is like the old 8 bit days when you do 1/3 and then * 3 and get this long line of 9s. I know I saw that on the commodore 64.
QB64 is the best!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Convert Decimal to Fraction
« Reply #38 on: April 28, 2019, 09:45:54 am »
I was proud to hack some kind of solution. I had my doubts. I have written one like your first part that does the dec equivalent, but never thought to make it go back again. Well done (in spite of any problems)

Why do you suppose there is so much rounding error between the versions? This is like the old 8 bit days when you do 1/3 and then * 3 and get this long line of 9s. I know I saw that on the commodore 64.


Hi Jack002,

I am sorry I missed the experience with a Commodore 64, you have obviously been deeply affected by it. I did have experience with GW BASIC and DOS and loved the way the two worked together, then later VB for DOS and DOS great stuff!

The great difference between our different results of this code, I am still attributing to the possibility you are using a 32 bit version of QB64 or even x86. You have not said X64, x32 or even x86 that your version of QB64 is. If you are using a X64 bit version of QB64 I am completely baffled! LOL wouldn't be first time!

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Convert Decimal to Fraction
« Reply #39 on: April 28, 2019, 12:46:57 pm »
Hi Jack002,

I am sorry I missed the experience with a Commodore 64, you have obviously been deeply affected by it. I did have experience with GW BASIC and DOS and loved the way the two worked together, then later VB for DOS and DOS great stuff!

The great difference between our different results of this code, I am still attributing to the possibility you are using a 32 bit version of QB64 or even x86. You have not said X64, x32 or even x86 that your version of QB64 is. If you are using a X64 bit version of QB64 I am completely baffled! LOL wouldn't be first time!

We’ve seen some drastic differences in the past with how Windows does math with 32-bit and 64-bit code, so I’m guessing that’s probably the difference as well. 
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline Jack002

  • Forum Regular
  • Posts: 123
  • Boss, l wanna talk about arrays
    • View Profile
Re: Convert Decimal to Fraction
« Reply #40 on: April 28, 2019, 04:15:03 pm »
I am on QB64 1.2, I have a 64 bit computer. Its a Dell latitude running windows 10

If we can't expect every computer to make the same calculations in things like this how can we ever plan to write a program that works for everyone? I'm stumped.
QB64 is the best!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Convert Decimal to Fraction
« Reply #41 on: April 28, 2019, 05:37:03 pm »
Hi Jack002,

Until version 1.3 all stable versions of QB64 were 32 bit, didn't matter if your computer was 64 bit.

« Last Edit: April 28, 2019, 05:42:11 pm by bplus »

Offline Jack002

  • Forum Regular
  • Posts: 123
  • Boss, l wanna talk about arrays
    • View Profile
Re: Convert Decimal to Fraction
« Reply #42 on: April 28, 2019, 05:39:12 pm »
For fun I put the program I made in QB64 to find what the issue was with getting ADJ in the vice C64 emulator. Similar problems, offsets were bigger.
 
vice vs qb64.jpg
QB64 is the best!

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
    • View Profile
Re: Convert Decimal to Fraction
« Reply #43 on: April 28, 2019, 08:19:17 pm »
To answer your question, Jack, you would need your program to identify the system it is running on and have algorithms for all possible situations. It's the same PITA that web designers go though these days.

Pete
Want to learn how to write code on cave walls? https://www.tapatalk.com/groups/qbasic/qbasic-f1/

Offline Jack002

  • Forum Regular
  • Posts: 123
  • Boss, l wanna talk about arrays
    • View Profile
Re: Convert Decimal to Fraction
« Reply #44 on: April 28, 2019, 11:55:29 pm »
Thanks Pete. Looks like I need to get over to v1.3 right away. These rounding issues are making me thirsty. (Seinfeld)

QB64 is the best!