Получить по степени двойки её показатель

Разговоры на любые темы: вы можете обсудить здесь какой-либо сайт, найти единомышленников или просто пообщаться...
tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Получить по степени двойки её показатель

Сообщение tyomitch » 07.05.2007 (Пн) 15:26

В качестве занимательной и развивающей головоломки, предлагается постить сюда способы получить по целой степени двойки, т.е. по числу от 1 до 2147483648, её показатель (например: 1024 -> 10). Чем интереснее способ, тем лучше: примерно как в классической заморочке физиков "измерить высоту здания барометром".
Изображение

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Сообщение Хакер » 07.05.2007 (Пн) 17:47

Код: Выделить всё
10 = Log(1024) / Log(2)


и всё таки, наверное я чего-то не понимаю.

Надо не юзая Log ?
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 07.05.2007 (Пн) 18:08

Это "померить давление внизу башни, померить наверху, сделать вывод".
Можно и так, да.
Первый, так сказать, вариант. Наименее интересный :)
Как только вы переберёте все варианты решения и не найдёте нужного, тут же обнаружится решение, простое и очевидное для всех, кроме вас

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Сообщение Хакер » 07.05.2007 (Пн) 18:31

померить давление внизу башни, померить наверху, сделать вывод


А разве в этом есть что то особенное? Помойму этот способ измерения - что то само-собой разумеющееся. Или я не прав?


Я так понял, что интересны изврашенские способы узнать степень числа 2. Что-ж :)

Код: Выделить всё
Public Function GetPow(ByVal num&)
    For GetPow = 0 To 31
        If num And (2 ^ GetPow) Then
            Exit Function
        End If
    Next GetPow
    GetPow = Empty
End Function


Код: Выделить всё
Public Function GetPow(ByVal num!)
    Do
        num! = num! / 2
        If Int(num!) = num! Then
            GetPow = GetPow + 1
        Else
            Exit Do
        End If
    Loop
End Function


Щас ещё один допишу...
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

keks-n
Доктор VB наук
Доктор VB наук
Аватара пользователя
 
Сообщения: 2509
Зарегистрирован: 19.09.2005 (Пн) 17:17
Откуда: г. Москва

Сообщение keks-n » 07.05.2007 (Пн) 18:56

Код: Выделить всё
Public Function GetPow(ByVal num as long)
dim p as long, i as long
if num=0 then GetPow=1: Exit Function
if num =1 then GetPow=2: ExitFunction
p=2
for i=2 to num
p=p*2
next
end function


А вообще - надо:
mov eax,1
rol eax, степень
Изображение

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 07.05.2007 (Пн) 20:20

for i=2 to num

Это будет значит for i=2 to, например, 1024, и каждый раз p будет удваиваться?..

mov eax,1
rol eax, степень

А это...
А, гы гы...
keks-n понял задачу ровно наоборот :)
Как только вы переберёте все варианты решения и не найдёте нужного, тут же обнаружится решение, простое и очевидное для всех, кроме вас

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Сообщение Хакер » 07.05.2007 (Пн) 20:37

Код: Выделить всё
Public Function GetPow(ByVal num&) As Long
    Dim xnum$
    xnum$ = Hex$(num&)
    Select Case Mid$(xnum$, 1, 1)
        Case "1": GetPow = 0
        Case "2": GetPow = 1
        Case "4": GetPow = 2
        Case "8": GetPow = 3
    End Select
    GetPow = GetPow + 4 * Len(xnum$) - 4
End Function
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

keks-n
Доктор VB наук
Доктор VB наук
Аватара пользователя
 
Сообщения: 2509
Зарегистрирован: 19.09.2005 (Пн) 17:17
Откуда: г. Москва

Сообщение keks-n » 07.05.2007 (Пн) 21:15

GSerg
Точно :lol:
Изображение

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 07.05.2007 (Пн) 23:21

2Хакер: твой первый код не работает для 2^31
Изображение

Matew
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 894
Зарегистрирован: 28.06.2004 (Пн) 17:44
Откуда: Дальний Восток, г. Ха

Сообщение Matew » 08.05.2007 (Вт) 2:54

Код: Выделить всё
Public Function GetPow(ByVal num&)
Dim bin As String
Do While num& > 1
  bin = bin & Trim$(num& Mod 2)
  num& = num& \ 2
