Round up to certain number - python

Lets say I have a list of numbers: [0.13,0.53,2.83]
I want these numbers to round UP to the nearest x=0.5 (or any other value for x)
This list would then become, given x=0.5: [0.5,1,3].
I tried somethings with % but neither of what I tried seemed to work.
Any ideas?
Harry
EDIT: the other posts want to know the nearest value, so 1.6 would become 1.5, but in my case it should become 2

You need math.ceil:
import math
numbers = [0.13, 0.53, 2.83]
x = 0.5
def roundup(numbers, x):
return [math.ceil(number / x) * x for number in numbers]
roundup(numbers, x)
# returns [0.5, 1.0, 3.0]

If a function suits your need then the function bellow works for positive numbers. "x" is the number you want to round and thresh is the value (between 0 and 1) used to round up.
def rounding_function(x, thresh):
if x == int(x):
return x
else:
float_part = x-int(x)
if float_part<=thresh:
return int(x) + thresh
else:
return int(x) + 1
Which gives the following result:
l = [0, 0.13,0.53, 0.61, 2.83, 3]
print([rounding_function(x, 0.5) for x in l]) # [0, 0.5, 1, 1, 3, 3]
print([rounding_function(x, 0.6) for x in l]) # [0, 0.6, 0.6, 1, 3, 3]

Here's a general solution. (Don't forget to handle all the "weird input"; e.g. negative incr, negative x, etc.)
import math
def increment_ceil(x, incr=1):
"""
return the smallest float greater than or equal to x
that is divisible by incr
"""
if incr == 0:
return float(x)
else:
return float(math.ceil(x / incr) * incr)

Related

How to represent values float in 2 float point in python?

I need to calculate values of type float, so, in python, 0.01 is not 0.01 but 0.10000000000000001 + some digits (referenced by python documentation Floating).
Ok, my function needs to calculate the number of coins for each value.
def calcula_moedas(resto):
moedas = [0.5, 0.1, 0.05, 0.01]
cont_moeda = {'0.5': 0, '0.1': 0, '0.05': 0, '0.01': 0}
if resto > 0.00:
for valor in moedas:
while resto >= valor:
str_valor = str(valor)
cont_moeda[str_valor] += 1
resto = round(resto, 2) - valor
break
return cont_moeda
return cont_moeda
I tried to use round(resto, 2), round(resto, 10) and Decimal(resto), but the result is wrong yet.
Using resto = round(resto, 2) - valor the result is 0.04999999999999999 when I pass a values 0.15.
Using Decimal the result is:
Image for Decimal module
How can I around this number so that the rounded number is 0.05?
you can use:
resto = round(resto - valor, 2)

calculate the mid points of a vector using Python

I started to learn python from scratch. I got some issues while doing the following problem.
I have the following vector ,x_vector = (0,1,2,3,4,5,6,7,8,9). Using this vector, I need to create this new vector x1 = (-0.5,0.5,1.5,2.5,3.5,4.5,5.5,6.5,7.5,8.5,9.5).
Basically the desired vector should have first element -0.5, mid points between each elements and the last element +0.5.
The code I tried so far as follows:
import numpy as np
x_vector=np.array([0,1,2,3,4,5,6,7,8,9])
x=len(x_vector)
mid=np.zeros(x+1)
for i in range (0,x):
if i==0 :
mid[i]= x_vector[i]-0.5
else :
mid[i]=(x_vector[i] + x_vector[i+1])/2
i +=1
Seems like this doesn't give the desired output. Can you one help me to figure out what can I do to get correct output?
Using itertools.pairwise:
from itertools import tee
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = tee(iterable)
next(b, None)
return zip(a, b)
res = []
res.append(min(x_vector)-0.5)
res.append(max(x_vector)+0.5)
res.extend([np.mean(z) for z in pairwise(x_vector)])
sorted(res)
Output:
[-0.5, 0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5]
Consider, what will happen for i = 0 and i = 1 in your loop:
mid[0] = x_vector[0] - 0.5 # = -0.5
mid[1] = (x_vector[1] + x_vector[2]) / 2 # (1 + 2) / 2 = 3 / 2 = 1 (or 1.5 if python3)
you mismatched indexes.
Try this:
for i in range (0,x):
if i == 0:
mid[i] = x_vector[i]-0.5
else :
mid[i] = (x_vector[i - 1] + x_vector[i]) / 2.0
Note, that i changed division to divide by 2.0 instead of 2 - this will make sure, that division result will be double (number with fraction) instead of integer (number without fraction, in python 2 division two integers will round to integer).
Also i += 1 is redundant, i variable in for loop will updated (overwriting your += 1 statement) every loop iteration.
It is not clear whether this is a homework, but given that you are using numpy I think it is fair game to use it as its whole potential, in this case you can just do:
import numpy as np
x_vector=np.array([0,1,2,3,4,5,6,7,8,9])
a = np.insert(x, 0, x[0] - 1)
b = np.append(x, x[-1] + 1)
mid = (a + b) / 2

