Why is sin(pi/4) different from cos(pi/4) in python? [duplicate] - python-2.7

This question already has answers here:
Why does floating-point arithmetic not give exact results when adding decimal fractions?
(31 answers)
Closed 8 years ago.
I wonder why this statement is evaluated false:
>>> from numpy import sin,cos,pi
>>> sin(pi/4)==cos(pi/4)
False
in fact sine and cosine of pi/4 should be √ 2 / 2. What's happen? And how to avoid this problem?

If you look at what the results actually are:
>>> sin(pi/4)
0.70710678118654746
>>> cos(pi/4)
0.70710678118654757
You will note that they are very, very close, but not exactly the same. Due to these kinds of floating point representation issues, it is usual to use a threshold to compare values that should be the same:
>>> abs(sin(pi/4) - cos(pi/4)) < 1e-9
True
Fun fact: using numpy's sqrt, too:
>>> sqrt(2)/2
0.70710678118654757
>>> sqrt(2)/2 == cos(pi/4)
True

Because floating point representation isn't always exact and functions like cos and sin are calculated by approximate numerical methods, it is unreasonable to imagine that the results will be bitwise identical. On my machine, I get this when I compare sine and cosine
>import numpy
>x=numpy.sin(numpy.pi/4)
>y=numpy.cos(numpy.pi/4)
>print numpy.abs(x-y)/numpy.max(x,y)
1.57009245868e-16
ie. the relative error is very close to the IEEE 754 double precision epsilon. If you need to compare two floating point values, compare a delta value to a tolerance, or use numpy.allclose()

Related

For with minor or equal condition in C++ [duplicate]

This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 5 years ago.
I am doing a loop to perform some calculations from t=0 to t=1 (included).
That should be easy like this:
for(double t = 0; t<=1; t = t + 0.05)
{
DEBUG_LOG1 (LVL1, t);
//DoMaths
}
But for some reason, t is being logged from 0 to 0.95, not including t=1, as it if was t<1 instead of t<=1.
Where is the problem in my code?
This is a simple problem with types. Because it is a floating point number will will likely never get precisely 0.05 or 1.00.
Rather you'll it will try for 0.05 but really will be something like 0.050000000000000012 which added together 20 times is not 1 but more like 1.00000000000000024 and will therefore not correspond with 1.
There is not problem with your code per se since you catch the problem by using <= instead of =.
You can read more about floating point numbers on http://www.learncpp.com/cpp-tutorial/25-floating-point-numbers/
I think it may be because 0.05 is not exactly representable as a floating point value. It is only approximate. Try running this program.
#include <stdio.h>
int main()
{
double x = 0.05;
printf("%.50lf\n", x);
return 0;
}
Here I tell printf to give me a lot of excess precision. This prints out the value
0.05000000000000000277555756156289135105907917022705.
Now if I take that value and multiply and add 0.5 to it 19 times in a loop I get...
1.00000000000000022204460492503130808472633361816406
See how it is not exactly 1 but slightly greater. This is the reason comparing equality between floats leads to strange results. You can get around this by adding a small epsilon to 1. For instance compare to 1.001 in your loop.
Decimal numbers can't be accurately represented using floating types. For example 0.05 can't be accurately represented in type double and depending on the platform it might be: 0.050000000000000003 or similar. So that tiny little bit always gets added in your loop. By the time you think it is 0.95 it is actually 0.95000000000000029 or similar and adding 0.05 makes it greater than 1, hence the observed results. More info on the subject in this SO post:
Is floating point math broken?

Python trig functions not returning matched results

I came across something rather interesting while I am playing around with the math module for trigonometric calculations using tan, sin, and cos.
As stated is all math textbooks, online source, and courses, the following is true:
tan(x) = sin(x) / cos(x)
Although I came across some precision errors while using the three trig functions with the following:
from math import tan, sin, cos
theta = -30
alpha = tan(theta)
omega = sin(theta) / cos(theta)
print(alpha, omega)
print(alpha == omega)
>>> (6.405331196646276, 6.4053311966462765)
>>> (False)
I have tried a couple of different values for theta and the last digit of the results has been off by a tiny bit.
Is there something that I am missing?
This issue is because of the finite floating point precision (not all real numbers can be represented exactly and not all calculations with them are precise). An accessible guide is in the Python docs.
Using the default, "double precision" floating point representation, you can never hope for better than about 15 decimal place precision and calculations involving such numbers will tend to degrade this precision (the rounding error refered to in the above comment). In the same way, you get False from the following:
In [1]: 0.01 == (0.1)**2
Out[1]: False
because the Python isn't squaring 0.1 but the "nearest representable number" to 0.1, which is neither 0.01 nor the nearest representable number to 0.01.
D Stanley has given the correct way to test for "equality" within some absolute tolerance: (abs(a-b) < tol) where tol is some small number you choose to fit your expected precision.
As you have discovered, there is a level of imprecision when comparing floating point numbers. A common way to test for "equality" is to determine a reasonable amount of difference you want to accept (commonly called "epsilon") an compare the difference between the two numbers against that maximum error:
epsilon = 1E-14
print(alpha, omega)
print(alpha == omega)
print(abs(alpha - omega) < epsilon)
First you should notice that the arguments of trigonometric functions are given in arc length, not in degree. Thus theta=-30 refers to an angle of -30*180/pi in degrees.
Second, the processor, and thus the calling math library, has separate internal procedures for the computation of tan and (sin, cos). The extra division operation loses 1/2 to 1 bit of precision, which explains the difference in results.

