Trouble with finding floor(log2(int)) using binary search in O(log2(amount_bits))Skip List vs. Binary Search TreeFind kth smallest element in a binary search tree in Optimum wayConverting an int to a binary string representation in Java?Cast to int vs floorhow to calculate binary search complexityComputing the floor log of a binary numberHaving trouble with basic Binary SearchFloor implementation in binary search treetrouble with binary search recursionTrouble converting from int in decimal to int in binary

Number of matrices with bounded products of rows and columns

Representing an indicator function: binary variables and "indicator constraints"

Pocket Clarketech

Can anybody tell me who this Pokemon is?

From where do electrons gain kinetic energy through a circuit?

What is the best way to use errors in mathematica M12?

Would getting a natural 20 with a penalty still count as a critical hit?

How does the illumination of the sky from the sun compare to that of the moon?

Why should P.I be willing to write strong LOR even if that means losing a undergraduate from his/her lab?

Do predators tend to have vertical slit pupils versus horizontal for prey animals?

Postdoc interview - somewhat positive reply but no news?

What modifiers are added to the attack and damage rolls of this unique longbow from Waterdeep: Dragon Heist?

How to render "have ideas above his station" into German

What should I do with the stock I own if I anticipate there will be a recession?

What if a restaurant suddenly cannot accept credit cards, and the customer has no cash?

What does a comma signify in inorganic chemistry?

Heyawacky: Ace of Cups

Can I submit a paper computer science conference using an alias if using my real name can cause legal trouble in my original country

Why is su world executable?

Ending a line of dialogue with "?!": Allowed or obnoxious?

Build a mob of suspiciously happy lenny faces ( ͡° ͜ʖ ͡°)

global variant of csname…endcsname

Are there any rules on how characters go from 0th to 1st level in a class?

The Lucky House



Trouble with finding floor(log2(int)) using binary search in O(log2(amount_bits))


Skip List vs. Binary Search TreeFind kth smallest element in a binary search tree in Optimum wayConverting an int to a binary string representation in Java?Cast to int vs floorhow to calculate binary search complexityComputing the floor log of a binary numberHaving trouble with basic Binary SearchFloor implementation in binary search treetrouble with binary search recursionTrouble converting from int in decimal to int in binary






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;








-1















In our algorithms class, we've got an extra question in the lab session by the professor. Find the floor(log2(x)) for an int of n bits in log2(n) steps (e.g. when T = uint64_t, then n = 64).



We've found that we should be able to solve this with binary search, but we get an off by 1 result or an endless loop in certain edge cases. We're scratching our heads for some time, but cannot seem to get this right. How do we best deal with this? We've tried to reason with the invariant trick as discussed here, but it seems to be a little more complex than. E.g. for a decimal number, when choosing between bit 7 or 6 is difficult as 128 is larger than 100, but 64 is smaller. Unfortunately, when mitigating this, we break some edge cases.



EDIT: As noted below, this is purely an academic question with low to none usability in real-life scenario's.



Here is our code so far:



//
// h l
// 76543210
// 0b01000001 = 65
//

using T = unsigned char;

int lgfloor(T value)

assert(value > 0);

int high = ((sizeof(value) * 8) - 1);
int low = 0;
int mid = 0;
T guess = 0;

while (high > low)

mid = (low + ((high - low) / 2));
guess = static_cast<T>(1) << mid;

printf("high: %d, mid: %d, low: %dn", high, mid, low);

if (value < guess)

high = mid - 1;

else

low = mid;



return low;



We have created the following unit tests (using GoogleTest):



TEST(LgFloor, lgfloor)

ASSERT_DEATH(lgfloor(-1), "Assertion `value > 0' failed.");
ASSERT_DEATH(lgfloor(0), "Assertion `value > 0' failed.");

ASSERT_EQ(lgfloor(1), 0);
ASSERT_EQ(lgfloor(2), 1);
ASSERT_EQ(lgfloor(64), 6);
ASSERT_EQ(lgfloor(100), 6);



Thanks in advance,
with kind regards,



Marten










share|improve this question


























  • Is char signed or unsigned on your platform? If it's unsigned you're in for some fun with your assertions. Since it's recommended to only perform shifts on unsigned quantities but you want tests with signed inputs, you kind of need to figure out which one you want to use.

    – Max Langhof
    Mar 27 at 13:16












  • @Max Langhof The algorithm also fails equivalently for using T = unsigned long long int, which was the type used when we originally developed this method.

    – MartenBE
    Mar 27 at 13:19












  • I'm just trying to help you improve the question. I understand that these nitpicks are not your main concern, but it's irritating for others to get stuck on these problems when they aren't what you care about.

    – Max Langhof
    Mar 27 at 13:20











  • In any case, what did you find when debugging this? Which test case fails, and what are the steps your search is taking?

    – Max Langhof
    Mar 27 at 13:24

















-1















In our algorithms class, we've got an extra question in the lab session by the professor. Find the floor(log2(x)) for an int of n bits in log2(n) steps (e.g. when T = uint64_t, then n = 64).



We've found that we should be able to solve this with binary search, but we get an off by 1 result or an endless loop in certain edge cases. We're scratching our heads for some time, but cannot seem to get this right. How do we best deal with this? We've tried to reason with the invariant trick as discussed here, but it seems to be a little more complex than. E.g. for a decimal number, when choosing between bit 7 or 6 is difficult as 128 is larger than 100, but 64 is smaller. Unfortunately, when mitigating this, we break some edge cases.



EDIT: As noted below, this is purely an academic question with low to none usability in real-life scenario's.



Here is our code so far:



//
// h l
// 76543210
// 0b01000001 = 65
//

using T = unsigned char;

int lgfloor(T value)

assert(value > 0);

int high = ((sizeof(value) * 8) - 1);
int low = 0;
int mid = 0;
T guess = 0;

