I recently started coding and was trying to make a fraction class on my own!
I've been stuck with reducing the fraction for hours! I need to use
"def reduction(self)", with self as the parameter, but I only know how to use this function without (self)! How can I reduce the fraction
with self as a parameter for my reduction function?
Can people please help me out? Here is my code...
class MyFraction:
def __init__(self, numerator: int, denominator: int):
self.numerator = numerator
self.denominator = denominator
def __str__(self):
return str(self.numerator) + "/" + str(self.denominator)
def negate(self):
return MyFraction(-1*self.numerator, self.denominator)
def inverse(self):
return MyFraction(self.denominator, self.numerator)
def reduction(self):
for i in range(self.denominator-1, 0, -1):
if self.denominator % i == 0 and self.numerator % i == 0:
return i
else:
return 1
self.numerator //= i
self.denominator //= i
return MyFraction(self.numerator, self.denominator)
def __add__(self, frac):
new_num = (self.numerator * frac.denominator) + \
(self.denominator * frac.numerator)
new_den = self.denominator*frac.denominator
return MyFraction(new_num, new_den)
def __sub__(self, frac):
new_num = (self.numerator * frac.denominator) - \
(self.denominator * frac.numerator)
new_den = self.denominator * frac.denominator
return MyFraction(new_num, new_den)
def __mul__(self, frac):
new_num = self.numerator * frac.numerator
new_den = self.denominator * frac.denominator
return MyFraction(new_num, new_den)
def __truediv__(self, frac):
new_num = self.denominator * frac.numerator
new_den = self.numerator * frac.denominator
return MyFraction(new_num, new_den)
if __name__ == '__main__':
a = MyFraction(1, 2)
b = MyFraction(13, 15)
x = a + b
print(f'x={x}, a={a}, b={b}')
c = x - a # 18/15
d = x - 1
y = c / d # 36/11
print(f'y={y}, c={c}, d={d}')
Related
I'm trying to reduce(self) to return fractions which have the lowest value.
This is the code I have:
class fraction:
def __init__(self,numerator,denominator):
self.numerator = numerator
self.denominator = denominator
self.reduce()
def get_numerator(self):
return self.numerator
def get_denominator(self):
return self.denominator
def reduce(self):
pass
def __str__(self):
return str(self.numerator) + "/" + str(self.denominator)
And this is the test code:
# y = fraction(2*7,7*2)
# z = fraction(13,14)
# a = fraction(13*2*7,14)
# print(x)
# print(y)
# print(z)
# print(a)
I don't want to use math.gcd or import fractions but rather do it by hand.
I'm not sure what to try without these operators. Would it be perhaps a while loop?
You can implement reduce() using Greatest Common Divisor. As #NickODell said in comment this GCD algorithm is described in Euclidean Algorithm Wiki. And implemented in my code below:
Try it online!
class fraction:
def __init__(self, numerator, denominator):
self.numerator = numerator
self.denominator = denominator
self.reduce()
def get_numerator(self):
return self.numerator
def get_denominator(self):
return self.denominator
#staticmethod
def gcd(a, b):
while b != 0:
a, b = b, a % b
return a
def reduce(self):
if self.numerator == 0 or self.denominator == 0:
return
g = self.gcd(self.numerator, self.denominator)
self.numerator //= g
self.denominator //= g
def __str__(self):
return str(self.numerator) + "/" + str(self.denominator)
y = fraction(2*7,7*2)
z = fraction(13,14)
a = fraction(13*2*7,14)
print(y)
print(z)
print(a)
print(fraction(15, 35))
Output:
1/1
13/14
13/1
3/7
I have written a code where I have defined a class Fraction. Throughout the code, all binary operations such as +, -, /, * can be performed. Now I would also like to be able to perform unary operations for the class Fraction such as abs() etc. However, this does not work at the moment, when performing for example the unary operation abs() I get a TypeError: bad operand type for abs (): 'Fraction'. Below is part of the code that deals purely with fraction subtraction, it is representative for the entire code:
def gcd(denominator, numerator):
if numerator == 0:
return denominator
else:
return gcd(numerator, (denominator % numerator))
class Fraction:
def __init__(self,numerator = 0, denominator = 1):
self.numerator = int(numerator / gcd(abs(denominator),abs(numerator) ))
self.denominator = int(denominator / gcd(abs(denominator),abs(numerator) ))
if self.denominator < 0:
self.denominator = abs(self.denominator)
self.numerator = -1*self.numerator
elif self.denominator == 0:
raise ZeroDivisionError
def __str__(self):
if self.denominator == 1:
return str(self.numerator)
else:
return str(self.numerator) + "/" + str(self.denominator)
def __neg__(self):
return Fraction(-self.numerator, self.denominator)
def __rsub__(self,other):
return self.__sub__(other)
def __sub__(self,other):
if type(other) == int:
other = Fraction(other,1)
return self.sub(other)
else:
return self.sub(other)
def sub(self,other):
result = Fraction()
result.numerator = other.denominator * self.numerator - self.denominator * other.numerator
result.denominator = other.denominator * self.denominator
multiple = gcd(result.denominator,result.numerator)
result.numerator = int(result.numerator / multiple)
result.denominator = int(result.denominator / multiple)
if result.denominator < 0:
result.denominator = abs(result.denominator)
result.numerator = 0 - result.numerator
return result
else:
return result
return result
p = Fraction(2,3)
q = Fraction(4,5)
r = (p - q)
What I would like is that when I give the statement print(abs(r)) the output is the fraction in absolute value. So in the example where p = Fraction(2,3), q = Fraction(4,5) and r = (p - q). Then the statement print(r) gives the output -2/15 and the statement print(abs(r)) gives the output 2/15. Or that for example print(float(r)) gives the output -0.133333333. However, I keep getting the previously mentioned TypeError.
I've been looking for a while, but so far I haven't been able to find a solution, do you know how I can fix this?
Thanks in advance!
As already mentioned in the comment implement __abs__ and __float__.
Add this to your class:
def __abs__(self):
return Fraction(abs(self.numerator), abs(self.denominator))
def __float__(self):
return self.numerator / self.denominator
Maybe
def __abs__(self):
return Fraction(abs(self.numerator), self.denominator)
would be already enough, when your denominator is always positive.
>>> p = Fraction(2, 3)
>>> q = Fraction(4, 5)
>>> r = p - q
>>> print(r)
-2/15
>>> print(abs(r))
2/15
>>> print(float(r))
-0.13333333333333333
In part of my code I can subtract fractions, however if I enter (- p) where p is a fraction I get a TypeError: unsupported operand type(s) for +: "Fraction" and "Fraction"
def gcd(denominator, numerator):
if numerator == 0:
return denominator
else:
return gcd(numerator, (denominator % numerator))
class Fraction:
def __init__(self,numerator = 0, denominator = 1):
self.numerator = int(numerator / gcd(abs(denominator),abs(numerator) ))
self.denominator = int(denominator / gcd(abs(denominator),abs(numerator) ))
if self.denominator < 0:
self.denominator = abs(self.denominator)
self.numerator = -1*self.numerator
elif self.denominator == 0:
raise ZeroDivisionError
def __str__(self):
if self.denominator == 1:
return str(self.numerator)
else:
return str(self.numerator) + "/" + str(self.denominator)
def __rsub__(self,other):
return self.__sub__(other)
def __sub__(self,other):
if type(other) == int:
other = Fraction(other,1)
return self.sub(other)
else:
return self.sub(other)
def sub(self,other):
result = Fraction()
result.numerator = other.denominator * self.numerator - self.denominator * other.numerator
result.denominator = other.denominator * self.denominator
multiple = gcd(result.denominator,result.numerator)
result.numerator = int(result.numerator / multiple)
result.denominator = int(result.denominator / multiple)
return result
p = Fraction(2,3)
r = (- p)
However, when my input is (1 - p) I get the correct output. Suppose p = Fraction(2, 3) then I would like (- p) to return (-2 / 3) or (2/ -3). The problem seems to me to be in the fact that no input is given for the first argument when subtracting. While searching I did come across things like __neg__, but I'm still new to python and using classes so I don't know exactly how to implement this. Does anyone know how I can fix this?
Thanks in advance!
You are right; you need to implement __neg__ because that minus is not the (binary) subtraction operator, but the unary minus.
Here is how you can do it:
def __neg__(self):
return Fraction(-self.numerator, self.denominator)
Other issues
__rsub__
You need to change the implementation of __rsub__, because that method will be called when other does not support __sub__. For instance, it will kick in when you evaluate this:
p = 1 - Fraction(2, 3)
That evaluation will not work as it currently stands. You need to have this:
def __rsub__(self, other):
return Fraction(other) - self
or, explicitly calling __sub__:
def __rsub__(self, other):
return Fraction(other).__sub__(self)
Normalising
The constructor correctly normalises the fraction, making sure the denominator is positive, but you don't do the same in the sub method. There the result may not be normalised: the denominator could remain negative.
Moreover, it is a pity that you duplicate the gcd-related code that is already in the constructor. It is better to rely on the constructor for that logic.
Immutability
It is better to treat instances as immutable. So you should not have any assignments to instance.numerator and instance.denominator outside of the constructor. Make sure to first determine the numerator and denominator (without normalisation), and then call the constructor passing these as arguments.
Comparisons
You may want to compare Fractions for equality or relative order. For that you can implement __eq__, __lt__, ...etc.
Proposed code
Here is how I would do it:
def gcd(denominator, numerator):
if numerator == 0:
return denominator
else:
return gcd(numerator, denominator % numerator)
class Fraction:
def __new__(cls, numerator=0, denominator=1):
if isinstance(numerator, Fraction):
return numerator # Use this instance and ignore 2nd argument
return super(Fraction, cls).__new__(cls)
def __init__(self, numerator=0, denominator=1):
if isinstance(numerator, Fraction):
return # self is already initialised by __new__
if denominator == 0:
raise ZeroDivisionError
div = gcd(abs(denominator), abs(numerator))
if denominator < 0:
div = -div
self.numerator = numerator // div
self.denominator = denominator // div
def __str__(self):
if self.denominator == 1:
return str(self.numerator)
else:
return f"{self.numerator}/{self.denominator}"
def __rsub__(self, other):
return Fraction(other) - self
def __sub__(self, other):
other = Fraction(other)
return Fraction(other.denominator * self.numerator
- self.denominator * other.numerator,
other.denominator * self.denominator)
def __neg__(self):
return Fraction(-self.numerator, self.denominator)
def __eq__(self, other):
other = Fraction(other)
return (self.numerator == other.numerator and
self.denominator == other.denominator)
def __lt__(self, other):
other = Fraction(other)
return (other.denominator * self.numerator <
self.denominator * other.numerator)
def __gt__(self, other):
return Fraction(other) < self
def __le__(self, other):
return self < other or self == other
def __ge__(self, other):
return self > other or self == other
Your __rsub__ code is flipped, you want other.__sub__(self).
def __rsub__(self,other):
return other.__sub__(self)
I'm using this code to add two points together using finite Fields
class FieldElement():
def __init__(self,num,prime):
if num>=prime or num < 0:
error = "num s not in field"
raise ValueError(error)
self.num = num
self.prime=prime
def __eq__(self,other):
if other is None:
return
return self.num == other.num and self.prime == other.prime
def __ne__(self,other):
return not (self == other)
def __add__ (self,other):
if self.prime != other.prime:
raise ValueError("cannot add two numbers in diffirent fields")
num = (self.num+other.num)%self.prime
return self.__class__(num,self.prime)
def __mul__(self,other):
if self.prime != other.prime:
raise ValueError("cannot add two numbers in different fields")
num = (self.num * other.num)%self.prime
return self.__class__(num,self.prime)
def __pow__(self,exponent):
n = exponent%(self.prime-1)
num = pow(self.num,n,self.prime)
return self.__class__(num,self.prime)
def __sub__(self,other):
if self.prime != other.prime:
raise ValueError("cannot add two numbers in different fields")
num = (other.num - self.num)%self.prime
return self.__class__(num,self.prime)
def __truediv__(self,other):
if self.prime != other.prime:
raise TypeError("cannot divide two numbers in different Fields")
num = self.num * pow(other.num,self.prime-2,self.prime)%self.prime
return self.__class__(num,self.prime)
class Point ():
def __init__(self, x,y,a,b):
self.a = a
self.b = b
self.y = y
self.x = x
if self.x is None and self.y is None:
return
if (self.y**2) != (self.x**3 + a*x + b):
raise ValueError("{} , {} not in the Curve".format(x.num,y.num))
def __repr__(self):
return "Point({},{}){}_{}".format(self.x,self.y,self.a,self.b)
def __eq__(self,other):
return self.x == other.x and self.y == other.y and self.a == other.a and self.b == other.b
def __add__(self,other):
if other.a != self.a or other.b != self.b:
raise TypeError("Points{},{} are the same curve".format(self,other))
if self.x is None:
return other
if other.x is None:
return self
if other.x == self.x and other.y != self.y:
return self.__class__(None,None,self.a,self.b)
if self != other:
s = (other.y-self.y)/(other.x-self.x)
x = (s**2 - self.x - other.x)
y = s*(self.x - x) - self.y
return self.__class__(x,y,self.a,self.b)
if self == other :
s = (3*self.x**2+self.a)/(2* self.y)
x = s**2-2*self.x
y = s*(self.x-x)-self.y
return self.__class__(x,y,self.a,self.b)
if self == other and self.y == 0*self.x:
return self.__class__(None,None,self.a,self.b)
def __eq__(self,other):
return self.x == other.x and self.y == other.y and self.a==other.a and self.b==other.b
def __mul__(self,other):
numX = self.x * other.x
numY = self.y * other.y
return self.__class__(numX,numY,self.a,self.b)
and the bellow code to test it ,
from test import FieldElement,Point
prime = 223
a = FieldElement(num=0,prime=prime)
b = FieldElement(num=7,prime=prime)
x1 = FieldElement(num=47,prime=prime)
y1 = FieldElement(num=71,prime=prime)
x2 = FieldElement(num=17,prime=prime)
y2 = FieldElement(num=56,prime=prime)
p1 = Point(x1,y1,a,b)
p2 = Point(x2,y2,a,b)
p3 = p1+p2
print(p3)
Whatever points I add I get the same error that the third point is not on the the curve, I think the problem is on if (self.y**2) != (self.x**3 + a*x + b) some how it's not checking the new point correctly or Point __add__ method does not calculate the new point correctly, what am missing here ?
You should test every module before use
In the Field, the subtraction is wrong! you calculate b-a not a-b
def __sub__(self,other):
if self.prime != other.prime:
raise ValueError("cannot add two numbers in different fields")
num = (other.num - self.num)%self.prime
return self.__class__(num,self.prime)
must be
def __sub__(self,other):
if self.prime != other.prime:
raise ValueError("cannot add two numbers in different fields")
num = (self.num - other.num)%self.prime
return self.__class__(num,self.prime)
The other problem as stated in the other answer doesn't make a problem since the first operand is the member of the class, however, you should use
if (self.y**2) != (self.x**3 + self.a*self.x + self.b):
You should also implement __str__ for your field and point classes to print easy to test your code!
def __str__(self):
return num
I've tested and now works. The below is the SageMath Code (test here) that you can compare the result and use a test base for your code.
E = EllipticCurve(GF(223),[0,7])
print(E)
R1 = E(47,71)
R2 = E(17,56)
print(R1+R2)
I think that the line:
if (self.y**2) != (self.x**3 + a*x + b):
should be
if (self.y**2) != (self.x**3 + self.a*self.x + self.b):
as a, x and b will not be treated as field elements.
I'm new to Python,
After initialising an instance f of class Fraction, I want the method reduce has been invoked, so the print result is after reduced
f = Fraction(3,6)
print f #=> 1/2 not 3/6
here's the code:
class Fraction(object):
'''Define a fraction type'''
def __init__(self, num=0, denom=1):
'''Create a new Fraction with numerator num and denominator demon'''
self.numerator = num
if denom != 0:
self.denominator = denom
else:
raise ZeroDivisionError
def reduce(self):
gcd = findgcd(self.numerator, self.denominator)
self.numerator /= gcd
self.denominator /= gcd
def findgcd(self, x, y):
gcd = None
min_number = min(x, y)
for i in range(min_number, 1, -1):
if x % i == 0 and y % i == 0:
gcd = i
return gcd
def __repr__(self):
return "{0}/{1}".format(self.numerator, self.denominator)
What prevent you from calling self.reduce() at the end of __init__ method?
You have two problems:
you need to call self.reduce() in your constructor __init__ to have method reduce() invoked during the instantiation phase.
you also need to change:
def reduce(self):
gcd = findgcd(self.numerator, self.denominator)
to:
def reduce(self):
gcd = self.findgcd(self.numerator, self.denominator)
because otherwise your instance will not be able to find findgcd.
The following code will fix your problem:
class Fraction(object):
'''Define a fraction type'''
def __init__(self, num=0, denom=1):
'''Create a new Fraction with numerator num and denominator demon'''
self.numerator = num
if denom != 0:
self.denominator = denom
else:
raise ZeroDivisionError
self.reduce()
def reduce(self):
gcd = self.findgcd(self.numerator, self.denominator)
self.numerator /= gcd
self.denominator /= gcd
def findgcd(self, x, y):
gcd = None
min_number = min(x, y)
for i in range(min_number, 1, -1):
if x % i == 0 and y % i == 0:
gcd = i
return gcd
def __repr__(self):
return "{0}/{1}".format(self.numerator, self.denominator)
>>>> f = Fraction(3,6)
>>>> f
1/2