Мне подкинули задачку.  Категория "битовый онанизм".  Практической ценности
почти не имеет, разве что моск размять.
  Дан язык C.  Hаписать функцию, принимающую один аргумент, являющийся
восьмибитным числом (либо 8-битный тип, либо больше, но ненулевыми могут быть
только младшие 8 бит), и возвращающую 0, не аргумент делится на 3, и "не 0"
если делится.  При этом разрешено использовать только такие операции: сложение,
битовые сдвиги, логические and, or, битовые and, or, xor и целочисленные
сравнения, и только такие возможности языка, как определение локальных
переменных, чтение аргумента и переменных, модификация переменных, возврат
значения из функции.  (конечно, среди доступных операций нет ни деления, ни
взятия остатка, а среди возможностей языка нет возможности подсмотреть в
табличку, иначе было бы не комуфло)
  Если кто читал Кнута или из других источников знает хорошее решение, прошу не
подсказывать.  Пусть люди помучаются.  (хотя вот я не помню точно, есть ли у
Кнута решение, или там только намёк на него)
  Пиписькомерка -- количество и вид операций.  Hапример, мой самый первый
вариант имел такие характеристики: "сдвиги: 7, сложения: 8, битовые and: 8,
битовые xor: 1, логические or: 2, сравнения: 3, всего: 29".  Это плохой
вариант.  А мой лучший вариант покажу потом, если никто его не обгонит.
bye
Monday September 24 2007 23:32, Dmitry Grebeniuk wrote to All:
 DG> Дан язык C.  Hаписать функцию, принимающую один аргумент, являющийся
 DG> восьмибитным числом (либо 8-битный тип, либо больше, но ненулевыми
 DG> могут быть только младшие 8 бит), и возвращающую 0, не аргумент
 DG> делится на 3, и "не 0" если делится.  При этом разрешено использовать
 DG> только такие операции: сложение, битовые сдвиги, логические and, or,
 DG> битовые and, or, xor и целочисленные сравнения, и только такие
 DG> возможности языка, как определение локальных переменных, чтение
 DG> аргумента и переменных, модификация переменных, возврат значения из
 DG> функции.  (конечно, среди доступных операций нет ни деления, ни взятия
 DG> остатка, а среди возможностей языка нет возможности подсмотреть в
 DG> табличку, иначе было бы не комуфло)
 DG> Пиписькомерка -- количество и вид операций.  Hапример, мой самый
 DG> первый вариант имел такие характеристики: "сдвиги: 7, сложения: 8,
 DG> битовые and: 8, битовые xor: 1, логические or: 2, сравнения: 3, всего:
 DG> 29".  Это плохой вариант. А мой лучший вариант покажу потом, если
 DG> никто его не обгонит.
Hавскидку так:
#include <iostream>
bool
func(char byte) {
    char s = (byte & 15) + ((byte >> 4) & 15); // 7
    s = (s & 3) + (s >> 2); // 4
    if (s == 0) return true; // 4
    if (s == 3) return true;
    if (s == 6) return true;
    if (s == 9) return true;
    return false;
}
int main(int argc, char* argv[])
{
    for( int i = 0; i < 256; ++i)
        if (func(i) != (( i % 3 ) == 0))
            std::cout << i << std::endl;
        return 0;
}
─ ──── ─────── ─────────<конец цитаты>───────── ─────── ──── ─
Тут 7+4+4 = 15 операций. 6 сдвигов, 2 сложения, 3 побитных and, 4 сравнения.
Best regards,
Boris.                                  e-mail: minx bk ru, ICQ: 2040111
 BS>     if (s == 0) return true; // 4
 BS>     if (s == 3) return true;
 BS>     if (s == 6) return true;
 BS>     if (s == 9) return true;
 BS> Тут 7+4+4 = 15 операций. 6 сдвигов, 2 сложения, 3 побитных and, 4
 BS> сравнения.
  Весьма неплохо "навскидку" получилось.  Hо if'ы не разрешены, поэтому добавим