while (high > low)

mid = (low + ((high - low) / 2));
guess = static_cast<T>(1) << mid;

printf("high: %d, mid: %d, low: %dn", high, mid, low);

if (value < guess)

high = mid - 1;

else

low = mid;



return low;



We have created the following unit tests (using GoogleTest):



TEST(LgFloor, lgfloor)

ASSERT_DEATH(lgfloor(-1), "Assertion `value > 0' failed.");
ASSERT_DEATH(lgfloor(0), "Assertion `value > 0' failed.");

ASSERT_EQ(lgfloor(1), 0);
ASSERT_EQ(lgfloor(2), 1);
ASSERT_EQ(lgfloor(64), 6);
ASSERT_EQ(lgfloor(100), 6);



Thanks in advance,
with kind regards,



Marten










share|improve this question


























  • Is char signed or unsigned on your platform? If it's unsigned you're in for some fun with your assertions. Since it's recommended to only perform shifts on unsigned quantities but you want tests with signed inputs, you kind of need to figure out which one you want to use.

    – Max Langhof
    Mar 27 at 13:16












  • @Max Langhof The algorithm also fails equivalently for using T = unsigned long long int, which was the type used when we originally developed this method.

    – MartenBE
    Mar 27 at 13:19












  • I'm just trying to help you improve the question. I understand that these nitpicks are not your main concern, but it's irritating for others to get stuck on these problems when they aren't what you care about.

    – Max Langhof
    Mar 27 at 13:20











  • In any case, what did you find when debugging this? Which test case fails, and what are the steps your search is taking?

    – Max Langhof
    Mar 27 at 13:24













-1












-1








-1








In our algorithms class, we've got an extra question in the lab session by the professor. Find the floor(log2(x)) for an int of n bits in log2(n) steps (e.g. when T = uint64_t, then n = 64).



We've found that we should be able to solve this with binary search, but we get an off by 1 result or an endless loop in certain edge cases. We're scratching our heads for some time, but cannot seem to get this right. How do we best deal with this? We've tried to reason with the invariant trick as discussed here, but it seems to be a little more complex than. E.g. for a decimal number, when choosing between bit 7 or 6 is difficult as 128 is larger than 100, but 64 is smaller. Unfortunately, when mitigating this, we break some edge cases.



EDIT: As noted below, this is purely an academic question with low to none usability in real-life scenario's.



Here is our code so far:



//
// h l
// 76543210
// 0b01000001 = 65
//

using T = unsigned char;

int lgfloor(T value)

assert(value > 0);

int high = ((sizeof(value) * 8) - 1);
int low = 0;
int mid = 0;
T guess = 0;

while (high > low)

mid = (low + ((high - low) / 2));
guess = static_cast<T>(1) << mid;

printf("high: %d, mid: %d, low: %dn", high, mid, low);

if (value < guess)

high = mid - 1;

else

low = mid;



return low;



We have created the following unit tests (using GoogleTest):



TEST(LgFloor, lgfloor)

ASSERT_DEATH(lgfloor(-1), "Assertion `value > 0' failed.");
ASSERT_DEATH(lgfloor(0), "Assertion `value > 0' failed.");

ASSERT_EQ(lgfloor(1), 0);
ASSERT_EQ(lgfloor(2), 1);
ASSERT_EQ(lgfloor(64), 6);
ASSERT_EQ(lgfloor(100), 6);



Thanks in advance,
with kind regards,



Marten










share|improve this question
















In our algorithms class, we've got an extra question in the lab session by the professor. Find the floor(log2(x)) for an int of n bits in log2(n) steps (e.g. when T = uint64_t, then n = 64).



We've found that we should be able to solve this with binary search, but we get an off by 1 result or an endless loop in certain edge cases. We're scratching our heads for some time, but cannot seem to get this right. How do we best deal with this? We've tried to reason with the invariant trick as discussed here, but it seems to be a little more complex than. E.g. for a decimal number, when choosing between bit 7 or 6 is difficult as 128 is larger than 100, but 64 is smaller. Unfortunately, when mitigating this, we break some edge cases.



EDIT: As noted below, this is purely an academic question with low to none usability in real-life scenario's.



Here is our code so far:



//
// h l
// 76543210
// 0b01000001 = 65
//

using T = unsigned char;

int lgfloor(T value)

assert(value > 0);

int high = ((sizeof(value) * 8) - 1);
int low = 0;
int mid = 0;
T guess = 0;

while (high > low)

mid = (low + ((high - low) / 2));
guess = static_cast<T>(1) << mid;

printf("high: %d, mid: %d, low: %dn", high, mid, low);

if (value < guess)

high = mid - 1;

else

low = mid;



return low;



We have created the following unit tests (using GoogleTest):



TEST(LgFloor, lgfloor)

ASSERT_DEATH(lgfloor(-1), "Assertion `value > 0' failed.");
ASSERT_DEATH(lgfloor(0), "Assertion `value > 0' failed.");

ASSERT_EQ(lgfloor(1), 0);
ASSERT_EQ(lgfloor(2), 1);
ASSERT_EQ(lgfloor(64), 6);
ASSERT_EQ(lgfloor(100), 6);



Thanks in advance,
with kind regards,



Marten







c++ algorithm binary






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Mar 27 at 23:31







MartenBE

















asked Mar 27 at 13:10









MartenBEMartenBE

3631 gold badge3 silver badges14 bronze badges




