Skip to content

Commit eab0ca7

Browse files
committed
[hist] Add a test for finding bins in TAxis.
The tests are based on two issues brought up in the forum, a few cases designed by hand to break the old algorithm, github issue #14105, and a test sampling 100 random points.
1 parent ca7740f commit eab0ca7

File tree

1 file changed

+98
-0
lines changed

1 file changed

+98
-0
lines changed

hist/hist/test/test_TH1.cxx

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,3 +149,101 @@ TEST(TH1, Normalize)
149149
EXPECT_FLOAT_EQ(v2.Integral("width"), 1.);
150150
EXPECT_FLOAT_EQ(v2.GetMaximum(), 7.9999990);
151151
}
152+
153+
TEST(TAxis, BinComputation_FPAccuracy)
154+
{
155+
// Example from 1703c54
156+
EXPECT_EQ(TAxis(1, -1., 0.).FindBin(-1e-17), 1);
157+
158+
{
159+
// https://root-forum.cern.ch/t/floating-point-rounding-error-when-filling-the-histogram/35189
160+
TAxis axis(128, -0.352, 0.352);
161+
constexpr double x = -0.0220;
162+
EXPECT_EQ(axis.FindBin(x), 61);
163+
EXPECT_EQ(axis.FindFixBin(x), 61);
164+
EXPECT_LE(axis.GetBinLowEdge(61), x);
165+
EXPECT_GT(axis.GetBinUpEdge(61), x);
166+
}
167+
168+
{
169+
// https://github.com/root-project/root/issues/14091
170+
constexpr int nBins = 30;
171+
constexpr double xMin=3.0, xMax=6.0;
172+
TAxis ax(nBins, xMin, xMax);
173+
174+
for (Int_t i=1; i <= ax.GetNbins(); i++) {
175+
EXPECT_EQ(i, ax.FindBin(ax.GetBinLowEdge(i)));
176+
}
177+
}
178+
179+
{
180+
TAxis axis(2000, -1000., 1000.);
181+
EXPECT_EQ(axis.FindFixBin(std::nextafter(-1000., -2000.)), 0);
182+
EXPECT_EQ(axis.FindFixBin(-1000.), 1);
183+
EXPECT_EQ(axis.FindFixBin(std::nextafter(-1000., 0)), 1);
184+
185+
EXPECT_EQ(axis.FindFixBin(-500.00000000001), 500);
186+
EXPECT_EQ(axis.FindFixBin(-500.), 501);
187+
EXPECT_EQ(axis.FindFixBin(-499.9), 501);
188+
189+
EXPECT_EQ(axis.FindFixBin(-1.E-20), 1000);
190+
EXPECT_EQ(axis.FindFixBin(std::nextafter(-0., -1)), 1000);
191+
EXPECT_EQ(axis.FindFixBin(-0.), 1001);
192+
EXPECT_EQ(axis.FindFixBin(0.), 1001);
193+
194+
EXPECT_EQ(axis.FindFixBin(499.9), 1500);
195+
EXPECT_EQ(axis.FindFixBin(500.), 1501);
196+
197+
EXPECT_EQ(axis.FindFixBin(1000. - 1.E-13), 2000);
198+
EXPECT_EQ(axis.FindFixBin(std::nextafter(1000., 0.)), 2000);
199+
EXPECT_EQ(axis.FindFixBin(1000.), 2001);
200+
201+
EXPECT_EQ(axis.FindBin(std::nextafter(-1000., -2000.)), 0);
202+
EXPECT_EQ(axis.FindBin(-1000.), 1);
203+
EXPECT_EQ(axis.FindBin(std::nextafter(-1000., 0)), 1);
204+
205+
EXPECT_EQ(axis.FindBin(-500.00000000001), 500);
206+
EXPECT_EQ(axis.FindBin(-500.), 501);
207+
EXPECT_EQ(axis.FindBin(-499.9), 501);
208+
209+
EXPECT_EQ(axis.FindBin(-1.E-20), 1000);
210+
EXPECT_EQ(axis.FindBin(std::nextafter(-0., -1)), 1000);
211+
EXPECT_EQ(axis.FindBin(-0.), 1001);
212+
EXPECT_EQ(axis.FindBin(0.), 1001);
213+
214+
EXPECT_EQ(axis.FindBin(499.9), 1500);
215+
EXPECT_EQ(axis.FindBin(500.), 1501);
216+
217+
EXPECT_EQ(axis.FindBin(1000. - 1.E-13), 2000);
218+
EXPECT_EQ(axis.FindBin(std::nextafter(1000., 0.)), 2000);
219+
EXPECT_EQ(axis.FindBin(1000.), 2001);
220+
}
221+
222+
for (const auto & [low, high] : std::initializer_list<std::pair<long double, long double>>{{-10654.1l, 32165.l},
223+
{-1.0656E23l, -20654.l},
224+
{1.1234E4l, 4.5678E20l},
225+
{1.E-60l, 1.E-20l},
226+
{-1.E-20l, -1.E-60l}}) {
227+
constexpr int N = 100;
228+
const double width = (high - low) / N;
229+
std::mt19937 gen;
230+
std::uniform_real_distribution dist{low - width, high + width};
231+
TAxis axis(N, low, high);
232+
for (unsigned int i = 0; i < 100000; ++i) {
233+
long double x = dist(gen);
234+
if (i == 0) {
235+
x = std::nextafter(double(high), double(low));
236+
}
237+
const auto bin = axis.FindFixBin(x);
238+
EXPECT_EQ(bin, axis.FindBin(x));
239+
240+
if (x < double(low))
241+
EXPECT_EQ(bin, 0);
242+
else if (x >= double(high))
243+
EXPECT_EQ(bin, N+1);
244+
245+
EXPECT_LE(axis.GetBinLowEdge(bin), x);
246+
EXPECT_LT(x, axis.GetBinUpEdge(bin));
247+
}
248+
}
249+
}

0 commit comments

Comments
 (0)