Python how to create fraction without using modules - fractions

I want to define a function named 'fraction' that given two integer 'numerator,denominator' as arguments and then use return to return them in (numerator/denominator) and the resulting fraction reduced in correct form without using (fraction import fraction,math.inf,gcd and other modules)
the problem is that I want to use range from 2 - numerator+1 and denominator+1
but it won't work so I put 100
example
fraction(9,24)
3/8
fraction(16,-48)
-1/3
def fraction( numerator, denominator):
for divisor in range(2,100):
if (numerator % divisor == 0 and denominator % divisor == 0):
return(fraction(numerator / divisor, denominator / divisor))
return('{}/{}'.format(numerator, denominator))

Related

Output showing 0 for random() function

So, I have this battle scenario here:
def band_attack():
global new_ship
print('Bandits attack!')
s.sleep(1)
c = r.random()
if c < 0.5:
print('Bandits missed!')
elif 0.5 < c < 0.7:
c = r.random()
new_ship = new_ship - int(c)
print('Your ship was hit for', c, 'damage!')
print('Your ship now has', int(new_ship), 'health!')
else:
new_ship = new_ship - int(c)
print('Critical strike! You were hit for', c, 'damage!')
print('Your ship now has', int(new_ship), 'health!')
if new_ship <= 0:
print('You\'ve been destroyed!')
else:
Fight.band_fight()
Fight is the class holding all the battle functions, r is the random module, s is the time module, band_attack is a function where you attack.
I want the damage obviously to be whole numbers above 0, hence why I turn the random function output to an integer.
It should be outputting a number greater than 0, or if it is 0, should just be a miss, but I'm clearly missing something. Maybe someone else can figure out what I'm missing?
The call to random.random() will always return a floating-point number in the range [0.0, 1.0) as per the documentation.
When you cast the result to int (by calling the int(c)), you are asking for the integer part of that float which is always equal to zero for floats in that range.
There are two ways to fix this: either multiply the result of random.random() by 10 or use the random.randint(a, b), which returns a random integer N, such that a <= N <= b. You will need to adjust your conditions accordingly.
You mentioned in the comments that you are worried about seeding the random number generator when using random.randint(a, b) but since the seed function affects the module's random number generator itself all functions (randint, choice, randrange) will behave as expected.
The random() function from the random module (which I assume is what you named r) returns a float between 0 and 1. You can't pass a float into int(). The best alternative would be to use either randint(x, y) (where x and y denote the range in which you want your random damage to be), or stick to random() and mulitply it by the upper limit of that intended range.

Python3: The Fraction

from fractions import Fraction
from functools import reduce
def product(fracs): ## fracs is a list of Fraction objects from the subsequent function call
t = Fractions(reduce(lambda x,y: x.numerator * y.numerator,fracs), reduce(lambda x,y: x.denominator * y.denominator, fracs))
return t.numerator, t.denominator
if __name__ == '__main__':
fracs = []
for _ in range(int(input())):
fracs.append(Fraction(*map(int, input().split())))
result = product(fracs)
print(*result)
I'm trying to multiply a series of fractions together using Python3 functool's Fraction function. The problem i have is with the denominator perimeter for the t variable in the product(fracs) function. Upon testing with the following test case:
3
1 2
3 4
10 6
5 1
The output was 5 1. The numerator seem to work fine but broke down for the denominator. I am aware and have found alternative solutions to my problem however i am hoping to get this mystery solved. I've ran it through python tutor but i couldn't decipher the code's behavior.
I think it's how you are using reduce. The first time it's called you are passing two Fraction objects:
Fraction(1,2).denominator * Fraction(3,4).denominator
which returns 8 and is what you expect. However, the reduce function is not making this 8 a fraction so the next call to reduce looks like this:
8.denominator * Fraction(10,6).denominator
Which is 6 not the expected 48. This problem doesn't exist for the numerator because for an Int X:
X = X.numerator
Therefore you get 30 in the numerator and 6 in the denominator which reduces to 5.
I'm not familiar with the Fraction class but it seems like you might be reinventing the wheel a bit.
I suspect you can just multiply the fraction objects and it's multiplication operator is overloaded:
def product(fracs):
return reduce(lambda x,y: x * y, fracs)