3631 gold badge3 silver badges14 bronze badges















  • Is char signed or unsigned on your platform? If it's unsigned you're in for some fun with your assertions. Since it's recommended to only perform shifts on unsigned quantities but you want tests with signed inputs, you kind of need to figure out which one you want to use.

    – Max Langhof
    Mar 27 at 13:16












  • @Max Langhof The algorithm also fails equivalently for using T = unsigned long long int, which was the type used when we originally developed this method.

    – MartenBE
    Mar 27 at 13:19












  • I'm just trying to help you improve the question. I understand that these nitpicks are not your main concern, but it's irritating for others to get stuck on these problems when they aren't what you care about.

    – Max Langhof
    Mar 27 at 13:20











  • In any case, what did you find when debugging this? Which test case fails, and what are the steps your search is taking?

    – Max Langhof
    Mar 27 at 13:24

















  • Is char signed or unsigned on your platform? If it's unsigned you're in for some fun with your assertions. Since it's recommended to only perform shifts on unsigned quantities but you want tests with signed inputs, you kind of need to figure out which one you want to use.

    – Max Langhof
    Mar 27 at 13:16












  • @Max Langhof The algorithm also fails equivalently for using T = unsigned long long int, which was the type used when we originally developed this method.

    – MartenBE
    Mar 27 at 13:19












  • I'm just trying to help you improve the question. I understand that these nitpicks are not your main concern, but it's irritating for others to get stuck on these problems when they aren't what you care about.

    – Max Langhof
    Mar 27 at 13:20











  • In any case, what did you find when debugging this? Which test case fails, and what are the steps your search is taking?

    – Max Langhof
    Mar 27 at 13:24
















Is char signed or unsigned on your platform? If it's unsigned you're in for some fun with your assertions. Since it's recommended to only perform shifts on unsigned quantities but you want tests with signed inputs, you kind of need to figure out which one you want to use.

– Max Langhof
Mar 27 at 13:16






Is char signed or unsigned on your platform? If it's unsigned you're in for some fun with your assertions. Since it's recommended to only perform shifts on unsigned quantities but you want tests with signed inputs, you kind of need to figure out which one you want to use.

– Max Langhof
Mar 27 at 13:16














@Max Langhof The algorithm also fails equivalently for using T = unsigned long long int, which was the type used when we originally developed this method.

– MartenBE
Mar 27 at 13:19






@Max Langhof The algorithm also fails equivalently for using T = unsigned long long int, which was the type used when we originally developed this method.

– MartenBE
Mar 27 at 13:19














I'm just trying to help you improve the question. I understand that these nitpicks are not your main concern, but it's irritating for others to get stuck on these problems when they aren't what you care about.

– Max Langhof
Mar 27 at 13:20





I'm just trying to help you improve the question. I understand that these nitpicks are not your main concern, but it's irritating for others to get stuck on these problems when they aren't what you care about.

– Max Langhof
Mar 27 at 13:20













In any case, what did you find when debugging this? Which test case fails, and what are the steps your search is taking?

– Max Langhof
Mar 27 at 13:24





In any case, what did you find when debugging this? Which test case fails, and what are the steps your search is taking?

– Max Langhof
Mar 27 at 13:24












4 Answers
4






active

oldest

votes


















1














You need a proper exit condition. Let's say y = floor(lg2(x)). You should exit the loop when 2^low <= x and x < 2^(low+1). But if high == low+1 then this is fulfilled, yet you do not currently exit. Just do:



