<p dir="auto">This issue has been seen in both python 2 and python 3 with numpy.</p>
<p dir="auto">Consider such numpy arrya <code class="notranslate">b = numpy.array([[]])</code>. <code class="notranslate">print(len(b))</code> would result in 1, <code class="notranslate">print(b.size)</code> would result in 0, and <code class="notranslate">print(b)</code> would result in [], as implemented in /numpy/core/arrayprint.py around line 665.</p>
<p dir="auto">We found this when debuging in our own project, where we need to check whether an array is empty or not. More description can be seen in this <a href="http://allenshieh.github.io/pythoncon/" rel="nofollow">blog</a>. We think when array size is 0, but it has some [] in the array, the printing should not just print an empty array out (actually it is completely not empty!).</p>
<p dir="auto">The output of <code class="notranslate">np.expm1</code> becomes unstable for small values (around 10^{-15} to 10^{-16}) when the argument is complex. This does not seem to be an issue with the numerical precision associated with the real and imaginary components: using a <code class="notranslate">float32</code> data type works as expected.</p>
<p dir="auto">The problem arises because of the way <code class="notranslate">expm1</code> is <a href="https://github.com/numpy/numpy/blob/deea4983aedfa96905bbaee64e3d1de84144303f/numpy/core/src/umath/funcs.inc.src#L360-L367">currently implemented</a> for complex arguments. In particular:</p>
<div class="highlight highlight-source-c notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="static void
nc_expm1@c@(@ctype@ *x, @ctype@ *r)
{
    @ftype@ a = npy_exp@c@(x-&gt;real);
    // If x-&gt;imag == 0, then we evaluate exp(x-&gt;real) - 1 naively 
    // rather than using a more stable implementation
    r-&gt;real = a*npy_cos@c@(x-&gt;imag) - 1.0@c@;
    r-&gt;imag = a*npy_sin@c@(x-&gt;imag);
    return;
}"><pre class="notranslate"><span class="pl-k">static</span> <span class="pl-smi">void</span>
<span class="pl-s1">nc_expm1</span>@<span class="pl-s1">c</span>@(@<span class="pl-s1">ctype</span>@ <span class="pl-c1">*</span><span class="pl-s1">x</span>, @<span class="pl-s1">ctype</span>@ <span class="pl-c1">*</span><span class="pl-s1">r</span>)
{
    @<span class="pl-s1">ftype</span>@ <span class="pl-s1">a</span> <span class="pl-c1">=</span> <span class="pl-s1">npy_exp</span>@<span class="pl-s1">c</span>@(<span class="pl-s1">x</span><span class="pl-c1">-&gt;</span><span class="pl-c1">real</span>);
    <span class="pl-c">// If x-&gt;imag == 0, then we evaluate exp(x-&gt;real) - 1 naively </span>
    <span class="pl-c">// rather than using a more stable implementation</span>
    <span class="pl-s1">r</span><span class="pl-c1">-&gt;</span><span class="pl-c1">real</span> <span class="pl-c1">=</span> <span class="pl-s1">a</span><span class="pl-c1">*</span><span class="pl-s1">npy_cos</span>@<span class="pl-s1">c</span>@(<span class="pl-s1">x</span><span class="pl-c1">-&gt;</span><span class="pl-c1">imag</span>) <span class="pl-c1">-</span> <span class="pl-c1">1.0</span>@<span class="pl-s1">c</span>@;
    <span class="pl-s1">r</span><span class="pl-c1">-&gt;</span><span class="pl-c1">imag</span> <span class="pl-c1">=</span> <span class="pl-s1">a</span><span class="pl-c1">*</span><span class="pl-s1">npy_sin</span>@<span class="pl-s1">c</span>@(<span class="pl-s1">x</span><span class="pl-c1">-&gt;</span><span class="pl-c1">imag</span>);
    <span class="pl-k">return</span>;
}</pre></div>
<h3 dir="auto">Reproducing code example:</h3>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="import numpy as np
from matplotlib import pyplot as plt

fig, ax = plt.subplots()

x = np.logspace(-16.2, -14)
xs = [
    x,
    x.astype(np.complex),
    x.astype(np.float32),
]

ys = [np.expm1(x_) for x_ in xs]

for x, y in zip(xs, ys):
    ax.plot(x, y, marker='.', label=f'{x.dtype}: np.expm(x)')

ax.set_xscale('log')
ax.set_yscale('log')
ax.set_xlabel('x')
ax.legend(loc='upper left')

