How to generate positive and negative random numbers in VHDL
In your code, you have:

x_int := integer(floor(x_real * real(2**W)));


Your generated values for x_int are in the range of 0 to 2**W, so for W=16, you get values from 0 to 65535.

But then next up you convert to a signed vector:

data_vec := std_logic_vector( to_signed( x_int, data_vec'LENGTH ) );


The problem is that a signed value of W bits can only represent -2W-1 to 2W-1-1.  So anytime the call to uniform generates a value greater than 2W-1-1, you exceed the range of your vector.

Since uniform returns a value in the range (0.0, 1.0), you need to scale your random value to be (-1.0, 1.0), then apply 2W-1.  Though this is equivalent to scaling your random value to (-0.5, 0.5) and then apply 2W.

EDIT:  Alternatively, you can use to_unsigned, for which 2W is fine (unsigned vectors have a range of 0 to 2W-1).  And since this is just going into an amorphous vector, will work fine.

data_vec := std_logic_vector( to_unsigned( x_int, data_vec'LENGTH ) );