Skip to content

Commit 50e7024

Browse files
committed
[hist] Add a test for finding bins in TAxis.
The test are based on two issues brought up in the forum, a few cases designed by hand to break the old algorithm, and a test sampling random points.
1 parent 0b20443 commit 50e7024

File tree

1 file changed

+86
-0
lines changed

1 file changed

+86
-0
lines changed

hist/hist/test/test_TH1.cxx

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,3 +149,89 @@ 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+
TAxis axis(2000, -1000., 1000.);
170+
EXPECT_EQ(axis.FindFixBin(std::nextafter(-1000., -2000.)), 0);
171+
EXPECT_EQ(axis.FindFixBin(-1000.), 1);
172+
EXPECT_EQ(axis.FindFixBin(std::nextafter(-1000., 0)), 1);
173+
174+
EXPECT_EQ(axis.FindFixBin(-500.00000000001), 500);
175+
EXPECT_EQ(axis.FindFixBin(-500.), 501);
176+
EXPECT_EQ(axis.FindFixBin(-499.9), 501);
177+
178+
EXPECT_EQ(axis.FindFixBin(-1.E-20), 1000);
179+
EXPECT_EQ(axis.FindFixBin(std::nextafter(-0., -1)), 1000);
180+
EXPECT_EQ(axis.FindFixBin(-0.), 1001);
181+
EXPECT_EQ(axis.FindFixBin(0.), 1001);
182+
183+
EXPECT_EQ(axis.FindFixBin(499.9), 1500);
184+
EXPECT_EQ(axis.FindFixBin(500.), 1501);
185+
186+
EXPECT_EQ(axis.FindFixBin(1000. - 1.E-13), 2000);
187+
EXPECT_EQ(axis.FindFixBin(std::nextafter(1000., 0.)), 2000);
188+
EXPECT_EQ(axis.FindFixBin(1000.), 2001);
189+
190+
EXPECT_EQ(axis.FindBin(std::nextafter(-1000., -2000.)), 0);
191+
EXPECT_EQ(axis.FindBin(-1000.), 1);
192+
EXPECT_EQ(axis.FindBin(std::nextafter(-1000., 0)), 1);
193+
194+
EXPECT_EQ(axis.FindBin(-500.00000000001), 500);
195+
EXPECT_EQ(axis.FindBin(-500.), 501);
196+
EXPECT_EQ(axis.FindBin(-499.9), 501);
197+
198+
EXPECT_EQ(axis.FindBin(-1.E-20), 1000);
199+
EXPECT_EQ(axis.FindBin(std::nextafter(-0., -1)), 1000);
200+
EXPECT_EQ(axis.FindBin(-0.), 1001);
201+
EXPECT_EQ(axis.FindBin(0.), 1001);
202+
203+
EXPECT_EQ(axis.FindBin(499.9), 1500);
204+
EXPECT_EQ(axis.FindBin(500.), 1501);
205+
206+
EXPECT_EQ(axis.FindBin(1000. - 1.E-13), 2000);
207+
EXPECT_EQ(axis.FindBin(std::nextafter(1000., 0.)), 2000);
208+
EXPECT_EQ(axis.FindBin(1000.), 2001);
209+
}
210+
211+
for (const auto & [low, high] : std::initializer_list<std::pair<long double, long double>>{{-10654.1l, 32165.l},
212+
{-1.0656E23l, -20654.l},
213+
{1.1234E4l, 4.5678E20l},
214+
{1.E-60l, 1.E-20l},
215+
{-1.E-20l, -1.E-60l}}) {
216+
constexpr int N = 100;
217+
const double width = (high - low) / N;
218+
std::mt19937 gen;
219+
std::uniform_real_distribution dist{low - width, high + width};
220+
TAxis axis(N, low, high);
221+
for (unsigned int i = 0; i < 100000; ++i) {
222+
long double x = dist(gen);
223+
if (i == 0) {
224+
x = std::nextafter(double(high), double(low));
225+
}
226+
const auto bin = axis.FindFixBin(x);
227+
if (x < double(low))
228+
EXPECT_EQ(bin, 0);
229+
else
230+
EXPECT_EQ(bin, 1 + int((x - low) / width))
231+
<< x << "[" << low << "," << high << "]"; // Note: Bin computation in long double here
232+
EXPECT_LE(axis.GetBinLowEdge(bin), x);
233+
EXPECT_LT(x, axis.GetBinUpEdge(bin));
234+
EXPECT_EQ(bin, axis.FindBin(x));
235+
}
236+
}
237+
}

0 commit comments

Comments
 (0)