Collatz Problem

Тема в разделе "WASM.A&O", создана пользователем blueboar, 30 авг 2004.

  1. blueboar

    blueboar New Member

    Публикаций:
    0
    Регистрация:
    29 авг 2004
    Сообщения:
    110
    Адрес:
    Россия, Курган
    Нужна как можно более эффективная программа, делающая

    следующее



    1) Берущая число(положительное натуральное)

    2) Если четное, делит на 2

    3) Если нечетное, умножает на 3 и прибавляет 1

    (можно еще поделить на 2, т.к. получится четное)

    4) Пункты 2-3 повторяют, пока не будет число =1



    Еще не доказано, что всегда так будет, так что

    нужно предусмотреть вариант зацикливания



    И еще. Нужны большие числа. Типа 10^20 или даже

    больше. Так что DWORD'ом тут не обойтись. Сам

    я пытался написать такую программу, но по скорости

    она явно была не лучшая.
     
  2. Icebp

    Icebp New Member

    Публикаций:
    0
    Регистрация:
    24 дек 2003
    Сообщения:
    39
    С 32-х битными числами можно сделать примерно так:

    mov eax,[number]

    cyc: test al,1

    jnz odd

    shr eax,1

    jmp cyc

    odd: mov ebx,eax

    shr eax,1

    add eax,ebx

    inc eax

    jmp cyc

    ...

    number: dd 12345678h



    Вроде так если я нигде не ошибся. А в связи с чем, кстати, у тебя возникла такая задача?
     
  3. blueboar

    blueboar New Member

    Публикаций:
    0
    Регистрация:
    29 авг 2004
    Сообщения:
    110
    Адрес:
    Россия, Курган
    Это, конечно, хорошо, но интересуют в первую

    очередь 128-битные числа.



    Задача эта возникла не у меня. Она существует

    уже давно и называется Collatz Problem. За

    доказательство, что любое число сходится

    подобным образом обещано 1000 фунтов стерлингов

    (наверное теперь уже Евро).



    А пока люди считают таким образом как можно

    большие числа (вдруг какое-нибудь не сойдется,

    тогда будет док-во от противного).



    Уже до 10^16 степени досчитали. Так что DWORD

    никак не пойдет. Но я думаю, что расширить

    пример будет не очень сложно?
     
  4. Kozyr

    Kozyr New Member

    Публикаций:
    0
    Регистрация:
    3 апр 2004
    Сообщения:
    6
    Адрес:
    Ukraine
    <skiped>
     
  5. Kozyr

    Kozyr New Member

    Публикаций:
    0
    Регистрация:
    3 апр 2004
    Сообщения:
    6
    Адрес:
    Ukraine
    blueboar

    Задача эта возникла не у меня. Она существует уже давно и называется Collatz Problem.

    Заинтриговал ты меня ;)



    Но я начал не программу писАть, а ручку с листочком взял. Предлагаю на это посмотреть вот с какой стороны:



    - числа представляем в двоичной системе

    - деление на степень двойки определяется количеством нулей в конце числа (соответственно, деление на степень 2 - удалением лишних нулей ;)



    Рассмотрим только последние 3 бита (нечетных чисел):

    001 (*3+1) 100

    011 (*3+1) 1010 -> 101 (*3+1) 10000

    101 (*3+1) 10000

    111 (*3+1) 10110 -> 1011 (*3+1) 10001 (*3+1) 110100 -> 1101 (*3+1) 101000 -> 101 (*3+1) 10000



    001 - 1 преобразование и 2 нуля

    011 - 2 преобразования и 5 нулей

    101 - 1 преобразование и 4 нуля

    111 - 5 преобразований и 10 нулей



    Одно преобразование (X*3+1)/2 может увеличить число максимум в полтора раза или 1.5 бита.



    Смотрим на наши тройки чисел - число изменяется на следующее кол-во бит (преобразование * 1.5 - кол-во нулей)..... везде отрицательная величина... можно предположить, что все числа сходятся..... да ты в добавок еще и проверил 10^16 штук :)



    Для затравки смотри аттач, там 4 бита.



    PS. Весь выше приведенный бред на математическую точность не претендует, но мне кажется нужно искать 1000 евро где-нибудь в другом месте ;)

    [​IMG] 539929080__3x+1.zip
     
  6. bogrus

    bogrus Active Member

    Публикаций:
    0
    Регистрация:
    24 окт 2003
    Сообщения:
    1.338
    Адрес:
    ukraine
    blueboar




    2/2=1 . Кажеться тут проблема гораздо глубже ?

    http://www.ega-math.narod.ru/Nquant/Collatz.htm



    Icebp Там получаеться условие такое : IF N MOD 2 = 0 THEN N = N/2 ELSE N = 3*N + 1

    Код примерно такой из этой статьи :
    Код (Text):
    1.      mov     eax,number (N)
    2. @@:  mov     ebx,eax
    3.      shr     eax,1
    4. ;    jz      exit      ; пришли к 4,2,1
    5.      jnc     @B
    6.      mov     eax,ebx
    7.      add     eax,ebx
    8.      add     eax,ebx
    9.      inc     eax
    10.      jmp     @B
    Исследованы числа до 2<sup>40</sup>, все они приходят к 1 . Статья датирована - март 1984 г.
     
  7. Kozyr

    Kozyr New Member

    Публикаций:
    0
    Регистрация:
    3 апр 2004
    Сообщения:
    6
    Адрес:
    Ukraine
    blueboar

    Если проверять числа по порядку (по возростанию), то можно проверять только нечетные.
     
  8. Icebp

    Icebp New Member

    Публикаций:
    0
    Регистрация:
    24 дек 2003
    Сообщения:
    39
    blueboar

    Тебе пойдет вариант с использованием SSE2? Если пойдет, то например деление на 2 для 128-битных чисел можно сделать так:



    movaps xmm0,[number]

    psrldq xmm0,1

    movaps xmm1,[mask]

    pand xmm0,xmm1

    movaps [number],xmm0

    ...

    align 16

    number: dq 123456789abcdefh, 521397caeh

    mask: dd 0ffffffffh,0ffffffffh,0ffffffffh,7fffffffh



    Если то число, что мы делим на 2 будет четным, то 3-ей и 4-ой строчек не надо. То есть не нужны: movaps xmm1,[mask] и pand xmm0,xmm1.
     
  9. Icebp

    Icebp New Member

    Публикаций:
    0
    Регистрация:
    24 дек 2003
    Сообщения:
    39
    blueboar



    Оказывается я был неправ: инструкция PSRLDQ сдвигает содержимое XMM вправо не на число бит, указанных во втором операнде, а на число БАЙТ, указанных во втором операнде. Сам убедился в этом когда пытался написать программу, аналогичную вышеприведенной. Она у меня не работала. Когда разбирался в чем дело, то в отладчике увидел что к чему. Потом внимательно глянул в описание этой инсрукции и убедился, что именно байт, а не бит. В аттачменте программа, которая проверяет числа по твоему алгоритму. Как ей пользоваться объяснять наверное не буду, так как из текста программы наверное все будет понятно.

    [​IMG] _1380416443__TOONE.ASM
     
  10. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Замечания по реализации.

    Во-первых, незачем "в лоб" вычислять 3x+1, т.к. это число всегда четное.

    "Изящнее" будет сразу (3x+1)/2 = x + (x div 2) + 1. Для dword это просто:
    Код (Text):
    1.     mov ebx,eax
    2.     shr eax,1
    3.     jnc @@even  ;четное
    4.     adc eax,ebx ;одна инструкция вместо 4
    Это же относится к MMX-реализации Icebp - не нужны будут переменная temp и цикл increm. Плюс экономия одного бесполезного цикла (т.к. 3х+1 - всегда четное). Плюс экономия кода, т.к. сложное деление мымыксов на 2 не нужно будет дублировать для чет\нечет.



    Во-вторых, не нужно крутить цикл до достижения единицы. Если известно, что все числа x < 2^n сходятся, то нужно выходить из цикла, если старшые разряды числа от n до Nmax равны нулю.



    Вообще, в этой задачке гораздо бОльшую экономию можно достичь за счет отсечения чисел, которые заведомо сходятся. Приведенная bogrus ссылочка на статью вызывает "удручающую смесь закономерности и беспорядка", якобы числа "не имеют никаких явных общих черт". Может они в десятичном виде не имеют общих черт, а в двоичном все нагляднее ? Считаем, что все x < 2^n сходятся и => все четные < 2^(n+1) тоже сходятся. Если посмотреть как работает алгоритм на младших разрядах, то увидим что, например, безусловно сходятся все числа оканчивающиеся на x101, т.к.на первом же шаге получаем несколько младших нулей и после shr получаем x < 2^n => нет смысла перебирать все старшие разряды. Числа заканчивающиеся на x001 точно сходятся если нет переноса в старший разряд (т.е. старшие 100х). Можно рассмотреть большее число разрядов и учесть "сваливание" на втором, третьем и т.д. шагах. Например, явно сходится х00011 и вообще все Х00..011..1, где нулей на 1 больше, чем единиц (сначала рост, затем спад).

    Вопрос как это все учесть в программе. Один из вариантов - заранее просчитать и составить табличку младших байтов, которые имеет смысл проверять (а может и вордов, если их не очень много).
     
  11. blueboar

    blueboar New Member

    Публикаций:
    0
    Регистрация:
    29 авг 2004
    Сообщения:
    110
    Адрес:
    Россия, Курган
    В общем, отвечаю всем по-порядку.



    1) У меня пень-MMX, так что никаких SSE2,

    MMX - можно.

    2) Я написал прогу, которая считает эти

    числа на АСМЕ, есс-но



    Выложу вместе с алгоритмом на

    http://www.bigblueboar.narod.ru/prog.rar

    (ссылка прямая, на сайте на нее не указано)



    Нужно:



    1) Указать на пути оптимизации проги

    (пусть даже на 2-3 такта каждый 1000 цикл)

    2) Указать на пути оптимизации алгоритма

    (в архиве есть также алгоритм работы программы)



    P.S 1)Программа ищет классы - то есть минимальные

    числа, которые раскладываются за N шагов. Пока

    найдены все классы до N=2000.

    2) Программа создана методом "Махохизма для

    Дзенствующих", как было сказано в какой-то статье,

    т.е. был взят Блокнот и программа "Воткнута" внутрь

    него прямо в машинном коде. Так что она не занимает

    50Кб, не пугайтесь!