Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2015.09.10;
Скачать: CL | DM;

Вниз

Задачка::Проверка бита   Найти похожие ветки 

 
Dimka Maslov ©   (2014-10-14 11:07) [0]

Дано: имеется целое число (n). Известно, что в нём установлен только один бит, остальные нули.
Требуется установить номер этого бита (i).

Возможные решения:
1) for (i = 0; n && (n & 1) == 0; n>>=1, i++);
2) i = (int)log2((double)n);
3) тупо через switch

Какие ещё могут быть варианты?


 
Romkin ©   (2014-10-14 11:11) [1]

Массив.
Вообще зависит от разрядности этого самого числа.


 
manaka ©   (2014-10-14 11:16) [2]


> Известно, что в нём установлен только один бит, остальные
> нули


Значит число есть степень 2
Номер бита=степень+1


 
Юрий Зотов ©   (2014-10-14 11:22) [3]

2^x = n

x = Log2(n)


 
manaka ©   (2014-10-14 11:23) [4]

i:=1;
while n<>1 do begin
 n=n/2;
 i=i+1;
end;


))))))


 
MBo ©   (2014-10-14 11:24) [5]

Ассемблер, BSR/BSF

Бинарный поиск

 if (x and $FFFF0000)>0 then Index := Index+16;
 и т.п.


 
oldman ©   (2014-10-14 11:24) [6]


> Юрий Зотов ©   (14.10.14 11:22) [3]
> x = Log2(n)


x=log2(n)+1


 
Юрий Зотов ©   (2014-10-14 11:33) [7]

> oldman ©   (14.10.14 11:24) [6]

Это зависит от соглашения о нумерации. Если оно не оговорено, то в мире IT биты принято нумеровать, начиная с нуля.


 
Юрий Зотов ©   (2014-10-14 11:35) [8]

Кто тег не закрыл?

Теперь закрыт.


 
Dimka Maslov ©   (2014-10-14 11:35) [9]


> Romkin ©   (14.10.14 11:11) [1]


Для 64 бит массив будет ооооооооооочень большим


> Юрий Зотов ©   (14.10.14 11:22) [3]


Вариант 2 получается


> manaka ©   (14.10.14 11:23) [4]


Вариант 1 получается


> MBo ©   (14.10.14 11:24) [5]


чё-то не понял


> oldman ©   (14.10.14 11:24) [6]


log2(1) = 0,  а биты нумеруются от 0 до 31. так что всё правильно


 
MBo ©   (2014-10-14 11:35) [10]


незакрытый тег, видимо, я оставил.

Погуглил - без ветвлений есть метод:

var
 i, x: integer;
 table: array[0..31] of Integer;
begin
 for i := 0 to 31 do //инициализация, метод de Brujin
   table[ ( $077CB531 * ( 1 shl i ) ) shr 27 ]  := i;

 x := 1 shl 17;
 Caption := IntToStr(table[(x * $077CB531) shr 27]);


 
MBo ©   (2014-10-14 11:37) [11]

>чё-то не понял
Не понял про ассемблерные команды, или про бинарный поиск?


 
Dimka Maslov ©   (2014-10-14 11:39) [12]

Про бинарный поиск


 
MBo ©   (2014-10-14 11:46) [13]


r:=0; //индекс единичного бита будет тут
if (x and $FFFF0000)>0 then r:=r+16; // бит в старшем слове
if (x and $FF00FF00)>0 then r:=r+8;  // бит в старшем байте одного из слов
if (x and $F0F0F0F0)>0 then r:=r+4;  // бит в старшем ниббле одного из байтов
if (x and $CCCCCCCC)>0 then r:=r+2;  //бит в одно из старших битов ниббла
if (x and $AAAAAAAA)>0 then r:=r+1;   //бит на нечетном месте  $AA = bin10101010


 
Дмитрий С ©   (2014-10-14 12:42) [14]

Неужели банальную подсветку так сложно сделать с первого раза? :))


 
Inovet ©   (2014-10-14 15:59) [15]

