Python Finding the median function error - python

Could anyone please explain to me why this is not working? The error message I'm getting is: TypeError: list indices must be integers or slices, not float.
def median(lst):
s = sorted(lst)
l = len(lst)/2
if len(lst) % 2 == 0:
print((s[l] + s[l-1])/2.0)
else:
print(s[l])
median([3,3,5,6,7,8,1])

error you made is in calculating l
dividing using operator / returns actual division i.e. a floating point value while // returns only quotient i.e. an integer
hence
you should calculate l as follows
l = len(lst) // 2
or convert l to int using
l = int(l)

If len(lst) is odd then l becomes a float.
Interestingly the code you've written is probably valid in Python 2 as it uses integer division if both the numerator and denominator are integers.
However in Python 3 true division is used by default.
For more information see: In Python 2, what is the difference between '/' and '//' when used for division? and https://docs.python.org/whatsnew/2.2.html#pep-238-changing-the-division-operator

Related

A typeerror I face when writing a Python program in order to solve a maths problem

I've been trying to solve this:
Find positive integer solutions for a,b,c that 1≤a<b<c≤30 and b/a+c/b+a/c is a positive integer.
So I worte this, in python:
for i,j,m in range(1,31):
if i<=j and j<=m and j/i+m/j+i/m>=0:
try:
print(int(j/i+m/j+i/m))
except TypeError:
continue
However it didn't work.
And the error message:
for i,j,m in range(1,31):
TypeError: cannot unpack non-iterable int object
Iterating over a triplet
range returns an iterable over single integers. To iterate over triplets, you can either nest three loops, or use itertools:
# using nested loops
for a in range(1, 29):
for b in range(a+1, 30):
for c in range(b+1, 31):
...
# using itertools
from itertools import combinations
for a,b,c in combinations(range(1,31), 3):
...
Note that in both cases, I wrote the loops to iterate directly over triplets (a,b,c) satisfying a < b < c. This is much more efficient than iterating over all triplets (a,b,c), then filtering for the condition a < b < c.
Testing whether b/a+c/b+a/c is an integer
When dealing with fractions with different denominators, the first thing to do is usually to put everything to a common denominator. In this case, the sum of three fractions b/a+c/b+a/c is equal to fraction (b*b*c + c*a*c + a*a*b) / (a*b*c). Testing whether this fraction is an integer or not is exactly testing whether its numerator is divisible by its denominator. This can be easily achieved with the modulo operator %.
if (b*b*c + c*a*c + a*a*b) % (a*b*c) == 0:
...
This is actually better than using floating-point division and testing if the result looks like an integer. Floating-point division results in a binary floating-point number. Not all numbers can be represented exactly in binary floating-point: just like fraction 1/3 cannot be represented exactly in decimal, many numbers cannot be represented exactly in binary. Imagine testing whether 1/3 + 1/3 + 1/3 is an integer: if 1/3 is rounded to 0.333, then we'll get 0.333 + 0.333 + 0.333 == 0.999, which is not an integer. This is an approximation error. If possible, when dealing with integer arithmetic, always use only integers, and never use floating-point division. Protect yourself from floating-point approximations!
Separating algorithm logic from input/output
It is very good practice to separate the parts of code that deal with algorithms and arithmetic, on the one side, from parts of code that deal with printing to screen, reading from and writing to files, etc.
You could append all the found triplets to a list, then return the list:
def get_triplet_list(n):
l = []
for a,b,c in combinations(range(1, n+1), 3):
if (b*b*c + c*a*c + a*a*b) % (a*b*c) == 0:
l.append((a,b,c))
return l
def main():
l = get_triplet_list(30)
for a,b,c in l:
print(a,b,c)
if __name__ == '__main__':
main()
# 2 9 12
# 3 4 18
# 4 18 24
Or use a list comprehension:
def get_triplet_list(n):
return [(a,b,c) for a,b,c in combinations(range(1, n+1), 3) if (b*b*c + c*a*c + a*a*b) % (a*b*c) == 0]
def main():
l = get_triplet_list(30)
for a,b,c in l:
print(a,b,c)
if __name__ == '__main__':
main()
Or use a generator function, with keyword yield instead of return:
def gen_triplets(n):
for a,b,c in combinations(range(1, n+1), 3):
if (b*b*c + c*a*c + a*a*b) % (a*b*c) == 0:
yield (a,b,c)
def main():
for a,b,c in gen_triplets(30):
print(a,b,c)
if __name__ == '__main__':
main()
You want to assign 3 variables, range() only returns a single "list" of values.
I'm not exactly sure what you are trying to do but I suspect you want to try every combination of values for i, j and m. One way to do this is creating nested loops. Each loop will iterate over the values for one variable.
Another solution would be using itertools and create a list of all combinations which will processed by your function (which would need some little adjustments).

