django decimal form field not taking value equal to max_value - django

I have a DecimalField in my form and i would like to restrict min_value=0.1 and max_value=99.99
purity_percent = forms.DecimalField(max_value=99.99, min_value=0.1, decimal_places=2)
But when i try to enter value equal to 0.1 or 99.99 i will not work i get these error
For 0.1 : Ensure this value is greater than or equal to 0.1.
For 99.99 : Ensure this value is less than or equal to 99.99.
How to do i include those in the limit too.?

Floats, like 99.99, are stored in binary. Many numbers that can be represented with finite decimal digits are repeating fractions in binary (see many other questions for that).
In particular, the literal 99.99 is closer to:
>>> "{:.15f}".format(99.99)
'99.989999999999995'
Python also has Decimals:
>>> from decimal import Decimal
>>> d = Decimal("99.99")
And sure enough, the Decimal 99.99 is larger than the float max_value 99.99:
>>> d <= 99.99
False
The Django developers knew about binary and this is the entire reason for the existence of the DecimalField: it stores Decimals.
Conclusion: Use Decimal("99.99") as your max_value, not a float.

Related

django-money object not limiting decimal fields

I'm using django-money for all currency fields in an app I'm building. According to the documentation the default CURRENCY_DECIMAL_PLACES is 2, and I am explicitly calling it in my settings.py file as well. However, when I am checking a remaining balance on an order it is returning a Money object, but showing all the decimal places instead of just 2.
In [2]: order.remaining_balance
Out[2]: Money('0.002500000000', 'USD')
Is there a reason it isn't restricting it to only the 2 decimal places that I am wanting? In the templates it is only showing two decimal places, but in my views.py file or the shell it renders the full decimal places.
I've set the CURRENCY_DECIMAL_PLACES to 2, but I'm getting back more than 2 decimal places.

Using MINIF/MAXIF with strings containing numbers?

I want to find the minimum number with given conditions(is writer and is under probation), the below code works if D contains numbers, but how do I do it if the number is a part of a string, like a fraction for example? Like how do I use this formula if numbers in D look like "1/8", "31/688", "21/33", etc?
=MINIFS(D3:D1007, A3:A1007, "Writer", C3:C1007, "Probation")
I already have another formula that I use that calculates a decimal value given the fraction, If the fraction is in cell D21 then it would look like this:
=left(D21,find("/",D21)-1)/(right(D21,len(D21)-find("/",D21)))
but how do I apply this kind of formula in a minif/maxif?
I have attached a picture to show what I mean, what I'm trying to do is to put a formula in the passed/total column of package stats(probation), and it will get the lowest passed/total value out of the ones with that package name and importance level. as you can see, the entire writer package's pass rate is 5/8 because the lowest pass rate out of the writer package 5/8 is the lowest pass rate out people with package=writers and importance = probation. But at the moment I have to enter the 5/8s manually, I want it to be able to get it automatically using the formula I'm trying to figure out above.
try:
=ARRAYFORMULA(MIN(IF((A3:A="writer")*(C3:C="probation"),
IFERROR(REGEXEXTRACT(D3:D, "\d+")/REGEXEXTRACT(D3:D, "/(\d+)"), D3:D), )))
or to return fraction:
=ARRAYFORMULA(VLOOKUP(MIN(IF((A3:A="writer")*(C3:C="probation"),
IFERROR(REGEXEXTRACT(D3:D, "\d+")/REGEXEXTRACT(D3:D, "/(\d+)"), D3:D), )),
{IF((A3:A="writer")*(C3:C="probation"),
IFERROR(REGEXEXTRACT(D3:D, "\d+")/REGEXEXTRACT(D3:D, "/(\d+)"), D3:D), ), D3:D}, 2, 0))
also make sure fractions are formatted as plain text not date

Python counter percentages returning 0 [duplicate]

