Round a number to a given set of values [duplicate] - python-3.x

This question already has answers here:
From list of integers, get number closest to a given value
(10 answers)
Closed 5 years ago.
Talking Python 3 here.
I'm looking to round a number to a given set of values which can vary
Assume value_set = [x, y, z] and for the sake of the example x, y, z = 1, 3.12, 4 I'm looking for a function that will round a given float to the closest number
custom_round(0) --> 1
custom_round(2.7) --> 3.12
Notice that it should be generic enough that value_set length will vary also

You can use the min function in order to find the minimum in your list when the key is the absolute value of x-n (x is each item in the list).
value_set = [1, 3.12, 4]
def return_closest(n):
return min(value_set, key=lambda x:abs(x-n))
number_to_check = 3
print (return_closest(number_to_check))
>>> 3.12

You can do this by first sorting the list, and then use binary search:
from bisect import bisect_left
class CustomRound:
def __init__(self,iterable):
self.data = sorted(iterable)
def __call__(self,x):
data = self.data
ndata = len(data)
idx = bisect_left(data,x)
if idx <= 0:
return data[0]
elif idx >= ndata:
return data[ndata-1]
x0 = data[idx-1]
x1 = data[idx]
if abs(x-x0) < abs(x-x1):
return x0
return x1
You can than construct your CustomRound like:
values = [1,3.12,4]
custom_round = CustomRound(values)
and simply call it:
>>> custom_round(0)
1
>>> custom_round(0.5)
1
>>> custom_round(1.5)
1
>>> custom_round(2.5)
3.12
>>> custom_round(3.12)
3.12
>>> custom_round(3.9)
4
>>> custom_round(4.1)
4
>>> custom_round(4.99)
4
This approach will work in O(log n) for rounding and O(n log n) for construction. So you will invest some additional time to construct the custom_round, but if you call it often, it will eventually pay off in rounding individual numbers.

Related

How to find minima and maxima of a function. I am limited to using numpy, sympy and matplotlib

I am asked to find the maxima and minima of few functions. One of the functions is y = (9x^3) - (7x^2) + (3x) + 10
The code I could write so far is:
from sympy import*
import matplotlib.pyplot as plt
x = symbols ('x')
f = (9*x**3) - (7*x**2) + (3*x) + 10
intervals = np.arange(-5, 7)
df = diff(f, x)
df2 = diff(f, x, 2)
f = lambdify (x, f)
y = f(intervals)
print (intervals)
print (y)
I am new to using these 3 libraries so I dont know how to find the answer using these 3 libraries
SymPy can tell you the derivative and f and can tell you when a function is zero. Since max/min occur when the derivative is zero you can find the zeros and then determine if those values make the 2nd derivative positive or negative, e.g.
>>> from sympy import real_roots
>>> from sympy.abc import x
>>> f = -x**2 + 1
>>> d1 = f.diff(x)
>>> d2 = d1.diff(x) # = f.diff(x,2)
>>> extrema = real_roots(d1)
>>> for i in extrema:
... if d2.subs(x, i).is_positive:
... print('minimum',i)
... else:
... print('maxima',i)
See also here. (If there are no real roots then there are no extrema for real values of x.)
If you want to pass the values of intervals into the formula and then get the minimum value, you can specify the intervals firstly and then just put this array into the formula instead x:
intervals = np.random.permutation(10)
# [8 4 3 0 2 7 9 1 6 5]
f = (9 * intervals ** 3) - (7 * intervals ** 2) + (3 * intervals) + 10
# [4194 486 199 10 60 2775 6031 15 1720 975]
f.argmin() # --> will get index of the minimum value
# 3
f.min() # --> will get minimum value resulted by the formula
# 10
or if you want to use the formula many times, you can define it as a function and just call it every time you need instead writing it again as:
def formula_1(x):
return (9 * x ** 3) - (7 * x ** 2) + (3 * x) + 10
results = formula_1(intervals)
results.min()

simpson integration on python

I am trying to integrate numerically using simpson integration rule for f(x) = 2x from 0 to 1, but keep getting a large error. The desired output is 1 but, the output from python is 1.334. Can someone help me find a solution to this problem?
thank you.
import numpy as np
def f(x):
return 2*x
def simpson(f,a,b,n):
x = np.linspace(a,b,n)
dx = (b-a)/n
for i in np.arange(1,n):
if i % 2 != 0:
y = 4*f(x)
elif i % 2 == 0:
y = 2*f(x)
return (f(a)+sum(y)+f(x)[-1])*dx/3
a = 0
b = 1
n = 1000
ans = simpson(f,a,b,n)
print(ans)
There is everything wrong. x is an array, everytime you call f(x), you are evaluating the function over the whole array. As n is even and n-1 odd, the y in the last loop is 4*f(x) and from its sum something is computed
Then n is the number of segments. The number of points is n+1. A correct implementation is
def simpson(f,a,b,n):
x = np.linspace(a,b,n+1)
y = f(x)
dx = x[1]-x[0]
return (y[0]+4*sum(y[1::2])+2*sum(y[2:-1:2])+y[-1])*dx/3
simpson(lambda x:2*x, 0, 1, 1000)
which then correctly returns 1.000. You might want to add a test if n is even, and increase it by one if that is not the case.
If you really want to keep the loop, you need to actually accumulate the sum inside the loop.
def simpson(f,a,b,n):
dx = (b-a)/n;
res = 0;
for i in range(1,n): res += f(a+i*dx)*(2 if i%2==0 else 4);
return (f(a)+f(b) + res)*dx/3;
simpson(lambda x:2*x, 0, 1, 1000)
But loops are generally slower than vectorized operations, so if you use numpy, use vectorized operations. Or just use directly scipy.integrate.simps.

