I am trying to generate a square wave starting from a sine wave using numpy.
I ran into a problem where:
numpy.pi
constant gives inaccurate results3.14
constant gives me the correct resultTo 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:
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.
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:
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.