Exact Sine/Cosine/Tangent of Various Angles [duplicate] - python

This question already has answers here:
Python cos(90) and cos(270) not 0
(3 answers)
Closed 9 years ago.
Is there a way to get the exact Tangent/Cosine/Sine of an angle (in radians)?
math.tan()/math.sin()/math.cos() does not give the exact for some angles:
>>> from math import *
>>> from decimal import Decimal
>>> sin(pi) # should be 0
1.2246467991473532e-16
>>> sin(2*pi) # should be 0
-2.4492935982947064e-16
>>> cos(pi/2) # should be 0
6.123233995736766e-17
>>> cos(3*pi/2) # 0
-1.8369701987210297e-16
>>> tan(pi/2) # invalid; tan(pi/2) is undefined
1.633123935319537e+16
>>> tan(3*pi/2) # also undefined
5443746451065123.0
>>> tan(2*pi) # 0
-2.4492935982947064e-16
>>> tan(pi) # 0
-1.2246467991473532e-16
I tried using Decimal(), but this does not help either:
>>> tan(Decimal(pi)*2)
-2.4492935982947064e-16
numpy.sin(x) and the other trigonometric functions also have the same issue.
Alternatively, I could always create a new function with a dictionary of values such as:
def new_sin(x):
sin_values = {math.pi: 0, 2*math.pi: 0}
return sin_values[x] if x in sin_values.keys() else math.sin(x)
However, this seems like a cheap way to get around it. Is there any other way? Thanks!

It is impossible to store the exact numerical value of pi in a computer. math.pi is the closest approximation to pi that can be stored in a Python float. math.sin(math.pi) returns the correct result for the approximate input.
To avoid this, you need to use a library that supports symbolic arithmetic. For example, with sympy:
>>> from sympy import *
>>> sin(pi)
0
>>> pi
pi
>>>
sympy will operate on an object that represents pi and can give exact results.