Finding a Dot Product without using np.dot or loops in Python

I need to write a function which:
Receives - two numpy.array objects
Returns - the floating-point dot product of the two input
numpy arrays
Not allowed to use:
numpy.dot()
loops of any kind
Any suggestions?
A possible solution makes use of recursion
import numpy as np
def multiplier (first_vector, second_vector, size, index, total):
if index < size:
addendum = first_vector[index]*second_vector[index]
total = total + addendum
index = index + 1
# ongoing job
if index < size:
multiplier(first_vector, second_vector, size, index, total)
# job done
else:
print("dot product = " + str(total))
def main():
a = np.array([1.5, 2, 3.7])
b = np.array([3, 4.3, 5])
print(a, b)
i = 0
total_sum = 0
# check needed if the arrays are not hardcoded
if a.size == b.size:
multiplier(a, b, a.size, i, total_sum)
else:
print("impossible dot product for arrays with different size")
if __name__== "__main__":
main()
Probably considered cheating, but Python 3.5 added a matrix multiply operator that numpy uses to compute the dot product without actually calling np.dot:
>>> arr1 = np.array([1,2,3])
>>> arr2 = np.array([3,4,5])
>>> arr1 # arr2
26
Problem solved!

What is the complexity for the following python code?

import math
# for loop includes k/2 (ie. if k/2 = 3.5, then i will go from [1, 3]. 1,2, and 3
def pow(x,k):
y =1
m = math.trunc(k/2)
if k == 0:
return 1
for i in range(1,m+1):
y = y * x
if(k%2 == 0):
return y * y
else:
return y*y*x
I think it uses O(1) memory and O(log k) steps. Is it correct?
The memory complexity is correct thus O(1).
The runtime complexity should be O(k). Each line is done in constant time except the for loop. You iterate in your for loop at most k/2 times. This means that the number of iteration will be linear in k. Note that O(k/2) = O(k).
Also you could see that the complexity of log(k) does not work. If k = 16, your loop will iterate 8 times and by taking the log (base 2) we would only obtain 4 times.

How to sort 4 integers using only min() and max()? Python

I am trying to sort 4 integers input by the user into numerical order using only the min() and max() functions in python. I can get the highest and lowest number easily, but cannot work out a combination to order the two middle numbers? Does anyone have an idea?
So I'm guessing your input is something like this?
string = input('Type your numbers, separated by a space')
Then I'd do:
numbers = [int(i) for i in string.strip().split(' ')]
amount_of_numbers = len(numbers)
sorted = []
for i in range(amount_of_numbers):
x = max(numbers)
numbers.remove(x)
sorted.append(x)
print(sorted)
This will sort them using max, but min can also be used.
If you didn't have to use min and max:
string = input('Type your numbers, separated by a space')
numbers = [int(i) for i in string.strip().split(' ')]
numbers.sort() #an optional reverse argument possible
print(numbers)
LITERALLY just min and max? Odd, but, why not. I'm about to crash, but I think the following would work:
# Easy
arr[0] = max(a,b,c,d)
# Take the smallest element from each pair.
#
# You will never take the largest element from the set, but since one of the
# pairs will be (largest, second_largest) you will at some point take the
# second largest. Take the maximum value of the selected items - which
# will be the maximum of the items ignoring the largest value.
arr[1] = max(min(a,b)
min(a,c)
min(a,d)
min(b,c)
min(b,d)
min(c,d))
# Similar logic, but reversed, to take the smallest of the largest of each
# pair - again omitting the smallest number, then taking the smallest.
arr[2] = min(max(a,b)
max(a,c)
max(a,d)
max(b,c)
max(b,d)
max(c,d))
# Easy
arr[3] = min(a,b,c,d)
For Tankerbuzz's result for the following:
first_integer = 9
second_integer = 19
third_integer = 1
fourth_integer = 15
I get 1, 15, 9, 19 as the ascending values.
The following is one of the forms that gives symbolic form of the ascending values (using i1-i4 instead of first_integer, etc...):
Min(i1, i2, i3, i4)
Max(Min(i4, Max(Min(i1, i2), Min(i3, Max(i1, i2))), Max(i1, i2, i3)), Min(i1, i2, i3, Max(i1, i2)))
Max(Min(i1, i2), Min(i3, Max(i1, i2)), Min(i4, Max(i1, i2, i3)))
Max(i1, i2, i3, i4)
It was generated by a 'bubble sort' using the Min and Max functions of SymPy (a python CAS):
def minmaxsort(v):
"""return a sorted list of the elements in v using the
Min and Max functions.
Examples
========
>>> minmaxsort(3, 2, 1)
[1, 2, 3]
>>> minmaxsort(1, x, y)
[Min(1, x, y), Max(Min(1, x), Min(y, Max(1, x))), Max(1, x, y)]
>>> minmaxsort(1, y, x)
[Min(1, x, y), Max(Min(1, y), Min(x, Max(1, y))), Max(1, x, y)]
"""
from sympy import Min, Max
v = list(v)
v0 = Min(*v)
for j in range(len(v)):
for i in range(len(v) - j - 1):
w = v[i:i + 2]
v[i:i + 2] = [Min(*w), Max(*w)]
v[0] = v0
return v
I have worked it out.
min_integer = min(first_integer, second_integer, third_integer, fourth_integer)
mid_low_integer = min(max(first_integer, second_integer), max(third_integer, fourth_integer))
mid_high_integer = max(min(first_integer, second_integer), min(third_integer, fourth_integer))
max_integer = max(first_integer, second_integer, third_integer, fourth_integer)

Resources