Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ARROW-4206: [Gandiva] support decimal divide and mod #3813

Closed
wants to merge 4 commits into from

Conversation

pravindra
Copy link
Contributor

No description provided.

@pravindra pravindra requested a review from pitrou March 5, 2019 12:09
@fsaintjacques
Copy link
Contributor

@pravindra, add me as a reviewer, @pitrou is not available.

@wesm
Copy link
Member

wesm commented Mar 5, 2019

the "review requested" feature is only informational, I think @pravindra is one of the only contributors who uses it regularly =)

@pravindra
Copy link
Contributor Author

@pravindra, add me as a reviewer, @pitrou is not available.

sorry I'm not able to add you as a reviewer. but, please do review.

Copy link
Contributor

@praveenbingo praveenbingo left a comment

Choose a reason for hiding this comment

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

+1 LGTM.

DCHECK_LE(scale, kMaxScaleMultiplier);

// Compute the scale multipliers once.
static std::array<int256_t, kMaxScaleMultiplier + 1> multipliers =
Copy link
Contributor

Choose a reason for hiding this comment

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

This is not thread safe.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The spec says it's thread-safe https://en.cppreference.com/w/cpp/language/storage_duration#Static_local_variables

Is there an exception for lambda ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've made this a global variable now.

Copy link
Contributor

Choose a reason for hiding this comment

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

There doesn't seem to be exception for lamda, I didn't know that local static storage was thread safe in C++11, wasn't in C11 and previous C++ versions. I'd say you can keep the previous version if you prefer.

([]() -> std::array<int256_t, kMaxScaleMultiplier + 1> {
std::array<int256_t, kMaxScaleMultiplier + 1> values;
values[0] = 1;
for (auto idx = 1; idx <= kMaxScaleMultiplier; idx++) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Don't use auto on primitive types.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

curious, why the restriction ? is this from the coding standard or for efficiency ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

Copy link
Contributor

Choose a reason for hiding this comment

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

Mostly for readability (and future refactoring), and making sure there's no signedness/width issues, though the compiler would help with the warnings.

@@ -138,6 +138,9 @@ class ARROW_EXPORT BasicDecimal128 {
/// - If 'round' is false, the right-most digits are simply dropped.
BasicDecimal128 ReduceScaleBy(int32_t reduce_by, bool round = true) const;

// returns 1 for positive and zero decimal values, -1 for negative decimal values.
int64_t Sign() const;
Copy link
Contributor

Choose a reason for hiding this comment

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

small enough to make it inline.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

@@ -482,6 +482,49 @@ TEST(Decimal128Test, Multiply) {
ASSERT_EQ(result.ToIntegerString(), "60501");
}

TEST(Decimal128Test, Divide) {
Decimal128 result;
Copy link
Contributor

Choose a reason for hiding this comment

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

This is valid for the next 3 tests:

  • Why the usage of a temporary variables, e.g. ASSERT_EQ(Decimal128("20100") / Decimal128("301"), ...)?
  • Why the usage of ToIntegerString, just compare Decimal("66")?
  • Would it be better to explicit some int64/int128 constructors such that you can at least call with Decimal(66)?

The end would look like

  ASSERT_EQ(Decimal(20100) / Decimal128(301), Decimal128(66));
  • Please do some minimal property testing against known types, e.g.
for (x: rand_int32_range())
  for (y: rand_int32_range())
    ASSERT_EQ(Decimal(x) / Decimal128(y), Decimal128(x/y));
  • I usually try to test all obvious edge cases and some close bounds, e.g.
    {INT_MIN, 0, INT_MAX} x {-2,-1,0,1,2}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The int64/int32 constructors already exist. I've added tests and fixed as suggested.

int256_t result_large = x_large_scaled_up / y_large;
int256_t remainder_large = x_large_scaled_up % y_large;

if (abs(2 * remainder_large) >= abs(y_large)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't follow, please comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

added comment

}

// scale upto the output scale, and do an integer division.
auto delta_scale = out_scale + y.scale() - x.scale();
Copy link
Contributor

Choose a reason for hiding this comment

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

Don't use auto on primitive types.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

decimalops::Divide(reinterpret_cast<int64>(&context), DecimalScalar128{"201", 20, 3},
DecimalScalar128{"1", 20, 2}, result_precision, result_scale,
&overflow);
EXPECT_EQ(context.has_error(), false);
Copy link
Contributor

Choose a reason for hiding this comment

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

EXPECT_TRUE and EXPECT_FALSE exists for this purpose.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

@fsaintjacques
Copy link
Contributor

One last issue with the newer changes, why the usage of str() if it's the lack of int128_t constructor, this is a good time to add one, e.g.

Decimal128 result = Decimal128(x.str()) * Decimal128(y.str());

@pravindra
Copy link
Contributor Author

One last issue with the newer changes, why the usage of str() if it's the lack of int128_t constructor, this is a good time to add one, e.g.

Decimal128 result = Decimal128(x.str()) * Decimal128(y.str());

Yeah - it's due to lack of int128_t constructor. I don't want to add boost dependency in the decimal header files since it'll spill over to the IR code, and glib. Since this is required only for testing, I'd like to leave this as now. Can revisit later if we have other uses of this.

I believe the gcc's int128_t doesn't work with windows.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants