Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Precision issue when using numpy.sin

I am trying to generate a square wave starting from a sine wave using numpy.
I ran into a problem where:

  • using the numpy.pi constant gives inaccurate results
  • using the 3.14 constant gives me the correct result

To create the square wave the sign of the sine wave is taken and then the -1s are transformed into 0s using the maximum function.

N = 15
x = np.arange(1, N)
s = np.maximum(np.sign(np.sin(3.14 * (x - 1))), np.zeros_like(x))
print(s)

>> [0. 1. 0. 1. 0. 1. 0. 1. 0. 1. 0. 1. 0. 1.]

While using the constant for pi in numpy gives:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

N = 15
x = np.arange(1, N)
s = np.maximum(np.sign(np.sin(np.pi * (x - 1))), np.zeros_like(x))
print(s)

>> [0. 1. 0. 1. 0. 1. 0. 1. 0. 1. 0. 1. 0. 0.]

where the sequence is not alternating 1s and 0s. With more elements you can observe patches of more than two 0s next to each other.

[0. 1. 0. 1. 0. 1. 0. 1. 0. 1. 0. 1. 0. 0. 0. 1. 0. 0. 0.]

I am mostly trying to understand how using more precise values can lead to imprecise results.

>Solution :

Your computation is numerically unstable. Using a higher precision will not solve the problem but just hide it a little bit more. The main issue is that sin(PI * x) should be theoretically always 0, but no floating-point function is perfect, so there is an error (typically 1 ULP). This error change the sign of the result. This is what you observe. This problem is independent of the precision. Here is a geometrical illustration of what you compute:

enter image description here

If you just want alternated 0-1 values, you can add a shift to the sin function (eg. np.maximum(np.sign(np.sin(np.pi * (x - 1) + np.pi/2)), np.zeros_like(x))). If the shift is pi/2, then you can use a cos function.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading