Reputation: 2127
Project Euler problem 33 asks solvers to find "curious fractions": fractions which are equal to the fraction obtained by deleting digits that appear in both numerator and denominator (for example, 49/98, which "cancels" to 4/8 by deleting the 9s).
NOTE: This is not a competition to solve the Project Euler problem FASTEST. I already rewrote this code into a solution that's as fast as Nickie's. This is done by removing the for loop and if float(numer)... conditionals. It looks like this:
def curious(numer,denom):
n = str(numer)
d = str(denom)
if len(n) == 2 and len(d) == 2:
if n[1] == d[0]:
if n != d:
if d[1] != "0":
if Fraction(int(n[0]), int(d[1])) \
== \
Fraction(numer, denom):
return n + d
I still don't understand the conditional problem though.
I am not new to Python programming and this is the first time I've encountered anything like this. In the function defined below, there are paired if and elif statements:
import time
from fractions import Fraction
def curious(numer,denom):
n = str(numer)
d = str(denom)
if len(n) == 2 and len(d) == 2:
if n[1] == d[0]:
for i in range(2, numer+1):
if float(numer)/i == float(int(n[0])) \
and float(denom)/i == float(int(d[1])):
if n != d:
return n + "/" + d
elif d[1] != "0":
if Fraction(int(n[0]), int(d[1])) \
== \
Fraction(numer, denom):
if n != d:
return n + d
start = time.time()
nums = []
denoms = []
for i in range(10, 100):
for j in range(10, 100):
if i < j:
if type(curious(i, j)) == str:
frac = (curious(i,j))
nums.append(frac[0]+frac[1])
denoms.append(frac[2]+frac[3])
print frac
pro = 1
duct = 1
for i in range(0, len(nums)):
pro *= int(nums[i])
duct *= int(denoms[i])
print Fraction(pro, duct)
elapsed = time.time() - start
print "The elapsed time is %s seconds." % (elapsed)
when I run the code with the elif statement commented out, the result is this:
16/64,
19/95,
26/65,
The elapsed time is 0.0500001907349 seconds.
But when the elif is included, the if statement is ignored and the result is this:
1664,
1995,
2665,
4998,
The elapsed time is 0.59700012207 seconds.
It appears that Python prefers to take the inefficient route, even though the conditions of the if statement are satisfied in both cases. Can anyone help me solve this mystery?
Ideally, I want the result to be:
16/64,
19/95,
26/65,
4998,
The elapsed time is 0.0500001907349 seconds.
Upvotes: 1
Views: 431
Reputation: 27575
In my following code, the elif section
is active or deactivated according to the value given to ELIF .
import time
from fractions import Fraction
def curious(numer,denom,disp=None):
n = str(numer)
d = str(denom)
fracs = []
if n!=d and n[1] == d[0]:
ELIF = 1
fn0 = float(n[0])
fd1 = float(d[1])
if disp:
print ('---------------------------------------\n'
'n == %s d == %s\n'
"float('%s'[0]) == %f float('%s'[1]) == %f"
% ( n,d,n,fn0,d,fd1 ) )
for i in range(2, numer+1):
if disp:
print ('i== %2d '
'%s./%2d==%10f %s./%2d==%10f %s' %
(i,n,i,float(n)/i,d,i,float(d)/i,
float(n)/i==fn0 and float(d)/i==fd1) )
if float(numer)/i==fn0 and float(denom)/i==fd1:
if disp:
print (' %s\n'
' - %s/%s returned by if section -' %
('- elif part is active -' if ELIF
else '- elif part is not active -',
n,d))
return n + "/" + d
elif ELIF and d[1] != "0":
if Fraction( n[0] + '/' + d[1] ) \
== \
Fraction(numer, denom):
if disp:
print (' %s\n'
" Fraction('%s/%s') == %s\n"
" Fraction(%s, %s) == %s\n"
' - %s%s returned by elif section -' %
('- elif part is active -' if ELIF
else '- elif part is not active -',
n[0],d[1],Fraction( n[0] + '/' + d[1] ),
numer,denom,Fraction(numer, denom),n,d) )
return n + d
else:
if n+d=='4998':
if disp:
print (' - elif part is active -' if ELIF
else ' - elif part is not active -')
print ' - No convenient divisor found for 49 98 : returned by else section -'
return 'No convenient divisor found for 49 98'
start = time.time()
nums,denoms = [],[]
fracs = []
for i in range(10, 100):
for j in range(10, 100):
if curious(i,j):
frac = (curious(i,j,'display'))
print('frac == %s' % frac)
fracs.append(frac)
deb,end = frac[0:2],frac[-2:]
try:
int(deb)
nums.append(deb)
denoms.append(end)
except:
print "can't record %r==frac[0:2] as numerator" % (deb,)
print '\ndetected :\n %s' % '\n '.join(fracs)
pro,duct = 1,1
print '\nnums ==',nums
print 'denoms ==',denoms
for i in range(0, len(nums)):
pro *= int(nums[i])
duct *= int(denoms[i])
print 'pro,duct ==',pro,duct
print 'Fraction(pro, duct) ==',Fraction(pro, duct)
elapsed = time.time() - start
print "The elapsed time is %s seconds." % (elapsed)
result with ELIF = 0
---------------------------------------
n == 16 d == 64
float('16'[0]) == 1.000000 float('64'[1]) == 4.000000
i== 2 16./ 2== 8.000000 64./ 2== 32.000000 False
i== 3 16./ 3== 5.333333 64./ 3== 21.333333 False
i== 4 16./ 4== 4.000000 64./ 4== 16.000000 False
i== 5 16./ 5== 3.200000 64./ 5== 12.800000 False
i== 6 16./ 6== 2.666667 64./ 6== 10.666667 False
i== 7 16./ 7== 2.285714 64./ 7== 9.142857 False
i== 8 16./ 8== 2.000000 64./ 8== 8.000000 False
i== 9 16./ 9== 1.777778 64./ 9== 7.111111 False
i== 10 16./10== 1.600000 64./10== 6.400000 False
i== 11 16./11== 1.454545 64./11== 5.818182 False
i== 12 16./12== 1.333333 64./12== 5.333333 False
i== 13 16./13== 1.230769 64./13== 4.923077 False
i== 14 16./14== 1.142857 64./14== 4.571429 False
i== 15 16./15== 1.066667 64./15== 4.266667 False
i== 16 16./16== 1.000000 64./16== 4.000000 True
- elif part is not active -
- 16/64 returned by if section -
frac == 16/64
---------------------------------------
n == 19 d == 95
float('19'[0]) == 1.000000 float('95'[1]) == 5.000000
i== 2 19./ 2== 9.500000 95./ 2== 47.500000 False
i== 3 19./ 3== 6.333333 95./ 3== 31.666667 False
i== 4 19./ 4== 4.750000 95./ 4== 23.750000 False
i== 5 19./ 5== 3.800000 95./ 5== 19.000000 False
i== 6 19./ 6== 3.166667 95./ 6== 15.833333 False
i== 7 19./ 7== 2.714286 95./ 7== 13.571429 False
i== 8 19./ 8== 2.375000 95./ 8== 11.875000 False
i== 9 19./ 9== 2.111111 95./ 9== 10.555556 False
i== 10 19./10== 1.900000 95./10== 9.500000 False
i== 11 19./11== 1.727273 95./11== 8.636364 False
i== 12 19./12== 1.583333 95./12== 7.916667 False
i== 13 19./13== 1.461538 95./13== 7.307692 False
i== 14 19./14== 1.357143 95./14== 6.785714 False
i== 15 19./15== 1.266667 95./15== 6.333333 False
i== 16 19./16== 1.187500 95./16== 5.937500 False
i== 17 19./17== 1.117647 95./17== 5.588235 False
i== 18 19./18== 1.055556 95./18== 5.277778 False
i== 19 19./19== 1.000000 95./19== 5.000000 True
- elif part is not active -
- 19/95 returned by if section -
frac == 19/95
---------------------------------------
n == 26 d == 65
float('26'[0]) == 2.000000 float('65'[1]) == 5.000000
i== 2 26./ 2== 13.000000 65./ 2== 32.500000 False
i== 3 26./ 3== 8.666667 65./ 3== 21.666667 False
i== 4 26./ 4== 6.500000 65./ 4== 16.250000 False
i== 5 26./ 5== 5.200000 65./ 5== 13.000000 False
i== 6 26./ 6== 4.333333 65./ 6== 10.833333 False
i== 7 26./ 7== 3.714286 65./ 7== 9.285714 False
i== 8 26./ 8== 3.250000 65./ 8== 8.125000 False
i== 9 26./ 9== 2.888889 65./ 9== 7.222222 False
i== 10 26./10== 2.600000 65./10== 6.500000 False
i== 11 26./11== 2.363636 65./11== 5.909091 False
i== 12 26./12== 2.166667 65./12== 5.416667 False
i== 13 26./13== 2.000000 65./13== 5.000000 True
- elif part is not active -
- 26/65 returned by if section -
frac == 26/65
---------------------------------------
n == 49 d == 98
float('49'[0]) == 4.000000 float('98'[1]) == 8.000000
i== 2 49./ 2== 24.500000 98./ 2== 49.000000 False
i== 3 49./ 3== 16.333333 98./ 3== 32.666667 False
i== 4 49./ 4== 12.250000 98./ 4== 24.500000 False
i== 5 49./ 5== 9.800000 98./ 5== 19.600000 False
i== 6 49./ 6== 8.166667 98./ 6== 16.333333 False
i== 7 49./ 7== 7.000000 98./ 7== 14.000000 False
i== 8 49./ 8== 6.125000 98./ 8== 12.250000 False
i== 9 49./ 9== 5.444444 98./ 9== 10.888889 False
i== 10 49./10== 4.900000 98./10== 9.800000 False
i== 11 49./11== 4.454545 98./11== 8.909091 False
i== 12 49./12== 4.083333 98./12== 8.166667 False
i== 13 49./13== 3.769231 98./13== 7.538462 False
i== 14 49./14== 3.500000 98./14== 7.000000 False
i== 15 49./15== 3.266667 98./15== 6.533333 False
i== 16 49./16== 3.062500 98./16== 6.125000 False
i== 17 49./17== 2.882353 98./17== 5.764706 False
i== 18 49./18== 2.722222 98./18== 5.444444 False
i== 19 49./19== 2.578947 98./19== 5.157895 False
i== 20 49./20== 2.450000 98./20== 4.900000 False
i== 21 49./21== 2.333333 98./21== 4.666667 False
i== 22 49./22== 2.227273 98./22== 4.454545 False
i== 23 49./23== 2.130435 98./23== 4.260870 False
i== 24 49./24== 2.041667 98./24== 4.083333 False
i== 25 49./25== 1.960000 98./25== 3.920000 False
i== 26 49./26== 1.884615 98./26== 3.769231 False
i== 27 49./27== 1.814815 98./27== 3.629630 False
i== 28 49./28== 1.750000 98./28== 3.500000 False
i== 29 49./29== 1.689655 98./29== 3.379310 False
i== 30 49./30== 1.633333 98./30== 3.266667 False
i== 31 49./31== 1.580645 98./31== 3.161290 False
i== 32 49./32== 1.531250 98./32== 3.062500 False
i== 33 49./33== 1.484848 98./33== 2.969697 False
i== 34 49./34== 1.441176 98./34== 2.882353 False
i== 35 49./35== 1.400000 98./35== 2.800000 False
i== 36 49./36== 1.361111 98./36== 2.722222 False
i== 37 49./37== 1.324324 98./37== 2.648649 False
i== 38 49./38== 1.289474 98./38== 2.578947 False
i== 39 49./39== 1.256410 98./39== 2.512821 False
i== 40 49./40== 1.225000 98./40== 2.450000 False
i== 41 49./41== 1.195122 98./41== 2.390244 False
i== 42 49./42== 1.166667 98./42== 2.333333 False
i== 43 49./43== 1.139535 98./43== 2.279070 False
i== 44 49./44== 1.113636 98./44== 2.227273 False
i== 45 49./45== 1.088889 98./45== 2.177778 False
i== 46 49./46== 1.065217 98./46== 2.130435 False
i== 47 49./47== 1.042553 98./47== 2.085106 False
i== 48 49./48== 1.020833 98./48== 2.041667 False
i== 49 49./49== 1.000000 98./49== 2.000000 False
- elif part is not active -
- No convenient divisor found for 49 98 : returned by else section -
frac == No convenient divisor found for 49 98
can't record 'No'==frac[0:2] as numerator
detected :
16/64
19/95
26/65
No convenient divisor found for 49 98
nums == ['16', '19', '26']
denoms == ['64', '95', '65']
pro,duct == 7904 395200
Fraction(pro, duct) == 1/50
The elapsed time is 2.40599989891 seconds.
result with ELIF = 1
---------------------------------------
n == 16 d == 64
float('16'[0]) == 1.000000 float('64'[1]) == 4.000000
i== 2 16./ 2== 8.000000 64./ 2== 32.000000 False
- elif part is active -
Fraction('1/4') == 1/4
Fraction(16, 64) == 1/4
- 1664 returned by elif section -
frac == 1664
---------------------------------------
n == 19 d == 95
float('19'[0]) == 1.000000 float('95'[1]) == 5.000000
i== 2 19./ 2== 9.500000 95./ 2== 47.500000 False
- elif part is active -
Fraction('1/5') == 1/5
Fraction(19, 95) == 1/5
- 1995 returned by elif section -
frac == 1995
---------------------------------------
n == 26 d == 65
float('26'[0]) == 2.000000 float('65'[1]) == 5.000000
i== 2 26./ 2== 13.000000 65./ 2== 32.500000 False
- elif part is active -
Fraction('2/5') == 2/5
Fraction(26, 65) == 2/5
- 2665 returned by elif section -
frac == 2665
---------------------------------------
n == 49 d == 98
float('49'[0]) == 4.000000 float('98'[1]) == 8.000000
i== 2 49./ 2== 24.500000 98./ 2== 49.000000 False
- elif part is active -
Fraction('4/8') == 1/2
Fraction(49, 98) == 1/2
- 4998 returned by elif section -
frac == 4998
detected :
1664
1995
2665
4998
nums == ['16', '19', '26', '49']
denoms == ['64', '95', '65', '98']
pro,duct == 387296 38729600
Fraction(pro, duct) == 1/100
The elapsed time is 6.40599989891 seconds.
When ELIF is False,
the result 16/64 19/95 26/65
is returned by the if section
, the format betrays this origin.
When ELIF is True,
the result 1664 1995 2665 4998
is returned by the elif section
, it's revealed by the format too.
The fact that it's returned by the elif section
makes you conclude that the if section
isn't run.
Your conclusion is false because you erroneously think that
"the conditions of the if statement are satisfied in both cases"
No, they aren't, since you doesn't allow the loop to test all the possible values for i
: for the first value i==2
the result of the test is always False, then the elif section
, is always entered after this first value (nikie has already explained this).
The values of the input are the same but the conditions necessary to bring the evidence it's the same are not fulfilled.
To give the loop the possibility to run completely, it is necessary to unindent the elif section
, .
Remark that in the following code , appending frac[0:2]
in nums
and frac[-2:]
in denoms
allows the execution to not stop because of error, and that the result is what you were waiting: 16/64 19/95 26/65 4998
def curious(numer,denom,disp=None):
n = str(numer)
d = str(denom)
fracs = []
if n!=d and n[1] == d[0]:
ELIF = 1
fn0 = float(n[0])
fd1 = float(d[1])
if disp:
print ('---------------------------------------\n'
'n == %s d == %s\n'
"float('%s'[0]) == %f float('%s'[1]) == %f"
% ( n,d,n,fn0,d,fd1 ) )
for i in range(2, numer+1):
if disp:
print ('i== %2d '
'%s./%2d==%10f %s./%2d==%10f %s' %
(i,n,i,float(n)/i,d,i,float(d)/i,
float(n)/i==fn0 and float(d)/i==fd1) )
if float(numer)/i==fn0 and float(denom)/i==fd1:
if disp:
print (' %s\n'
' - %s/%s returned by if section -' %
('- elif part is active -' if ELIF
else '- elif part is not active -',
n,d))
return n + "/" + d
if ELIF and d[1] != "0":
if Fraction( n[0] + '/' + d[1] ) \
== \
Fraction(numer, denom):
if disp:
print (' %s\n'
" Fraction('%s/%s') == %s\n"
" Fraction(%s, %s) == %s\n"
' - %s%s returned by elif section -' %
('- elif part is active -' if ELIF
else '- elif part is not active -',
n[0],d[1],Fraction( n[0] + '/' + d[1] ),
numer,denom,Fraction(numer, denom),n,d) )
return n + d
else:
if n+d=='4998':
if disp:
print (' - elif part is active -' if ELIF
else ' - elif part is not active -')
print ' - No convenient divisor found for 49 98 : returned by else section -'
return 'No convenient divisor found for 49 98'
displays
(skiped lines)
---------------------------------------
n == 26 d == 65
float('26'[0]) == 2.000000 float('65'[1]) == 5.000000
i== 2 26./ 2== 13.000000 65./ 2== 32.500000 False
i== 3 26./ 3== 8.666667 65./ 3== 21.666667 False
i== 4 26./ 4== 6.500000 65./ 4== 16.250000 False
i== 5 26./ 5== 5.200000 65./ 5== 13.000000 False
i== 6 26./ 6== 4.333333 65./ 6== 10.833333 False
i== 7 26./ 7== 3.714286 65./ 7== 9.285714 False
i== 8 26./ 8== 3.250000 65./ 8== 8.125000 False
i== 9 26./ 9== 2.888889 65./ 9== 7.222222 False
i== 10 26./10== 2.600000 65./10== 6.500000 False
i== 11 26./11== 2.363636 65./11== 5.909091 False
i== 12 26./12== 2.166667 65./12== 5.416667 False
i== 13 26./13== 2.000000 65./13== 5.000000 True
- elif part is active -
- 26/65 returned by if section -
frac == 26/65
---------------------------------------
n == 49 d == 98
float('49'[0]) == 4.000000 float('98'[1]) == 8.000000
i== 2 49./ 2== 24.500000 98./ 2== 49.000000 False
i== 3 49./ 3== 16.333333 98./ 3== 32.666667 False
i== 4 49./ 4== 12.250000 98./ 4== 24.500000 False
i== 5 49./ 5== 9.800000 98./ 5== 19.600000 False
i== 6 49./ 6== 8.166667 98./ 6== 16.333333 False
i== 7 49./ 7== 7.000000 98./ 7== 14.000000 False
i== 8 49./ 8== 6.125000 98./ 8== 12.250000 False
i== 9 49./ 9== 5.444444 98./ 9== 10.888889 False
i== 10 49./10== 4.900000 98./10== 9.800000 False
i== 11 49./11== 4.454545 98./11== 8.909091 False
i== 12 49./12== 4.083333 98./12== 8.166667 False
i== 13 49./13== 3.769231 98./13== 7.538462 False
i== 14 49./14== 3.500000 98./14== 7.000000 False
i== 15 49./15== 3.266667 98./15== 6.533333 False
i== 16 49./16== 3.062500 98./16== 6.125000 False
i== 17 49./17== 2.882353 98./17== 5.764706 False
i== 18 49./18== 2.722222 98./18== 5.444444 False
i== 19 49./19== 2.578947 98./19== 5.157895 False
i== 20 49./20== 2.450000 98./20== 4.900000 False
i== 21 49./21== 2.333333 98./21== 4.666667 False
i== 22 49./22== 2.227273 98./22== 4.454545 False
i== 23 49./23== 2.130435 98./23== 4.260870 False
i== 24 49./24== 2.041667 98./24== 4.083333 False
i== 25 49./25== 1.960000 98./25== 3.920000 False
i== 26 49./26== 1.884615 98./26== 3.769231 False
i== 27 49./27== 1.814815 98./27== 3.629630 False
i== 28 49./28== 1.750000 98./28== 3.500000 False
i== 29 49./29== 1.689655 98./29== 3.379310 False
i== 30 49./30== 1.633333 98./30== 3.266667 False
i== 31 49./31== 1.580645 98./31== 3.161290 False
i== 32 49./32== 1.531250 98./32== 3.062500 False
i== 33 49./33== 1.484848 98./33== 2.969697 False
i== 34 49./34== 1.441176 98./34== 2.882353 False
i== 35 49./35== 1.400000 98./35== 2.800000 False
i== 36 49./36== 1.361111 98./36== 2.722222 False
i== 37 49./37== 1.324324 98./37== 2.648649 False
i== 38 49./38== 1.289474 98./38== 2.578947 False
i== 39 49./39== 1.256410 98./39== 2.512821 False
i== 40 49./40== 1.225000 98./40== 2.450000 False
i== 41 49./41== 1.195122 98./41== 2.390244 False
i== 42 49./42== 1.166667 98./42== 2.333333 False
i== 43 49./43== 1.139535 98./43== 2.279070 False
i== 44 49./44== 1.113636 98./44== 2.227273 False
i== 45 49./45== 1.088889 98./45== 2.177778 False
i== 46 49./46== 1.065217 98./46== 2.130435 False
i== 47 49./47== 1.042553 98./47== 2.085106 False
i== 48 49./48== 1.020833 98./48== 2.041667 False
i== 49 49./49== 1.000000 98./49== 2.000000 False
- elif part is active -
Fraction('4/8') == 1/2
Fraction(49, 98) == 1/2
- 4998 returned by elif section -
frac == 4998
detected :
16/64
19/95
26/65
4998
nums == ['16', '19', '26', '49']
denoms == ['64', '95', '65', '98']
pro,duct == 387296 38729600
Fraction(pro, duct) == 1/100
The elapsed time is 2.45300006866 seconds.
However the difference of formats betrays that the last value is returned by another section (elif section
) than the 3 first values (returned by if section
).
This deserves to be clarified.
The display shows that there is no value of i
for which 49./i
would be 4
and 98./i
would be 8
: that means that there is no reason that n[0]==4
would be a divisor of n==49
and d[1]==8
a divisor of d==98
.
So the origin of the problem isn't the impossibility to represent exactly decimal values with binary representation (leading to difficulties to do comparisons in floating point arithmetic), it was a problem of algorithm.
Only if the test 49./i==1.0 and 98.i==2.00
would be performed, it would lead to the return of the value 49/98
identicaly formated as the 3 first values by the if section
. So I think that the following code has the correct algorithm. But then, neither the elif section
nor the else section
are executed, whatever value is given to ELIF; that only means that the algorithm in the if section
is equivalent to the principle in the elif section
with Fraction
.
def curious(numer,denom,disp=None):
n = str(numer)
d = str(denom)
fracs = []
if n!=d and n[1] == d[0]:
ELIF = 1
fn0 = float(n[0])
fd1 = float(d[1])
GCD = gcd(fn0,fd1)
fn0DD = fn0/GCD
fd1DD = fd1/GCD
if disp:
print ('---------------------------------------\n'
'n == %s d == %s\n'
"float('%s'[0]) == %f float('%s'[1]) == %f"
% ( n,d,n,fn0,d,fd1 ) )
for i in range(2, numer+1):
if disp:
print ('i== %2d '
'%s./%2d==%10f %s./%2d==%10f %s' %
(i,n,i,float(n)/i,d,i,float(d)/i,
float(n)/i==fn0DD and float(d)/i==fd1DD) )
if float(numer)/i==fn0DD and float(denom)/i==fd1DD:
if disp:
print (' %s\n'
' - %s/%s returned by if section -' %
('- elif part is active -' if ELIF
else '- elif part is not active -',
n,d))
return n + "/" + d
if ELIF and d[1] != "0":
if Fraction( n[0] + '/' + d[1] ) \
== \
Fraction(numer, denom):
if disp:
print (' %s\n'
" Fraction('%s/%s') == %s\n"
" Fraction(%s, %s) == %s\n"
' - %s%s returned by elif section -' %
('- elif part is active -' if ELIF
else '- elif part is not active -',
n[0],d[1],Fraction( n[0] + '/' + d[1] ),
numer,denom,Fraction(numer, denom),n,d) )
return n + d
awaited displaying
(skipped lines)
i== 44 49./44== 1.113636 98./44== 2.227273 False
i== 45 49./45== 1.088889 98./45== 2.177778 False
i== 46 49./46== 1.065217 98./46== 2.130435 False
i== 47 49./47== 1.042553 98./47== 2.085106 False
i== 48 49./48== 1.020833 98./48== 2.041667 False
i== 49 49./49== 1.000000 98./49== 2.000000 True
- elif part is active -
- 49/98 returned by if section -
frac == 49/98
detected :
16/64
19/95
26/65
49/98
nums == ['16', '19', '26', '49']
denoms == ['64', '95', '65', '98']
pro,duct == 387296 38729600
Fraction(pro, duct) == 1/100
The elapsed time is 2.39100003242 seconds.
Upvotes: 2
Reputation: 5808
This is an oddly structured answer, as it was written incrementally. I apologize for this. Even so, I think it is worth reading in this order. Each part, separated with a horizontal ruler, says something different.
Equality comparisons in floating point arithmetic are usual sources of trouble and should be avoided. Instead of testing for:
float(numer)/i == float(int(n[0])) and float(denom)/i == float(int(d[1]))
why not the following? Simpler and equivalent (in mathematics, but not in Python!):
numer == i * int(n[0]) and denom == i * int(d[1])
On top of this, not only is floating point arithmetic a source of trouble but translating from int
to float
too often is bad for performance too.
I do not understand why you expect your program to print the same result when you remove the elif
clause. It does two different things, when you have the elif
and when you don't. You're just returning the same result (n/d) so you don't see the difference.
The if
statement is not "being bypassed". But, if it does not return something in the first iteration of the for
loop, then the elif
statement (which does the same thing in every iteration) will have the chance to return its value. Then the if
statement will not be executed again.
As now more information has been supplied concerning the question (this is intended as part of a solution to Euler project's problem #33), I will stick to the original version of the question and try to refactor function curious
, which I believe is poorly written. I believe that the following function is equivalent and much faster, as the for
loop only computes things that depend on i
:
def curious(numer,denom):
n = str(numer)
d = str(denom)
if len(n) == 2 == len(d) and n[1] == d[0] and n != d:
for i in range(2, numer+1):
if numer == i*int(n[0]) and denom == i*int(d[1]):
return n + "/" + d
elif i == 2 and d[1] != "0":
if Fraction(int(n[0]), int(d[1])) == Fraction(numer, denom):
return n + d
With this function, Cawb07's program produces the same output (the four fractions plus 1/100, which is the answer to the problem) much faster.
Now that I understand what curious
is trying to do, let me suggest a much better approach. Let us assume that a brute force solution is to be sought. It can be easily arranged so that curious
is always called with two 2-digit parameters, for which numer < denom
is true, and that it returns a Boolean result, denoting whether the fraction is curious or not. Furthermore, there's no need for a for
loop in curious
, which can be greatly simplified.
import time
from fractions import Fraction
def curious(numer, denom):
n = str(numer)
d = str(denom)
return (n[0] == d[1] != '0' and denom * int(n[1]) == numer * int(d[0])) \
or (n[0] == d[0] != '0' and denom * int(n[1]) == numer * int(d[1])) \
or (n[1] == d[0] != '0' and denom * int(n[0]) == numer * int(d[1])) \
or (n[1] == d[1] != '0' and denom * int(n[0]) == numer * int(d[0]))
start = time.time()
for i in range(10, 100):
for j in range(i+1, 100):
if curious(i, j):
print i, "/", j
elapsed = time.time() - start
print "The elapsed time is", elapsed, "seconds."
This program just prints the four curious fractions, again much faster than the previous one.
Notice also that, for reducing the product of the curious fractions to lowest common terms, you could easily calculate the nominator and denominator and then divide by their GCD, which can be found using Euclid's algorithm.
Cawb07: Can also use fractions.gcd(n,d)
:).
Upvotes: 4