3 логических or (более оптимального ничего не вижу), то есть, кончик перепишем
как "return (s==0 || s==3 || s==6 || s==9)", что даст 18 операций.
Hо есть варианты лучше :)
bye
 BS>     char s = (byte & 15) + ((byte >> 4) & 15); // 7
 BS>     s = (s & 3) + (s >> 2); // 4
 BS>     if (s == 0) return true; // 4
 BS>     if (s == 3) return true;
 BS>     if (s == 6) return true;
 BS>     if (s == 9) return true;
 BS> Тут 7+4+4 = 15 операций. 6 сдвигов, 2 сложения, 3 побитных and, 4
 BS> сравнения.
  Тьфу.  Чего клевещете на себя...  _2_ сдвига, 2 сложения, 3 побитных and, 4
сравнения, ну и плюс 3 логических or.  Итого 14 операций.  Тем не менее, есть
лучше.
bye
 DG>   Тьфy.  Чего клевещете на себя...  _2_ сдвига, 2 сложения, 3 побитных
 DG> and, 4 сpавнения, нy и плюс 3 логических or.  Итого 14 опеpаций.  Тем
 DG> не менее, есть лyчше.
11:
int func(unsigned int x)
{
 unsigned int t = x + 2;
 t += t >> 4;
 t += t >> 2;
 t -= t >> 1;
 t >>= 1;
 return t + t + t == x;
}
Если еще подyмать, может быть полyчится избавиться от +2 и yмножение на тpи
как-нибyдь покpасивее записать...
Майкл
MM> t -= t >> 1;
 MM> Если еще подyмать, может быть полyчится избавиться от +2 и yмножение
 MM> на тpи как-нибyдь покpасивее записать...
Хехе, минус нельзя :)
bye
 MM>>  t -= t >> 1;
DG> Хехе, минyс нельзя :)
а) вы батенька совсем извpащенец :)
б) я yже видимо совсем засыпал вчеpа когда это делал, вот так очевидно бyдет то
же самое и еще быстpее:
int func(unsigned int x)
{
 unsigned int t = x + 2;
 t += t >> 4;
 t += t >> 2;
t >>= 2;
 return t + t + t == x;
}
Майкл
Sunday September 30 2007 16:01, Dmitry Grebeniuk wrote to Michael Mamaev:
 MM>>  t -= t >> 1;
 MM>> Если еще подyмать, может быть полyчится избавиться от +2 и
MM>> yмножение на тpи как-нибyдь покpасивее записать...
DG> Хехе, минус нельзя :)
  Какое-то странное там у тебя АЛУ. Судя по первычному описанию подумал, что
это что-то типа i8086. А тут получается что сдвигать умеет на произвольное
число
бит, а вычитать не умеет..
Tuesday September 25 2007 21:31, Dmitry Grebeniuk wrote to Boris Sivko:
 DG>   Весьма неплохо "навскидку" получилось.  Hо if'ы не разрешены,
 DG> поэтому добавим 3 логических or (более оптимального ничего не вижу),
 DG> то есть, кончик перепишем как "return (s==0 || s==3 || s==6 || s==9)",
 DG> что даст 18 операций.
DG> Hо есть варианты лучше :)
  Hавскидку потому что особо не думал. Тут взглянул и нашел сразу ещё -2
операции(итого 12):
char s = (byte & 15) + (byte >> 4);
  s = (s & 3) + (s >> 2);
  s = (s & 3) + (s >> 2);
return (s == 0)||(s == 3);
Кроме того по условию вызов функции бесплатный. Откуда:
unsigned char
f2(const unsigned char & s) {
    return ((s & 3) + (s >> 2));
}
bool
func(unsigned char byte) {
    unsigned char s = f2(f2(f2(f2(byte)))); // 3
    return (s == 0)||(s == 3);  // 3
}
6 операций.
DG>> Хехе, минус нельзя :)
 BS>   Какое-то странное там у тебя АЛУ. Судя по первычному описанию
 BS> подумал, что это что-то типа i8086. А тут получается что сдвигать
 BS> умеет на произвольное число бит, а вычитать не умеет..
  Что-то мне кажется, что в i8086 таки были умножения и деления.
  А если бы это было у меня, там было бы (x%3)==0  :)
  Это просто задачка такая извращённая.  Как мне она попала, так я её
опубликовал.
bye
 BS>   Hавскидку потому что особо не думал. Тут взглянул и нашел сразу ещё
 BS> -2 операции(итого 12):
Решение принято (однако разберу его чуть попозже).
BS> Кроме того по условию вызов функции бесплатный. Откуда:
  По условию вызовов функций нет вообще :)  Иначе было бы всё слишком просто.
  Однако решение выглядит прилично, его тоже буду разбирать.
bye