> [14] Дмитрий С ©   (14.10.14 12:42)

Сделай


 
Inovet ©   (2014-10-14 15:59) [16]

> [9] Dimka Maslov ©   (14.10.14 11:35)
> Для 64 бит массив будет ооооооооооочень большим

64 элемента и будет по условию задачи.


 
Rouse_ ©   (2014-10-14 18:05) [17]

Самое быстрое, конечно BSR, если задача на оптимизацию по скорости


 
MBo ©   (2014-10-14 18:37) [18]


> Самое быстрое, конечно BSR, если задача на оптимизацию по
> скорости

Не факт. Оно, кажется, конвейеры с панталыку сбивает.
Я 4 метода испытал на старом Athlon - с магическим умножением, бинарный поиск, и BSR дают примерно одно и то же время, а сдвиг числа вправо, пока бит не найдется - втрое большее на таком тесте:
for k := 1 to 100000000 do begin
   i := 1 shl (k mod 32);
   l := l + BitIndex(i);
 end;


 
Dimka Maslov ©   (2014-10-14 19:20) [19]


> Самое быстрое, конечно BSR, если задача на оптимизацию по
> скорости


Проблема в том, что на 64 битах злые вредоносные существа не дают прямого доступа к ассемблеру. Вот и приходится извращаться.


 
Pavia ©   (2014-10-14 19:21) [20]


> Не факт. Оно, кажется, конвейеры с панталыку сбивает.

Только если на микрокоде сделана.


 
Rouse_ ©   (2014-10-14 19:24) [21]


> MBo ©   (14.10.14 18:37) [18]
> Не факт. Оно, кажется, конвейеры с панталыку сбивает.

uses
 Windows;

function GetIndexBsr(Value: DWORD): Byte; assembler;
asm
 bsr eax, eax
end;

function GetIndexMBo(Value: DWORD): Byte;
begin
 Result := 0; //индекс единичного бита будет тут
 if (Value and $FFFF0000) > 0 then Result := Result + 16; // бит в старшем слове
 if (Value and $FF00FF00) > 0 then Result := Result + 8;  // бит в старшем байте одного из слов
 if (Value and $F0F0F0F0) > 0 then Result := Result + 4;  // бит в старшем ниббле одного из байтов
 if (Value and $CCCCCCCC) > 0 then Result := Result + 2;  //бит в одно из старших битов ниббла
 if (Value and $AAAAAAAA) > 0 then Result := Result + 1;   //бит на нечетном месте  $AA = bin10101010
end;

var
 I: Integer;
 S: DWORD;
begin
 Randomize;
 S := GetTickCount;
 for I := 0 to 100000000 do
   GetIndexBsr(I);
 Writeln(GetTickCount - S);
 S := GetTickCount;
 for I := 0 to 100000000 do
   GetIndexMBo(I);
 Writeln(GetTickCount - S);
 Readln;
end.


265
1778


 
Rouse_ ©   (2014-10-14 19:27) [22]

PS^ тем более что GetIndexMBo(6) = 3.
Или я не тот алгритм взял?


 
Rouse_ ©   (2014-10-14 19:28) [23]


> Dimka Maslov ©   (14.10.14 19:20) [19]
> Проблема в том, что на 64 битах злые вредоносные существа
> не дают прямого доступа к ассемблеру. Вот и приходится извращаться.

Приведенный в [21] код достаточно успешно компилируется и работает в 64 битах :)


 
Rouse_ ©   (2014-10-14 19:34) [24]

Может и не в тему, но тоже хочу задачку для разминки мозга подкинуть.
Дан ряд чисел от единицы до N (к примеру если N = 6, то ряд выглядит как 1,2,3,4,5,6).
Задача: написать функцию возвращающую сумму всех чисел ряда. (При N = 6, результат 21)
Ограничения - функция не должна использовать цикл или рекурсию.


 
Dimka Maslov ©   (2014-10-14 19:35) [25]


> Приведенный в [21] код достаточно успешно компилируется
> и работает в 64 битах :)