Python 2.7 round 1 decimal not correct

Rounding on 1 decimal is not working correct:
See below:
round(11.35, 1)
11.3
round(1.35, 1)
1.4
How can this be solved in Python?
The solution of this problem is:
def round_decimal(value, rounding):
number = decimal.Decimal(str(value))
decimal_point = float("1e%d" % -rounding)
return float(number.quantize(decimal.Decimal(str(decimal_point))))
This is a problem with the representation of decimals in computers in general (so non-specific to Python).
The way I thought this is solved is by using the standard library module decimal. In your case it would look something like this:
num1 = decimal.Decimal("11.35")
print num1.quantize(decimal.Decimal("0.1")) # round to one decimal
# output: 11.4
num2 = decimal.Decimal("1.35")
print num2.quantize(decimal.Decimal("0.1"))
# output: 1.4
The reason for this is that 11.35 is held as a float which is stored using binary floating point representation. And 11.35 cannot be represented exactly as a binary floating point value.
Representable binary floating point values have the form s×2e where s and e are integers. Note that 11.35 cannot be written in this form. What happens in Python when you write 11.35 is that the system uses the closest representable value.
The closest double precision value to 11.35 is:
11.35 = + 11.34999 99999 99999 64472 86321 19949 90706 44378 66210 9375
This explains why round(11.35, 1) behaves as it does.
Interestingly, round(11.35, 1) isn't even exactly equal to 11.3 because 11.3 is not exactly representable using binary floating point. And so it goes on.
If you want to represent 11.35 exactly then you will need to store it in a decimal data type. The decimal standard library is the obvious way to do so in Python. This question covers that topic in some detail: How can I format a decimal to always show 2 decimal places?
In addition to the previous answers, I think it is helpful to know the rules of rounding. You assume that the value 11.35 should be rounded to 11.4, but in reality, rounding down is an option when you hit the mid-point value in rounding. See: http://en.wikipedia.org/wiki/Rounding
Using the decimal library is the best way to solve you issue in python for your case.

Why string-to-float conversion may not work? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Precision of Floating Point
Can you compare floating point values exactly to zero?
floating point issue
In my c++ code I have the string: "0.55".
And I want to convert it to float value "0.55", but all function I used give me the float value "0.55000001".
Why? How can I take the clear value?
Last version of code is:
wstring s = L"0.55";
float f = stof(s);
Floats are not exact. This is because there are infinite number of possible values, but only finite number of bits to represent them!
So because 0.55 cannot be represented, it gives you the value 0.55000001 instead.
More info can be found in: what every programmer should know about floating points arithmetics
0.55 does not have an exact binary representation. There will always be some rounding errors.
There is no float value 0.55 - the format cannot represent that value.
Read the Floating-Point Guide for a detailed explanation.
If you need an exact representation for decimal fractions, use a decimal format, such as provided by the GMP library.
you can use a little algebra and you will get 0.55
wstring s = L"0.55";
float f = stof(s);
use floor function
f = floor(f);

C++ Cosine Problem

I have the following code using C++:
double value = .3;
double result = cos(value);
When I look at the values in the locals window for "value" it shows 0.2999999999
Then, when I get the value of "result" I get: 0.95533648912560598
However, when I run cos(.3) on the computers calculator I get: .9999862922474
So clearly there is something that I am doing wrong.
Any thoughts on what might be causing the difference in results?
I am running Win XP on an Intel processor.
Thanks
The difference in results is because:
Your computer's calculator is returning the cosine of an angle specified in degrees.
The C++ cos() function is returning cosine of an angle specified in radians.
The .2999999999 is due to the way floating point numbers are handled in computers. .3 cannot be represented exactly in a double. For details, I recommend reading What Every Computer Scientist Should Know about Floating Point Arithmetic.
cos(.3 radians) = 0.95533...
cos(.3 degrees) = 0.99998...
cos(0.3) = 0.99998629224742679269138848004408 using degrees
cos(0.3) = 0,95533648912560601964231022756805 using radians
When I look at the values in the locals window for "value" it shows 0.2999999999
Long story short, your calculator uses decimal arithmetic, while your C++ code uses binary arithmetic (double is a binary floating-point number). Decimal number 0.3 cannot be represented exactly as a binary floating-point number. Read What Every Computer Scientist Should Know About Floating-Point Arithmetic, that will explain all implications in more detail.
Your calculator is using degrees. For example:
>>> import math
>>> math.cos (.3)
0.95533648912560598
>>> math.cos (.3 * math.pi / 180) # convert to degrees
0.99998629224742674
C++ does not exactly represent floating point numbers due to the insane amount of storage that would be required to get the infinite precision necessary. For a demonstration of this, try the following:
double ninth = 1.0/9.0;
double result = 9.0 * ninth;
This should yield a value in result of .99999999999
So, in essence, you need to compare floating point values within a small epsilon (I tend to use 1e-7). You can do a strict bit-by-bit comparison, but this consists of converting the memory used by the floating point to an array of characters of length sizeof(float), then comparing the characters.
Another thing to check would be whether or not you are using degrees. The computer's calculator uses degrees for its cosine calculation (notice how the result from the calculator is .99999..., which is very close to 1. The cosine of zero is 1 exactly), whereas the cosine function offered in <math> is in radians. Try multiplying your value by PI/180.0 and seeing if the result is more inline with your expectations.