BUG: `take` casting logic with an `out=` argument

When it receives an `out` argument, `np.take` converts the `out` array to
the dtype of the array being taken from. This results in wrong `TypeError`s
being raised when `out` has a larger dtype than the array (and not being
raised when it has a smaller dtype, even though they should):

```
>>> a = np.arange(3, dtype=np.int16) + 128
>>> b = np.empty((3,), dtype=np.int8)
>>> a.take([0, 1, 2], out=b) # wrong, should raise an error
array([-128, -127, -126], dtype=int8)
>>> b = np.empty((3,), dtype=np.int32)
>>> a.take([0, 1, 2], out=b) # perfectly OK, but raises an error
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Cannot cast array data from dtype('int32') to dtype('int16') according to the rule 'safe'
```

This PR makes an explicit casting check, then either sets `NPY_ARRAY_FORCECAST`
or explicitly raises the error.

The tests added check the logic for conversion between all pairs of ints and
floats only.