How to disable python rounding? - python

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.

Related

Decimal library and round() function

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

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.

What is the default accuracy for the mpmath function hyperu?

Computation of the Tricomi confluent hypergeometric function can be ill-conditioned when it uses the sum of two 1F1 functions, as they can be nearly equal in size but opposite in sign. The mpmath function "hyperu" uses arbitrary precision internally and produces a result with 35 significant figures in default mode. How many of these digits are reliable? Does it depend on the parameters passed?
import mpmath
x = mpmath.hyperu(a, b + 1, u)
I have just received an email from the main author of mpmath, Fredrik Johansson, confirming that the full 35 digits are usable. He writes "hyperu uses adaptive higher precision internally, so the result should nearly always be accurate to the full precision set by the user".

Haversine's Formula and Python 3 - Math Domain Error

I'm trying to implement Haversine's formula to determine whether a given location's latitude and longitude is within a specified radius. I used a formula detailed here:
Calculate distance between two latitude-longitude points? (Haversine formula)
I am experiencing a Math Domain Error with the following re-producible input, it does not happen all the time, but often enough to make me think I've written in-correct code:
from math import atan2, sqrt, sin, cos
# All long / lat values are in radians and of type float
centerLongitude = -0.0391412861306467
centerLatitude = 0.9334153362515779
inputLatitudeValue = -0.6096173085842176
inputLongitudeValue = 2.4190393564390438
longitudeDelta = inputLongitudeValue - centerLongitude # 2.4581806425696904
latitudeDelta = inputLatitudeValue - centerLatitude # -1.5430326448357956
a = (sin(latitudeDelta / 2) ** 2 + cos(centerLatitude) * cos(centerLongitude)
* sin(longitudeDelta / 2) ** 2)
# a = 1.0139858858386017
c = 2 * atan2(sqrt(a), sqrt(1 - a)) # Error occurs on this line
# Check whether distance is within our specified radius below
You cannot use sqrt on negative numbers:
>>> sqrt(-1)
ValueError: math domain error
use cmath.srt:
>>> import cmath
>>> cmath.sqrt(-1)
1j
in your case:
>>> a = 1.0139858858386017
>>> sqrt(1-a)
ValueError: math domain error
Speaking generally, and said simply... the variable a must be protected. It must never be greater than 1.0, and it must never be less than 0.0, and normally, with clean data, it should be properly in this range.
The problem is with how the common popular computer implementation of floating point arithmetic does its approximation and roundings, and how those results can sometimes be out of range or out of domain for a builtin math function. It is not particularly common that the combination of operations results in a number that is out of domain for a following math function, but in those cases where it does occur, depending on the algorithm, it is consistently reproducable, and needs to be accounted for and mitigated, beyond a normal theoretical algorithm intuition. What we code in computers is subject to how theoretical concepts have been implemented for the software and hardware. On paper, with pencil, we still must have guidelines for when and how to round floating point math results. Computer implementations are no different, but sometimes we are blissfully unaware of such things going on under the hood. Popular computer implementations not only need to know at what precision to round, but also are dealing with how and when to approximate and round in the conversion to and from the binary number representations that are actually calculated at the machine level.
Regarding the haversine formula, what a am I speaking about?
as seen in this version of code (for reference):
import math
a = math.sin(dlat / 2)**2 + math.cos(lat1) * math.cos(lat2) * math.sin(dlon / 2)**2
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
In this above example, the a is not properly protected. It is a lurking problem waiting to crash the c calculation on the next line, in certain conditions presented particularly to the haversine formula.
If some latlon combination of data results in
a = 1.00000000000000000000000000000000000001
the following c calculation with cause an error.
If some latlon combination of data results in
a = -0.00000000000000000000000000000000000000000000001
the following c calculation will cause an error.
It is the floating point math implementation of your language/platform and its method of rounding approximation that can cause the rare but actual and consistently repeatable ever so slightly out of domain condition that causes the error in an unprotected haversine coding.
Years ago I did a three day brute force test of relative angular distances between 0 and 1, and 179 and 180, with VERY small step values. The radius of the sphere is one, a unit sphere, so that radius values are irrelevant. Of course, finding approximate distances on the surface of the sphere in any unit other than angular distance would require including the radius of the sphere in its units. But I was testing the haversine logic implementation itself, and a radius of 1 eliminated a complication. When the relative angular distances are 0 -1, or 179-180, these are the conditions where haversine can have difficulties, implemented with popular floating point implementations that involve converting to and from binary at a low system level, if the a is not protected. Haversine is supposed to be well conditioned for small angular distances, theoretically, but a machine or software implementation of FPA (floating point arithmetic) is not always precisely cooperative with the ideals of a spherical geometry theory. After 3 days of my brute force test, there were logged thousands of latlon combinations that would crash the unprotected popularly posted haversine formula, because the a was not protected. You must protect the a. If it goes above 1.0, or below 0.0, even the very slightest bit, all one need do is simply test for that condition and nudge it back into range. Simple.
I protected an a of -0.000000000000000000002 or in other words, if a < 0.0, by reassigning the value 0.0 to it, and also setting another flag that I could inspect so I would know if a protective action had been necessary for that data.
I protected an a of 1.000000000000000000002 or in other words, if a > 1.0, by reassigning the value 1.0 to it, and also setting another flag that I could inspect so I would know if a protective action had been necessary for that data.
It is a simple 2 extra lines before the c calculation. You could squeeze it all on one line. The protective line(s) of code go after the a calculation, and before the c calculation. Protect your a.
Are you then loosing precision with those slight nudges? No more than what the floating point math with that data is already introducing with its approximations and rounding. It crashed with data that should not have crashed a pure theoretical algorithm, one that doesn't have FPA rare issues. Simply protect the a, and this should mitigate those errors, with haversine in this form. There are alternatives to haversine, but haversine is completely suitable for many uses, if one understands where it is well suited. I use it for skysphere calculations where the ellipsoid shape of the earth has nothing to do with anything. Haversine is simple and fast. But remember to protect your a.