Split a Decimal number into a random array where the sum of the numbers equals the split number

I want to split a decimal number into a random table where the sum of the elements in the array equals the original number
# Call a function which receives a decimal number
from decimal import Decimal
from something import split_random_decimal
split_decimal = split_random_decimal(Decimal('10.00'))
print(split_decimal)
# Output: [1.3, 0.7, 1.2, 0.8, 1.0, 1.5, 0.5, 1.9, 0.1, 1.0]
print(sum(split_decimal))
# Output: Decimal('10.00') - The original decimal value
Has anyone an idea how I could do this in pure Python without using a library?
Solved!
Thks for all who have help me, the final beautiful code who saved my life is this:
import random
def random_by_number(number, min_random, max_random, spaces=1, precision=2):
if spaces <= 0:
return number
random_numbers = [random.uniform(min_random, max_random) for i in range(0, spaces)]
increment_number = (number - sum(random_numbers)) / spaces
return [round(n + increment_number, precision) for n in random_numbers]
number = 2500.50
spaces = 30
max_random = number / spaces
min_random = max_random * 0.6
random_numbers = random_by_number(number, min_random, max_random, spaces=spaces, precision=2)
print(random_numbers)
print(len(random_numbers))
print(sum(random_numbers))
You could start with something like:
numberLeft = 10.0
decList = list()
while numberLeft > 0:
cur = random.uniform(0, numberLeft)
decList.append(cur)
numberLeft -= cur
This implementation would choose higher random numbers at first which wouldn't be that hard to logically change.
numberLeft will never hit exactly 0 so you could do something with rounding. You could also wait for numberLeft to get low enough and that would be your last random number in the list.
The problem is a little under defined: into how many pieces should it be split and how large may any piece be? Should the values only be positive? An approximate solution from what you've said would be to pick a random number of pieces (defaulting to 10) and making the values be distributed normally about the average size of the pieces with a standard deviation of 1/10 of the average:
from decimal import Decimal
def split_random_decimal(x, n=10):
assert n > 0
if n == 1:
return [x]
from random import gauss
mu = float(x)/n
s = mu/10
if '.' in str(x):
p = len(str(x)) - str(x).find('.') - 1
else:
p = 0
rv = [Decimal(str(round(gauss(mu, s), p))) for i in range(n-1)]
rv.append(x - sum(rv))
return rv
>>> splited_decimal = split_random_decimal(Decimal('10.00'))
>>> print(splited_decimal)
[Decimal('0.84'), Decimal('1.08'), Decimal('0.85'), Decimal('1.04'),
Decimal('0.96'), Decimal('1.2'), Decimal('0.9'), Decimal('1.09'),
Decimal('1.08'), Decimal('0.96')]
I think this is what you're looking for:
import random as r
def random_sum_to(n, num_terms = None):
n = n*100
num_terms = (num_terms or r.randint(2, n)) - 1
a = r.sample(range(1, n), num_terms) + [0, n]
list.sort(a)
return [(a[i+1] - a[i])/100.00 for i in range(len(a) - 1)]
print(random_sum_to(20, 3)) # [8.11, 3.21, 8.68] example
print(random_sum_to(20, 5)) # [5.21, 7.57, 0.43, 3.83, 2.96] example
print(random_sum_to(20)) # [1 ,2 ,1 ,4, 4, 2, 2, 1, 3] example
n is the number in which you are summing to, and num_terms is the length of the string you would like as a result. Also if you look at the last example you can see that if you don't want to specify a "num_terms" you don't have to and it will do that for you!

Recursion function - Python