Loop
bin = bin & Trim$(num&)
GetPow = InStr(bin, "1") - 1
End Function
Алкоголь и сканеры-ваши враги! Не верите-смотрите аватару :-)

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 08.05.2007 (Вт) 5:22

Как-то у вас всё однообразно, с циклами.
А мне вот так больше нравится:

Код: Выделить всё
Public Function GetPow(ByVal num As Long) As Long
If num And &HFFFF0000 Then GetPow = GetPow Or 16
If num And &HFF00FF00 Then GetPow = GetPow Or 8
If num And &HF0F0F0F0 Then GetPow = GetPow Or 4
If num And &HCCCCCCCC Then GetPow = GetPow Or 2
If num And &HAAAAAAAA Then GetPow = GetPow Or 1
End Function


Это чтобы стимулировать творчество и поиск нетривиальных вариантов.
Изображение

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 08.05.2007 (Вт) 5:33

И ещё один, в стиле OMG WTF:

Код: Выделить всё
Public Function GetPow(ByVal num As Double) As Long
Static lut As Object
If lut Is Nothing Then
    Set lut = CreateObject("ADODB.Recordset")
    lut.Fields.Append "pow", vbInteger
    lut.Fields.Append "num", vbDouble
    lut.Open
    Dim pow As Integer
    For pow = 0 To 31: lut.AddNew Array("pow", "num"), Array(pow, 2 ^ pow): Next
End If
lut.Filter = "num=" & num
GetPow = lut!pow
End Function
Изображение

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 08.05.2007 (Вт) 5:55

Гибрид двух предыдущих вариантов:

Код: Выделить всё
Public Function GetPow(ByVal num As Long) As Long
GetPow = Array(-1, 0, 1, 26, 2, 23, 27, -1, 3, 16, _
               24, 30, 28, 11, -1, 13, 4, 7, 17, -1, _
               25, 22, -1, 15, 29, 10, 12, 6, -1, 21, _
               14, 9, 5, 20, 8, 19, 18)(num Mod 37)
End Function


Этот вариант не работает для 2^31, точно так же как и код от Matew.
Изображение

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 08.05.2007 (Вт) 7:14

До кучи, вот более компактная запись моего первого варианта:

Код: Выделить всё
Public Function GetPow(ByVal num As Long) As Long
GetPow = (CBool(num And &HFFFF0000) And 16) Or _
         (CBool(num And &HFF00FF00) And 8) Or _
         (CBool(num And &HF0F0F0F0) And 4) Or _
         (CBool(num And &HCCCCCCCC) And 2) Or _
         (CBool(num And &HAAAAAAAA) And 1)
End Function
Изображение

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Сообщение alibek » 08.05.2007 (Вт) 7:30

Хм... А рекурсия?
Код: Выделить всё
Function GetPow(ByVal num As Long) As Long
If num < 2 Then Exit Function
GetPow = 1+GetPow(num\2)
End Function

2^31, увы, не принимает, беззнаковость скажется на компактности.
Lasciate ogni speranza, voi ch'entrate.

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Сообщение alibek » 08.05.2007 (Вт) 7:50

А вот если бы в VB была встроенная функция Bin(), то можно было бы сделать так:
Код: Выделить всё
Function GetPow(ByVal num As Long) As Long
GetPow = 32 - Len(RTrim$(Replace$(Replace$(Dec2Bin(num), String$(32, "0"), String$(32, "-")), "0", " ")))
End Function

Function Dec2Bin(ByVal Value As Long) As String
Dim I As Long, res As String
If Value < 0& Then
  Value = &HFFFFFFFF + Value + 1
  res = res & "1"
Else
  res = res & "0"
End If
For I = 30 To 0 Step -1
  If Value And 2 ^ I Then
    Value = Value - 2 ^ I
    res = res & "1"
  Else
    res = res & "0"
  End If
Next I
Dec2Bin = res
End Function
Lasciate ogni speranza, voi ch'entrate.

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 08.05.2007 (Вт) 11:44

alibek писал(а):Хм... А рекурсия?
Код: Выделить всё
Function GetPow(ByVal num As Long) As Long
If num < 2 Then Exit Function
GetPow = 1+GetPow(num\2)
End Function

2^31, увы, не принимает, беззнаковость скажется на компактности.

Отнюдь -- достаточно лишь переобъявить num As Double :-)