When you're dealing with inexact numbers, you need to deal with error explicitly. math.pi (or numpy.pi) isn't exactly π, it's, e.g., the closest binary rational number in 56 digits to π. And the sin of that number is not 0.
But it is very close to 0. And likewise, tan(pi/2) is not infinity (or NaN), but huge, and asin(1)/pi is very close to 0.5.
So, even if the algorithms were somehow exact, the results still wouldn't be exact.
If you've never read What Every Computer Scientist Should Know About Floating-Point Arithmetic, you should do so now.
The way to deal with this is to use epsilon-comparisons rather than exact comparisons everywhere, and explicitly round things when printing them out, and so on.
Using decimal.Decimal numbers instead of float numbers makes this easier. First, you probably think in decimal rather than binary, so it's easier for you to understand and make decisions about the error. Second, you can explicitly set precision and other context information on Decimal values, while float are always IEEE double values.
The right way to do it is to do full error analysis on your algorithms, propagate the errors appropriately, and use that information where it's needed. The simple way is to just pick some explicit absolute or relative epsilon (and the equivalent for infinity) that's "good enough" for your application, and use that everywhere. (You'll probably also want to use the appropriate domain-specific knowledge to treat some values as multiples of pi instead of just raw values.)

Related

Answer becomes infinite [duplicate]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I am working on a program that outputs the condition number of a big matrix, so I used the Power Method to get the Largest EigenValue, but the values are large numbers (float) larger than 1*10^310, and in the end the values become "Infinity", I tried the decimal module but it's the same. How can I store those large float values? Or maybe another method that uses shorter values?
(I'm not allowed to use any module that helps explicitly the proccess as Numpy)
You want to use the decimal module:
from decimal import Decimal
x = Decimal('1.345e1310')
y = Decimal('1.0e1310')
print(x + y)
Result:
2.345E+1310
Don't work with floating point values if you can help it; they are very difficult to reason about and will bite you!
Whenever you are trying to work with floats, especially ones with lots of digits, you should consider how you can shift it into an integer range and if you have invalid or needless accuracy beyond the floating part of your value
perhaps into a bigger int such as 10**400 or 10**100000, which should provide plenty of room for your floating point digits, while allowing you to work in the integer space
directly convert or scale down, discarding digits beyond the decimal point (consider how accurate the measurement really is)
>>> int(1.0 * 10) * 10**999 # divide off 10**690 later or note in units
10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
>>> int(1.0 * 10**10) # multiply by 10**300 later or note in units
10000000000
Practically, this is why you would want scientific notation - don't store the data with all its digits if you don't need them, keep the smallest amount you need and a second multiplier for the size factor (scientific notation does use a floating-point, but the idea is the same for integers)
Then, rather than working with floating points, you can recall the multiplier(s) at the end when you're done with your math (even multiplying them out separately)
It may even be sufficient to remove a significant portion of the digits entirely in some regular manner, and display the factor in the post-calculation units for whom or whatever is consuming the data
While this question is about large numbers, even decimal.Decimal unfortunately does not handle the small bits of floating points the way one might expect, as they're subject to some aliasing from how they're stored
https://en.wikipedia.org/wiki/Floating-point_arithmetic#IEEE_754:_floating_point_in_modern_computers
This is problematic with normal python floats, and so extends to Decimals, even of a size you may expect to see in normal use!
>>> 9007199254740993.0
9007199254740992.0
>>> Decimal(9007199254740993.0) # NOTE converted to float before Decimal
Decimal('9007199254740992')
Adapted from Which is the first integer that an IEEE 754 float is incapable of representing exactly?
Example to the original question
>>> a = Decimal(10**310) * Decimal(1.0)
>>> b = Decimal(1)
>>> a + b - a
Decimal('0E+283')
Further examples
>>> a = Decimal(10**310)
>>> b = Decimal(0.1)
>>> a + b - a
Decimal('0')
>>> a
Decimal('10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000')
>>> b
Decimal('0.1000000000000000055511151231257827021181583404541015625')
>>> 10**-100
1e-100
>>> Decimal(10**-100)
Decimal('1.00000000000000001999189980260288361964776078853415942018260300593659569925554346761767628861329298958274607481091185079852827053974965402226843604196126360835628314127871794272492894246908066589163059300043457860230145025079449986855914338755579873208034769049845635890960693359375E-100')
>>> 10**-1000
0.0
>>> Decimal(10**-1000)
Decimal('0')

How can I store float numbers larger than 1*10^310 in python? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I am working on a program that outputs the condition number of a big matrix, so I used the Power Method to get the Largest EigenValue, but the values are large numbers (float) larger than 1*10^310, and in the end the values become "Infinity", I tried the decimal module but it's the same. How can I store those large float values? Or maybe another method that uses shorter values?
(I'm not allowed to use any module that helps explicitly the proccess as Numpy)
You want to use the decimal module:
from decimal import Decimal
x = Decimal('1.345e1310')
y = Decimal('1.0e1310')
print(x + y)
Result:
2.345E+1310
Don't work with floating point values if you can help it; they are very difficult to reason about and will bite you!
Whenever you are trying to work with floats, especially ones with lots of digits, you should consider how you can shift it into an integer range and if you have invalid or needless accuracy beyond the floating part of your value
perhaps into a bigger int such as 10**400 or 10**100000, which should provide plenty of room for your floating point digits, while allowing you to work in the integer space
directly convert or scale down, discarding digits beyond the decimal point (consider how accurate the measurement really is)
>>> int(1.0 * 10) * 10**999 # divide off 10**690 later or note in units
10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
>>> int(1.0 * 10**10) # multiply by 10**300 later or note in units
10000000000
Practically, this is why you would want scientific notation - don't store the data with all its digits if you don't need them, keep the smallest amount you need and a second multiplier for the size factor (scientific notation does use a floating-point, but the idea is the same for integers)
Then, rather than working with floating points, you can recall the multiplier(s) at the end when you're done with your math (even multiplying them out separately)
It may even be sufficient to remove a significant portion of the digits entirely in some regular manner, and display the factor in the post-calculation units for whom or whatever is consuming the data
While this question is about large numbers, even decimal.Decimal unfortunately does not handle the small bits of floating points the way one might expect, as they're subject to some aliasing from how they're stored
https://en.wikipedia.org/wiki/Floating-point_arithmetic#IEEE_754:_floating_point_in_modern_computers
This is problematic with normal python floats, and so extends to Decimals, even of a size you may expect to see in normal use!
>>> 9007199254740993.0
9007199254740992.0
>>> Decimal(9007199254740993.0) # NOTE converted to float before Decimal
Decimal('9007199254740992')
Adapted from Which is the first integer that an IEEE 754 float is incapable of representing exactly?
Example to the original question
>>> a = Decimal(10**310) * Decimal(1.0)
>>> b = Decimal(1)
>>> a + b - a
Decimal('0E+283')
Further examples
>>> a = Decimal(10**310)
>>> b = Decimal(0.1)
>>> a + b - a
Decimal('0')
>>> a
Decimal('10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000')
>>> b
Decimal('0.1000000000000000055511151231257827021181583404541015625')
>>> 10**-100
1e-100
>>> Decimal(10**-100)
Decimal('1.00000000000000001999189980260288361964776078853415942018260300593659569925554346761767628861329298958274607481091185079852827053974965402226843604196126360835628314127871794272492894246908066589163059300043457860230145025079449986855914338755579873208034769049845635890960693359375E-100')
>>> 10**-1000
0.0
>>> Decimal(10**-1000)
Decimal('0')

Is there a way to make sure Decimal('0) times something returns actually 0?

Using python 3.4.3 or python 3.5.1 I'm surprised to see that:
from decimal import Decimal
Decimal('0') * Decimal('123.456789123456')
returns:
Decimal('0E-12')
Worse part is that this specific use case works with float.
Is there anything I could do to make sure the maths work and 0 multiplied by anything returns 0?
0E-12 actually is 0 (it's short for 0 * 10 ** -12; since the coefficient is 0, that's still 0), Decimal just provides the E-12 bit to indicate the "confidence level" of the 0. What you've got will still behave like zero (it's falsy, additive identity, etc.), the only quirk is in how it prints.
If you need formatting to match, you can use the formatting mini-language, or you can call .normalize() on the result, which will turn Decimal('0E-12') into Decimal('0') (the method's purpose is to strip trailing zeroes from the result to produce a minimal canonical form that represents all equal numbers the same way).
Even though Decimal('0E-12') is not visually the same as Decimal('0'), there is no difference to python.
>>> Decimal('0E-12') == 0
True
The notation 0E-12 actually represents: 0 * 10 ** -12. This expression evaluates to 0.
You may quantize your result to required precision.
from decimal import Decimal, ROUND_HALF_UP
result = Decimal('0') * Decimal('123.456789123456')
result.quantize(Decimal('.01'), rounding = ROUND_HALF_UP)
>>>Decimal('0.00')
For more info (eg. about rounding modes or even setting up a context for all decimals) refer to https://docs.python.org/3/library/decimal.html
Edit: I guess your best hit would be using result.normalize() method as mentioned by ShadowRanger.
Do the multiplication with floats and convert to decimal afterwards.
x = 0
y = 123.456789123456
Decimal(x*y)
returns (on Python 3.5.2):
Decimal('0')

Python, infinite floats?

What I wanted to do:
Paradox: Suppose Peter Parker were running to catch a bus. To reach it, he’d first need to get halfway there. Before that, he’d need to get a quarter of the way there……before a quarter, an eighth; before an eighth, a 16th; and so on. Since the distance can be halved infinitely, he’d be trying to complete an infinite number of tasks… WHICH WOULD BE LOGICALLY IMPOSSIBLE!
I tried to to resolve this paradox using Python
I have some questions:
How can I get a number to have no limitations with decimals? Python limits the numbers of decimals, I think to 12, How to make that number infinite?
Aparrently there is no way to make the float decimals infinite, the closest I could get was using this
from decimal import Decimal
Is this the correct way of asking the user for an input in numbers?
Code modified
from decimal import Decimal
def infinite_loop():
x = 0;
number = Decimal(raw_input())
while x != number:
x = x + number
number = number/2
print x
infinite_loop()
What you ask is impossible. There are no "infinite precision" floating point values in the real world of finite computing systems. If there were, a single floating point value could consume all of the system's resources. pi * d? Ooops!! pi is infinite. There goes the system!
What you can do, however, is get arbitrary precision decimal values. They're still finite, but you can choose how much precision you want (and are willing to pay for). E.g.:
>>> from decimal import Decimal
>>> x = Decimal('1.' + '0' * 200)
>>> x
Decimal('1.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000')
Now you have 200 digits of precision. Not enough? Go 400. 800. However many you like. As long as that's a finite, practical value.
If you want "infinite" precision (e.g. a decimal number that be extended as far as you have memory for), either use Python's builtin module Decimal or for more heavy computation, mpmath:
import mpmath as mp
mp.mp.dps = 100
print mp.sqrt(mp.mpf(2))
>> 1.414213562373095048801688724209698078569671875376948073176679737990732478462107038850387534327641573

generate random numbers truncated to 2 decimal places

I would like to generate uniformly distributed random numbers between 0 and 0.5, but truncated to 2 decimal places.
without the truncation, I know this is done by
import numpy as np
rs = np.random.RandomState(123456)
set = rs.uniform(size=(50,1))*0.5
could anyone help me with suggestions on how to generate random numbers up to 2 d.p. only? Thanks!
A float cannot be truncated (or rounded) to 2 decimal digits, because there are many values with 2 decimal digits that just cannot be represented exactly as an IEEE double.
If you really want what you say you want, you need to use a type with exact precision, like Decimal.
Of course there are downsides to doing that—the most obvious one for numpy users being that you will have to use dtype=object, with all of the compactness and performance implications.
But it's the only way to actually do what you asked for.
Most likely, what you actually want to do is either Joran Beasley's answer (leave them untruncated, and just round at print-out time) or something similar to Lauritz V. Thaulow's answer (get the closest approximation you can, then use explicit epsilon checks everywhere).
Alternatively, you can do implicitly fixed-point arithmetic, as David Heffernan suggests in a comment: Generate random integers between 0 and 50, keep them as integers within numpy, and just format them as fixed point decimals and/or convert to Decimal when necessary (e.g., for printing results). This gives you all of the advantages of Decimal without the costs… although it does open an obvious window to create new bugs by forgetting to shift 2 places somewhere.
decimals are not truncated to 2 decimal places ever ... however their string representation maybe
import numpy as np
rs = np.random.RandomState(123456)
set = rs.uniform(size=(50,1))*0.5
print ["%0.2d"%val for val in set]
How about this?
np.random.randint(0, 50, size=(50,1)).astype("float") / 100
That is, create random integers between 0 and 50, and divide by 100.
EDIT:
As made clear in the comments, this will not give you exact two-digit decimals to work with, due to the nature of float representations in memory. It may look like you have the exact float 0.1 in your array, but it definitely isn't exactly 0.1. But it is very very close, and you can get it closer by using a "double" datatype instead.
You can postpone this problem by just keeping the numbers as integers, and remember that they're to be divided by 100 when you use them.
hundreds = random.randint(0, 50, size=(50, 1))
Then at least the roundoff won't happen until at the last minute (or maybe not at all, if the numerator of the equation is a multiple of the denominator).
I managed to find another alternative:
import numpy as np
rs = np.random.RandomState(123456)
set = rs.uniform(size=(50,2))
for i in range(50):
for j in range(2):
set[i,j] = round(set[i,j],2)

Categories