Floor or Ceiling away from zero in Python

Using Python 3, is there a more Pythonic way to floor/ceil as float away from zero than doing this:
import math
def away_from_zero(x):
if x > 0:
return int(math.ceil(x))
else:
return int(math.floor(x))
Is there a better (perhaps more elegant) way to get the nearest integer with greater absolute magnitude?
I would not necessarily consider this more Pythonic, but if you'd like to avoid invoking the math.floor and math.ceiling functions and are looking for something more algebraic, you could do something like this:
def away_from_zero(x):
return int(x // 1 + 2 ** (x > 0) - 1)
As an explanation:
The integer division x // 1 will round down any floating point number, negative or positive, to the nearest integer that's less than x. So 1.5 goes to 1.0 and -1.5 goes to -2.0. This alone solves the problem for negative values and whole numbers, but positive non-integers are off-by-one.
To account for the positive case, we want to offset the result by 1 when x is positive but not when it's negative. You could use conditional logic for this, but if you want to restrict the computation to a single equation, you could also add some term that equals 1 when x is positive and 0 when x is negative. To that end, we have 2 ** (x > 0) - 1. Here, when x is positive, we have
>>> 2 ** True - 1
1
When x is negative, we have
>>> 2 ** False - 1
0
Finally, since integer division of a float returns a float, we cast the result to an int, which gives the desired behavior:
>>> away_from_zero(1.4)
2
>>> away_from_zero(1.6)
2
>>> away_from_zero(-1.4)
-2
>>> away_from_zero(-1.6)
-2
A more elegant way of writing the function you already have would be:
import math
def away_from_zero(x):
return int(math.floor(x) if x > 0 else math.ceil(x))

How can I solve finding consecutive factors problem in an optimal way?

I need to develop a function which finds consecutive factors of the given number and then the function will return the smallest of these consecutive numbers.
I tried to solve a Codility question. (I submitted my solution)
I need to develop the solution function.
def solution(N):
# write your code in Python 3.6
pass
An example:
If N is 6, the function will return 2 (because of 6 = 2 * 3)
If N is 20, the function will return 4 (because of 20 = 4 * 5)
If N is 29, the function will return 0
I developed the solution function (by checking all the numbers from 1 up to N, brute force search) and it works.
However, when the argument of the solution function is too big, the execution of the function takes too much time. Codility Python engine is running the function for a while and then it is throwing TIMEOUT ERROR.
What may be an optimal solution for this problem?
Thank you
I developed the function but it is not optimized.
def solution(N):
for i in range(1,N+1):
if i * (i+1) == N:
return i
return 0
When N is too big like 12,567,543, the function execution takes too much time.
After my comment, I thought a little bit about the question.
If you have an integer, N, and two consecutive factors, m and m+1, then it MUST be true that m < sqrt(N) and m + 1 > sqrt(N)
Therefore, all you have to do is check if the floor of the square root times the ceiling of the square root is equal to your original number..
import math
def solution(N):
n1 = math.floor(math.sqrt(N))
n2 = n1 + 1 # or n2 = math.ceil(math.sqrt(N))
if n1*n2 == N:
return n1
return 0
This has a run time of O(1).
import math
import math
def mysol(n):
s = math.sqrt(n)
if math.floor(s) * math.ceil(s) == n:
return math.floor(s)
else:
return 0

Efficient Mersenne prime generator in python

I have made a code that doesn't seem to be very efficient. It only calculates a few of the primes.
This is my code:
num=float(1)
a=1
while(num>0): # Create variable to hold the factors and add 1 and itself (all numbers have these factors)
factors = [1, num]
# For each possible factor
for i in range(2, int(num/4)+3):
# Check that it is a factor and that the factor and its corresponding factor are not already in the list
if float(num) % i == 0 and i not in factors and float(num/i) not in factors:
# Add i and its corresponding factor to the list
factors.append(i)
factors.append(float(num/i))
num=float(num)
number=num
# Takes an integer, returns true or false
number = float(number)
# Check if the only factors are 1 and itself and it is greater than 1
if (len(factors) == 2 and number > 1):
num2=2**num-1
factors2=[1, num]
for i in range(2, int(num2/4)+3):
# Check that it is a factor and that the factor and its corresponding factor are not already in the list
if float(num2) % i == 0 and i not in factors2 and float(num2/i) not in factors2:
# Add i and its corresponding factor to the list
factors2.append(i)
factors2.append(float(num2/i))
if(len(factors2)==2 and num2>1):
print(num2)
a=a+1
num=num+2
How can I make my code more efficient and be able to calculate the Mersenne Primes quicker. I would like to use the program to find any possible new perfect numbers.
All the solutions shown so far use bad algorithms, missing the point of Mersenne primes completely. The advantage of Mersenne primes is we can test their primality more efficiently than via brute force like other odd numbers. We only need to check an exponent for primeness and use a Lucas-Lehmer primality test to do the rest:
def lucas_lehmer(p):
s = 4
m = 2 ** p - 1
for _ in range(p - 2):
s = ((s * s) - 2) % m
return s == 0
def is_prime(number):
"""
the efficiency of this doesn't matter much as we're
only using it to test the primeness of the exponents
not the mersenne primes themselves
"""
if number % 2 == 0:
return number == 2
i = 3
while i * i <= number:
if number % i == 0:
return False
i += 2
return True
print(3) # to simplify code, treat first mersenne prime as a special case
for i in range(3, 5000, 2): # generate up to M20, found in 1961
if is_prime(i) and lucas_lehmer(i):
print(2 ** i - 1)
The OP's code bogs down after M7 524287 and #FrancescoBarban's code bogs down after M8 2147483647. The above code generates M18 in about 15 seconds! Here's up to M11, generated in about 1/4 of a second:
3
7
31
127
8191
131071
524287
2147483647
2305843009213693951
618970019642690137449562111
162259276829213363391578010288127
170141183460469231731687303715884105727
6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151
531137992816767098689588206552468627329593117727031923199444138200403559860852242739162502265229285668889329486246501015346579337652707239409519978766587351943831270835393219031728127
This program bogs down above M20, but it's not a particulary efficient implementation. It's simply not a bad algorithm.
import math
def is_it_prime(n):
# n is already a factor of itself
factors = [n]
#look for factors
for i in range(1, int(math.sqrt(n)) + 1):
#if i is a factor of n, append it to the list
if n%i == 0: factors.append(i)
else: pass
#if the list has more than 2 factors n is not prime
if len(factors) > 2: return False
#otherwise n is prime
else: return True
n = 1
while True:
#a prime P is a Mersenne prime if P = 2 ^ n - 1
test = (2 ** n) - 1
#if test is prime is also a Mersenne prime
if is_it_prime(test):
print(test)
else: pass
n += 1
Probably it will stuck to 2147483647, but you know, the next Mersenne prime is 2305843009213693951... so don't worry if it takes more time than you expected ;)
If you just want to check if a number is prime, then you do not need to find all its factors. You already know 1 and num are factors. As soon as you find a third factor then the number cannot be prime. You are wasting time looking for the fourth, fifth etc. factors.
A Mersenne number is of the form 2^n - 1, and so is always odd. Hence all its factors are odd. You can halve the run-time of your loop if you only look for odd factors: start at 3 and step 2 to the next possible factor.
Factors come in pairs, one larger than the square root and one smaller. Hence you only need to look for factors up to the square root, as #Francesco's code shows. That can give you a major time saving for the larger Mersenne numbers.
Putting these two points together, your loop should be more like:
#look for factors
for i in range(3, int(math.sqrt(n)) + 1, 2):

Resources