Converting Decimals to Reduced, Mixed Fractions


#1

Hello!

I am attempting to take decimal numbers from fields (i.e., 6.09375), convert them to a mixed fraction (i.e., 6 6/64), reduce the mixed fraction (i.e., 6 3/32), and then display the reduced fraction as text in a form. Is there a function that will convert a decimal to a mixed, reduced fraction? If not, do you have any suggestions on how to accomplish this task?

I am working on Panorma 6.

Thank you,
Paul


#2

Sorry, there is no such function.


#3

This will do it:

local a,b
a = 21.46876
b = ?(int(a)>0,int(a),0)
a = int(round((a-b)/0.015625,1.0))
b = str(b) +" "+ ?(a mod 32 = 0,str(a/32)+"/2",?(a mod 16 = 0,str(a/16)+"/4",
    ?(a mod 8 = 0,str(a/8)+"/8",?(a mod 4 = 0,str(a/4)+"/16",
    ?(a mod 2 = 0,str(a/2)+"/32",str(a)+"/64")))))

The variable, a, is your original number. The above code gives the result: 21 15/32


#4

That code is inadequate in that it doesn’t cater for some boundary conditions and it’s unnecessarily complex. Here’s a version that should cater for all positive values (it will return an empty string if the input is zero):

local a,b
a = 21.46876
a = round(a,0.015625)
b = int(a)
a = (a-b)/0.015625
b = ?(b=0,"",str(b)+" ") + ?(a=0,"",
    ?(a mod 32 = 0,str(a/32)+"/2",?(a mod 16 = 0,str(a/16)+"/4",
    ?(a mod 8 = 0,str(a/8)+"/8",?(a mod 4 = 0,str(a/4)+"/16",
    ?(a mod 2 = 0,str(a/2)+"/32",str(a)+"/64"))))))

I have assumed that Paul’s data is empirical rather than abstract and that there will be no negative values. Paul, let me know if you do need to cater for negative numbers.


#5

I was thinking about a different approach to this question, but before proceeding, would you explain what your formula does and why it works? Where did you get 0.015625?
Also, do you know how to generate the next prime number from any given prime? Or is there an array of primes available somewhere, up to some reasonably large value?


#6

What you are searching for is called “The sieve of Eratosthenes”, and I have put together some pieces of code from Bill Bush, Jay Schille and David Thompson into one Panorama X database “Sieb des Eratosthenes”. Panorama X calculates e.g. the prime numbers from 2 to 150,000 in about 36 seconds.


#7
local a,b
a = 13.4875

The number 0.015625 is exactly 1/64 so this rounds the number to 64ths. If the fraction component is less than 1/128, it is set to zero; if it’s greater than 127/128, it’s set to zero and the mantissa is incremented by one, so an initial 13.993 would become 14.0. In the above case, the value of a becomes 13.484375, where 0.484375 is exactly 31/64.

a = round(a,0.015625)

The mantissa (integer component) is stored in b.

b = int(a)

The fraction component is divided by 0.015625 to calculate the number of 64ths.

a = (a-b)/0.015625

