Skip to content
New issue

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

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

Already on GitHub? # to your account

STYLE: Remove std::pow calls from BoundingBox::ComputeCorners() #5255

Merged

Conversation

N-Dekker
Copy link
Contributor

@N-Dekker N-Dekker commented Feb 24, 2025

The use of bit-shift and modulo is a bit more elegant in this case, it may be slightly faster, and it takes away the need to do static_cast's.

The use of std::bitset is a bit clearer in this case, it may be slightly faster than those std::pow calls, and it takes away the need to do static_cast's.

@github-actions github-actions bot added area:Core Issues affecting the Core module type:Style Style changes: no logic impact (indentation, comments, naming) labels Feb 24, 2025
pnt[i] = center[i] +
std::pow(-1.0, (static_cast<double>(j / (static_cast<int>(std::pow(2.0, static_cast<double>(i))))))) *
radius[i];
pnt[i] = center[i] + ((((j >> i) % 2ULL) == 0) ? 1 : -1) * radius[i];
Copy link
Member

Choose a reason for hiding this comment

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

I have stared at this statement for a min or two. It looks like its just checking the value of the i'th bit... The following may be clearer:

const bool bit_i = ((1ULL << i) & j);
pnt[i] = center[i] + (bit_i ? -1 :  1 ) * radius[I];

Minimally, I find the current one statement bit too complex for clarity.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks @blowekamp but maybe std::bitset can make it even clearer 🤔

  for (SizeValueType j = 0; j < NumberOfCorners; ++j)
  {
    const std::bitset<PointDimension> bitSet{ j };
    PointType pnt;
    for (unsigned int i = 0; i < PointDimension; ++i)
    {
      pnt[i] = center[i] + (bitSet[i] ? -1 : 1) * radius[i];
    }

    result[j] = pnt;
  }

Instead of the original:

for (SizeValueType j = 0; j < NumberOfCorners; ++j)
{
PointType pnt;
for (unsigned int i = 0; i < PointDimension; ++i)
{
pnt[i] = center[i] +
std::pow(-1.0, (static_cast<double>(j / (static_cast<int>(std::pow(2.0, static_cast<double>(i))))))) *
radius[i];
}
result[j] = pnt;
}

Would such a std::bitset also be OK to you as well?

Copy link
Member

Choose a reason for hiding this comment

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

bitset looks like it was introduced with C++20?

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 guess you mean C++98!

Copy link
Member

Choose a reason for hiding this comment

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

I saw some "since C+20, since C++23" notes on some functions/constructors.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

And in C++, 98 < 20 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

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

By the way, I did not yet apply my idea to use std::bitset, because I still think the initial version of my PR is also OK. I feel that it is already a significant improvement to the original, std::pow(-1.0, (static_cast<double>(j / (static_cast<int>(std::pow(2.0, static_cast<double>(i))))))).

Regarding Bradley's (@blowekamp) suggestion, it would be OK to me to use ((1ULL << i) & j), instead of ((j >> i) % 2ULL). Does that already make things clearer to anyone? In general, I prefer not to add variables that are used only once. But if it helps to make people happy, and increases code readability, OK... but then I think it should still be adjusted somewhat. I think it should be camel case, e.g., isBitSet, and it should not silently convert integer to bool. So maybe:

    // Is the i-th bit of j set?
    const bool isBitSet{ ((1ULL << i) & j) != 0 };

What do you think?

Copy link
Member

Choose a reason for hiding this comment

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

I think your postposed statement is on the complicated side. Your iteration on my suggestion is fine, using a std::bitset maybe better. At minimal a comment it needed to this current proposal IMHO. Many option to improve the PR, thank you for the consideration.

Copy link
Member

Choose a reason for hiding this comment

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

Breaking up that statement into two, as Brad suggested, is highly appealing to me. It significantly aids understanding. The other variations are less important to me, with mild preference for your original (using std::bitset) proposal.

The use of `std::bitset` is a bit clearer in this case, it may be slightly faster
than those `std::pow` calls, and it takes away the need to do static_cast's.
@N-Dekker N-Dekker force-pushed the Remove-pow-from-BoundingBox branch from da5aed3 to b979fb0 Compare February 25, 2025 18:33
@N-Dekker N-Dekker marked this pull request as ready for review February 25, 2025 18:38
@dzenanz dzenanz merged commit 5c8dbc1 into InsightSoftwareConsortium:master Feb 26, 2025
16 checks passed
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
area:Core Issues affecting the Core module type:Style Style changes: no logic impact (indentation, comments, naming)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants