Decimal library and round() function - python

Difference between rounding using Decimal library and rounding using round() function in Python 3.
I don't know whether to use the round() function or use the Decimal library to round numbers
Decimal
from decimal import*
getcontext().prec = 3
print(Decimal(10)/3)
3,33
round()
print(round(10/3,2))
3,33
I hope everyone can answer my questions

They serve different purposes, you can use both. While you use the function round to perform an actual rounding action, as per the docs:
Return number rounded to ndigits precision after the decimal point. If ndigits is omitted or is None, it returns the nearest integer to its input.
With decimal, you can get and set the context for which you want numerical variables to operate (and a lot more, but for the sake of your question, I will limit it to this)
from decimal import *
getcontext()
Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
capitals=1, clamp=0, flags=[], traps=[Overflow, DivisionByZero,
InvalidOperation])
Thus allowing me to set it differently with:
getcontext().rounding = ROUND_UP
With the latter you are not rounding per se, but doing it as a consequence of the context you define.
The module design is centered around three concepts: the decimal number, the context for arithmetic, and signals.
The context for arithmetic is an environment specifying precision, rounding rules, limits on exponents, flags indicating the results of operations, and trap enablers which determine whether signals are treated as exceptions. Rounding options include ROUND_CEILING, ROUND_DOWN, ROUND_FLOOR, ROUND_HALF_DOWN, ROUND_HALF_EVEN, ROUND_HALF_UP, ROUND_UP, and ROUND_05UP.

from decimal import *
print(Decimal("3.33"))
#output
Decimal('3.33')
# These Decimal objects can be converted to float(), int(), etc. and can be fed to round functions as well.
print(round(Decimal("3.33")))
#ouput
3
print(round('3.33'))
#output
TypeError: type str doesn't define __round__ method
round() always take argument as an integer, while you can pass string in Decimal()
You can pass Decimal object in round function as well.
round() documentation https://docs.python.org/3/library/functions.html#round
Decimal() documentation https://docs.python.org/3/library/decimal.html#decimal-objects

Related

How to disable python rounding?

I'm looking for a way to disable this:
print(0+1e-20) returns 1e-20, but print(1+1e-20) returns 1.0
I want it to return something like 1+1e-20.
I need it because of this problem:
from numpy import sqrt
def f1(x):
return 1/((x+1)*sqrt(x))
def f2(x):
return 1/((x+2)*sqrt(x+1))
def f3(x):
return f2(x-1)
print(f1(1e-6))
print(f3(1e-6))
print(f1(1e-20))
print(f3(1e-20))
returns
999.9990000010001
999.998999986622
10000000000.0
main.py:10: RuntimeWarning: divide by zero encountered in double_scalars
return 1/((x+2)*sqrt(x+1))
inf
f1 is the original function, f2 is f1 shifted by 1 to the left and f3 is f2 moved back by 1 to the right. By this logic, f1 and f3 should be equal to eachother, but this is not the case.
I know about decimal. Decimal and it doesn't work, because decimal doesn't support some functions including sin. If you could somehow make Decimal work for all functions, I'd like to know how.
Can't be done. There is no rounding - that would imply that the exact result ever existed, which it did not. Floating-point numbers have limited precision. The easiest way to envision this is an analogy with art and computer screens. Imagine someone making a fabulously detailed painting, and all you have is a 1024x768 screen to view it through. If a microscopic dot is added to the painting, the image on the screen might not change at all. Maybe you need a 4K screen instead.
In Python, the closest representable number after 1.0 is 1.0000000000000002 (*), according to math.nextafter(1.0, math.inf) (Python 3.9+ required for math.nextafter).1e-20 and 1 are too different in magnitude, so the result of their addition cannot be represented by a Python floating-point number, which are precise to up to about 16 digits.
See Is floating point math broken? for an in-depth explanation of the cause.
As this answer suggests, there are libraries like mpmath that implement arbitrary-precision arithmetics:
from mpmath import mp, mpf
mp.dps = 25 # set precision to 25 decimal digits
mp.sin(1)
# => mpf('0.8414709848078965066525023183')
mp.sin(1 + mpf('1e-20')) # mpf is a constructor for mpmath floats
# => mpf('0.8414709848078965066579053457')
mpmath floats are sticky; if you add up an int and a mpf you get a mpf, so I did not have to write mp.mpf(1). The result is still not precise, but you can select what precision is sufficient for your needs. Also, note that the difference between these two results is, again, too small to be representable by Python's floating point numbers, so if the difference is meaningful to you, you have to keep it in the mpmath land:
float(mpf('0.8414709848078965066525023183')) == float(mpf('0.8414709848078965066579053457'))
# => True
(*) This is actually a white lie. The next number after 1.0 is 0x1.0000000000001, or 0b1.0000000000000000000000000000000000000000000000001, but Python doesn't like hexadecimal or binary float literals. 1.0000000000000002 is Python's approximation of that number for your decimal convenience.
As others have stated, in general this can't be done (due to how computers commonly represent numbers).
It's common to work with the precision you've got, ensuring that algorithms are numerically stable can be awkward.
In this case I'd redefine f1 to work on the logarithms of numbers, e.g.:
from numpy as sqrt, log, log1p,
def f1(x):
prod = log1p(x) + log(x) / 2
return exp(-prod)
You might need to alter other parts of the code to work in log space as well depending on what you need to do. Note that most stats algorithms work with log-probabilities because it's much more compatible with how computers represent numbers.
f3 is a bit more work due to the subtraction.