This is the problem:
Write a recursive function f that generates the sequence 0, 1, 0.5, 0.75, 0.625, 0.6875, 0.65625, 0.671875, 0.6640625, 0.66796875. The first two terms are 0 and 1, every other term is the average of the two previous.
>>> f(0)
0
>>> f(1)
1
>>> f(2)
0.5
>>> [(i,f(i)) for i in range(10)]
[(0, 0), (1, 1), (2, 0.5), (3, 0.75), (4, 0.625), (5, 0.6875), (6, 0.65625), (7, 0.671875), (8, 0.6640625), (9, 0.66796875)]
This is my code so far, I can't seem to figure it out. Any help/suggestions would be appreciated.
def f(n):
if n==0:
return 0
if n==1:
return 1
else:
return f(n-2)//f(n-1)
The recursive case is wrong:
return f(n-2)//f(n-1) # not the formula for the average of two numbers
The average of two numbers a and b is (a+b)/2. So you can define your function as:
def f(n):
if n==0:
return 0
if n==1:
return 1
else:
return (f(n-1)+f(n-2))/2
Or we can make it Python version-independent like:
def f(n):
if n==0:
return 0
if n==1:
return 1
else:
return 0.5*(f(n-1)+f(n-2))
You can then generate the sequence with list comprehension like:
>>> [f(i) for i in range(10)]
[0, 1, 0.5, 0.75, 0.625, 0.6875, 0.65625, 0.671875, 0.6640625, 0.66796875]
or by using a map:
>>> list(map(f,range(10)))
[0, 1, 0.5, 0.75, 0.625, 0.6875, 0.65625, 0.671875, 0.6640625, 0.66796875]
So you have U0 = 0, U1 = 1, and Un = (U(n-1) + U(n-2)) / 2 for n > 1.
You just have to literally translate this as a function:
def f(n):
if n == 0:
return 0
elif n == 1:
return 1
else:
return (f(n-1) + f(n-2)) / 2
Now for generating the sequence of the Ui from 0 to n:
def generate_sequence(n):
return [f(i) for i in range(n)]
This could (and really should) be optimized with memoization. Basically, you just have to store the previously computed results in a dictionary (while you could directly use a list instead in this case).
results = dict()
def memoized_f(n):
if n in results:
return results[n]
else:
results[n] = f(n)
return results[n]
This way, f(n) will be computed only once for each n.
As a bonus, when memoized_f(n) is called, the results dictionary holds the values of f(i) from 0 to at least n.
Recursion à la auxiliary function
You can define this using a simple auxiliary procedure and a couple state variables – the following f implementation evolves a linear iterative process
def f (n):
def aux (n, a, b):
if n == 0:
return a
else:
return aux (n - 1, b, 0.5 * (a + b))
return aux(n, 0, 1)
print([f(x) for x in range(10)])
# [0, 1, 0.5, 0.75, 0.625, 0.6875, 0.65625, 0.671875, 0.6640625, 0.66796875]
Going generic
Or you can genericize the entire process in what I'll call fibx
from functools import reduce
def fibx (op, seed, n):
[x,*xs] = seed
if n == 0:
return x
else:
return fibx(op, xs + [reduce(op, xs, x)], n - 1)
Now we could implement (eg) fib using fibx
from operator import add
def fib (n):
return fibx (add, [0,1], n)
print([fib(x) for x in range(10)])
# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
Or we can implement your f using fibx and a custom operator
def f (n):
return fibx (lambda a,b: 0.5 * (a + b), [0, 1], n)
print([f(x) for x in range(10)])
# [0, 1, 0.5, 0.75, 0.625, 0.6875, 0.65625, 0.671875, 0.6640625, 0.66796875]
Wasted computations
Some answers here are recursing with (eg) 0.5 * (f(n-1) + f(n-2)) which duplicates heaps of work. n values around 40 take astronomically longer (minutes compared to milliseconds) to compute than the methods I've described here.
Look at the tree recursion fib(5) in this example: see how fib(3) and fib(2) are repeated several times? This is owed to a naïve implementation of the fib program. In this particular case, we can easily avoid this duplicated work using the auxiliary looping function (as demonstrated in my answer) or using memoisation (described in another answer)
Tree recursion like this results in O(n2), whereas linear iterative recursion in my answer is O(n)
Generating a sequence for n
Another answer provided by #MadPhysicist generates a sequence for a single n input value – ie, f(9) will generate a list of the first 10 values. However, the implementation is simultaneously complex and naïve and wastes heaps of computations due to the same f(n-1), andf(n-2)` calls.
A tiny variation on our initial approach can generate the same sequence in a fraction of the time – f(40) using my code will take a fraction of a second whereas these bad tree recursion answers would take upwards of 2 minutes
(Changes in bold)
def f (n):
def aux (n, acc, a, b):
if n == 0:
return acc + [a]
else:
return aux (n - 1, acc + [a], b, 0.5 * (a + b))
return aux(n, [], 0, 1)
print(f(9))
# [0, 1, 0.5, 0.75, 0.625, 0.6875, 0.65625, 0.671875, 0.6640625, 0.66796875]
If you want a function that generates your sequence in a single call, without having to call the function for each element of the list, you can store the values you compute as you unwind the stack:
def f(n, _sequence=None):
if _sequence is None:
_sequence = [0] * (n + 1)
if n == 0 or n == 1:
val = n
else:
f(n - 1, _sequence)
f(n - 2, _sequence)
val = 0.5 * (_sequence[n - 1] + _sequence[n - 2])
_sequence[n] = val
return _sequence
This has the advantage of not requiring multiple recursions over the same values as you would end up doing with [f(n) for n in range(...)] if f returned a single value.
You can use a more global form of memoization as suggested by #RightLeg to record the knowledge between multiple calls.
Unlike the other solutions, this function will actually generate the complete sequence as it goes. E.g., your original example would be:
>>> f(9)
[0, 1, 0.5, 0.75, 0.625, 0.6875, 0.65625, 0.671875, 0.6640625, 0.66796875]
Another simple solution might look like this:
a=0.0
b=1.0
count = 0
def f(newavg, second, count):
avg = (second+newavg)/2
print avg
count=count+1
if count<8:
newavg = avg
f(second, avg, count)
f(a, b, count)
Granted this code just outputs to the monitor...if you want the output into a list just add the code in the recursion.
Also be careful to properly indent where required.