Смотря каких. Маздайный С++ говорит, что
error C4235: nonstandard extension used : "__asm" keyword not supported on this architecture

И всё. Приплыли.


 
Rouse_ ©   (2014-10-14 19:38) [26]

Под арму чтоль компилишь?


 
Rouse_ ©   (2014-10-14 19:39) [27]

под 64 битами все пахет в MS VC++ 2010


 
MBo ©   (2014-10-14 19:39) [28]


> Или я не тот алгритм взял?

Тот. Входные данные некорректные - один бит должен быть установлен, я выделение младшего бита убрал. Это может повлиять на ветвления, но не настолько радикально. Видимо, другая архитектура ядра процессора сказывается. Вот мой полный тест.


var
 i, k, l: Integer;
 table: array[0..31] of Integer;
 t: DWord;

function BitIndexBSR(Value: Integer): Integer;
asm
  BSR   EAX,EAX
end;

function BitIndexDeBruijn(Value: Integer): Integer;
begin
 Result := table[(Value * $077CB531) shr 27];
end;

function BitIndexSHR(Value: Integer): Integer;
begin
 Result :=0;
 while (Value and 1) = 0 do begin
   Inc(Result);
   Value := Value shr 1;
 end;
end;

function BitIndexBinS(Value: Integer): Integer;
begin
 result:=0; //индекс единичного бита будет тут
 if (Value and $FFFF0000)<>0 then result:=result+16; // бит в старшем слове
 if (Value and $FF00FF00)<>0 then result:=result+8;  // бит в старшем байте одного из слов
 if (Value and $F0F0F0F0)<>0 then result:=result+4;  // бит в старшем ниббле одного из байтов
 if (Value and $CCCCCCCC)<>0 then result:=result+2;  //бит в одно из старших битов ниббла
 if (Value and $AAAAAAAA)<>0 then result:=result+1;   //бит на нечетном месте  $AA = bin10101010
end;

begin
 l := 0;
 for i := 0 to 31 do //инициализация, метод de Brujin
   table[ ( $077CB531 * ( 1 shl i ) ) shr 27 ]  := i;

 t := GetTickCount;
 for k := 1 to 100000000 do begin
   i := 1 shl (k mod 32);
   l := l + BitIndexBSR(i);
 end;
 Memo1.Lines.Add(Format("BSR %d", [GetTickCount- t]));

 t := GetTickCount;
 for k := 1 to 100000000 do begin
   i := 1 shl (k mod 32);
   l := l + BitIndexDeBruijn(i);
 end;
 Memo1.Lines.Add(Format("DeBruijn %d", [GetTickCount- t]));

 t := GetTickCount;
 for k := 1 to 100000000 do begin
   i := 1 shl (k mod 32);
   l := l + BitIndexBinS(i);
 end;
 Memo1.Lines.Add(Format("BinSearch %d", [GetTickCount- t]));

 t := GetTickCount;
 for k := 1 to 100000000 do begin
   i := 1 shl (k mod 32);
   l := l + BitIndexSHR(i);
 end;
 Memo1.Lines.Add(Format("SHR %d", [GetTickCount- t]));


Athlon 3500+
BSR 1422
DeBruijn 1578
BinSearch 1438
SHR 6422


 
Dimka Maslov ©   (2014-10-14 19:40) [29]

Нет x64 под Венду. Не даёт. А если как в спраке сказано, понизить уровень до ворнинга, то говорит, что bsr и eax неизвестные идентификаторы, однако...


 
MBo ©   (2014-10-14 19:41) [30]

А вот магические числа deBruijn для 64 бит:
Table[(uint64_t)(val * 0x022fdd63cc95386dull) >> 58];


 
Rouse_ ©   (2014-10-14 19:48) [31]


> MBo ©   (14.10.14 19:39) [28]

Ну как я и говорил изначально - BSR самый шустрый по скорости :)


> Dimka Maslov ©   (14.10.14 19:40) [29]
> Нет x64 под Венду. Не даёт.