Power digit sum

I am trying to solve this excercise:
https://projecteuler.net/problem=16
The code is pretty self-explanatory: I calculate 2^n in power(n), and in sum(n), I cut off the last digit of the number. I do this as long as pow > 0. I receive the right solution for 2^15, but for one reason or another, the same code doesn't work for 2^1000. I receive 1889, which is apparently wrong.
def power(n):
power = 2
for x in range(1, n):
power = 2*power
return power
def sum(n):
pow = power(n)
sum = 0
while pow > 0:
modulo = pow%10
sum = sum + modulo
pow = int((pow - modulo)/10)
return sum
def main():
print(int(sum(1000)))
if __name__ == '__main__':
main()
A simple change in your code will give you the correct answer,
def power(n):
power = 2
for x in range(1, n):
power = 2*power
return power
def sum(n):
pow = power(n)
sum = 0
while pow > 0:
modulo = pow%10
sum = sum + modulo
pow = pow//10 # modified line
return sum
def main():
print(int(sum(1000)))
if __name__ == '__main__':
main()
The reason why your example doesn't work is because you are casting the result of a float operation to int. Floats are never precise and when they are very large, they loose precision. Hence if you convert them back to integer, you get a much lower value.
A better function using divmod() is,
def sum(n):
pow = power(n)
sum = 0
while pow > 0:
pow,modulo = divmod(pow,10)
sum = sum + modulo
return sum
Your original solution would have worked in Python 2 because Python 2 and Python 3 handle division differently.
For example print(1/2) gives 0 in Python2, and 0.5 in Python3. In Python3, we use // for floor division (which is what you want here).
Your code doesn't work for any number >= 57
The problem here is very easy to solve.
In python 3 and higher, / is a division that returns a float, while // is an integer division that always returns an integer. Since you are using float division, you are encountering the issues with floating point arithmetic.
More about the issues and limitations.
To solve your problem, change the line
pow = int(pow - modulo)/10
into
pow = int(pow - modulo)//10
or even better, you can just say pow//=10
Isn't python beatiful?
def Power_digit_sum(n):
number = list(str(2**n)) # pow number and convert number in string and list
result= [int(i) for i in number]# convert number in int and
return sum(result) # sum list
print(Power_digit_sum(15)) # result 26
print(Power_digit_sum(1000)) # result 1366

How to change solution? (codecademy, median, python3.4)

I use python 3.4 for coding. Codecademy editor doesn't accept my solution. Task is to write a function to find the median of a list.
My code:
def median(nums):
a = sorted(nums)
if len(a)==1:
return a[0]
elif len(a) % 2 != 0:
return a[int((len(a) - 1)/2)]
else:
return (a[int((len(a))/2)] + a[int(((len(a))/2) - 1)])/2
So, how to change my code that it will be accepted?
From the information that you have provided so far, I believe it is probably a problem of integer division. In the case when there are an even number of elements in the list, you have to take the average. In python3.4, / does float division but in python2, it does integer division. So you should modifying your line to the following (2.0 instead of 2):
return (a[int((len(a))/2)] + a[int(((len(a))/2) - 1)]) / 2.0
This will force python to do float division instead of integer division

Python Shorthand Operator?