Function "Interval_point"

I have a task for my pyton101 course at uni which is as follows:
Create a function interval_point(a, b, x) that takes three numbers and interprets a and b as the start and end point of an interval, and x as a fraction between 0 and 1 that determines how far to go towards b, starting at a.
Examples (IPython):
In [ ]: interval_point(100, 200, 0.5)
Out[ ]: 150.0
In [ ]: interval_point(100, 200, 0.2)
Out[ ]: 120.0
I came up with this:
def interval_point(a, b, x):
"""takes three numbers and interprets a and b as the start and end point
of an interval, and x as a fraction between 0 and 1 that determines how
far to go towards b, starting at a"""
if (a == b):
return a
if (x == 0):
return a
if (x > 0):
return((abs(a - b) + a) * x)
It worked for most of the tests that the automated test system looks for but it could't deal with a or b being a negative value.
Can someone suggest how I could make a function that does negative numbers as well as being able to handle if a is negative and b is positve.
Here was the report from the automated test system:
Test failure report
test_interval_point
def test_interval_point():
#if x=0, we expect to get value a back
assert s.interval_point(1.0, 2.0, 0.0) == 1.0
#if x=1, we expect to get value b back
assert s.interval_point(1.0, 2.0, 1.0) == 2.0
#test half-way, expect (a+b)/2
assert s.interval_point(1.0, 2.0, 0.5) == 1.5
#test trivial case of a=b
a, b = 1., 1.
x = 0.0
assert s.interval_point(a, b, x) == a
x = 1.0
assert s.interval_point(a, b, x) == a
x = 0.5
assert s.interval_point(a, b, x) == a
#test for negative numbers
assert s.interval_point(-2.0, -1.0, 0.5) == -1.5
#test for negative numbers
assert s.interval_point(-2.0, -1.0, 0.0) == -2.0
#test for negative numbers
assert s.interval_point(-2.0, -1.0, 1.0) == -1.0
#test for positive and negative limits
assert s.interval_point(-10, 10, 0.25) == -5.0
In addition to Goyo's comment, I would personally not check for edge-cases:
def interval_point(a, b, x):
return (b - a) * x + a
This should work for all values of a, b and x, including your special cases a == b and x == 0. If there is any performance gain by doing those checks, it will be negligable in most cases.
This version will also work if x is not in [0, 1], for example:
>>> interval_point(100, 200, 2)
300
>>> interval_point(100, 200, -1)
0
Which is probably acceptable. If not, your function should check that 0 <= x <= 1, because now your implementation of the function will return nothing if x < 0

Categories

Resources