Ты че там такое компиляш?
Давай демку архивом, завтра гляну.


 
Ega23 ©   (2014-10-14 19:57) [32]


> Rouse_ ©   (14.10.14 19:34) [24]
>
> Может и не в тему, но тоже хочу задачку для разминки мозга
> подкинуть.
> Дан ряд чисел от единицы до N (к примеру если N = 6, то
> ряд выглядит как 1,2,3,4,5,6).
> Задача: написать функцию возвращающую сумму всех чисел ряда.
>  (При N = 6, результат 21)
> Ограничения - функция не должна использовать цикл или рекурсию.
>


Result := (((N + 1) * N) shr 1);


 
Dimka Maslov ©   (2014-10-14 20:00) [33]

#define BIT0    0x01
#define BIT1    0x02
#define BIT2    0x04
#define BIT3    0x08
#define BIT4    0x10
#define BIT5    0x20
#define BIT6    0x40
#define BIT7    0x80

long BitIndex(long N)
{
__asm
{
mov eax, N
       bsr eax, eax
}
}

Microsoft Visual Studio 2013 простое консольное приложение 64 бита. Ассемблер более не дозволен.


 
MBo ©   (2014-10-14 20:03) [34]


> Microsoft Visual Studio 2013 простое консольное приложение
> 64 бита. Ассемблер более не дозволен.


Интринсики же есть _BitScanReverse64


 
Юрий Зотов ©   (2014-10-14 20:04) [35]

А логарифм как, по скорости?


 
Rouse_ ©   (2014-10-14 20:10) [36]


> Ega23 ©   (14.10.14 19:57) [32]

Гаусс? Молоток, зарраза :)


 
Inovet ©   (2014-10-14 20:10) [37]

> [24] Rouse_ ©   (14.10.14 19:34)
> Задача: написать функцию возвращающую сумму всех чисел ряда. При N = 6, результат 21)

Это что ли?
Для нечётных Н*Н/2
для чётных Н*(Н+1)/2


 
Kerk ©   (2014-10-14 20:11) [38]


> Дан ряд чисел от единицы до N

https://ru.wikipedia.org/wiki/%C0%F0%E8%F4%EC%E5%F2%E8%F7%E5%F1%EA%E0%FF_%EF%F0%EE%E3%F0%E5%F1%F1%E8%FF#.D0.A1.D1.83.D0.BC.D0.BC.D0.B0_.D0.BF.D0.B5.D1.80.D0.B2.D1.8B.D1.85_.D1.87.D0 .BB.D0.B5.D0.BD.D0.BE.D0.B2_.D0.B0.D1.80.D0.B8.D1.84.D0.BC.D0.B5.D1.82.D0.B8.D1. 87.D0.B5.D1.81.D0.BA.D0.BE.D0.B9_.D0.BF.D1.80.D0.BE.D0.B3.D1.80.D0.B5.D1.81.D1.8 1.D0.B8.D0.B8

?


 
Rouse_ ©   (2014-10-14 20:12) [39]


> Inovet ©   (14.10.14 20:10) [37]

Угу, оно... забыл что вы тут все умные, каюсь. Задачка - так себе :)


 
Rouse_ ©   (2014-10-14 20:14) [40]

Есть еще один вариант не методом Гаусса решается, но в принципе - задача решена :)



Страницы: 1 2 вся ветка

Текущий архив: 2015.09.10;
Скачать: CL | DM;

Наверх




Память: 0.57 MB
Время: 0.057 c
2-1365077543
JohnKorsh
2013-04-04 16:12
2015.09.10
Иконка программы.


1-1332746450
CRLF
2012-03-26 11:20
2015.09.10
Подружить IXMLDOMDocument2 и MS SQL XML


15-1418746443
Erracado
2014-12-16 19:14
2015.09.10
Прерывание выполнения ADOQuery


2-1392709575
Alex_C
2014-02-18 11:46
2015.09.10
Сообщение при клике правой кнопкой мыши на кнопке панели задач


15-1422271890
alexdn
2015-01-26 14:31
2015.09.10
Требуется модератор