Я работаю с побитовыми и логическими операторами в C. Я знаком с концепцией и назначением этих операторов, но столкнулся с небольшой проблемой.
Мне нужно определить, может ли целое число x поместиться в шорт. Я ограничен использованием операторов ! ~ & ^ | + << >>. Кроме того, я могу использовать только до 8 из этих операторов.
Я знаю из нескольких других сообщений (например, этого: Как определить, может ли 32-битное целое поместиться в 16-битное короткое), что такое решение, как
!(((((x) & 0xffff8000) >> 15) + 1) & 0x1fffe)
будет работать нормально (кредит Эмилю Романусу). Однако мне также запрещено использовать любые константы, кроме 0x0 и 0xff.
Меня больше всего смущает логика здесь. Любые идеи?
Обновлено: я забыл упомянуть, что условное утверждение также запрещено. Так что никаких ifs, elses, циклов и т.д.
@pmg ааааааааааааааааааааааааааааааааааааааааааааааааааа, я улавливаю твой дрейф
Прежде всего, знаете ли вы размер int и размер short для вашей архитектуры/компилятора? Предполагая, что sizeof(int) == sizeof(int32_t) и sizeof(short) == sizeof(int16_t) - это большое предположение.





это твое решение
(unsigned)~0 == 0xffff
или без ==
!((unsigned)~0 - 0xffff)
!((unsigned)~0 ^ 0xffff)
или если разрешено только 0xff
!((unsigned)~0 ^ (((0xff << (!!0xff << !!0xff << !!0xff << !!0xff))) | 0xff)))
Я как бы понимаю, что вы делаете, но зачем добавлять два оператора ! рядом с каждым 0xff? Не будет ли это просто отрицанием отрицания? Кроме того, я должен использовать максимум 8 операторов.
Мне нужен номер 1. !! преобразует любое ненулевое значение в 1.
затем 3-е решение. Другого пути нет
@P__J__ подержите мое пиво ;-)
Для удобочитаемости установите invuint = ~0u и invushort = ~((short)0u), тогда мы можем сделать invuint - invushort, который либо является 0, либо нет. 0 в стандарте C равен false, поэтому с помощью простого !(invuint - invushort) вы можете увидеть, подходит ли unsigned int к unsigned short.
Но это, скорее всего, не то, что вас просят сделать, это было бы слишком просто. Если вам нужно знать, подходит ли содержимое unsigned int к unsigned short, это становится немного сложнее.
Мы можем повторно использовать incushort = ~((short)0u) в качестве маски.
С an_uint = 0; an_uint = incushort мы устанавливаем младшие биты an_uint равными единицам, поэтому у нас есть 0x0000ffff. Если изменить это с помощью ~an_uint, вы получите 0xXXXX0000, где X означает неизвестное количество единиц. Итак, если sizeof(unsigned int) == sizeof(unsigned short), мы получаем 0, но мы могли бы сделать это проще, см. выше.
Если мы используем mask = 0xXXXX0000 в качестве маски, чтобы получить все биты, которые больше, чем unsigned short с uint_with_unknown_content & mask, мы получим 0, если uint_with_unknown_content подходит к unsigned short.
Решение основано на том факте, что x^(x<<1) будет иметь свои 16 MSB равными нулю, если и только если все 17 MSB x равны и x может быть закодирован 16 битами.
Следовательно
return (x^(x<<1))&(0xffff0000)==0;
решает проблему.
Для удобства чтения операции разбиты на несколько инструкций и для уменьшения количества используемых операторов финальный тест переворачивается (похоже, это не запрещено).
int canNOTbemappedto16bits(int x) {
int one = !0x0; // 1 op
int ffff = (unsigned short) ~0x0;//1 op
int ffff0000 = (unsigned int) ~0x0 ^ ffff; // 2ops
return (x^(x<<one))&ffff0000 ; // 3ops
}
7 операций!
Мне нравится ваша логика, и ваш ответ очень четкий и лаконичный, но как мне это сделать без использования оператора -? Кроме того, мне разрешено использовать только 8 операторов.
Я пропустил тот факт, что "-" было запрещено. Но единственная требуемая операция — это «-1», и ее можно заменить на +(~0). По количеству операторов подходит, но не с ванлайнером. Я обновляю ответ.
@vastImmortalSuns В предыдущем ответе была ошибка, но я нашел гораздо более простой способ, полностью учитывающий ограничения.
Ах я вижу! Спасибо, что прояснили это, я не знал, что вы можете даже отрицать 0, но теперь это имеет смысл :)
!0x0 == 1...!0x0 + !0x0 == 2...просто говорю :)