I was researching some information on the topic of trial division, and I came across this symbol in Python:
//=
I got this from here where the code in the example says:
n //= p
I can't tell what this is supposed to mean, and my research continues to bring poor results in terms of webpages.
// is integer division and the
n //= p
syntax is short for
n = n // p
except the value n is modified directly if it supports this.
When you see an operator followed by an =, that is performing the operation and then assigning it into the variable. For example, x += 2 means x = x + 2 or add 2 to x.
The // operator specifically does integer devision instead of floating point division. For example, 5 // 4 gives you 1, while 5 / 4 gives you 1.25 (in Python 3).
Therefore, x //= 3 means divide x by 3 (in an integer division fashion), and store the value back into x. It is equivalent to x = x // 3
// is the floor division operator, therefore //= is simply the inplace floor division operator.

Checking if float is equivalent to an integer value in python

In Python 3, I am checking whether a given value is triangular, that is, it can be represented as n * (n + 1) / 2 for some positive integer n.
Can I just write:
import math
def is_triangular1(x):
num = (1 / 2) * (math.sqrt(8 * x + 1) - 1)
return int(num) == num
Or do I need to do check within a tolerance instead?
epsilon = 0.000000000001
def is_triangular2(x):
num = (1 / 2) * (math.sqrt(8 * x + 1) - 1)
return abs(int(num) - num) < epsilon
I checked that both of the functions return same results for x up to 1,000,000. But I am not sure if generally speaking int(x) == x will always correctly determine whether a number is integer, because of the cases when for example 5 is represented as 4.99999999999997 etc.
As far as I know, the second way is the correct one if I do it in C, but I am not sure about Python 3.
There is is_integer function in python float type:
>>> float(1.0).is_integer()
True
>>> float(1.001).is_integer()
False
>>>
Both your implementations have problems. It actually can happen that you end up with something like 4.999999999999997, so using int() is not an option.
I'd go for a completely different approach: First assume that your number is triangular, and compute what n would be in that case. In that first step, you can round generously, since it's only necessary to get the result right if the number actually is triangular. Next, compute n * (n + 1) / 2 for this n, and compare the result to x. Now, you are comparing two integers, so there are no inaccuracies left.
The computation of n can be simplified by expanding
(1/2) * (math.sqrt(8*x+1)-1) = math.sqrt(2 * x + 0.25) - 0.5
and utilizing that
round(y - 0.5) = int(y)
for positive y.
def is_triangular(x):
n = int(math.sqrt(2 * x))
return x == n * (n + 1) / 2
You'll want to do the latter. In Programming in Python 3 the following example is given as the most accurate way to compare
def equal_float(a, b):
#return abs(a - b) <= sys.float_info.epsilon
return abs(a - b) <= chosen_value #see edit below for more info
Also, since epsilon is the "smallest difference the machine can distinguish between two floating-point numbers", you'll want to use <= in your function.
Edit: After reading the comments below I have looked back at the book and it specifically says "Here is a simple function for comparing floats for equality to the limit of the machines accuracy". I believe this was just an example for comparing floats to extreme precision but the fact that error is introduced with many float calculations this should rarely if ever be used. I characterized it as the "most accurate" way to compare in my answer, which in some sense is true, but rarely what is intended when comparing floats or integers to floats. Choosing a value (ex: 0.00000000001) based on the "problem domain" of the function instead of using sys.float_info.epsilon is the correct approach.
Thanks to S.Lott and Sven Marnach for their corrections, and I apologize if I led anyone down the wrong path.
Python does have a Decimal class (in the decimal module), which you could use to avoid the imprecision of floats.
floats can exactly represent all integers in their range - floating-point equality is only tricky if you care about the bit after the point. So, as long as all of the calculations in your formula return whole numbers for the cases you're interested in, int(num) == num is perfectly safe.
So, we need to prove that for any triangular number, every piece of maths you do can be done with integer arithmetic (and anything coming out as a non-integer must imply that x is not triangular):
To start with, we can assume that x must be an integer - this is required in the definition of 'triangular number'.
This being the case, 8*x + 1 will also be an integer, since the integers are closed under + and * .
math.sqrt() returns float; but if x is triangular, then the square root will be a whole number - ie, again exactly represented.
So, for all x that should return true in your functions, int(num) == num will be true, and so your istriangular1 will always work. The only sticking point, as mentioned in the comments to the question, is that Python 2 by default does integer division in the same way as C - int/int => int, truncating if the result can't be represented exactly as an int. So, 1/2 == 0. This is fixed in Python 3, or by having the line
from __future__ import division
near the top of your code.
I think the module decimal is what you need
You can round your number to e.g. 14 decimal places or less:
>>> round(4.999999999999997, 14)
5.0
PS: double precision is about 15 decimal places
It is hard to argue with standards.
In C99 and POSIX, the standard for rounding a float to an int is defined by nearbyint() The important concept is the direction of rounding and the locale specific rounding convention.
Assuming the convention is common rounding, this is the same as the C99 convention in Python:
#!/usr/bin/python
import math
infinity = math.ldexp(1.0, 1023) * 2
def nearbyint(x):
"""returns the nearest int as the C99 standard would"""
# handle NaN
if x!=x:
return x
if x >= infinity:
return infinity
if x <= -infinity:
return -infinity
if x==0.0:
return x
return math.floor(x + 0.5)
If you want more control over rounding, consider using the Decimal module and choose the rounding convention you wish to employ. You may want to use Banker's Rounding for example.
Once you have decided on the convention, round to an int and compare to the other int.
Consider using NumPy, they take care of everything under the hood.
import numpy as np
result_bool = np.isclose(float1, float2)
Python has unlimited integer precision, but only 53 bits of float precision. When you square a number, you double the number of bits it requires. This means that the ULP of the original number is (approximately) twice the ULP of the square root.
You start running into issues with numbers around 50 bits or so, because the difference between the fractional representation of an irrational root and the nearest integer can be smaller than the ULP. Even in this case, checking if you are within tolerance will do more harm than good (by increasing the number of false positives).
For example:
>>> x = (1 << 26) - 1
>>> (math.sqrt(x**2)).is_integer()
True
>>> (math.sqrt(x**2 + 1)).is_integer()
False
>>> (math.sqrt(x**2 - 1)).is_integer()
False
>>> y = (1 << 27) - 1
>>> (math.sqrt(y**2)).is_integer()
True
>>> (math.sqrt(y**2 + 1)).is_integer()
True
>>> (math.sqrt(y**2 - 1)).is_integer()
True
>>> (math.sqrt(y**2 + 2)).is_integer()
False
>>> (math.sqrt(y**2 - 2)).is_integer()
True
>>> (math.sqrt(y**2 - 3)).is_integer()
False
You can therefore rework the formulation of your problem slightly. If an integer x is a triangular number, there exists an integer n such that x = n * (n + 1) // 2. The resulting quadratic is n**2 + n - 2 * x = 0. All you need to know is if the discriminant 1 + 8 * x is a perfect square. You can compute the integer square root of an integer using math.isqrt starting with python 3.8. Prior to that, you could use one of the algorithms from Wikipedia, implemented on SO here.
You can therefore stay entirely in python's infinite-precision integer domain with the following one-liner:
def is_triangular(x):
return math.isqrt(k := 8 * x + 1)**2 == k
Now you can do something like this:
>>> x = 58686775177009424410876674976531835606028390913650409380075
>>> math.isqrt(k := 8 * x + 1)**2 == k
True
>>> math.isqrt(k := 8 * (x + 1) + 1)**2 == k
False
>>> math.sqrt(k := 8 * x + 1)**2 == k
False
The first result is correct: x in this example is a triangular number computed with n = 342598234604352345342958762349.
Python still uses the same floating point representation and operations C does, so the second one is the correct way.
Under the hood, Python's float type is a C double.
The most robust way would be to get the nearest integer to num, then test if that integers satisfies the property you're after:
import math
def is_triangular1(x):
num = (1/2) * (math.sqrt(8*x+1)-1 )
inum = int(round(num))
return inum*(inum+1) == 2*x # This line uses only integer arithmetic

Categories

Resources