When working to understand any algorithm, you step through it with pencil-and-paper validating each step of the code. Pick a small test case, such as 10 as your input, which you know has a binary representation of 1010 and step through the four-iterations understanding what is happening.
If you do so, you will find the following:
    while (i <= num)            /* find next power-of-two greater than num */
        i *= 2;
and then it is reduced by a power-of-two to eliminate any leading zeros as output, e.g.
    i /= 2;                     /* divide by two, 1st power-of-two less than num */
This ensures i is the next power-of-two less than num. Now look at the algorithm in the do .. while (i > 0); loop (rearranged and indented so it makes more sense):
    do {                        /* loop until i <= 0 */
        if (num >= i) {         /* is num >= i? */
            std::cout << '1';   /* if so, output character '1' */
            num -= i;           /* reduce num by i */
        }
        else    /* otherwise */
            std::cout << '0';   /* output '0' character if num < i */
        i /= 2;                 /* divide i by 2 (integer division intentional) */
    } while (i > 0);
The algorithm is simple.
- Iteration one - since iis the next power-of-two less thannumthe conditionalif (num >= i)will test true guaranteeing the first character output will be'1'.numis then reduced byi(in the case wherenum = 10;),i = 8on the first iteration sonum -= i;leavesnum = 2.iis divided by2leavingi = 4.
- Iteration two - the conditional is false, '0'is output andiis divided again by2leavingi = 2, soi = num = 2.
- Third iteration - the conditional tests true, the character '1'is output,numis reduced to0,iis reduced to1, you loop again.
- Fourth iteration - the conditional is false, '0'is output andiis reduced to zero exiting the loop.
The correct binary representation of 10 is output:
1010
If you refactor the code to eliminate the unnecessary else condition based on whether num >= 0, you simply handle the negative or zero case and return. That saves a complete level of indention throughout the code. Putting it altogether, you can rewrite the same code as:
#include <iostream>
int main()
{
    int num, i = 1;
    std::cout << "Please enter a number: ";
    std::cin >> num;
    
    if (num <= 0) {
        std::cout << "0\n";
        return 0;
    }
    
    while (i <= num)            /* find next power-of-two greater than num */
        i *= 2;
    
    i /= 2;                     /* divide by two, 1st power-of-two less than num */
    do {                        /* loop until i <= 0 */
        if (num >= i) {         /* is num >= i? */
            std::cout << '1';   /* if so, output character '1' */
            num -= i;           /* reduce num by i */
        }
        else    /* otherwise */
            std::cout << '0';   /* output '0' character if num < i */
        i /= 2;                 /* divide i by 2 (integer division intentional) */
    } while (i > 0);
    
    std::cout << '\n';          /* tidy up with newline */
}
(note: See Why is “using namespace std;” considered bad practice? -- learning good habits is much easier than breaking bad ones later....)
Example Use/Output
$ ./bin/binary_conversion
Please enter a number: 10
1010
or
$ ./bin/binary_conversion
Please enter a number: 126
1111110
or
$ ./bin/binary_conversion
Please enter a number: 170
10101010
The code works fine. Look things over and let me know if you have further questions.