How to represent values float in 2 float point in python? - 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)

Related

Round up to 2 decimal in Python

I have a beginner problem. How can I round up to 2 decimal?
Here is what I tried and what I want to achieve:
import math
var_1 = 14.063 # expected = 14.06
var_2 = 10.625 # expected = 10.63
print(round(14.063, 2))
print(round(10.625, 2))
print('===========================')
def round_up(n, decimals=0):
multiplier = 10 ** decimals
return math.ceil(n * multiplier) / multiplier
print(round_up(var_1, 2))
print(round_up(var_2, 2))
And the Output is:
14.06
10.62
===========================
14.07
10.63
So neither of those wroks for me...
The Decimal class, quantize() method, and ROUND_HALF_UP rule from the decimal module can handle this:
from decimal import Decimal, ROUND_HALF_UP
var_1 = 14.063 # expected = 14.06
var_2 = 10.625 # expected = 10.63
# a Decimal object with an explicit exponent attribute/property (to be interpreted by quantize)
Two_places = Decimal("1e-2")
for var in [var_1, var_2]:
rounded = Decimal(var).quantize(Two_places, rounding=ROUND_HALF_UP)
print(f"decimal: {rounded}")
print(f"float: {float(rounded)}")
and I get:
decimal: 14.06
float: 14.06
decimal: 10.63
float: 10.63
Keep in mind that when you're dealing with floats, you're always manipulating a less-than-precise representation of what you probably (naturally) have in mind:
Decimal(1.65) # Decimal('1.649999999999999911182158029987476766109466552734375')
Decimal('1.65') # Decimal('1.65')
In the first case, 1.65 was first turned into an IEEE-754 float, which has precision errors going from base-10 to base-2, then passed to Decimal. In the second case, Decimal interpreted the number as "one, and 65 100-ths" which equates to "165 times 10 raised to the minus 2", or 165e-2.
Try this. This finds the nearest one and if not, then round up -
import math
v1 = 14.063
v2 = 10.625
def round_up(n, decimals=0):
multiplier = 10 ** decimals
var_down = round(n, 2)
var_up = math.ceil(n * multiplier) / multiplier
if n - var_down >= var_up - n:
return var_up
else:
return var_down
v1_round = round_up(v1, 2)
v2_round = round_up(v2, 2)
print (v1_round) # 14.06
print (v2_round) # 10.63
this should work, although there is probebly a more efficient way of doing it. I just took your code and determined which one was closer, and if they are the same to round up.
Edit: It seems that PCM has made such version.
import math
decimals = 2
var_1 = 14.063
var_2 = 10.625
var_1down = round(var_1, decimals)
var_2down = round(var_2, decimals)
def round_up(n, decimals=0):
multiplier = 10 ** decimals
return math.ceil(n * multiplier) / multiplier
var_1up = round_up(var_1, decimals)
var_2up = round_up(var_2, decimals)
if var_1 - var_1down >= var_1up - var_1:
var_1round = var_1up
else:
var_1round = var_1down
if var_2 - var_2down >= var_2up - var_2:
var_2round = var_2up
else:
var_2round = var_2down
print (var_1round)
print (var_2round)
If you check the docs you will see that "values are rounded to the closest multiple of 10 to the power minus ndigits; if two multiples are equally close, rounding is done toward the even choice (so, for example, both round(0.5) and round(-0.5) are 0, and round(1.5) is 2)".
So 10.625 rounds to 10.62. You may try adding a very small value, e.g. 0.00001, but even so, since the way float numbers work, you may have some surprise in a few cases.

Unpack error in a function that converts float to binary

I am trying to make a Python function that takes a float number, and converts it to a string with its binary (considering the fractional part too, separated by a dot), but for some values ​-such as 0.5, 0.25, 0.10, 0.05 , 0.05, ...- it gives the following error:
line 7, in floatToBinary integerPart, fractionalPart = str((convertDecimal(fractional))*2).split(".")
ValueError: Not enough values ​​to unpack (expected 2, got 1)
Functions:
def floatToBinary(floatNumber, decimalPlaces):
    integerPart, fractionalPart = str(floatNumber).split(".")
    integerPart = int(integerPart)
    fractionalPart = int(fractionalPart)
    result = bin(integerPart).lstrip("0b") + "."
    for i in range(decimalPlaces):
        integerPart, fractionalPart = str((convertDecimal(fractionalPart))*2).split(".")
        fractionalPart = int(fractionalPart)
        result += integerPart
    return result
def convertDecimal(n):
    while n > 1:
        n /= 10
    return n
Hope you can help me.
The function convertDecimal returns 0 when n = 0. So there is no '.' to split.
You can fix that by casting the return value as float
def convertDecimal(n):
while n > 1:
n /= 10
return float(n)

Round up to certain number

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)

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!

Imitating 'ppoints' R function in python

The R ppoints function is described as:
Ordinates for Probability Plotting
Description:
Generates the sequence of probability points ‘(1:m - a)/(m +
(1-a)-a)’ where ‘m’ is either ‘n’, if ‘length(n)==1’, or
‘length(n)’.
Usage:
ppoints(n, a = ifelse(n <= 10, 3/8, 1/2))
...
I've been trying to replicate this function in python and I have a couple of doubts.
1- The first m in (1:m - a)/(m + (1-a)-a) is always an integer: int(n) (ie: the integer of n) if length(n)==1 and length(n) otherwise.
2- The second m in the same equation is NOT an integer if length(n)==1 (it assumes the real value of n) and it IS an integer (length(n)) otherwise.
3- The n in a = ifelse(n <= 10, 3/8, 1/2) is the real number n if length(n)==1 and the integer length(n) otherwise.
This points are not made clear at all in the description and I'd very much appreciate if someone could confirm that this is the case.
Add
Well this was initially posted at https://stats.stackexchange.com/ because I was hoping to get the input of staticians who work with the ppoints function. Since it has been migrated here, I'll paste below the function I wrote to replicate ppoints in python. I've tested it and both seem to give back the same results, but I'd be great if someone could clarify the points made above because they are not made at all clear by the function's description.
def ppoints(vector):
'''
Mimics R's function 'ppoints'.
'''
m_range = int(vector[0]) if len(vector)==1 else len(vector)
n = vector[0] if len(vector)==1 else len(vector)
a = 3./8. if n <= 10 else 1./2
m_value = n if len(vector)==1 else m_range
pp_list = [((m+1)-a)/(m_value+(1-a)-a) for m in range(m_range)]
return pp_list
I would implement this with numpy:
import numpy as np
def ppoints(n, a):
""" numpy analogue or `R`'s `ppoints` function
see details at http://stat.ethz.ch/R-manual/R-patched/library/stats/html/ppoints.html
:param n: array type or number"""
try:
n = np.float(len(n))
except TypeError:
n = np.float(n)
return (np.arange(n) + 1 - a)/(n + 1 - 2*a)
Sample output:
>>> ppoints(5, 1./2)
array([ 0.1, 0.3, 0.5, 0.7, 0.9])
>>> ppoints(5, 1./4)
array([ 0.13636364, 0.31818182, 0.5 , 0.68181818, 0.86363636])
>>> n = 10
>>> a = 3./8. if n <= 10 else 1./2
>>> ppoints(n, a)
array([ 0.06097561, 0.15853659, 0.25609756, 0.35365854, 0.45121951,
0.54878049, 0.64634146, 0.74390244, 0.84146341, 0.93902439])
One can use R fiddle to test implementation.

Categories

Resources