Моё развитие идеи:
Код: Выделить всё
Function GetPow(ByVal num As Double) As Long
Const Sqr2 = 1.4142135623731
Dim root As Double
    If num < 2 Then Exit Function
    root = Sqr(num)
    If CLng(root) * root <> num Then
        root = CLng(root / Sqr2)
        GetPow = 1
    End If
    GetPow = GetPow + GetPow(root) * 2
End Function
Изображение

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Сообщение Хакер » 08.05.2007 (Вт) 12:20

Поиздеваюсь :D


Код: Выделить всё
Public Function GetPow(byval num&) as long
Select Case num&
Case =  1
    GetPow =  0
Case =  2
    GetPow =  1
Case =  4
    GetPow =  2
Case =  8
    GetPow =  3
Case =  16
    GetPow =  4
Case =  32
    GetPow =  5
Case =  64
    GetPow =  6
Case =  128
    GetPow =  7
Case =  256
    GetPow =  8
Case =  512
    GetPow =  9
Case =  1024
    GetPow =  10
Case =  2048
    GetPow =  11
Case =  4096
    GetPow =  12
Case =  8192
    GetPow =  13
Case =  16384
    GetPow =  14
Case =  32768
    GetPow =  15
Case =  65536
    GetPow =  16
Case =  131072
    GetPow =  17
Case =  262144
    GetPow =  18
Case =  524288
    GetPow =  19
Case =  1048576
    GetPow =  20
Case =  2097152
    GetPow =  21
Case =  4194304
    GetPow =  22
Case =  8388608
    GetPow =  23
Case =  16777216
    GetPow =  24
Case =  33554432
    GetPow =  25
Case =  67108864
    GetPow =  26
Case =  134217728
    GetPow =  27
Case =  268435456
    GetPow =  28
Case =  536870912
    GetPow =  29
Case =  1073741824
    GetPow =  30
Case =  2147483648
    GetPow =  31
End Select
End Function
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 08.05.2007 (Вт) 15:59

Вот ещё один новый подход:

Код: Выделить всё
Public Function GetPow(ByVal num As Double) As Long
CopyMemory GetPow, ByVal VarPtr(num) + 6, 2
GetPow = (GetPow \ 16) - 1023
End Function
Изображение

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Сообщение Хакер » 08.05.2007 (Вт) 16:14

PutMem2 быстрее будет :wink:
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

uhm
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1597
Зарегистрирован: 02.12.2004 (Чт) 15:21

Сообщение uhm » 10.05.2007 (Чт) 14:47

Код: Выделить всё
Option Base 1

Function GetPow(ByVal num As Double) As Long
    bases = Array(0, 4, 7, 10, 14, 17, 20, 24, 27, 30)
    a = Len(CStr(num))
    b = Len(CStr(num / 2))
    c = Len(CStr(num / 4))
    d = Len(CStr(num / 8))
   
    GetPow = bases(a) - (a = b) - (a = c) - (a = d)
   
End Function
Быть... или не быть. Вот. В чём вопрос?

uhm
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1597
Зарегистрирован: 02.12.2004 (Чт) 15:21

Сообщение uhm » 10.05.2007 (Чт) 14:54

Код: Выделить всё
Function GetPow2(ByVal num As Double) As Long
On Error GoTo exit_function
    Dim b As Long
    For i = 31 To 0 Step -1
        b = CLng(num)
        num = num * 2
    Next i
exit_function:
    GetPow2 = i
End Function
Быть... или не быть. Вот. В чём вопрос?

uhm
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1597
Зарегистрирован: 02.12.2004 (Чт) 15:21

Сообщение uhm » 10.05.2007 (Чт) 15:34

Код: Выделить всё
Function GetPow3(ByVal num As Double) As Long
    Dim p As Integer
   
    Randomize
   
    While num <> 2 ^ p
        p = CInt(Rnd * 32)
    Wend
   
    GetPow3 = p
End Function
Быть... или не быть. Вот. В чём вопрос?

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Сообщение Хакер » 10.05.2007 (Чт) 15:35

Последний вариант рулит :thumright:
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 10.05.2007 (Чт) 15:38

uhm, отлично! :-D
Изображение

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 07.06.2007 (Чт) 12:38

Черпая вдохновение из обзора финалистов OMGWTF, создал ещё один вариант.

Код: Выделить всё
Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (lpfn As Any, ByVal param) As Long

Function GetPow(ByVal num As Long) As Long
GetPow = CallWindowProc(471695703125.1215@, num)
End Function
Изображение


Вернуться в Народный треп

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 35

    TopList  
cron