Find the base of the power and power with given base in python

I have a number N let's say 5451 and I want to find the base for power 50. How do I do it with python?
The answer is 1.1877622648368 according this website (General Root calculator) But i need to find it with computation.
Second question. If I have the number N 5451, and I know the base 1.1877622648368, how do I find the power?
Taking the n-th root is the same as raising to the power 1/n. This is very simple to do in Python using the ** operator (exponentiation):
>>> 5451**(1/50)
1.1877622648368031
The second one requires a logarithm, which is the inverse of exponentiation. You want to take the base-1.1877622648368031 logarithm of 5451, which is done with the log function in the math module:
>>> import math
>>> math.log(5451, 1.1877622648368031)
50.00000000000001
As you can see, there's some roundoff error. This is unavoidable when working with limited-precision floating point numbers. Apply the round() function to the result if you know that it must be an integer.

Fractions with python

I'm trying to do this calculation:
from fractions import Fraction
z=4
x=Float(Fraction(1+math.pi,1+2*z**2))
But this results in the following error:
TypeError: both arguments should be Rational instances
If I change pi value for integer value works. But if I use a decimal value shows me that error.
Any idea?
Regards
Thanks
Taken from the documented for the fractions module:
The [two argument constructor] requires that numerator and denominator are instances of numbers.Rational.
In your snippet, 1+math.pi is a float, not an instance of numbers.Rational, hence the TypeError.

What's the rationale behind 2.5 // 2.0 returning a float rather than an int in Python 3.x?

What's the rationale behind 2.5 // 2.0 returning a float rather than an int in Python 3.x?
If it's an integral value, why not put it in a type int object?
[edit]
I am looking for a justification of the fact that this is so. What were the arguments in making it this way. Haven't been able to find them yet.
[edit2]
The relation with floor is more problematic than the term "floor division" suggests!
floor(3.5 / 5.5) == 0 (int)
whereas
3.5 // 5.5 == 0.0 (float)
Can not yet discern any logic here :(
[edit3]
From PEP238:
In a
unified model, the integer 1 should be indistinguishable from the
floating point number 1.0 (except for its inexactness), and both
should behave the same in all numeric contexts.
All very nice, but a not unimportant library like Numpy complains when offering floats as indices, even if they're integral. So 'indistinguishable' is not reality yet. Spent some time hunting a bug in connection with this. I was very surprise to learn about the true nature of //. And it wasn't that obvious from the docs (for me).
Since I've quite some trust in the design of Python 3.x, I thought I must have missed a very obvious reason to define // in this way. But now I wonder...
The // operator is covered in PEP 238. First of all, note that it's not "integer division" but "floor division", i.e. it is never claimed that the result would be an integer.
From the section on Semantics of Floor Division:
Floor division will be implemented in all the Python numeric types, and will have the semantics of
a // b == floor(a/b)
except that the result type will be the common type into which a and b are coerced before the operation.
And later:
For floating point inputs, the result is a float. For example:
3.5//2.0 == 1.0
The rationale behind this decision is not explicitly stated (or I could not find it). However, the way it is implemented, it is consistent with the other mathematical operations (emphasis mine):
Specifically, if a and b are of the same type, a//b will be of that type too. If the inputs are of different types, they are first coerced to a common type using the same rules used for all other arithmetic operators.
Also, if the results would be automatically converted to int, that could yield weird and surprising results for very large floating point numbers that are beyond integer precision:
>>> 1e30 // 2.
5e+29
>>> int(1e30 // 2.)
500000000000000009942312419328

evaluating a sympy function at an arbitrary-precision floating point

Given a sympy symbolic function, for example
x=symbols("x")
h=sin(x)
when one calls
h.subs(x, mpf('1.0000000000000000000000000000000000000000000001'))
sympy returns a floating point number. The return value is not an mpf.
Is there a convenient way to get sympy to evaluate symbolic standard functions (like exponential and trig functions), using arbitrary precision?
To evaluate an expression, use expr.evalf(), which takes a precision as the first argument (the default is 15). You can substitute expressions using expr.evalf(prec, subs=subs_dict).
>>> sin(x).evalf(50, subs={x: Float('1.0')})
0.84147098480789650665250232163029899962256306079837

Categories