Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/iceberg/expression/literal.cc
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,9 @@ std::strong_ordering CompareFloat(T lhs, T rhs) {
// and -NAN < NAN.
bool lhs_is_negative = std::signbit(lhs);
bool rhs_is_negative = std::signbit(rhs);
return lhs_is_negative <=> rhs_is_negative;
// A negative sign bit sorts below a positive one (-NaN < +NaN), so a
// negative operand must compare as less.
return rhs_is_negative <=> lhs_is_negative;
Comment on lines +447 to +449

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keeping rhs <=> lhs: it's the idiom for reversing the order relation, and the comment above states the intent. The SignedNaNComparison tests pin the direction either way.

}

namespace {
Expand Down
25 changes: 25 additions & 0 deletions src/iceberg/test/literal_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#include "iceberg/expression/literal.h"

#include <cmath>
#include <limits>
#include <numbers>
#include <unordered_set>
Expand Down Expand Up @@ -216,6 +217,18 @@ TEST(LiteralTest, FloatNaNComparison) {
EXPECT_EQ(nan1 <=> signaling_nan, std::partial_ordering::equivalent);
}

TEST(LiteralTest, FloatSignedNaNComparison) {
auto neg_nan =
Literal::Float(std::copysign(std::numeric_limits<float>::quiet_NaN(), -1.0f));
auto pos_nan =
Literal::Float(std::copysign(std::numeric_limits<float>::quiet_NaN(), +1.0f));

// Per the total ordering -NaN < ... < +NaN, a negative NaN sorts below a
// positive NaN.
EXPECT_EQ(neg_nan <=> pos_nan, std::partial_ordering::less);
EXPECT_EQ(pos_nan <=> neg_nan, std::partial_ordering::greater);
}

TEST(LiteralTest, FloatInfinityComparison) {
auto neg_inf = Literal::Float(-std::numeric_limits<float>::infinity());
auto pos_inf = Literal::Float(std::numeric_limits<float>::infinity());
Expand Down Expand Up @@ -267,6 +280,18 @@ TEST(LiteralTest, DoubleNaNComparison) {
EXPECT_EQ(nan1 <=> signaling_nan, std::partial_ordering::equivalent);
}

TEST(LiteralTest, DoubleSignedNaNComparison) {
auto neg_nan =
Literal::Double(std::copysign(std::numeric_limits<double>::quiet_NaN(), -1.0));
auto pos_nan =
Literal::Double(std::copysign(std::numeric_limits<double>::quiet_NaN(), +1.0));

// Per the total ordering -NaN < ... < +NaN, a negative NaN sorts below a
// positive NaN.
EXPECT_EQ(neg_nan <=> pos_nan, std::partial_ordering::less);
EXPECT_EQ(pos_nan <=> neg_nan, std::partial_ordering::greater);
}

TEST(LiteralTest, DoubleInfinityComparison) {
auto neg_inf = Literal::Double(-std::numeric_limits<double>::infinity());
auto pos_inf = Literal::Double(std::numeric_limits<double>::infinity());
Expand Down
Loading