joshua chris
joshua chris

Reputation: 53

how do you take a decimal to a fraction in lua with no added libraries?

i am working on a calculator running in pure lua but i need help with making the out put decimals in to fractions

Upvotes: 0

Views: 2030

Answers (2)

Egor Skriptunoff
Egor Skriptunoff

Reputation: 23757

This solution uses continued fraction to exactly restore fractions with denominator up to 107

local function to_frac(num)
   local W = math.floor(num)
   local F = num - W
   local pn, n, N = 0, 1
   local pd, d, D = 1, 0
   local x, err, q, Q
   repeat
      x = x and 1 / (x - q) or F
      q, Q = math.floor(x), math.floor(x + 0.5)
      pn, n, N = n, q*n + pn, Q*n + pn
      pd, d, D = d, q*d + pd, Q*d + pd
      err = F - N/D
   until math.abs(err) < 1e-15
   return N + D*W, D, err
end

local function print_frac(numer,denom)
   print(string.format("%.14g/%d = %d/%d + %g", numer, denom, to_frac(numer/denom)))
end

print_frac(1,  4)            -->  1/4 = 1/4 + 0
print_frac(12, 8)            -->  12/8 = 3/2 + 0
print_frac(4,  2)            -->  4/2 = 2/1 + 0
print_frac(16, 11)           -->  16/11 = 16/11 + 5.55112e-17
print_frac(1,  13)           -->  1/13 = 1/13 + 0
print_frac(math.sqrt(3), 1)  -->  1.7320508075689/1 = 50843527/29354524 + -4.44089e-16
print_frac(math.pi,      1)  -->  3.1415926535898/1 = 80143857/25510582 + 4.44089e-16
print_frac(0,   3)           -->  0/3 = 0/1 + 0
print_frac(-10, 3)           -->  -10/3 = -10/3 + -1.11022e-16

Upvotes: 2

Henri Menke
Henri Menke

Reputation: 10939

This is not possible. You need a class which stores fractions for that.

You can achieve an approximate solution. It works nicely for things that can be expressed as fraction and blows up for everything else

local function gcd(a, b)
    while a ~= 0 do
        a, b = b%a, a;
    end
    return b;
end

local function round(a)
   return math.floor(a+.5)
end

function to_frac(num)
   local integer = math.floor(num)
   local decimal = num - integer

   if decimal == 0 then
      return num, 1.0, 0.0
   end

   local prec = 1000000000
   local gcd_ = gcd(round(decimal*prec), prec)

   local numer = math.floor((integer*prec + round(decimal*prec))/gcd_)
   local denom = math.floor(prec/gcd_)
   local err   = numer/denom - num
   return numer, denom, err
end

function print_frac(numer,denom)
   print(string.format("%d/%d = %d/%d + %g", numer, denom, to_frac(numer/denom)))
end

print_frac(1,4)
print_frac(12,8)
print_frac(4,2)

print_frac(16,11)
print_frac(1,13)

Output:

1/4 = 1/4 + 0
12/8 = 3/2 + 0
4/2 = 2/1 + 0
16/11 = 290909091/200000000 + 4.54546e-10
1/13 = 76923077/1000000000 + 7.69231e-11

Upvotes: 1

Related Questions