Цикл while повторяется больше или меньше, чем должен

Ответы Остина Гастингса и Майкла Берра решили мою проблему, эта петля всегда верна, как я только что понял, и она решена, когда сделал это так, как это сделал Остин Гастингс. Не могу пометить как ответ, так как это комментарий. Спасибо за вашу помощь!

У меня есть задание на C, которое состоит в том, чтобы печатать только определенные виды чисел от 128 до 255 (то есть 8-значные двоичные представления), и я должен делать это без использования каких-либо арифметических операторов. Условия:

  1. Двоичное представление числа должно иметь одинаковое количество нулей и единиц.
  2. Двоичное представление числа не может иметь больше 0, чем 1 в любой момент при чтении слева направо. Например, 156 (1001 1100) не удовлетворяет 2-му условию, потому что в 3-й цифре два нуля и только одна 1, а 210 (1101 0010) удовлетворяет этим условиям.

Я использую функциональную реализацию и использовал одну функцию для этих двух условий, и эта часть кода:

int checkOneToZero(unsigned int num) {
    unsigned int carry = 7, 
        counterOne = 0, 
        counterZero = 0, 
        ct = 0;

    while ((carry > 0) || (carry == 0)) {
        if ((num >> carry) & 1) {
            counterOne = binaryAddition(counterOne, 1);
            ct ++;
            printf(" %d ", ct); 
        }
        else {
            counterZero = binaryAddition(counterZero, 1);
            ct ++;
            printf(" %d ", ct); 
        }

        carry = binarySubtraction(carry, 1);
        printf(" CARRY %d \n", carry);

        if (counterZero > counterOne) {
            printf(" breakCounterZero %d breakCounterOne %d ", counterZero, counterOne);
            return 0;
        }
    }

    printf("successCounterZero = %d successCounterOne = %d", counterZero, counterOne);

    if (counterZero == counterOne)
        return 1;

    return 0;
}

У меня постоянно был неправильный вывод, поэтому я добавил некоторые механизмы управления, которые не влияют на код, чтобы отслеживать проблему. Эти:

  • ct : подсчитывает, сколько раз он входил в цикл if или else в цикле while.

  • printf(" CARRY %d \n", перенос): показывает значение переноса после того, как оно было уменьшено на единицу.

  • printf(" breakCounterZero = &d breakCounterOne = %d "): показывает 0 и 1 счетчики, если он застрял на "if (counterZero > counterOne)", который проверяет, что 0 счетчиков не может быть выше 1 счетчика в конце каждого цикла while.

  • printf("successCounterZero = %d successCounterOne = %d") : показывает, прошел ли цикл while.

Моя проблема заключается в том, что если я попытаюсь позволить циклу while работать до тех пор, пока перенос не будет использован последним с переносом = 0, он выдаст результат 210, который должен работать, поскольку он зацикливается 8 раз, а при CARRY = -1 он должен выйти из цикла, пока он подобно:

1  CARRY 6
2  CARRY 5
3  CARRY 4
4  CARRY 3
5  CARRY 2
6  CARRY 1
7  CARRY 0
8  CARRY -1
9  CARRY -2
breakCounterZero 5 breakCounterOne 4

поэтому он зацикливается на 1 раз больше, чем должен, и делает счет еще на один 0, поэтому он терпит неудачу. Но когда я увеличил лимит переноса до 1 в цикле while, чтобы посмотреть, что произойдет, это дает:

1  CARRY 6
2  CARRY 5
3  CARRY 4
4  CARRY 3
5  CARRY 2
6  CARRY 1
7  CARRY 0
successCounterZero = 3 successCounterOne = 4

поэтому он проходит 3-е условие, но на один 0 меньше, чем должен, поэтому терпит неудачу во 2-м условии.

Это кажется сложным и слишком специфичным вопросом, но спасибо за любые подсказки.


person morpheus    schedule 24.03.2016    source источник
comment
В той степени, в которой ваша проблема связана с carry, я думаю, вы можете изменить реализацию, чтобы использовать carry = 1 << 7;, а затем while (carry) { ... ; carry >>=1; }   -  person aghast    schedule 25.03.2016
comment
((carry > 0) || (carry == 0)) всегда верно для unsigned int carry.   -  person Michael Burr    schedule 25.03.2016


Ответы (1)


Я не уверен насчет ваших функций binaryAddition и binarySubtraction - требуется ли вам их использовать или вы просто используете их для выполнения условия, при котором не используются никакие арифметические операции.

Для этого простого случая стоит отметить, что вы можете «досчитать» до 31, используя биты целого числа. Определенно достаточно, чтобы обработать 8 возможных значений:

int checkOneToZero(unsigned num) 
{
    unsigned count_0s = 0;
    unsigned count_1s = 0;

    // Using a 'for' loop here because I know the start, stop, and update.
    for (unsigned check_bit = 1 << 7; check_bit; check_bit >>= 1) {
        if (num & check_bit) {
            /* ++count_1s; */
            count_1s |= (count_1s << 1) | 1;
        }
        else {
            /* ++count_0s; */
            count_0s |= (count_0s << 1) | 1;

            if (count_0s > count_1s) return 0;
        }
    }

    return count_0s == count_1s;
}
person aghast    schedule 24.03.2016
comment
Да, я отредактировал свой пост, так как это был комментарий. двоичное сложение и вычитание — это хорошо работающие функции, которые я создал для замены арифметических уравнений, которые я не дал, но благодаря вашему способу мне также не нужна функция двоичного вычитания. Спасибо за ваш подробный ответ. - person morpheus; 25.03.2016