Error 34, Result too large

I am trying to print the Fibonacci sequence and it always returns an Overflow error after about the 600th term.
def fib():
import math
from math import sqrt
print "\nFibonacci Sequence up to the term of what?"
n=raw_input(prompt)
if n.isdigit():
if int(n)==0:
return 0
elif int(n)==1:
return 1
else:
n_count=2
print "\n0\n1"
while n_count<int(n):
fib=int(((1+sqrt(5))**n_count-(1-sqrt(5))**n_count)/(2**n_count*sqrt(5)))
print fib
n_count+=1
fib()
else:
print "\nPlease enter a number."
fib()
fib()
When I run this:
Traceback (most recent call last):
File "<pyshell#21>", line 1, in <module>
fib()
File "<pyshell#20>", line 15, in fib
fib=int(((1+sqrt(5))**n_count-(1-sqrt(5))**n_count)/(2**n_count*sqrt(5)))
OverflowError: (34, 'Result too large')
Well, first, let's split that big expression up into smaller ones, so we can see where it's going wrong. And use a debugger or some print statements to see what values are making it go wrong. That way, we're not just taking a stab in the dark.
If you do that, you can tell that (1+sqrt(5)**n_count) is raising this exception when n_count hits 605. Which you can verify pretty easily:
>>> (1+sqrt(5))**604
1.1237044275099689e+308
>>> (1+sqrt(5))**605
OverflowError: (34, 'Result too large')
So, why is that a problem?
Well, Python float values, unlike its integers, aren't arbitrary-sized, they can only hold what an IEEE double can hold:*
>>> 1e308
1e308
>>> 1e309
inf
So, the problem is that one of the terms in your equation is greater than the largest possible IEEE double.
That means you either need to pick a different algorithm,** or get a "big-float" library.
As it happens, Python has a built-in big-float library, in the decimal module. Of course as the name implies, it handles decimal floats, not binary floats, so you'll get different rounding errors if you use it. But you presumably don't care much about rounding errors, given your code.
So:
import decimal
s5 = decimal.Decimal(5).sqrt()
… then …
fib=int(((1+s5)**n_count-(1-s5)**n_count)/(2**n_count*s5))
* In fact, the limits are platform-specific; implementations aren't required to use IEEE doubles for float. So, use sys.float_info to see the max value for your platform. But it's almost always going to be 1.7976931348623157e+308.
** Note that the only advantage of the algorithm you're using over the naive one is that it allows you to approximate the Nth Fibonacci number directly, without calculating the preceding N-1. But since you want to print them all out anyway, you're not getting any advantage. You're just getting the disadvantages—it's an approximation; it's more complicated; it requires floating-point math, which is subject to rounding error; it's slower; it takes more memory; the built-in floating-point types in most languages on most platforms can't hold F(605), … All that for no benefit doesn't seem worth it.
As abarnert pointed out, floats are limited in python. You can see the limit by
>>> import sys
>>> sys.float_info
sys.float_info(max=1.7976931348623157e+308, max_exp=1024, max_10_exp=308, min=2.2250738585072014e-308, min_exp=-1021, min_10_exp=-307, dig=15, mant_dig=53, epsilon=2.220446049250313e-16, radix=2, rounds=1)
You will reach some more terms if you divide by 2 before raising to the power:
int(( ((1+sqrt(5))/2)**n_count - ((1-sqrt(5))/2)**n_count)/sqrt(5))
But since Fibonacci sequence grows exponentially, you will soon hit the same wall. Try computing Fibonacci by holding the last two terms and adding them. That way you will use ints.

Categories