@t3m2/# Converts rational numbers in decimal notation to fractions

Files

- main.py

main.py

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155

```
"""
Author: @t3m2.
Date of creation: 09/07/2019, , dd/mm/yyyy, (july).
Version: 14/12/2019, dd/mm/yyyy, (december).
Language: Python.
This program defines three functions which can be used to
converts rational numbers into fractions:
from_string_to_fraction(),
gcd() and number_of_decimal_places_of().
I have built the function from_string_to_fraction()
that receives a string representing a rational number
in decimal notation (including repeating decimals),
such as "2.5(37)", "-7.8" or "4"
and returns a string with the correspondent fraction
in form "n/m" where n and m are integers.
Eg.: from_string_to_fraction("-2.5(37)") returns "-1256/495".
If the number is a repeating decimal,
its peridod should appear between round brackets.
It needs the functions gcd() and number_of_decimal_places_of()!
Read the functions' docstrings for more information.
"""
__author__ = "t3m2"
__date__ = "09/07/2019, , dd/mm/yyyy, (july)"
__version__ = "14/12/2019, dd/mm/yyyy, (december)"
def gcd(a=1, b=1):
"""Returns the greatest common divisor
between two positive integers.
(Recursive solution)
Make sure a and b are positive int's
because this function assumes that."""
if b == 0:
return a
else:
return gcd(b, a%b)
def number_of_decimal_places_of(x=0):
"""Returns the number of decimal places of a float or int.
Make sure x is a float or int
because this function assumes that."""
if x == int(x):
return 0
return len(str(x)[str(x).index('.')+1:])
def from_string_to_fraction(x='0'):
"""Receives a string representing a rational number in decimal notation,
(including repeating decimals) such as "-2.5(37)", "-7.8" or "4", and
returns a string with the correspondent fraction in form "n/m",
where both n and m are integers.
Eg.: from_string_to_fraction("-2.5(37)") returns "-1256/495".
It needs the functions gcd() and number_of_decimal_places_of()!
This only works with rational numbers because rational numbers
are all the numbers and the only numbers that can be written as
the divison of two integers, that's the definition of rational numbers.
Note that recurring decimals are rational numbers, and that 0,(9)=1.
Make sure that: (input restrictions)
- the argument is a valid string representing
a rational number in decimal notation;
- the decimal separator (if there) is a '.' or a ',';
- if the input is a recurring decimal, the period comes between round brackets.
(12.431111111111111... is represented as "12.43(1)".)
Because this function assumes that!"""
# The input string can have a ',' or a '.' separating the int and the decimal part:
x = x.replace(',', '.', 1)
sign = 1
if x[0] == '-':
# iff x represent a negative number, this turns x into
# a string representing positive number,
# because if it easier to work with positives numbers.
# And, in the end, we turn the result into negative again
# by making something like: "final_result*=sign".
sign = -1
x = x[1:]
### Getting the finit part (f) and the period (p): ###
# I will explain this with an example:
# If x == "2.5(37)"; then I set f, the finit part, to 2.5 and p, the period, to 37.
# If the number is non-recurring, f = x, since it has no period.
# Eg: if x == "-3.4"; then f = -3.4 and p = 0.
# Note that x, our argument, is still a 'string'.
try: # This will be executed iff x is a non-recurring decimal:
f = eval(x) # eval(x) "turns" the string x into a float or int.
p = 0
except TypeError: # This will be executed iff x is a recurring decimal:
f = float(x[:x.index('(')]) # The finit part of the dizim is all the way until '('.
p = int(x[x.index('(')+1:x.index(')')]) # The period of the dizim is
# the part of the number between '(' and ')').
### Getting the numerator and denominator: ###
# With f and p defined, I have to discover the numerator and the denominator:
# Here is a method that can be used in order to discover the fraction:
# If y=2,5(37): (mathematical notation)
# 1000y - 10y = 2537,(37) - 25,(37) <=>
# 1000y - 10y = 2537 - 25 <=>
# (1000-10) * y = 2537 - 25 <=>
# <=> y = (2537-25) / (1000-10) <=>
# <=> y = 2512 / 990 =>
# => y = numerator / denominator => # Then we need to simplify the fraction,
# => y = 1256 / 495 # and this will be the final result.
# Note that both numerator and denominator are integers.
# I implemented this with f and p:
numerator = f*10**(number_of_decimal_places_of(f)+len(str(p)))+p \
- f*10**number_of_decimal_places_of(f)
denominator = 10**(number_of_decimal_places_of(f)+len(str(p))) \
- 10**number_of_decimal_places_of(f)
### Simplifying the fraction: ###
# Here I am slimplifying the fraction, if it's possible:
factor = gcd(numerator, denominator)
# "sign*" is used to get the correct sign of the final answer,
# ie, the same sign of x.
numerator = sign*(numerator/factor)
denominator = denominator/factor
return "%d/%d" % (numerator, denominator)
### TESTING ###
print("This program turns \"any\" rational number in decimal notation \
into a fraction, for example: -2.5(37) = -2.537373737373737... = -1256/495\n\n")
while 1:
try:
x = input("Enter a rational number in decimal notation (exit: 'b'): ")
if x == 'b':
break
print("%s = %s" % (x, from_string_to_fraction(x)))
except:
print("Error: probably, invalid input.")
print()
```

Fetching token