This question already has answers here:
How can I force division to be floating point? Division keeps rounding down to 0?
(11 answers)
Closed 4 months ago.
I was trying to normalize a set of numbers from -100 to 0 to a range of 10-100 and was having problems only to notice that even with no variables at all, this does not evaluate the way I would expect it to:
>>> (20-10) / (100-10)
0
Float division doesn't work either:
>>> float((20-10) / (100-10))
0.0
If either side of the division is cast to a float it will work:
>>> (20-10) / float((100-10))
0.1111111111111111
Each side in the first example is evaluating as an int which means the final answer will be cast to an int. Since 0.111 is less than .5, it rounds to 0. It is not transparent in my opinion, but I guess that's the way it is.
What is the explanation?
You're using Python 2.x, where integer divisions will truncate instead of becoming a floating point number.
>>> 1 / 2
0
You should make one of them a float:
>>> float(10 - 20) / (100 - 10)
-0.1111111111111111
or from __future__ import division, which the forces / to adopt Python 3.x's behavior that always returns a float.
>>> from __future__ import division
>>> (10 - 20) / (100 - 10)
-0.1111111111111111
You're putting Integers in so Python is giving you an integer back:
>>> 10 / 90
0
If if you cast this to a float afterwards the rounding will have already been done, in other words, 0 integer will always become 0 float.
If you use floats on either side of the division then Python will give you the answer you expect.
>>> 10 / 90.0
0.1111111111111111
So in your case:
>>> float(20-10) / (100-10)
0.1111111111111111
>>> (20-10) / float(100-10)
0.1111111111111111
In Python 2.7, the / operator is an integer division if inputs are integers:
>>>20/15
1
>>>20.0/15.0
1.33333333333
>>>20.0/15
1.33333333333
In Python 3.3, the / operator is a float division even if the inputs are integer.
>>> 20/15
1.33333333333
>>>20.0/15
1.33333333333
For integer division in Python 3, we will use the // operator.
The // operator is an integer division operator in both Python 2.7 and Python 3.3.
In Python 2.7 and Python 3.3:
>>>20//15
1
Now, see the comparison
>>>a = 7.0/4.0
>>>b = 7/4
>>>print a == b
For the above program, the output will be False in Python 2.7 and True in Python 3.3.
In Python 2.7 a = 1.75 and b = 1.
In Python 3.3 a = 1.75 and b = 1.75, just because / is a float division.
You need to change it to a float BEFORE you do the division. That is:
float(20 - 10) / (100 - 10)
It has to do with the version of python that you use. Basically it adopts the C behavior: if you divide two integers, the results will be rounded down to an integer. Also keep in mind that Python does the operations from left to right, which plays a role when you typecast.
Example:
Since this is a question that always pops in my head when I am doing arithmetic operations (should I convert to float and which number), an example from that aspect is presented:
>>> a = 1/2/3/4/5/4/3
>>> a
0
When we divide integers, not surprisingly it gets lower rounded.
>>> a = 1/2/3/4/5/4/float(3)
>>> a
0.0
If we typecast the last integer to float, we will still get zero, since by the time our number gets divided by the float has already become 0 because of the integer division.
>>> a = 1/2/3/float(4)/5/4/3
>>> a
0.0
Same scenario as above but shifting the float typecast a little closer to the left side.
>>> a = float(1)/2/3/4/5/4/3
>>> a
0.0006944444444444445
Finally, when we typecast the first integer to float, the result is the desired one, since beginning from the first division, i.e. the leftmost one, we use floats.
Extra 1: If you are trying to answer that to improve arithmetic evaluation, you should check this
Extra 2: Please be careful of the following scenario:
>>> a = float(1/2/3/4/5/4/3)
>>> a
0.0
Specifying a float by placing a '.' after the number will also cause it to default to float.
>>> 1 / 2
0
>>> 1. / 2.
0.5
Make at least one of them float, then it will be float division, not integer:
>>> (20.0-10) / (100-10)
0.1111111111111111
Casting the result to float is too late.
In python cv2 not updated the division calculation. so, you must include from __future__ import division in first line of the program.
Either way, it's integer division. 10/90 = 0. In the second case, you're merely casting 0 to a float.
Try casting one of the operands of "/" to be a float:
float(20-10) / (100-10)
You're casting to float after the division has already happened in your second example. Try this:
float(20-10) / float(100-10)
I'm somewhat surprised that no one has mentioned that the original poster might have liked rational numbers to result. Should you be interested in this, the Python-based program Sage has your back. (Currently still based on Python 2.x, though 3.x is under way.)
sage: (20-10) / (100-10)
1/9
This isn't a solution for everyone, because it does do some preparsing so these numbers aren't ints, but Sage Integer class elements. Still, worth mentioning as a part of the Python ecosystem.
Personally I preferred to insert a 1. * at the very beginning. So the expression become something like this:
1. * (20-10) / (100-10)
As I always do a division for some formula like:
accuracy = 1. * (len(y_val) - sum(y_val)) / len(y_val)
so it is impossible to simply add a .0 like 20.0. And in my case, wrapping with a float() may lose a little bit readability.
In Python 3, the “//” operator works as a floor division for integer and float arguments. However, the operator / returns a float value if one of the arguments is a float (this is similar to C++)
eg:
# A Python program to demonstrate the use of
# "//" for integers
print (5//2)
print (-5//2)
Output:
2
-3
# A Python program to demonstrate use of
# "/" for floating point numbers
print (5.0/2)
print (-5.0/2)
Output:
2.5
-2.5
ref: https://www.geeksforgeeks.org/division-operator-in-python/

How do you Force Type Decimal Number to always Round Up to 2dp

E.g. 23.122 will round to 23.13
So you need to use Math and ceil for this and the code looks something like below
>>> import math
>>> print(math.ceil(23.122*100)/100)
>>>23.13
Here you multiply your number with 100 and then divide and find its ceil value

How to query floatfield in Django?

I have a FloatField which can have values like 22.33405, 33.567 etc. Now, I need to query using only upto 2 places after decimal like below
#find all objects with value equal to 22.33
ModelName.objects.filter(field = 22.33)
Is it possible to do so - can I round off or just take first 2 places after decimal?
thanks
try this
ModelName.objects.filter(field__gte=22.33, field__lt=(22.33 + 0.01))
or
ModelName.objects.filter(field__range=(22.33, 22.33 + 0.01))
range lookup
Not directly. If you need this level of accuracy then you should be using DecimalField.