The mantissa is stored in b as a string and this is concatenated with the result of a set of cascading ?( functions which test for the number of 64ths in the variable, a, being a multiple of 0, 32, 16, 8, 4, 2 or 1 and then display the outcome as a fraction.

b = ?(b=0,"",str(b)+" ") + ?(a=0,"",
    ?(a mod 32 = 0,str(a/32)+"/2",?(a mod 16 = 0,str(a/16)+"/4",
    ?(a mod 8 = 0,str(a/8)+"/8",?(a mod 4 = 0,str(a/4)+"/16",
    ?(a mod 2 = 0,str(a/2)+"/32",str(a)+"/64"))))))

#8

I posted a very similar but less elegant version as part of my Maths package on the Database Exchange some time back. The gold standard is still Dave Thompson’s Panorama 6.0 solution which is very much faster than the Panorama X one because it uses the chunkfilter statement which, sadly, could not be ported to Panorama X.

And your list of credits omits the lady who wrote the first pseudo-code - I forget her name, I think she was an Elizabeth.

And, finally, I just ran your code and it took less than 12 seconds to produce the primes up to 150,000.


#9

Her name is Lisa Worthington, or at least it was in 2002.


#10

Thank you Dave - her contribution should not go unnoticed.


#11

I just ran Dave’s code - it did the 150,000 in six seconds.


#12

Thanks Michael and Kurt. Tom


#13

She is referenced in the Info form of my database.


#14

Michael’s approach uses an approach that yields a fraction thatn is accurate to the nearest 1/64th. I came up with an approach to obtain a more accurate answer. In the example we started with, I think that 21.46876 is actually 21 11719/25000. Here is the code that I used:

setdialogtrigger ""
local lvn, lvRN, lva,lvb,lvx,lvpnum,
lvprimes,lvinput,lvI,lvest

lvest=""
lvinput=""
/* Get input value:  lvinput, then break down into lvI and lvRN*/
alertsheetinput "Enter decimal number...",lvinput
/*This is a custom function on my computer that replaces Gettext*/
if info("dialogtrigger")="Cancel"
       nsnotify "You cancelled!"
       rtn
endif

lvI=array(lvinput,1,".")
lvRN=array(lvinput,2,".")
lvn=length(lvRN)
lva=val(lvRN)
lvb=10^lvn
/* The fraction is lva/lvb. Now we have to reduce the fraction by dividing by prime numbers*/
lvpnum=1
lvprimes=fileload("~/Desktop/primes.csv")
/*I used the database from Kurt to create an array of primes
from 2 to 500,000 and stored it in a file on my desktop.  There are 41,538 primes in the array*/
lvx=val(array(lvprimes,lvpnum,","))

Tryx:

/*Test to see if lva and lvb are evenly divisible by lvx. If so, do it.
   Repeat until it is not, then get the next prime and try it.*/

If lva mod lvx = 0 and lvb mod lvx = 0
    lva=lva/lvx
    lvb=lvb/lvx
    goto Tryx
else
    /*Get next prime number try it*/
    lvpnum=lvpnum+1
    lvx=val(array(lvprimes,lvpnum,","))
    if lvpnum>41538 
        lvest=" (approximately)"
        goto Done 
    endif

    if lva≥lvx and lvb≥lvx 
       /*I think we could have a better test of when to stop testing primes.*/
        goto Tryx
    endif
endif
Done:
alertsheet "Final answer: "+lvinput+" is"+lvest+":  "+lvI+" "+lva+"/"+lvb
nsnotify lvpnum + "primes used to test!"

I am not quite sure how to assess the accuracy when you get to longer decimal strings, but if you run out of primes before getting the exact answer, the result will indicate that the result is an approximation.


#15

Just to pick some numbers, I tried 1 237/238, which equals 1.9957983193. If you enter that into my program, you get the answer 9957983193/10000000000. You run out of the primes and the program stops. Not very satisfactory. I think there are methods for finding the greatest common divisor of two numbers, so I will investigate doing that to reduce the fraction.


#16

Rather than trying one prime after another, you could use the Euclidean Algorithm.

Local A,B,C
A=lva
B=lvb
Loop
    C=B mod A
    B=A
    A=C
Until C=0
lva=lva/B
lvb=lvb/B

#17

Since the numerator isn’t divisible by either 2 or 5, that is the reduced fraction. The trouble is that 237/238 will be a repeating decimal. Those ten digits can only be an approximation.

This sort of thing can only make sense if you consider the intended use. For example, a tape measure graduated in feet and inches will have graduations every 16th or perhaps 32nd of an inch. If you have calculated a diagonal or something, and you want to convert your decimal answer to something that will be easy to measure with that tape, it makes sense to round to the nearest 64th and then reduce the fraction.

We don’t really know if that’s the intended use here.


#18

I agree completely. It was just a mental exercise.


#20

Michael,

Yes, you are correct. My data is empirical without negative numbers.


#21

Thanks for this code Michael! I think this will work well. I very much appreciate your help.