Convert Fraction to Float?

Kind of like this question, but in reverse.

Given a string like 1, 1/2, or 1 2/3, what's the best way to convert it into a float? I'm thinking about using regexes on a case-by-case basis, but perhaps someone knows of a better way, or a pre-existing solution. I was hoping I could just use eval, but I think the 3rd case prevents that.

9 Answers

maybe something like this (2.6+)

from fractions import Fraction
float(sum(Fraction(s) for s in '1 2/3'.split()))
3

I tweaked James' answer a bit.

def convert_to_float(frac_str):
    try:
        return float(frac_str)
    except ValueError:
        num, denom = frac_str.split('/')
        try:
            leading, num = num.split(' ')
            whole = float(leading)
        except ValueError:
            whole = 0
        frac = float(num) / float(denom)
        return whole - frac if whole < 0 else whole + frac


print convert_to_float('3') # 3.0
print convert_to_float('3/2') # 1.5
print convert_to_float('1 1/2') # 1.5
print convert_to_float('-1 1/2') # -1.5

Though you should stear clear of eval completely. Perhaps some more refined version of:

num,den = s.split( '/' )
wh, num = num.split()
result = wh + (float(num)/float(den))

Sorry, meant to be num.split not s.split, and casts. Edited.

I see there are already several good answers here, but I've had good luck with this. It also has the benefit that it will tolerate non-fraction strings if you're parsing mixed sets of data, so there's no need to check if it's a fraction string or not upfront.

def convert_to_float(frac_str):
    try:
        return float(frac_str)
    except ValueError:
        try:
            num, denom = frac_str.split('/')
        except ValueError:
            return None
        try:
            leading, num = num.split(' ')
        except ValueError:
            return float(num) / float(denom)        
        if float(leading) < 0:
            sign_mult = -1
        else:
            sign_mult = 1
        return float(leading) + sign_mult * (float(num) / float(denom))

>>> convert_to_float('3')
3.0
>>> convert_to_float('1/4')
0.25
>>> convert_to_float('1 2/3')
1.6666666666666665
>>> convert_to_float('-2/3')
-0.6666666666666666
>>> convert_to_float('-3 1/2')
-3.5
6

That might be a dirty workaround, but you could convert spaces to a + sign to solve the 3rd case (or to a - if your fraction is negative).

def fractionToFloat(fraction):

    num = 0
    mult = 1

    if fraction[:1] == "-":
        fraction = fraction[1:]     
        mult = -1

    if " " in fraction:
        a = fraction.split(" ")
        num = float(a[0])
        toSplit = a[1]
    else:
        toSplit = fraction

    frac = toSplit.split("/")
    num += float(frac[0]) / float(frac[1])

    return num * mult

It can also handle "2 1/1e-8", "-1/3" and "1/5e3".

4

This implementation avoids using eval and works on pre-2.6 versions of Python.

# matches a string consting of an integer followed by either a divisor
# ("/" and an integer) or some spaces and a simple fraction (two integers
# separated by "/")
FRACTION_REGEX = re.compile(r'^(\d+)(?:(?:\s+(\d+))?/(\d+))?$')

def parse(x):
  i, n, d = FRACTION_REGEX.match(x).groups()
  if d is None: n, d = 0, 1  # if d is None, then n is also None
  if n is None: i, n = 0, i
  return float(i) + float(n) / float(d)

To test:

>>> for x in ['1', '1/2', '1 2/3']: print(repr(parse(x)))
... 
1.0
0.5
1.6666666666666665

Depending on what syntax you want to support for your fractions, eval('+'.join(s.split())) (with true division in place -- i.e., Python 3 or from __future__ import division in Python 2 -- might work. It would cover all the cases you mention, in particular.

>>> s="1/2"
>>> eval('/'.join(map(str,map(float,s.split("/")))))
0.5

>>> s="3/5"
>>> eval('/'.join(map(str,map(float,s.split("/")))))
0.59999999999999998
2

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Sarah Jenkins

Sarah Jenkins

Senior Technology Editor & AI Specialist

Sarah Jenkins is a veteran tech journalist with over 12 years of experience covering artificial intelligence, mobile innovations, and digital ethics. Her insights have appeared in leading technology publications worldwide.

Share this article
Twitter Facebook Pinterest