while (high > low+1)
{


It is good to look at invariants in your loop. For example, we could try to maintain x < 2^high (that would require starting at sizeof(T)*8, not sizeof(T)*8 - 1). Then all you need to do is bisecting until low == high-1 and you are done.



We can maintain this invariant by only changing high to mid if x < 2^mid, i.e. if value < guess. That's the first case:



if (value < guess)
high = mid;


We further must maintain 2^low <= x = value. So, in the else branch (which requires 2^mid == guess < value, we can safely set low = mid.



else
low = mid;


All that is left is to prove that the loop always progresses. Since high > low+1, we have high - low >= 2 and thus mid != low and mid != high. Clearly, we are reducing the interval (by half) each iteration.



So there you go:



int lgfloor(T value)

assert(value > 0);

int high = (sizeof(value) * 8);
int low = 0;

while (high > low+1)

int mid = (low + ((high - low) / 2));
T guess = static_cast<T>(1) << mid;

printf("high: %d, mid: %d, low: %dn", high, mid, low);

if (value < guess)
high = mid;
else
low = mid;


return low;




I should of course note that there are dedicated intrinsics for this exact purpose in modern hardware. For example, search Intel's intrinsics guide for _BitScanReverse which will complete in a fraction of the cycles the above code would take.



One way or another, asymptotic runtimes that depend on bit-width are pretty meaningless when dealing with fixed-width types such as C++' integral ones (although the question has educational value still).






share|improve this answer



























  • if (value < guess) high = mid; else low = mid + 1; causes lgfloor(1) to fail. if (value < guess) high = mid - 1; else low = mid; causes an endless loop in lgfloor(2): high: 2, mid: 1, low: 1. Fixing one case causes others to fail. We suspect that this is not the average binary search application, but has an additional difficulty which we constantly seem to miss. We debugged various variations of this method, but seem to constantly fail one test or another.

    – MartenBE
    Mar 27 at 13:40











  • @MartenBE In that case just add a check for guess == value and return mid. Note that low can never reach high in your implementation, so if at any point high is the correct guess then you currently have no way of returning high (you only ever return low). Alternatively, did you try high = mid and low = mid yet? Again, the correct solution should be really obvious if you sit down with a piece of paper and do it by hand once (which I admit to not having done myself).

    – Max Langhof
    Mar 27 at 13:44












  • We've tried that, but such a solution fails lgfloor(100): if (value == guess) return mid; else if (value < guess) high = mid - 1; else low = mid + 1; . Additionally: if (value < guess) high = mid; else low = mid; also gives an endless loop: high: 7, mid: 6, low: 6. It's really tricky :p

    – MartenBE
    Mar 27 at 13:47







  • 1





    Ok value == guess is of course wrong. What you'd need to check is if you are at the leftmost bit. That is, if ((guess ^ value) < guess) return mid;.

    – Max Langhof
    Mar 27 at 13:58






  • 1





    Also note that there is an intrinsic that does this whole job instruction for you (in essentially O(1)): _BitScanReverse. Doesn't qualify for the assignment (I mean, you could argue that the inbuilt operations for addition, division shifts and comparisons are all O(numBits) just the same), but just in case you ever have to do this in practice, you know.

    – Max Langhof
    Mar 27 at 14:01



















0














Endless loop is due to this line:



 mid = (low + ((high - low) / 2));


if high and low is differ by 1, the result could be mid == low and then at the condition that cause low = mid inside the while loop, you resulted in checking the same condition forever. My suggestion would be, if you have low = mid in the loop, you have to make sure your mid != low in that case. So just check this before the assignment and do low = mid+1 instead if that happens.






share|improve this answer
































    0














    The solution must be found in lg(n) steps, which means that an initialisation such as low= 0, high= 32 won't work, because it would take 5 steps in every case and wouldn't work for x larger than 2^32. A correct solution must combine a first geometric search where you double the exponent, then a standard dichotomic search.



    # Geometric search
    low= 0
    high= 1
    while (1 << high) <= x:
    low= high
    high+= high

    # Dichotomic search
    while high - low > 1:
    mid= (high + low) >> 1
    if x < mid:
    high= mid
    else:
    low= mid





    share|improve this answer


































      -1














      Seems like you just have to shift if to the right 'log' times, until you have a '1'.



      using T = unsigned char;

      int lgfloor(T value)

      assert(value > 0);

      int log = 0;
      while(value != 1)
      value >> 1;
      log++;

      return log;






      share|improve this answer




















      • 2





        This solution is O(amount_bits) instead of O(log2(amount_bits)).

        – MartenBE
        Mar 27 at 14:34













      Your Answer






      StackExchange.ifUsing("editor", function ()
      StackExchange.using("externalEditor", function ()
      StackExchange.using("snippets", function ()
      StackExchange.snippets.init();
      );
      );
      , "code-snippets");

      StackExchange.ready(function()
      var channelOptions =
      tags: "".split(" "),
      id: "1"
      ;
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function()
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled)
      StackExchange.using("snippets", function()
      createEditor();
      );

      else
      createEditor();

      );

      function createEditor()
      StackExchange.prepareEditor(
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: true,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: 10,
      bindNavPrevention: true,
      postfix: "",
      imageUploader:
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      ,
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      );



      );













      draft saved

      draft discarded


















      StackExchange.ready(
      function ()
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55378046%2ftrouble-with-finding-floorlog2int-using-binary-search-in-olog2amount-bits%23new-answer', 'question_page');

      );

      Post as a guest















      Required, but never shown

























      4 Answers
      4






      active

      oldest

      votes








      4 Answers
      4






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      1














      You need a proper exit condition. Let's say y = floor(lg2(x)). You should exit the loop when 2^low <= x and x < 2^(low+1). But if high == low+1 then this is fulfilled, yet you do not currently exit. Just do:



      while (high > low+1)
      {


      It is good to look at invariants in your loop. For example, we could try to maintain x < 2^high (that would require starting at sizeof(T)*8, not sizeof(T)*8 - 1). Then all you need to do is bisecting until low == high-1 and you are done.



      We can maintain this invariant by only changing high to mid if x < 2^mid, i.e. if value < guess. That's the first case:



      if (value < guess)
      high = mid;


      We further must maintain 2^low <= x = value. So, in the else branch (which requires 2^mid == guess < value, we can safely set low = mid.



      else
      low = mid;


      All that is left is to prove that the loop always progresses. Since high > low+1, we have high - low >= 2 and thus mid != low and mid != high. Clearly, we are reducing the interval (by half) each iteration.



      So there you go:



      int lgfloor(T value)

      assert(value > 0);

      int high = (sizeof(value) * 8);
      int low = 0;

      while (high > low+1)

      int mid = (low + ((high - low) / 2));
      T guess = static_cast<T>(1) << mid;

      printf("high: %d, mid: %d, low: %dn", high, mid, low);

      if (value < guess)
      high = mid;
      else
      low = mid;


      return low;




      I should of course note that there are dedicated intrinsics for this exact purpose in modern hardware. For example, search Intel's intrinsics guide for _BitScanReverse which will complete in a fraction of the cycles the above code would take.



      One way or another, asymptotic runtimes that depend on bit-width are pretty meaningless when dealing with fixed-width types such as C++' integral ones (although the question has educational value still).






      share|improve this answer



























      • if (value < guess) high = mid; else low = mid + 1; causes lgfloor(1) to fail. if (value < guess) high = mid - 1; else low = mid; causes an endless loop in lgfloor(2): high: 2, mid: 1, low: 1. Fixing one case causes others to fail. We suspect that this is not the average binary search application, but has an additional difficulty which we constantly seem to miss. We debugged various variations of this method, but seem to constantly fail one test or another.

        – MartenBE
        Mar 27 at 13:40











      • @MartenBE In that case just add a check for guess == value and return mid. Note that low can never reach high in your implementation, so if at any point high is the correct guess then you currently have no way of returning high (you only ever return low). Alternatively, did you try high = mid and low = mid yet? Again, the correct solution should be really obvious if you sit down with a piece of paper and do it by hand once (which I admit to not having done myself).

        – Max Langhof
        Mar 27 at 13:44












      • We've tried that, but such a solution fails lgfloor(100): if (value == guess) return mid; else if (value < guess) high = mid - 1; else low = mid + 1; . Additionally: if (value < guess) high = mid; else low = mid; also gives an endless loop: high: 7, mid: 6, low: 6. It's really tricky :p

        – MartenBE
        Mar 27 at 13:47







      • 1





        Ok value == guess is of course wrong. What you'd need to check is if you are at the leftmost bit. That is, if ((guess ^ value) < guess) return mid;.

        – Max Langhof
        Mar 27 at 13:58






      • 1





        Also note that there is an intrinsic that does this whole job instruction for you (in essentially O(1)): _BitScanReverse. Doesn't qualify for the assignment (I mean, you could argue that the inbuilt operations for addition, division shifts and comparisons are all O(numBits) just the same), but just in case you ever have to do this in practice, you know.

        – Max Langhof
        Mar 27 at 14:01
















      1














      You need a proper exit condition. Let's say y = floor(lg2(x)). You should exit the loop when 2^low <= x and x < 2^(low+1). But if high == low+1 then this is fulfilled, yet you do not currently exit. Just do:



      while (high > low+1)
      {


      It is good to look at invariants in your loop. For example, we could try to maintain x < 2^high (that would require starting at sizeof(T)*8, not sizeof(T)*8 - 1). Then all you need to do is bisecting until low == high-1 and you are done.



      We can maintain this invariant by only changing high to mid if x < 2^mid, i.e. if value < guess. That's the first case:



      if (value < guess)
      high = mid;


      We further must maintain 2^low <= x = value. So, in the else branch (which requires 2^mid == guess < value, we can safely set low = mid.



      else
      low = mid;


      All that is left is to prove that the loop always progresses. Since high > low+1, we have high - low >= 2 and thus mid != low and mid != high. Clearly, we are reducing the interval (by half) each iteration.



      So there you go:



      int lgfloor(T value)

      assert(value > 0);

      int high = (sizeof(value) * 8);
      int low = 0;

      while (high > low+1)

      int mid = (low + ((high - low) / 2));
      T guess = static_cast<T>(1) << mid;

      printf("high: %d, mid: %d, low: %dn", high, mid, low);

      if (value < guess)
      high = mid;
      else
      low = mid;


      return low;




      I should of course note that there are dedicated intrinsics for this exact purpose in modern hardware. For example, search Intel's intrinsics guide for _BitScanReverse which will complete in a fraction of the cycles the above code would take.



      One way or another, asymptotic runtimes that depend on bit-width are pretty meaningless when dealing with fixed-width types such as C++' integral ones (although the question has educational value still).






      share|improve this answer



























      • if (value < guess) high = mid; else low = mid + 1; causes lgfloor(1) to fail. if (value < guess) high = mid - 1; else low = mid; causes an endless loop in lgfloor(2): high: 2, mid: 1, low: 1. Fixing one case causes others to fail. We suspect that this is not the average binary search application, but has an additional difficulty which we constantly seem to miss. We debugged various variations of this method, but seem to constantly fail one test or another.

        – MartenBE
        Mar 27 at 13:40











      • @MartenBE In that case just add a check for guess == value and return mid. Note that low can never reach high in your implementation, so if at any point high is the correct guess then you currently have no way of returning high (you only ever return low). Alternatively, did you try high = mid and low = mid yet? Again, the correct solution should be really obvious if you sit down with a piece of paper and do it by hand once (which I admit to not having done myself).

        – Max Langhof
        Mar 27 at 13:44












      • We've tried that, but such a solution fails lgfloor(100): if (value == guess) return mid; else if (value < guess) high = mid - 1; else low = mid + 1; . Additionally: if (value < guess) high = mid; else low = mid; also gives an endless loop: high: 7, mid: 6, low: 6. It's really tricky :p

        – MartenBE
        Mar 27 at 13:47







      • 1





        Ok value == guess is of course wrong. What you'd need to check is if you are at the leftmost bit. That is, if ((guess ^ value) < guess) return mid;.

        – Max Langhof
        Mar 27 at 13:58






      • 1





        Also note that there is an intrinsic that does this whole job instruction for you (in essentially O(1)): _BitScanReverse. Doesn't qualify for the assignment (I mean, you could argue that the inbuilt operations for addition, division shifts and comparisons are all O(numBits) just the same), but just in case you ever have to do this in practice, you know.

        – Max Langhof
        Mar 27 at 14:01














      1












      1








      1







      You need a proper exit condition. Let's say y = floor(lg2(x)). You should exit the loop when 2^low <= x and x < 2^(low+1). But if high == low+1 then this is fulfilled, yet you do not currently exit. Just do:



      while (high > low+1)
      {


      It is good to look at invariants in your loop. For example, we could try to maintain x < 2^high (that would require starting at sizeof(T)*8, not sizeof(T)*8 - 1). Then all you need to do is bisecting until low == high-1 and you are done.



      We can maintain this invariant by only changing high to mid if x < 2^mid, i.e. if value < guess. That's the first case:



      if (value < guess)
      high = mid;


      We further must maintain 2^low <= x = value. So, in the else branch (which requires 2^mid == guess < value, we can safely set low = mid.



      else
      low = mid;


      All that is left is to prove that the loop always progresses. Since high > low+1, we have high - low >= 2 and thus mid != low and mid != high. Clearly, we are reducing the interval (by half) each iteration.



      So there you go:



      int lgfloor(T value)

      assert(value > 0);

      int high = (sizeof(value) * 8);
      int low = 0;

      while (high > low+1)

      int mid = (low + ((high - low) / 2));
      T guess = static_cast<T>(1) << mid;

      printf("high: %d, mid: %d, low: %dn", high, mid, low);

      if (value < guess)
      high = mid;
      else
      low = mid;


      return low;




      I should of course note that there are dedicated intrinsics for this exact purpose in modern hardware. For example, search Intel's intrinsics guide for _BitScanReverse which will complete in a fraction of the cycles the above code would take.



      One way or another, asymptotic runtimes that depend on bit-width are pretty meaningless when dealing with fixed-width types such as C++' integral ones (although the question has educational value still).






      share|improve this answer















      You need a proper exit condition. Let's say y = floor(lg2(x)). You should exit the loop when 2^low <= x and x < 2^(low+1). But if high == low+1 then this is fulfilled, yet you do not currently exit. Just do:



      while (high > low+1)
      {


      It is good to look at invariants in your loop. For example, we could try to maintain x < 2^high (that would require starting at sizeof(T)*8, not sizeof(T)*8 - 1). Then all you need to do is bisecting until low == high-1 and you are done.



      We can maintain this invariant by only changing high to mid if x < 2^mid, i.e. if value < guess. That's the first case:



      if (value < guess)
      high = mid;


      We further must maintain 2^low <= x = value. So, in the else branch (which requires 2^mid == guess < value, we can safely set low = mid.



      else
      low = mid;


      All that is left is to prove that the loop always progresses. Since high > low+1, we have high - low >= 2 and thus mid != low and mid != high. Clearly, we are reducing the interval (by half) each iteration.



      So there you go:



      int lgfloor(T value)

      assert(value > 0);

      int high = (sizeof(value) * 8);
      int low = 0;

      while (high > low+1)

      int mid = (low + ((high - low) / 2));
      T guess = static_cast<T>(1) << mid;

      printf("high: %d, mid: %d, low: %dn", high, mid, low);

      if (value < guess)
      high = mid;
      else
      low = mid;


      return low;




      I should of course note that there are dedicated intrinsics for this exact purpose in modern hardware. For example, search Intel's intrinsics guide for _BitScanReverse which will complete in a fraction of the cycles the above code would take.



      One way or another, asymptotic runtimes that depend on bit-width are pretty meaningless when dealing with fixed-width types such as C++' integral ones (although the question has educational value still).







      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited Mar 27 at 15:28

























      answered Mar 27 at 13:31









      Max LanghofMax Langhof

      14.9k3 gold badges26 silver badges47 bronze badges




      14.9k3 gold badges26 silver badges47 bronze badges















      • if (value < guess) high = mid; else low = mid + 1; causes lgfloor(1) to fail. if (value < guess) high = mid - 1; else low = mid; causes an endless loop in lgfloor(2): high: 2, mid: 1, low: 1. Fixing one case causes others to fail. We suspect that this is not the average binary search application, but has an additional difficulty which we constantly seem to miss. We debugged various variations of this method, but seem to constantly fail one test or another.

        – MartenBE
        Mar 27 at 13:40











      • @MartenBE In that case just add a check for guess == value and return mid. Note that low can never reach high in your implementation, so if at any point high is the correct guess then you currently have no way of returning high (you only ever return low). Alternatively, did you try high = mid and low = mid yet? Again, the correct solution should be really obvious if you sit down with a piece of paper and do it by hand once (which I admit to not having done myself).

        – Max Langhof
        Mar 27 at 13:44












      • We've tried that, but such a solution fails lgfloor(100): if (value == guess) return mid; else if (value < guess) high = mid - 1; else low = mid + 1; . Additionally: if (value < guess) high = mid; else low = mid; also gives an endless loop: high: 7, mid: 6, low: 6. It's really tricky :p

        – MartenBE
        Mar 27 at 13:47







      • 1





        Ok value == guess is of course wrong. What you'd need to check is if you are at the leftmost bit. That is, if ((guess ^ value) < guess) return mid;.

        – Max Langhof
        Mar 27 at 13:58






      • 1





        Also note that there is an intrinsic that does this whole job instruction for you (in essentially O(1)): _BitScanReverse. Doesn't qualify for the assignment (I mean, you could argue that the inbuilt operations for addition, division shifts and comparisons are all O(numBits) just the same), but just in case you ever have to do this in practice, you know.

        – Max Langhof
        Mar 27 at 14:01


















      • if (value < guess) high = mid; else low = mid + 1; causes lgfloor(1) to fail. if (value < guess) high = mid - 1; else low = mid; causes an endless loop in lgfloor(2): high: 2, mid: 1, low: 1. Fixing one case causes others to fail. We suspect that this is not the average binary search application, but has an additional difficulty which we constantly seem to miss. We debugged various variations of this method, but seem to constantly fail one test or another.

        – MartenBE
        Mar 27 at 13:40











      • @MartenBE In that case just add a check for guess == value and return mid. Note that low can never reach high in your implementation, so if at any point high is the correct guess then you currently have no way of returning high (you only ever return low). Alternatively, did you try high = mid and low = mid yet? Again, the correct solution should be really obvious if you sit down with a piece of paper and do it by hand once (which I admit to not having done myself).

        – Max Langhof
        Mar 27 at 13:44












      • We've tried that, but such a solution fails lgfloor(100): if (value == guess) return mid; else if (value < guess) high = mid - 1; else low = mid + 1; . Additionally: if (value < guess) high = mid; else low = mid; also gives an endless loop: high: 7, mid: 6, low: 6. It's really tricky :p

        – MartenBE
        Mar 27 at 13:47







      • 1





        Ok value == guess is of course wrong. What you'd need to check is if you are at the leftmost bit. That is, if ((guess ^ value) < guess) return mid;.

        – Max Langhof
        Mar 27 at 13:58






      • 1





        Also note that there is an intrinsic that does this whole job instruction for you (in essentially O(1)): _BitScanReverse. Doesn't qualify for the assignment (I mean, you could argue that the inbuilt operations for addition, division shifts and comparisons are all O(numBits) just the same), but just in case you ever have to do this in practice, you know.

        – Max Langhof
        Mar 27 at 14:01

















      if (value < guess) high = mid; else low = mid + 1; causes lgfloor(1) to fail. if (value < guess) high = mid - 1; else low = mid; causes an endless loop in lgfloor(2): high: 2, mid: 1, low: 1. Fixing one case causes others to fail. We suspect that this is not the average binary search application, but has an additional difficulty which we constantly seem to miss. We debugged various variations of this method, but seem to constantly fail one test or another.

      – MartenBE
      Mar 27 at 13:40





      if (value < guess) high = mid; else low = mid + 1; causes lgfloor(1) to fail. if (value < guess) high = mid - 1; else low = mid; causes an endless loop in lgfloor(2): high: 2, mid: 1, low: 1. Fixing one case causes others to fail. We suspect that this is not the average binary search application, but has an additional difficulty which we constantly seem to miss. We debugged various variations of this method, but seem to constantly fail one test or another.

      – MartenBE
      Mar 27 at 13:40













      @MartenBE In that case just add a check for guess == value and return mid. Note that low can never reach high in your implementation, so if at any point high is the correct guess then you currently have no way of returning high (you only ever return low). Alternatively, did you try high = mid and low = mid yet? Again, the correct solution should be really obvious if you sit down with a piece of paper and do it by hand once (which I admit to not having done myself).

      – Max Langhof
      Mar 27 at 13:44






      @MartenBE In that case just add a check for guess == value and return mid. Note that low can never reach high in your implementation, so if at any point high is the correct guess then you currently have no way of returning high (you only ever return low). Alternatively, did you try high = mid and low = mid yet? Again, the correct solution should be really obvious if you sit down with a piece of paper and do it by hand once (which I admit to not having done myself).

      – Max Langhof
      Mar 27 at 13:44














      We've tried that, but such a solution fails lgfloor(100): if (value == guess) return mid; else if (value < guess) high = mid - 1; else low = mid + 1; . Additionally: if (value < guess) high = mid; else low = mid; also gives an endless loop: high: 7, mid: 6, low: 6. It's really tricky :p

      – MartenBE
      Mar 27 at 13:47






      We've tried that, but such a solution fails lgfloor(100): if (value == guess) return mid; else if (value < guess) high = mid - 1; else low = mid + 1; . Additionally: if (value < guess) high = mid; else low = mid; also gives an endless loop: high: 7, mid: 6, low: 6. It's really tricky :p

      – MartenBE
      Mar 27 at 13:47





      1




      1





      Ok value == guess is of course wrong. What you'd need to check is if you are at the leftmost bit. That is, if ((guess ^ value) < guess) return mid;.

      – Max Langhof
      Mar 27 at 13:58





      Ok value == guess is of course wrong. What you'd need to check is if you are at the leftmost bit. That is, if ((guess ^ value) < guess) return mid;.

      – Max Langhof
      Mar 27 at 13:58




      1




      1





      Also note that there is an intrinsic that does this whole job instruction for you (in essentially O(1)): _BitScanReverse. Doesn't qualify for the assignment (I mean, you could argue that the inbuilt operations for addition, division shifts and comparisons are all O(numBits) just the same), but just in case you ever have to do this in practice, you know.

      – Max Langhof
      Mar 27 at 14:01






      Also note that there is an intrinsic that does this whole job instruction for you (in essentially O(1)): _BitScanReverse. Doesn't qualify for the assignment (I mean, you could argue that the inbuilt operations for addition, division shifts and comparisons are all O(numBits) just the same), but just in case you ever have to do this in practice, you know.

      – Max Langhof
      Mar 27 at 14:01














      0














      Endless loop is due to this line:



       mid = (low + ((high - low) / 2));


      if high and low is differ by 1, the result could be mid == low and then at the condition that cause low = mid inside the while loop, you resulted in checking the same condition forever. My suggestion would be, if you have low = mid in the loop, you have to make sure your mid != low in that case. So just check this before the assignment and do low = mid+1 instead if that happens.






      share|improve this answer





























        0














        Endless loop is due to this line:



         mid = (low + ((high - low) / 2));


        if high and low is differ by 1, the result could be mid == low and then at the condition that cause low = mid inside the while loop, you resulted in checking the same condition forever. My suggestion would be, if you have low = mid in the loop, you have to make sure your mid != low in that case. So just check this before the assignment and do low = mid+1 instead if that happens.






        share|improve this answer



























          0












          0








          0







          Endless loop is due to this line:



           mid = (low + ((high - low) / 2));


          if high and low is differ by 1, the result could be mid == low and then at the condition that cause low = mid inside the while loop, you resulted in checking the same condition forever. My suggestion would be, if you have low = mid in the loop, you have to make sure your mid != low in that case. So just check this before the assignment and do low = mid+1 instead if that happens.






          share|improve this answer













          Endless loop is due to this line:



           mid = (low + ((high - low) / 2));


          if high and low is differ by 1, the result could be mid == low and then at the condition that cause low = mid inside the while loop, you resulted in checking the same condition forever. My suggestion would be, if you have low = mid in the loop, you have to make sure your mid != low in that case. So just check this before the assignment and do low = mid+1 instead if that happens.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Mar 27 at 13:26









          adrtamadrtam

          3,8731 gold badge4 silver badges23 bronze badges




          3,8731 gold badge4 silver badges23 bronze badges
























              0














              The solution must be found in lg(n) steps, which means that an initialisation such as low= 0, high= 32 won't work, because it would take 5 steps in every case and wouldn't work for x larger than 2^32. A correct solution must combine a first geometric search where you double the exponent, then a standard dichotomic search.



              # Geometric search
              low= 0
              high= 1
              while (1 << high) <= x:
              low= high
              high+= high

              # Dichotomic search
              while high - low > 1:
              mid= (high + low) >> 1
              if x < mid:
              high= mid
              else:
              low= mid





              share|improve this answer































                0














                The solution must be found in lg(n) steps, which means that an initialisation such as low= 0, high= 32 won't work, because it would take 5 steps in every case and wouldn't work for x larger than 2^32. A correct solution must combine a first geometric search where you double the exponent, then a standard dichotomic search.



                # Geometric search
                low= 0
                high= 1
                while (1 << high) <= x:
                low= high
                high+= high

                # Dichotomic search
                while high - low > 1:
                mid= (high + low) >> 1
                if x < mid:
                high= mid
                else:
                low= mid





                share|improve this answer





























                  0












                  0








                  0







                  The solution must be found in lg(n) steps, which means that an initialisation such as low= 0, high= 32 won't work, because it would take 5 steps in every case and wouldn't work for x larger than 2^32. A correct solution must combine a first geometric search where you double the exponent, then a standard dichotomic search.



                  # Geometric search
                  low= 0
                  high= 1
                  while (1 << high) <= x:
                  low= high
                  high+= high

                  # Dichotomic search
                  while high - low > 1:
                  mid= (high + low) >> 1
                  if x < mid:
                  high= mid
                  else:
                  low= mid





                  share|improve this answer















                  The solution must be found in lg(n) steps, which means that an initialisation such as low= 0, high= 32 won't work, because it would take 5 steps in every case and wouldn't work for x larger than 2^32. A correct solution must combine a first geometric search where you double the exponent, then a standard dichotomic search.



                  # Geometric search
                  low= 0
                  high= 1
                  while (1 << high) <= x:
                  low= high
                  high+= high

                  # Dichotomic search
                  while high - low > 1:
                  mid= (high + low) >> 1
                  if x < mid:
                  high= mid
                  else:
                  low= mid






                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Mar 27 at 15:13

























                  answered Mar 27 at 14:48









                  Yves DaoustYves Daoust

                  39.8k8 gold badges30 silver badges64 bronze badges




                  39.8k8 gold badges30 silver badges64 bronze badges
























                      -1














                      Seems like you just have to shift if to the right 'log' times, until you have a '1'.



                      using T = unsigned char;

                      int lgfloor(T value)

                      assert(value > 0);

                      int log = 0;
                      while(value != 1)
                      value >> 1;
                      log++;

                      return log;






                      share|improve this answer




















                      • 2





                        This solution is O(amount_bits) instead of O(log2(amount_bits)).

                        – MartenBE
                        Mar 27 at 14:34















                      -1














                      Seems like you just have to shift if to the right 'log' times, until you have a '1'.



                      using T = unsigned char;

                      int lgfloor(T value)

                      assert(value > 0);

                      int log = 0;
                      while(value != 1)
                      value >> 1;
                      log++;

                      return log;






                      share|improve this answer




















                      • 2





                        This solution is O(amount_bits) instead of O(log2(amount_bits)).

                        – MartenBE
                        Mar 27 at 14:34













                      -1












                      -1








                      -1







                      Seems like you just have to shift if to the right 'log' times, until you have a '1'.



                      using T = unsigned char;

                      int lgfloor(T value)

                      assert(value > 0);

                      int log = 0;
                      while(value != 1)
                      value >> 1;
                      log++;

                      return log;






                      share|improve this answer













                      Seems like you just have to shift if to the right 'log' times, until you have a '1'.



                      using T = unsigned char;

                      int lgfloor(T value)

                      assert(value > 0);

                      int log = 0;
                      while(value != 1)
                      value >> 1;
                      log++;

                      return log;







                      share|improve this answer












                      share|improve this answer



                      share|improve this answer










                      answered Mar 27 at 14:32









                      GardenerGardener

                      2,0191 gold badge7 silver badges17 bronze badges




                      2,0191 gold badge7 silver badges17 bronze badges










                      • 2





                        This solution is O(amount_bits) instead of O(log2(amount_bits)).

                        – MartenBE
                        Mar 27 at 14:34












                      • 2





                        This solution is O(amount_bits) instead of O(log2(amount_bits)).

                        – MartenBE
                        Mar 27 at 14:34







                      2




                      2





                      This solution is O(amount_bits) instead of O(log2(amount_bits)).

                      – MartenBE
                      Mar 27 at 14:34





                      This solution is O(amount_bits) instead of O(log2(amount_bits)).

                      – MartenBE
                      Mar 27 at 14:34

















                      draft saved

                      draft discarded
















































                      Thanks for contributing an answer to Stack Overflow!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid


                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.

                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function ()
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55378046%2ftrouble-with-finding-floorlog2int-using-binary-search-in-olog2amount-bits%23new-answer', 'question_page');

                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      Popular posts from this blog

                      Kamusi Yaliyomo Aina za kamusi | Muundo wa kamusi | Faida za kamusi | Dhima ya picha katika kamusi | Marejeo | Tazama pia | Viungo vya nje | UrambazajiKuhusu kamusiGo-SwahiliWiki-KamusiKamusi ya Kiswahili na Kiingerezakuihariri na kuongeza habari

                      Swift 4 - func physicsWorld not invoked on collision? The Next CEO of Stack OverflowHow to call Objective-C code from Swift#ifdef replacement in the Swift language@selector() in Swift?#pragma mark in Swift?Swift for loop: for index, element in array?dispatch_after - GCD in Swift?Swift Beta performance: sorting arraysSplit a String into an array in Swift?The use of Swift 3 @objc inference in Swift 4 mode is deprecated?How to optimize UITableViewCell, because my UITableView lags

                      Access current req object everywhere in Node.js ExpressWhy are global variables considered bad practice? (node.js)Using req & res across functionsHow do I get the path to the current script with Node.js?What is Node.js' Connect, Express and “middleware”?Node.js w/ express error handling in callbackHow to access the GET parameters after “?” in Express?Modify Node.js req object parametersAccess “app” variable inside of ExpressJS/ConnectJS middleware?Node.js Express app - request objectAngular Http Module considered middleware?Session variables in ExpressJSAdd properties to the req object in expressjs with Typescript