<p dir="auto">(Numpy Version 1.8)</p>
<p dir="auto">See the following example for the precision where it happens:</p>
<ol dir="auto">
<li></li>
</ol>
<code class="notranslate">
In [68]: numpy.histogramdd([0.9999995], bins=[[0, 0.5, 1]])
Out[68]: (array([ 1.,  0.]), [array([ 0. ,  0.5,  1. ])])
</code>
<p dir="auto">As you can see the entry lands in the wrong bin.<br>
Lowering the value by 10^-7 suddenly makes the jump to the last bin (which is correct):<br>
2)<br>
<code class="notranslate"><br>
In [69]: numpy.histogramdd([0.9999994], bins=[[0, 0.5, 1]])<br>
Out[69]: (array([ 0.,  1.]), [array([ 0. ,  0.5,  1. ])])<br>
</code></p>
<p dir="auto">Interestingly, increasing the 2nd to last edge value to a high precision also helps:<br>
3)<br>
<code class="notranslate"><br>
In [88]: numpy.histogramdd([0.9999999997], bins=[[0, 0.99999,   1]])<br>
Out[88]: (array([ 0.,  1.]), [array([ 0.     ,  0.99999,  1.     ])]<br>
</code></p>
<p dir="auto">Standard numpy.histogram behaves as expected to arbitrary high values close to 1:<br>
4)<br>
<code class="notranslate"><br>
In [71]: numpy.histogram(0.99999999999, bins=[0, 0.5, 1])<br>
Out[71]: (array([0, 1]), array([ 0. ,  0.5,  1. ]))<br>
</code></p>
<p dir="auto">The whole issue is only there for the rightmost boundary, not for intermediate ones. But as you can see in snippet 3), it has to do with the 2nd to last edge-value aswell.<br>
I hope it gets fixed soon. The precision is not that high (cosine of small angles can easily be in this regime - actually for my work it is) and a wrong bin is populated... if unnoticed wrong results are the outcome.</p>
<p dir="auto">My numpy  version is 1.6.1-6 on ubuntu 12.04 64-bit with python 2.7.3.</p>
<p dir="auto">I want to create histograms with the function histogramdd.<br>
When I have data points that are very close to the rightmost bin-edge, they will land in the wrong bin, that is, in the second-to-right bin, instead of the rightmost bin!</p>
<p dir="auto">Here is some code to reproduce this behavior:</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="&gt;&gt;&gt; import numpy as np
&gt;&gt;&gt; x = np.random.randint(0,3,100)
&gt;&gt;&gt; edges = [[-0.5, 0.5, 1.5, 2+1e-7]]
&gt;&gt;&gt; np.histogramdd(x,edges)
(array([ 33.,  67.,   0.]),
 [array([-0.5      ,  0.5      ,  1.5      ,  2.0000001])])"><pre class="notranslate"><span class="pl-c1">&gt;&gt;</span><span class="pl-c1">&gt;</span> <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-c1">&gt;&gt;</span><span class="pl-c1">&gt;</span> <span class="pl-s1">x</span> <span class="pl-c1">=</span> <span class="pl-s1">np</span>.<span class="pl-s1">random</span>.<span class="pl-en">randint</span>(<span class="pl-c1">0</span>,<span class="pl-c1">3</span>,<span class="pl-c1">100</span>)
<span class="pl-c1">&gt;&gt;</span><span class="pl-c1">&gt;</span> <span class="pl-s1">edges</span> <span class="pl-c1">=</span> [[<span class="pl-c1">-</span><span class="pl-c1">0.5</span>, <span class="pl-c1">0.5</span>, <span class="pl-c1">1.5</span>, <span class="pl-c1">2</span><span class="pl-c1">+</span><span class="pl-c1">1e-7</span>]]
<span class="pl-c1">&gt;&gt;</span><span class="pl-c1">&gt;</span> <span class="pl-s1">np</span>.<span class="pl-en">histogramdd</span>(<span class="pl-s1">x</span>,<span class="pl-s1">edges</span>)
(<span class="pl-en">array</span>([ <span class="pl-c1">33.</span>,  <span class="pl-c1">67.</span>,   <span class="pl-c1">0.</span>]),
 [<span class="pl-en">array</span>([<span class="pl-c1">-</span><span class="pl-c1">0.5</span>      ,  <span class="pl-c1">0.5</span>      ,  <span class="pl-c1">1.5</span>      ,  <span class="pl-c1">2.0000001</span>])])</pre></div>