fig.tight_layout()"><pre class="notranslate"><span class="pl-k">import</span> <span class="pl-s1">numpy</span> <span class="pl-k">as</span> <span class="pl-s1">np</span>
<span class="pl-k">from</span> <span class="pl-s1">matplotlib</span> <span class="pl-k">import</span> <span class="pl-s1">pyplot</span> <span class="pl-k">as</span> <span class="pl-s1">plt</span>

<span class="pl-s1">fig</span>, <span class="pl-s1">ax</span> <span class="pl-c1">=</span> <span class="pl-s1">plt</span>.<span class="pl-en">subplots</span>()

<span class="pl-s1">x</span> <span class="pl-c1">=</span> <span class="pl-s1">np</span>.<span class="pl-en">logspace</span>(<span class="pl-c1">-</span><span class="pl-c1">16.2</span>, <span class="pl-c1">-</span><span class="pl-c1">14</span>)
<span class="pl-s1">xs</span> <span class="pl-c1">=</span> [
    <span class="pl-s1">x</span>,
    <span class="pl-s1">x</span>.<span class="pl-en">astype</span>(<span class="pl-s1">np</span>.<span class="pl-s1">complex</span>),
    <span class="pl-s1">x</span>.<span class="pl-en">astype</span>(<span class="pl-s1">np</span>.<span class="pl-s1">float32</span>),
]

<span class="pl-s1">ys</span> <span class="pl-c1">=</span> [<span class="pl-s1">np</span>.<span class="pl-en">expm1</span>(<span class="pl-s1">x_</span>) <span class="pl-k">for</span> <span class="pl-s1">x_</span> <span class="pl-c1">in</span> <span class="pl-s1">xs</span>]

<span class="pl-k">for</span> <span class="pl-s1">x</span>, <span class="pl-s1">y</span> <span class="pl-c1">in</span> <span class="pl-en">zip</span>(<span class="pl-s1">xs</span>, <span class="pl-s1">ys</span>):
    <span class="pl-s1">ax</span>.<span class="pl-en">plot</span>(<span class="pl-s1">x</span>, <span class="pl-s1">y</span>, <span class="pl-s1">marker</span><span class="pl-c1">=</span><span class="pl-s">'.'</span>, <span class="pl-s1">label</span><span class="pl-c1">=</span><span class="pl-s">f'<span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">x</span>.<span class="pl-s1">dtype</span><span class="pl-kos">}</span></span>: np.expm(x)'</span>)

<span class="pl-s1">ax</span>.<span class="pl-en">set_xscale</span>(<span class="pl-s">'log'</span>)
<span class="pl-s1">ax</span>.<span class="pl-en">set_yscale</span>(<span class="pl-s">'log'</span>)
<span class="pl-s1">ax</span>.<span class="pl-en">set_xlabel</span>(<span class="pl-s">'x'</span>)
<span class="pl-s1">ax</span>.<span class="pl-en">legend</span>(<span class="pl-s1">loc</span><span class="pl-c1">=</span><span class="pl-s">'upper left'</span>)

<span class="pl-s1">fig</span>.<span class="pl-en">tight_layout</span>()</pre></div>
<p dir="auto">Virtually identical behaviour can be observed by replacing <code class="notranslate">ys = [np.expm1(x_) for x_ in xs]</code> with <code class="notranslate">ys = [-np.expm1(-x_) for x_ in xs]</code>, i.e. the problem is not unique to positive values of the argument.</p>
<p dir="auto"><a target="_blank" rel="noopener noreferrer nofollow" href="https://user-images.githubusercontent.com/966348/61252620-025a2900-a756-11e9-910d-8b06c7d9221d.png"><img src="https://user-images.githubusercontent.com/966348/61252620-025a2900-a756-11e9-910d-8b06c7d9221d.png" alt="image" style="max-width: 100%;"></a></p>
<h3 dir="auto">Error message:</h3>
<p dir="auto">No error message to report. However, the expected behaviour would be for the complex datatype to behave in the same fashion as the float32 and float64 data types.</p>
<h3 dir="auto">Numpy/Python version information:</h3>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="1.16.4 3.7.2 (default, Jul 11 2019, 09:18:04) 
[Clang 10.0.1 (clang-1001.0.46.4)]"><pre class="notranslate"><code class="notranslate">1.16.4 3.7.2 (default, Jul 11 2019, 09:18:04) 
[Clang 10.0.1 (clang-1001.0.46.4)]
</code></pre></div>