Repository: numpy/numpy

Issue:
Wrong std for implicitly complex input
<!-- Please describe the issue in detail here, and fill in the fields below -->

Standart deviation formula could give unexpected result (e.g. imaginary values) when input is implicitly complex.

### Reproducing code example:

<!-- A short code example that reproduces the problem/missing feature. It should be
self-contained, i.e., possible to run as-is via 'python myproblem.py' -->

```python
import numpy as np
a = np.array([None, 0])
a[0] = 1j
b = np.array([1j, 0])

print(f'res={np.std(a)}, dtype={a.dtype}') # gives imaginary std
print(f'res={np.std(b)}, dtype={b.dtype}')

```

<!-- Remove these sections for a feature request -->

### Error message:

<!-- If you are reporting a segfault please include a GDB traceback, which you
can generate by following
https://github.com/numpy/numpy/blob/master/doc/source/dev/development_environment.rst#debugging -->

<!-- Full error message, if any (starting from line Traceback: ...) -->

### Numpy/Python version information:
numpy 1.16.2
python 3.7

<!-- Output from 'import sys, numpy; print(numpy.__version__, sys.version)' -->
res=0.5j, dtype=object
res=0.5, dtype=complex128



Discussion:
I'd bet this is a somewhat pervasive issue...
I’m not sure that you could make object arrays still useful and prevent this kind of thing. 

Types can only help you if you actually use them. Making an object array is opting out of that help. 
@ewmoore: The only reason this is a problem is an incorrect optimization that avoids calling `conjugate` on non-complex arrays (which would make an unnecessary copy):
https://github.com/numpy/numpy/blob/6b3ea20d3eea2813826adb35254347a99c094a50/numpy/core/_methods.py#L118-L121

If the optimization is reframed as avoiding calling conjugate on `floating` or `integer` arrays, then this problem would go away.
I think conjugate on object used to be broken, but it is not anymore, so we should fix this!
@eric-wieser, sorry for the noise then.  I didn't look, and assumed what the bug was.
Hmmm, of course fixing it could in principle break arrays with object types that do not support `.conjugate()`, although `decimal.Decimal` and the built-in numerical types all do (at least by now) I believe.

Resolving patch:
diff --git a/numpy/core/_methods.py b/numpy/core/_methods.py
--- a/numpy/core/_methods.py
+++ b/numpy/core/_methods.py
@@ -115,10 +115,11 @@ def _var(a, axis=None, dtype=None, out=None, ddof=0, keepdims=False):
     # Note that x may not be inexact and that we need it to be an array,
     # not a scalar.
     x = asanyarray(arr - arrmean)
-    if issubclass(arr.dtype.type, nt.complexfloating):
-        x = um.multiply(x, um.conjugate(x), out=x).real
-    else:
+    if issubclass(arr.dtype.type, (nt.floating, nt.integer)):
         x = um.multiply(x, x, out=x)
+    else:
+        x = um.multiply(x, um.conjugate(x), out=x).real
+
     ret = umr_sum(x, axis, dtype, out, keepdims)
 
     # Compute degrees of freedom and make sure it is not negative.


Test patch:
diff --git a/numpy/core/tests/test_numeric.py b/numpy/core/tests/test_numeric.py
--- a/numpy/core/tests/test_numeric.py
+++ b/numpy/core/tests/test_numeric.py
@@ -216,6 +216,9 @@ def test_var(self):
             assert_(np.isnan(np.var([])))
             assert_(w[0].category is RuntimeWarning)
 
+        B = np.array([None, 0])
+        B[0] = 1j
+        assert_almost_equal(np.var(B), 0.25)
 
 class TestIsscalar(object):
     def test_isscalar(self):