<p dir="auto">The last bin is empty and all data points with value 2 are in the second bin.<br>
Note that the last bin edge is very close to 2 but not exactly 2!<br>
This doesn't happen using the 1d function:</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="&gt;&gt;&gt; np.histogram(x,edges[0])
(array([33, 37, 30]), array([-0.5      ,  0.5      ,  1.5      ,  2.0000001]))"><pre class="notranslate"><span class="pl-c1">&gt;&gt;</span><span class="pl-c1">&gt;</span> <span class="pl-s1">np</span>.<span class="pl-en">histogram</span>(<span class="pl-s1">x</span>,<span class="pl-s1">edges</span>[<span class="pl-c1">0</span>])
(<span class="pl-en">array</span>([<span class="pl-c1">33</span>, <span class="pl-c1">37</span>, <span class="pl-c1">30</span>]), <span class="pl-en">array</span>([<span class="pl-c1">-</span><span class="pl-c1">0.5</span>      ,  <span class="pl-c1">0.5</span>      ,  <span class="pl-c1">1.5</span>      ,  <span class="pl-c1">2.0000001</span>]))</pre></div>
<p dir="auto">The problem seems to be in line 347 of function_base.py (in my version):</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="    for i in arange(D):
        Ncount[i] = digitize(sample[:,i], edges[i])"><pre class="notranslate">    <span class="pl-k">for</span> <span class="pl-s1">i</span> <span class="pl-c1">in</span> <span class="pl-en">arange</span>(<span class="pl-v">D</span>):
        <span class="pl-v">Ncount</span>[<span class="pl-s1">i</span>] <span class="pl-c1">=</span> <span class="pl-en">digitize</span>(<span class="pl-s1">sample</span>[:,<span class="pl-s1">i</span>], <span class="pl-s1">edges</span>[<span class="pl-s1">i</span>])</pre></div>
<p dir="auto">...together with the following code (line 356ff), where all the data points that fall on the rightmost edge are shifted one bin to the left:</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="        if not np.isinf(mindiff):
            decimal = int(-log10(mindiff)) + 6
            # Find which points are on the rightmost edge.
            on_edge = where(around(sample[:,i], decimal) == around(edges[i][-1],
                                                                   decimal))[0]"><pre class="notranslate">        <span class="pl-k">if</span> <span class="pl-c1">not</span> <span class="pl-s1">np</span>.<span class="pl-en">isinf</span>(<span class="pl-s1">mindiff</span>):
            <span class="pl-s1">decimal</span> <span class="pl-c1">=</span> <span class="pl-en">int</span>(<span class="pl-c1">-</span><span class="pl-en">log10</span>(<span class="pl-s1">mindiff</span>)) <span class="pl-c1">+</span> <span class="pl-c1">6</span>
            <span class="pl-c"># Find which points are on the rightmost edge.</span>
            <span class="pl-s1">on_edge</span> <span class="pl-c1">=</span> <span class="pl-en">where</span>(<span class="pl-en">around</span>(<span class="pl-s1">sample</span>[:,<span class="pl-s1">i</span>], <span class="pl-s1">decimal</span>) <span class="pl-c1">==</span> <span class="pl-en">around</span>(<span class="pl-s1">edges</span>[<span class="pl-s1">i</span>][<span class="pl-c1">-</span><span class="pl-c1">1</span>],
                                                                   <span class="pl-s1">decimal</span>))[<span class="pl-c1">0</span>]</pre></div>
<p dir="auto">What happens is that the data points that are 2 fall into the 3rd bin, because they are smaller then the last edge 2.0000001. The 'digitize' function would put all points that were exactly 2.0000001  into an outlier bin! Then, in order to correct for the edge-points that were classified as outliers, these are shifted one bin to the left. However, to find them the data points and edges are rounded to 'decimal' precision, which has not be done in the first 'digitize' operation. So this time all the 2s are thought to be on the edge and shifted to the 2nd bin, although they were already in the correct bin!</p>
<p dir="auto">I recommend to change line 347 to round the edges already here to 'decimal' precision:</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="    for i in arange(D):
        if not np.isinf(mindiff):
            decimal = int(-log10(mindiff)) + 6
            Ncount[i] = digitize(sample[:,i], around(edges[i], decimal))
        else:
            Ncount[i] = digitize(sample[:,i], edges[i])"><pre class="notranslate">    <span class="pl-k">for</span> <span class="pl-s1">i</span> <span class="pl-c1">in</span> <span class="pl-en">arange</span>(<span class="pl-v">D</span>):
        <span class="pl-k">if</span> <span class="pl-c1">not</span> <span class="pl-s1">np</span>.<span class="pl-en">isinf</span>(<span class="pl-s1">mindiff</span>):
            <span class="pl-s1">decimal</span> <span class="pl-c1">=</span> <span class="pl-en">int</span>(<span class="pl-c1">-</span><span class="pl-en">log10</span>(<span class="pl-s1">mindiff</span>)) <span class="pl-c1">+</span> <span class="pl-c1">6</span>
            <span class="pl-v">Ncount</span>[<span class="pl-s1">i</span>] <span class="pl-c1">=</span> <span class="pl-en">digitize</span>(<span class="pl-s1">sample</span>[:,<span class="pl-s1">i</span>], <span class="pl-en">around</span>(<span class="pl-s1">edges</span>[<span class="pl-s1">i</span>], <span class="pl-s1">decimal</span>))
        <span class="pl-k">else</span>:
            <span class="pl-v">Ncount</span>[<span class="pl-s1">i</span>] <span class="pl-c1">=</span> <span class="pl-en">digitize</span>(<span class="pl-s1">sample</span>[:,<span class="pl-s1">i</span>], <span class="pl-s1">edges</span>[<span class="pl-s1">i</span>])</pre></div>
<p dir="auto">I hope I could make clear what the problem is. For now I found the error and can design my bin-edges to be far enough away or exactly at the maximum of the data. But it would be nice if this could be fixed in future releases.</p>