Skip to content

Commit 6b74c28

Browse files
egpbosguitargeek
authored andcommitted
[RF] additional RooNaNPacker tests
These are also sanity checks meant in part as code-as-documentation for users to see how things work. It turns out that GCC on the one hand and Clang and MSVC on the other hand have two different solutions for binary arithmetic operations on two NaNs. In both cases, one of the two NaNs is returned, but in one case it's the first, in the other is it's the second. The tests added in this commit will hopefully warn RooNaNPacker users of this behavior.
1 parent 6ce64ed commit 6b74c28

File tree

1 file changed

+53
-0
lines changed

1 file changed

+53
-0
lines changed

roofit/roofitcore/test/testNaNPacker.cxx

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,59 @@ TEST(RooNaNPacker, PackedNaNPreservedAfterArithmetic)
138138
EXPECT_TRUE(rnp2.isNaNWithPayload());
139139
// nothing can harm the PackedNaN
140140
EXPECT_EQ(rnp.getPayload(), rnp2.getPayload());
141+
142+
// multiply packed NaN by 0
143+
rnp2._payload = 0. * rnp.getNaNWithPayload();
144+
EXPECT_TRUE(rnp2.isNaNWithPayload());
145+
// PackedNaN pays no mind
146+
EXPECT_EQ(rnp.getPayload(), rnp2.getPayload());
147+
148+
// the following tests have compiler dependent behavior
149+
// (note that this behavior was tested for msvc as well, even though this
150+
// whole test is currently disabled in msvc)
151+
#if defined(__clang__) || defined(_MSC_VER)
152+
// add packed NaN to regular NaN
153+
rnp2._payload = std::numeric_limits<double>::quiet_NaN() + rnp.getNaNWithPayload();
154+
// first NaN wins, though! now the payload is gone
155+
EXPECT_FALSE(rnp2.isNaNWithPayload());
156+
// a quiet NaN has a "payload" of zero
157+
EXPECT_EQ(0, rnp2.getPayload());
158+
159+
// ... other way around
160+
rnp2._payload = rnp.getNaNWithPayload() + std::numeric_limits<double>::quiet_NaN();
161+
EXPECT_TRUE(rnp2.isNaNWithPayload());
162+
// if it comes first, the PackedNaN does survive
163+
EXPECT_EQ(rnp.getPayload(), rnp2.getPayload());
164+
165+
// multiply regular NaN with packed NaN
166+
rnp2._payload = rnp.getNaNWithPayload() * std::numeric_limits<double>::quiet_NaN();
167+
EXPECT_TRUE(rnp2.isNaNWithPayload());
168+
// if it comes first, the PackedNaN does survive
169+
EXPECT_EQ(rnp.getPayload(), rnp2.getPayload());
170+
171+
// ... other way around
172+
rnp2._payload = std::numeric_limits<double>::quiet_NaN() * rnp.getNaNWithPayload();
173+
// same as with addition: the first NaN wins
174+
EXPECT_FALSE(rnp2.isNaNWithPayload());
175+
// a quiet NaN has a "payload" of zero
176+
EXPECT_EQ(0, rnp2.getPayload());
177+
#endif // defined(__clang__) || defined(_MSC_VER)
178+
#if defined(__GNUC__) && !defined(__clang__)
179+
// on gcc, a different NaN is preserved than in clang and msvc!
180+
181+
// add packed NaN to regular NaN
182+
rnp2._payload = rnp.getNaNWithPayload() + std::numeric_limits<double>::quiet_NaN();
183+
// on gcc, the second NaN wins! now the payload is gone
184+
EXPECT_FALSE(rnp2.isNaNWithPayload());
185+
// a quiet NaN has a "payload" of zero
186+
EXPECT_EQ(0, rnp2.getPayload());
187+
188+
// ... other way around
189+
rnp2._payload = std::numeric_limits<double>::quiet_NaN() + rnp.getNaNWithPayload();
190+
EXPECT_TRUE(rnp2.isNaNWithPayload());
191+
// if it comes second, the PackedNaN does survive
192+
EXPECT_EQ(rnp.getPayload(), rnp2.getPayload());
193+
#endif // __GNUC__
141194
}
142195

143196
#endif // !defined(_MSC_VER) || defined(R__ENABLE_BROKEN_WIN_TESTS)

0 commit comments

Comments
 (0)