Re: Наконечно досчиталось до а14 !
От: Seon  
Дата: 26.01.09 14:39
Оценка: 35 (3) +2 :))
Распределенный вариант программы сегодня нашел а(14) = 2^53619497 !!!!

На это ушло 21 день и 2 часа!

Одновременно эту задачу считало от 2-х до 8 компов попеременно. В среднем гдето 4-5 штук.
Задача без всяких оптимизаций — первоначальный вариант — десятичные числа на чарах!!

Продолжать считать думаю на этом варианте нет смысла — до а(15) — топать в 4 раза дольше! Ой ой ой...

Еще тут на одном проце оптимизированная до интов(9 десятичных цифр на 1 элемент массива — ИНТ) задача посчитала уже свыше 35 000 000. На это ушло уже 7 дней!
Движемся на ней до а(14), интересно же узнать, опередит ли эта оптимальная версия — распределенную..
Re: k нулей
От: Beam Россия  
Дата: 23.12.08 21:19
Оценка: 26 (4)
Здравствуйте, vadimcher, Вы писали:

V>Докажите, что для любого k найдется такое число n, что в [i]десятичной[i] записи числа 2^n, встречается k нулей подряд.


Решение этой части этюда

Предисловие. Пытаясь найти какие-нибудь зависимости в последовательности натолкнулся на интересный результат

Написал программку, которая вычисляет количество возможных остатков чисел 2^n при делении их на 10^k
Например 1, 2, 4, 8, 16, 32, 64, 128 ... при делении на 10^1 дает остатки 1, 2, 4, 8, 6, 2, 4, 8, 6 ...
После некоторого числа остатки начинают повторяться (в данном случае после 6).
Количество возможных остатков при делении на 10 равно 5. Это 1, 2, 4, 8 и 6
Аналогично для деления на 100 получаем 22 остатка, при делении на 1000 получаем 103 остатка.
Т.е. имеем последовательность f(k) = 5, 22, 103, 504, 2505, 12506, 62507, 312508 ...
Обобщив ее получаем f(k) = 100*5^(k-3) + k

Как уже сказал, остатки после некоторого числа начинают повторяться.
Найдя эти "последние" остатки получил еще одну интересную последовательность 6, 52, 504, 5008, 50016, 500032, 5000064 ...
Обобщив ее получаем g(k) = 5*10^(k-1) + 2^(k-1)

Вот такой вот результат.
Попытался доказать, что это верно не только для протестированных чисел (k <= 8), но и для всех.
Получилось вот что:




1. Докажем что, для любых целых m > 0, существует целое x, такое что 2^(f(m)-1) = x*10^m + g(m)

Итак f(m)-1 = 100 * 5^(m-3) + m - 1 и g(m) = 5*10^(m-1) + 2^(m-1). 

Подставляя в выражением получим
2^(100 * 5^(m-3) + m - 1) = x*10^m + 5*10^(m-1) + 2^(m-1)

Умножаем на 2 
2^(100 * 5^(m-3) + m) = 2x*10^m + 10^m + 2^m

Переносим 2^m в левую часть и выносим общий множитель
2^m * (2^(100 * 5^(m-3)) - 1) = 10^m * (2x + 1)

Делим на 10^m
(2^(100 * 5^(m-3)) - 1) / 5^m = 2x + 1

Обозначим 5^(m-1) = y, заметим, что y нечетно
(2^(4y) - 1) / 5y = 2x + 1

Откуда
x = (16^y - 1 - 5y) / (2*5y)

а) (16^y - 1 - 5y) делится на 2, т.к. 16^y четное, 5y - нечетное, 1 - нечетное
б) 5y делится на 5y :)
в) (16^y - 1) делится на 5y, т.к. 
16^y - 1 = (15+1)^y - 1, 
т.е. получим многочлен в котором y+1 членов, один из которых 1 (мы эту единицу отнимаем), 
а остальные члены являются степенью 15 (таких членов y). Значит и весь многочлен делится на 5y

Из этого следует, что x - целое число, для любых m>0

2. Очевидно, что в последовательности g(m) мы найдем число с k нулями.
А значит существует такое число n, что при делении 2^n на 10^k получим остаток, содержащий k нулей.
Из этого следует решение этюда :)

3. Более того, такие n не только существуют, но их существует бесконечное количество.





К сожалению, представленные выше рассуждения хотя и позволяют найти нужное n для k нулей,
но не позволяют высчитывать члены той-самой последовательности, которая обсуждается в этом топике.
Т.к. в последовательности присутствуют только минимальные 2^n содержащие k нулей.
Этот же алгоритм позволяет всего лишь доказать их существование

Спасибо за интересный этюд
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Best regards, Буравчик
k нулей
От: vadimcher  
Дата: 19.12.08 00:34
Оценка: 20 (4)
Докажите, что для любого k найдется такое число n, что в [i]десятичной[i] записи числа 2^n, встречается k нулей подряд.

Этюд для программиста.
Обозначим минимальное такое n как a(k). Например, a(1)=10, т.к. 2^10=1024 -- минимальная степень двойки, содержащая один ноль (подряд? ). a(2)=53, т.к. 2^53=9007199254740992 -- минимальная степень двойки, содержащая два нуля подряд. Ну и т.д.
Найти a(1),...,a(7).

А вот зайца кому, зайца-выбегайца?!
Re[2]: k нулей
От: Аноним  
Дата: 25.12.08 09:11
Оценка: 24 (3)
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, vadimcher, Вы писали:


V>>Докажите, что для любого k найдется такое число n, что в [i]десятичной[i] записи числа 2^n, встречается k нулей подряд.


V>>Этюд для программиста.

V>>Обозначим минимальное такое n как a(k). Например, a(1)=10, т.к. 2^10=1024 -- минимальная степень двойки, содержащая один ноль (подряд? ). a(2)=53, т.к. 2^53=9007199254740992 -- минимальная степень двойки, содержащая два нуля подряд. Ну и т.д.
V>>Найти a(1),...,a(7).

А>Теоретическая часть доказывается сразу. из утверждения, что степень 2 может начинаться на любую наперед заданную последовательность цифр (берем 10^k)


А>Схема доказательства первого утверждения — 2^n начинается на число x <=> {n*ln 2} (в смысле дробная часть) лежит в неком непустом интервале. собственно, все... всюду плотность доказывается вручную... ну или гуглом по "критерий Вейля"



Подобная задача, по-моему, вошла в сборник всероссийских (или всесоюзных?) математических олимпиад (такая красненькая книжка). И решение там было такое же. Я всегда думал, что только с этого "конца" задачу и можно решить, но вроде бы можно и с другого...

Теорема Эйлера
a^φ(m)-1 = 0 (mod m), где φ(m) = m(1 — 1/p1)(1 — 1/p2)...(1 — 1/pk) и a и m взаимно простые.

В нашем случае имеем:

2^φ(5^k)-1=0 (mod 5^k)

φ(5^k)=5^(k-1)*4

2^(5^(k-1)*4+k)=2^k (mod 10^k)

2^k содержит приблизительно k*lg(2) десятичных знаков
Значит,2^(5^(k-1)*4+k) имеем как минимум k*(1-lg(2)) подряд идущих нулей.
Re: k нулей
От: Аноним  
Дата: 22.12.08 13:18
Оценка: 25 (2)
Здравствуйте, vadimcher, Вы писали:

V>Найти a(1),...,a(7).


Brute force на J:
  zr =: 3 : '<: >./ 2 -~/\ I. ''0'' ~: ": 2 ^ x: y'
  (>:i.7) i.~ zr"0 i.7000
10 53 242 377 1491 1492 6801

Т.к. тупо и "в лоб" — считает 6 секунд..
Re[2]: k нулей
От: nikholas Россия  
Дата: 15.01.09 15:59
Оценка: 14 (2)
Здравствуйте, Seon, Вы писали:

S>Здравствуйте, vadimcher, Вы писали:


S>По одному из вариантов программы (пусть не самый быстрый) на процессоре рейтинга 2000 считается 70 000 000 знаков в секунду.



S>число а17 — это приблизительно миллиардная степень двойки.


S>для расчета 2^1 000 000 000 придется обработать (1000000000 ^ 2) / (2 * 3.31) знаков. (3.31 — коэффициент ширины десятичного представления степени двойки)

S>итого это 151 057 401 812 688 821 знаков.
S>для их расчета 1-му процессору потребуется 2 157 962 883 секунд
S>или 599 434 часов
S>или 24 976 суток
S>или 68 лет

S>если на эту задачу бросить 70 процессоров, то потребуется почти год.


S>явно, что а17 расчитывалось, либо каким то другим способом (не удвоением), либо на каком то жутко мощном майнфрэйме

S>ну или на огромном количестве компов...

Сделал алгоритм, работающий заметно быстрее.

В скобках — реальное кол-во умножений.
Основные моменты, из-за которых получилось быстрее:
— если в N-й степени двойки есть K нулей подряд, то в N+1,N+2,N+3 — не менее (K-1), N+4,N+5,N+6 — не менее (K-2) и т.д.
И обратно: если в N-й степени двойки есть не более K нулей подряд, то в N-1 — не более (K+1), N-2,N-3,N-4 — не более (K+2)
Поэтому скакнув на несколько степеней вперед мы частенько сможем отбросить все промежуточные.
— Число хранится в виде групп десятичных цифр, и быстро можно умножить это число на степень двойки, умещающееся в десятичном представлении в одной группе, кол-во нулей в группе берется из заранее посчитаной таблицы — кол-во нулей в начале, кол-во нулей в конце. Поэтому нули, идущие в середине группы, не определяются, и для i=(ширина группы — 2) a(i) неверно

Вот результат:

   0.000:  1 :          1 (         1)
   0.000:  2 :          2 (         2)
   0.000:  3 :        242 (       244)
   0.000:  4 :        377 (       296)
   0.000:  5 :       1491 (       518)
   0.000:  6 :       1492 (       522)
   0.000:  7 :       6801 (      1217)
   0.000:  8 :      14007 (      1922)
   0.469:  9 :     100823 (      9548)
  13.797: 10 :     559940 (     47855)
  55.641: 11 :    1148303 (     94153)
 667.266: 12 :    4036338 (    317876)
 667.281: 13 :    4036339 (    317880)


Pentium(R)D 3.4 MHz
В последнем столбце — реальное кол-во умножений

Аппроксимация времени — квадратичная, и до арда потребуется примерно 667*(1.000.000.000 / 4.036.338)^2 = 40.000.000 сек = 11.111 час = 462 дня

Судя по времени появления a17 и с учетом прогресса подобный алгоритм скорее всего и был использован

А вот и код:

#include "stdafx.h"
#include <vector>
#include <time.h>

#pragma warning (disable : 4244)

#define My_N 4
//#define CORRECT_ZEROS


template<int N>
struct HolderType;

template<>
struct HolderType<1>
{
    typedef unsigned char ValueType;
    typedef unsigned short MulType;
    enum {
        TableSize = 10
    };
};

template<>
struct HolderType<2>
{
    typedef unsigned char ValueType;
    typedef unsigned short MulType;
    enum {
        TableSize = 100
    };
};

template<>
struct HolderType<3>
{
    typedef unsigned short ValueType;
    typedef unsigned MulType;
    enum {
        TableSize = 1000
    };
};

template<>
struct HolderType<4>
{
    typedef unsigned short ValueType;
    typedef unsigned MulType;
    enum {
        TableSize = 10000
    };
};

template<>
struct HolderType<5>
{
    typedef unsigned int ValueType;
    typedef unsigned long long MulType;
    enum {
        TableSize = 100000
    };
};

template<>
struct HolderType<6>
{
    typedef unsigned int ValueType;
    typedef unsigned long long MulType;
    enum {
        TableSize = 1000000
    };
};

template<>
struct HolderType<7>
{
    typedef unsigned int ValueType;
    typedef unsigned long long MulType;
    enum {
        TableSize = 10000000
    };
};

template<>
struct HolderType<8>
{
    typedef unsigned int ValueType;
    typedef unsigned long long MulType;
    enum {
        TableSize = 100000000
    };
};

struct ZerosInfo 
{
    unsigned char m_beginZeros;
    unsigned char m_endZeros;
#ifdef CORRECT_ZEROS
    unsigned char m_maxZeros;
#endif
    ZerosInfo()
    {}
    ZerosInfo(unsigned b, unsigned e, unsigned m)
        : m_beginZeros(b)
        , m_endZeros(e)
#ifdef CORRECT_ZEROS
        , m_maxZeros(m)
#endif
    {}
};

template<int N>
struct CurrZerosInfo
{
    unsigned maxZeros;
    unsigned currZeros;
    CurrZerosInfo()
#ifdef CORRECT_ZEROS
        : maxZeros(0)
#else
        : maxZeros(N - 2)
#endif
        , currZeros(0)
    {}
    void AddNextDigit(ZerosInfo zi)
    {
        if(zi.m_beginZeros == N)
        {
            currZeros += N;
        }
        else
        {
            if(currZeros + zi.m_endZeros > maxZeros)
            {
                maxZeros = currZeros + zi.m_endZeros;
            }
#ifdef CORRECT_ZEROS
            if(zi.m_maxZeros > maxZeros)
            {
                maxZeros = zi.m_maxZeros;
            }
#endif
            currZeros = zi.m_beginZeros;
        }

    }
    void AddLastDigit(ZerosInfo zi)
    {
        if(currZeros + zi.m_endZeros > maxZeros)
        {
            maxZeros = currZeros + zi.m_endZeros;
        }
#ifdef CORRECT_ZEROS
        if(zi.m_maxZeros > maxZeros)
        {
            maxZeros = zi.m_maxZeros;
        }
#endif
    }
};

template<int N>
struct ZerosInfoRetriever
{
    ZerosInfo operator [] (unsigned i)
    {
        return m_table[i];
    }

    ZerosInfo m_table[HolderType<N>::TableSize];
    ZerosInfoRetriever()
    {
        GenNumber(0, ZerosInfo(0, 0, 0), N);
    }

#ifdef CORRECT_ZEROS
#define INFO_MAX_ZEROS info.m_maxZeros
#else
#define INFO_MAX_ZEROS 0
#endif
    void GenNumber(unsigned upperPart, ZerosInfo info, int n)
    {
        if(n > 0)
        {
            GenNumber(
                upperPart * 10, 
                ZerosInfo(
                    info.m_beginZeros + (upperPart == 0 ? 1 : 0), info.m_endZeros + 1, INFO_MAX_ZEROS),
                n - 1);
#ifdef CORRECT_ZEROS
            if(info.m_endZeros > info.m_maxZeros && upperPart != 0)
                info.m_maxZeros = info.m_endZeros;
#endif
            for(int i = 1; i < 10; ++i)
            {
                GenNumber(
                    upperPart * 10 + i, 
                    ZerosInfo(info.m_beginZeros, 0, INFO_MAX_ZEROS),
                    n - 1);
            }
        }
        else m_table[upperPart] = info;
    }
};

template<int N>
struct DigitsGroup
{
    static ZerosInfoRetriever<N> ms_retriever;
    typename HolderType<N>::ValueType m_digits;
    ZerosInfo GetZerosInfo()
    {
        return ms_retriever[m_digits];
    }
    DigitsGroup(unsigned v)
        : m_digits(v)
    {}
    DigitsGroup()
        : m_digits(0)
    {}
};

template<> ZerosInfoRetriever<My_N> DigitsGroup<My_N>::ms_retriever;


template<int N>
struct Power2
{
    typedef std::vector<DigitsGroup<N> > Container;
    Container m_value;
    int m_power;
    Power2()
        : m_value(1, DigitsGroup<N>(1))
        , m_power(0)
    {}

    void swap(Power2<N>& d)
    {
        m_value.swap(d.m_value);
        int tmp = m_power;
        m_power = d.m_power;
        d.m_power = tmp;
    }

    void print()
    {
        for(Container::reverse_iterator riter = m_value.rbegin(); riter != m_value.rend(); ++riter)
        {
            printf("%0*u", N, riter->m_digits);
        }
        printf("\n");
    }

    int MultplyBy(int digit2, Power2<N>& result)
    {
        result.m_value.resize(m_value.size());
        HolderType<N>::MulType mlt = 1 << digit2;
        result.m_power = m_power + digit2;
        CurrZerosInfo<N> czi;
        unsigned shift = 0;
        Container::iterator iter = m_value.begin();
        Container::iterator end = m_value.end();
        int i = 0;
        for(-- end; iter != end; ++ iter, ++i)
        {
            HolderType<N>::MulType tmp = mlt * iter->m_digits + shift;
            shift = tmp / HolderType<N>::TableSize;
            result.m_value[i].m_digits = tmp % HolderType<N>::TableSize;
            czi.AddNextDigit(result.m_value[i].GetZerosInfo());
        }
        HolderType<N>::MulType tmp = mlt * iter->m_digits + shift;
        shift = tmp / HolderType<N>::TableSize;
        result.m_value[i].m_digits = tmp % HolderType<N>::TableSize;
        czi.AddLastDigit(result.m_value[i].GetZerosInfo());
        if(shift)
        {
            result.m_value.push_back(DigitsGroup<N>(shift));
        }
        return czi.maxZeros;
    }
};

static int distance [] = {0, 1, 4, 7, 10, 14, 17, 20, 23, 27, 30, 33, 36, 39, 42, 46, 49};

int _tmain(int argc, _TCHAR* argv[])
{
    clock_t start = clock();
    static const int deep = 2;
    Power2<My_N> number;
    Power2<My_N> numberNext;
    Power2<My_N> numberTmp;

    int mul_count = 0;

    for(int i = 1; i < 20; ++i)
    {
        unsigned step = 1;
        if(i > 1) 
        {
            step = distance[My_N + 1] - 1;
        }
        do 
        {
            int zeros = number.MultplyBy(step, numberNext);
            mul_count++;
            int currIndex = number.m_power + step;
            if(zeros >= i)
            {
                break;
            }
            while((currIndex -= distance[i - zeros]) > number.m_power)
            {
                int delta = currIndex - number.m_power;
                zeros = number.MultplyBy(delta, numberTmp);
                mul_count++;
                if(zeros >= i)
                {
                    break;
                }
            }
            if(currIndex > number.m_power)
            {
                break;
            }
            number.swap(numberNext);
        } 
        while(true);
        while(number.MultplyBy(1, number) < i)
            mul_count++;
        printf("%8.3f: %2u : %10u (%10u)\n", ((double)(clock() - start)) / CLOCKS_PER_SEC, i, number.m_power, mul_count);
    }
    return 0;
}
Re: A16
От: nikholas Россия  
Дата: 10.02.09 09:06
Оценка: 13 (2)
Здравствуйте, vadimcher, Вы писали:

4-х головый Intel Xeon 1.6GHz, 64 бита, в среднем загрузка CPU 95%, занимает памяти 200 MB:


  0 days 00:00:00.000s:  1 :         10 (       586)
  0 days 00:00:00.000s:  2 :         53 (       586)
  0 days 00:00:00.000s:  3 :        242 (       586)
  0 days 00:00:00.000s:  4 :        377 (       586)
  0 days 00:00:00.015s:  5 :       1491 (       586)
  0 days 00:00:00.015s:  6 :       1492 (       586)
  0 days 00:00:00.015s:  7 :       6801 (      1456)
  0 days 00:00:00.015s:  8 :      14007 (      2266)
  0 days 00:00:00.140s:  9 :     100823 (     10009)
  0 days 00:00:03.468s: 10 :     559940 (     48503)
  0 days 00:00:13.875s: 11 :    1148303 (     94967)
  0 days 00:02:47.601s: 12 :    4036338 (    318504)
  0 days 00:02:47.601s: 13 :    4036339 (    318504)
  0 days 08:28:36.830s: 14 :   53619497 (   4135670)
  1 days 18:08:30.187s: 15 :  119476156 (   9202865)
  2 days 14:49:08.222s: 16 :  146226201 (  11260686)


Дальше считать не вижу смысла, 100 дней аптайма анрил...
Re[8]: k нулей
От: Pro100Oleh Украина  
Дата: 22.12.08 14:40
Оценка: 6 (2)
Как и обещал, выкладываю прогу. Считал уже дома на Е6550 — 2 ядра, 3,17 GHz (разгон), загрузка где-то на 60%.
Результат: (время указанно не с самого начала расчета, а начиная от прошлого результата)

a(1) = 10. Time 00:00:00.0014568, Length 4
a(2) = 53. Time 00:00:00.0000059, Length 16
a(3) = 242. Time 00:00:00.0005876, Length 73
a(4) = 377. Time 00:00:00.0000536, Length 114
a(5) = 1491. Time 00:00:00.0028288, Length 449
a(6) = 1492. Time 00:00:00.0000014, Length 450
a(7) = 6801. Time 00:00:00.0124860, Length 2048
a(8) = 14007. Time 00:00:00.0414484, Length 4217
a(9) = 100823. Time 00:00:02.1975814, Length 30351
a(10) = 559940. Time 00:01:07.1116630, Length 168559
a(11) = 1148303. Time 00:03:05.2465847, Length 345674
a(12) = 4036338. Time 00:46:04.8292335, Length 1215059


Код:

    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                Find();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
        }

        public static void Find()
        {
            int k;
            int power;
            Finder finder = new Finder();
            System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
            do
            {
                watch.Reset();
                watch.Start();
                finder.FindNext(out k, out power);
                watch.Stop();
                Console.WriteLine("a({0}) = {1}. Time {2}, Length {3}", k, power, watch.Elapsed, finder.Length);
            }
            while (k < 12);
        }
    }

    public class Finder
    {
        public static readonly int MaxSegments = 1000000;
        private int[] m_number;
        private int m_length;
        private int m_power;
        private int m_k;
        private int m_segmentLength;
        private int m_maxValue;

        public Finder()
        {
            m_segmentLength = 1;
            m_length = 1;
            m_number = new int[MaxSegments];
            m_number[0] = 1;
            m_k = 0;
            m_power = 0;
            m_maxValue = 9;
        }

        private void Mult()
        {
            int ost = 0;

            for (int index = 0; index < m_length; index++)
            {
                m_number[index] = (m_number[index] << 1) + ost;
                if (m_number[index] > m_maxValue)
                {
                    m_number[index] -= m_maxValue + 1;
                    ost = 1;
                }
                else
                {
                    ost = 0;
                }
            }

            if (ost == 1)
            {
                if (m_length >= MaxSegments) throw new Exception("MaxSegments");
                m_length++;
                m_number[m_length - 1] = 1;
            }
        }

        public void FindNext(out int k, out int power)
        {
            m_k++;
            Rebuild();

            while (!Check())
            {
                m_power++;
                Mult();
                if (m_power % 10000 == 0) Console.WriteLine("{0}, {1}", m_power, Length);
            }
            k = m_k;
            power = m_power;
        }

        public int Length
        {
            get
            {
                int length = m_number[m_length - 1].ToString().Length;
                if (m_length > 0) length += (m_length - 1) * m_segmentLength;
                return length;
            }
        }

        private bool Check()
        {
            int count;
            int x;
            int a;
            bool isOk = false;

            //change first number
            int first = m_number[m_length - 1];
            x = (m_maxValue + 1) / 10;
            a = 0;
            while (first > x && x > 0)
            {
                a += x;
                x /= 10;
            }
            m_number[m_length - 1] += a;

            for (int index = 0; index < m_length; index++)
            {
                if (m_number[index] != 0) continue;
                count = m_segmentLength;

                //previous
                if (index > 0)
                {
                    x = (m_maxValue + 1) / 10;
                    while (x > 0)
                    {
                        if (m_number[index - 1] < x)
                        {
                            count++;
                            x /= 10;
                        }
                        else
                        {
                            x = 0;
                        }
                    }
                }

                //next
                if (index < m_length)
                {
                    a = m_number[index + 1];
                    x = m_segmentLength;
                    while (x > 0)
                    {
                        if (a % 10 == 0)
                        {
                            count++;
                            a /= 10;
                            x--;
                        }
                        else
                        {
                            x = 0;
                        }
                    }
                }

                if (count >= m_k)
                {
                    isOk = true;
                    break;
                }
            }

            m_number[m_length - 1] = first;
            return isOk;
        }

        private void Rebuild()
        {
            if (2 * m_segmentLength >= m_k) return;
            string number = ToString();
            m_segmentLength++;
            m_maxValue = 10 * m_maxValue + 9;
            m_number = new int[MaxSegments];
            m_length = number.Length / m_segmentLength;
            int prefix = number.Length % m_segmentLength;
            for (int index = 0; index < m_length; index++)
            {
                m_number[index] = int.Parse(number.Substring(prefix + m_segmentLength * (m_length - index - 1), m_segmentLength));
            }
            if (prefix > 0)
            {
                m_length++;
                m_number[m_length - 1] = int.Parse(number.Substring(0, prefix));
            }
        }

        public override string ToString()
        {
            StringBuilder builder = new StringBuilder(m_segmentLength * m_length);
            string format = "d" + m_segmentLength.ToString();
            builder.Append(m_number[m_length - 1]);
            for (int index = m_length - 2; index >= 0; index--)
            {
                builder.Append(m_number[index].ToString(format));
            }
            return builder.ToString();
        }
    }
Pro
Re[2]: k нулей
От: vadimcher  
Дата: 19.12.08 18:50
Оценка: 1 (1) +1
Здравствуйте, Pro100Oleh, Вы писали:

PO>Считал на проце Q6600 на C# .Net 3.5 sp1. Программа однопоточная, но юзалось четыре проца где-то по 25% каждый.


PO>

PO>a(1) = 10. Time 00:00:00.0038011, Length 4
PO>a(2) = 53. Time 00:00:00.0000592, Length 16
PO>a(3) = 242. Time 00:00:00.0006503, Length 73
PO>a(4) = 377. Time 00:00:00.0008813, Length 114
PO>a(5) = 1491. Time 00:00:00.0204129, Length 449
PO>a(6) = 1492. Time 00:00:00.0000576, Length 450
PO>a(7) = 6801. Time 00:00:00.4025472, Length 2048
PO>a(8) = 14007. Time 00:00:00.1214338, Length 4217
PO>a(9) = 100823. Time 00:00:08.0502971, Length 30351
PO>a(10) = 559940. Time 00:03:16.3552767, Length 168559
PO>a(11) = 1148303. Time 00:10:54.2630780, Length 345674


Было бы здорово, если бы все еще свой код выкладывали. Просто интересно сравнить эффективность/простоту для разных языков.

А вот зайца кому, зайца-выбегайца?!
Re[2]: k нулей
От: Кодт Россия  
Дата: 21.12.08 00:09
Оценка: :))
Здравствуйте, vadimcher, Вы писали:

V>Все верно расчитали. Тут можно посмотреть вплоть до a(17): здесь. Внизу комментарий: некто Sacha Roscoe добавил a(15), затем через пару недель a(16), а затем еще a(17)... через 4 года.


... а потом он защитил докторскую диссертацию в своём Западно-Австралийском Университете и забил.
Перекуём баги на фичи!
Re[6]: k нулей
От: Beam Россия  
Дата: 19.12.08 11:07
Оценка: 15 (1)
Здравствуйте, Seon, Вы писали:

S>А можно подкорректировать Вашу программу, чтобы писало текущее значение степени, ну типа как


S>std::cout << p << "\r";


import Data.List
import Debug.Trace

zeros n = head [p | p <- [1..], trace ("curent = " ++ show p) $ (replicate n '0') `isInfixOf` (show $ 2^p)]
Best regards, Буравчик
Re[10]: k нулей
От: Seon  
Дата: 19.12.08 11:58
Оценка: 15 (1)
S>а(8) — до 2х секунд!
S>а(9) — 80 секунд!

а(10) — 2^559940 — 24 минуты и 20 секунд
Re[2]: Наконечно досчиталось до а14 !
От: Seon  
Дата: 04.02.09 13:28
Оценка: 15 (1)
Здравствуйте, Seon, Вы писали:

S>Распределенный вариант программы сегодня нашел а(14) = 2^53619497 !!!!


S>На это ушло 21 день и 2 часа!


S>Одновременно эту задачу считало от 2-х до 8 компов попеременно. В среднем гдето 4-5 штук.

S>Задача без всяких оптимизаций — первоначальный вариант — десятичные числа на чарах!!

Сегодня посчиталось а14 — оптимизированный вариант (9 десятичных цифр на 1 инт)
Работал 1 процессор Sempron 3400 1.8 ГГЦ.
ушло 15 суток и 13 часов!
Re[10]: И снова об STL
От: Roman Odaisky Украина  
Дата: 22.12.08 10:17
Оценка: 10 (1)
Здравствуйте, Erop, Вы писали:

E>А разве так можно? :shuffle:


Твой код:
    const small* src = buffer + 1;
    small* dst = buffer + 1 + count;
    for( int i = count * 9; i > 0; --i )
        *dst++ = *src++;
    ++*--dst;

и мой код:
std::copy(buffer + 1, buffer + 1 + count * 9, buffer + 1 + count);
++buffer[10 * count];

делают одно и то же. Меня, правда, смущает то, что диапазоны пересекаются, но результат будет один и тот же, даже если это и не то, что ты планировал.
До последнего не верил в пирамиду Лебедева.
Re[6]: k нулей
От: Аноним  
Дата: 12.01.09 08:19
Оценка: 10 (1)
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, vadimcher.

А>После нового года я постараюсь выложить и саму олимпиадную задачу и решение из сборника задач.

А>Заодно узнаем насколько она старая.


К сожалению, я так и не нашёл книги с решением задачи с помощью логарифмов.

Зато в книге "Зарубежные математические олимпиады" нашёл решение в стиле теоремы Эйлера:

[/img]http://files.rsdn.ru/41706/zad.jpg[/img]

[img]http://files.rsdn.ru/41706/solution.jpg[img]

PS Фотограф из меня не очень.
Re: k нулей
От: Beam Россия  
Дата: 11.02.09 15:31
Оценка: 10 (1)
Intel Core 2 Duo 2.67 GHz. Загрузка процессоров 100%.
Работает достаточно быстро. Хотелось бы увидеть результат на 4-ядернике, но у меня такого нет.

2^100823 contains 9 zeros ===> 0 days 00:00:00.45
2^559940 contains 10 zeros ===> 0 days 00:00:06.75
2^1148303 contains 11 zeros ===> 0 days 00:00:23.38
2^4036338 contains 12 zeros ===> 0 days 00:03:58.80
2^4036339 contains 13 zeros ===> 0 days 00:03:58.81

1. Число состоит из "цифр" от 0000 до 9999 (unsigned short). Это позволило сделать умножение на степень двойки и определение количества нулей без использования деления — на таблицах. Таблицы готовятся заранее.
2. Используется обычное прыганье вперед на (нужное количество нулей — текущее количество нулей).
3. Алгоритм многопоточный, на основе OpenMP (надо включить поддержку в VS). Многопоточность используется при умножении и вычислении количества нулей. Причем потоки все вместе работают над одним и тем же большим числом (это удалось разрулить вроде).

Длинненько, но зато полный вариант:

#include <stdlib.h>
#include <time.h>
#include <memory.h>
#include <omp.h>

// #define TEST_MULT_COUNT

/////////////////////////////////////
/// BIG NUM

// число в памяти представлено в виде массива слов (unsigned short)
// каждое слово - число от 0000 до 9999
#define CELL_TYPE unsigned short
#define MAX_CELL 10000


/////////////////////////////////////
// УМНОЖЕНИЕ ЧИСЛА НА СТЕПЕНЬ ДВОЙКИ
/////////////////////////////////////

// mulTable - вспомогательная таблица для быстрого умножения чисел от 0000 до 9999 на степени двойки
// mulTable[x * 16 + pow] = struct {result, carry}
// x - число от 0000 до 9999
// pow - степень двойки, на которую умножается число x (от 0 до 15)
// result - результат умножения % 10000
// carry - перенос в соседнюю клетку = результат умножения / 10000 (т.е. то, что не поместилось в result)

#define MUL_TABLE_LEN 10000

struct MulInfo {
    CELL_TYPE result;
    CELL_TYPE carry;
};

MulInfo mulTable[MUL_TABLE_LEN*16];

void initMulTable() {
    for (int i = 0; i < MUL_TABLE_LEN; i++) {
        for (unsigned char pow = 0; pow < 16; pow++) {
            unsigned int y = i << pow;
            mulTable[(i << 4) + pow].result = y % 10000;
            mulTable[(i << 4) + pow].carry = y / 10000;
        }
    }
}

// умножение длинного числа arr длиной len на 2^pow
// результат записывается в arr2 (может совпадать с arr), новая длина записывается в len2 (может совпадать с len)
// многопоточная реализация - массив разбивается на равные части, каждый поток обрабатывает свою часть
void multArrayC(CELL_TYPE * arr, size_t len, CELL_TYPE * arr2, size_t & len2, int pow) 
{
#pragma omp parallel
    {
        CELL_TYPE carry = 0;
        unsigned int index = 0;    

        // поток берет каждый разряд и умножает его на степень двойки, прибавляя перенос если он есть
#pragma omp for
        for (int i = 0; static_cast<unsigned int>(i) < len; i++) {
            index = i;
            MulInfo x = mulTable[ (arr[i] << 4) + pow ];
            CELL_TYPE res = x.result + carry;
            carry = res >= 10000 ? (res -= 10000, x.carry + 1) : x.carry;
            arr2[i] = res;
        }
        // после обработки своей части массива у нас остался перенос carry, который относится к "чужой части"
        // в index хранится индекс последнего обработанного потоком "разряда"

        // каждый поток прибавляет оставшийся в конце перенос к следующему "разряду"
        // один из потоков, который обрабатывал самые старшие "разряды" числа, при необходимости, увеличивает длину массива
        index++;    // index = i + 1
#pragma omp critical
        if (carry != 0) {
            if (index < len) {
                arr2[ index ] += carry;
                if (arr2[index] >= 10000) {
                    arr2[index] -= 10000;
                    arr2[index+1]++;
                }
            } else {
                len2++;
                arr2[index] = carry;
            }
        }
    }
}


/////////////////////////////////////
// ПОДСЧЕТ КОЛИЧЕСТВА НУЛЕЙ
/////////////////////////////////////

// zerosTable - вспомогательная таблица для быстрого поиска нулей в числах от 0000 до 9999
// учитываются только нули в начале и в конце таких чисел, нули в середине не подсчитываются
// zerosTable[x] = struct {left, right}
// x - число от 0000 до 9999
// left - количество начальных (левых) нулей
// right - количество конечных (правых) нулей

#define ZEROS_TABLE_LEN 10000

struct ZerosInfo {
    unsigned char left;
    unsigned char right;
};

ZerosInfo zerosTable[ZEROS_TABLE_LEN];

void initZerosTable() {
    zerosTable[0].left = 0;
    zerosTable[0].right = 4;

    for (int i = 1; i < ZEROS_TABLE_LEN; i++) {
        zerosTable[i].left = 0;
        zerosTable[i].right = 0;

        char buf[10];
        sprintf_s<10>(buf, "%04d", i);

        int len = 4;
        for (int x = len-1; x >= 0 && buf[x] == '0'; x--) 
            zerosTable[i].right++;
        for (int x = 0; x < len && buf[x] == '0'; x++) 
            zerosTable[i].left++;
    }
}

// возвращает максимальное количество последовательных нулей в числе arr длиной len
// многопоточная реализация - массив разбивается на части, каждый поток обрабатывает свою часть
int countZeros(CELL_TYPE * arr, size_t len) {
    char globalMax = 0;
#pragma omp parallel
    {
        char max = 0;
        char cur = 0;
        CELL_TYPE x;
        int index = -1;
        // каждый поток подсчитывает нули в своей части
#pragma omp for
        for (int i = 0; static_cast<unsigned int>(i) < len-1; i++) {
            index = i;
            x = arr[i];
            cur += zerosTable[x].right;
            if (x != 0 && max >= cur) {
                cur = zerosTable[x].left;
            } else if (x != 0) {
                max = cur;
                cur = zerosTable[x].left;
            }
        }
        // после обработки каждый поток хранит в max максимальное количество нулей в его части
        // в index хранится индекс последнего обработанного потоком "разряда" или -1 если цикл не выполнялся

        // если поток что-то обрабатывал, обработаем еще один дополнительный (старший) "разряд"
        if (index != -1) {
            cur += zerosTable[ arr[index+1] ].right;
            max = max < cur ? cur : max;

            // globalMax - максимальное количество нулей в массиве
#pragma omp critical
            globalMax = max > globalMax ? max : globalMax; 
        }
    }
    return globalMax;
}

////////////////////////////////////////////
/// LOGGING

// печать длинного числа в файл и консоль
void print_num(FILE * f, CELL_TYPE * arr, size_t len) {
    fprintf(f, "%d ", (int)arr[len-1]);
    for (int i = len-2; i >= 0; i--) {
        fprintf(f, "%04d ", (int)arr[i]);
    }
    fflush(f);
}

void printProgress(FILE * f, int i, clock_t start, clock_t end) {
    double duration = (end - start) * 1.0f / CLOCKS_PER_SEC + 0.00000005;
    int t = (int) duration; // seconds
    double s = t % 60 + (duration - t);
    int m = t / 60 % 60;
    int h = t / 60 / 60 % 24;
    int d = t / 60 / 60 / 24;

    fprintf(f, "%12d mln ===> %d days %02d:%02d:%05.2f ===> %5.2f * 10^9 bits per sec\n", 
        i, d, h, m, s, i * 1.0f * (i+1) / 2e9 / duration);
    fflush(f);
}

void printResult(FILE * f, int i, int k) {
    fprintf(f, "\n!!!!! 2^%d contains %d zeros\n\n", i, k);
    fflush(f);
}

////////////////
///// MAIN 
////////////////

CELL_TYPE * arr;

int _tmain(int argc, _TCHAR* argv[]){
    // init tables
    initZerosTable();
    initMulTable();

    // file for logging
    FILE * f = fopen("log.txt", "w");

    // arr = 2^0
    arr = (CELL_TYPE *) malloc(1000*1000*1000);    // хватит на 6.500.000.000 степеней двойки
    size_t len = 1;
    arr[0] = 1;

    // time measure
    clock_t start = clock();

    int i = 0;        // текущая степень двойки
    int last = 0;    // последняя степень двойки, информацию о которой записывали в файл
    int k = 2;        // ищем степень двойки с таким количеством нулей

#ifdef TEST_MULT_COUNT
    for (int i=1; i < 100; i++) {
        //doubleArrayC(arr, len);
        multArrayC(arr, len, arr, len, 1);
        printf("i = %d ===> ", i);
        print_num(arr, len);
        printf(" ===> zeros = %d", countZeros(arr, len));
        printf("\n");
    }
#else
    while (true) {

        // каждую тысячу выводим сообщение, чтобы показать что не зависли
        if (i - last > 100000) {
            last = i;
            printProgress(f, i, start, clock());
            printProgress(stdout, i, start, clock());
        }

        int zeros = countZeros(arr,len);

        // если нашли нужное количество нулей, то выводим результат
        while (zeros >= k) {
            printProgress(f, i, start, clock());
            printProgress(stdout, i, start, clock());
            printResult(f, i, k);
            printResult(stdout, i, k);
            k++;
        }

        // "прыгаем" на расстояние (нужноеКоличествоНулей - найденноеКоличествоНулей)
        // нельзя прыгнуть дальше 13, иначе переписывать функцию multArray 
        int step = k - zeros <= 13 ? k - zeros : 13;
        multArrayC(arr, len, arr, len, step);
        i += step;
    }
#endif

    free(arr);
    puts("Press Enter\n");
    getchar();

    return 0;
}


И еще.

Можно было бы ускорить все это, используя SSE инструкции. Но мне пока непонятно как на основе арифметических функций и минимума if-ов реализовать умножение на степень двойки. Возьмем например, 128-битное число. В него влезет 8 "разрядов". ABCDEFGH. При умножении на 2^x должно получиться A'B'C'D'E'F'G'H' и некий перенос в следующий разряд. Вот как такое реализовать оперируя этим 128-битным числом как единым целым? Ну или 64-битным.

Еще я экспериментировал с алгоритмом nikholas (с "хитрым" прыганьем). И сделал вывод, что "простое прыганье" работает не медленнее, чем "хитрое". Причина в том, что умножение на большую степень двойки производится "столбиком". Т.е. если надо умножить некое большое число на 2^x и это число включает в себя n "разрядов", то мы должны сделать n больших умножений и потом n больших сложений. При умножении же на маленькую степень мы должны сделать одно большое умножение и одно большое сложение (переносы).
Вот и получается, что время умножения на большую степень двойки сравнимо с последовательным умножением несколько раз на маленькую степень двойки (если алгоритм учитывает, что умножение произодится только на маленькую степень). Например, время умножения на 2^22, сравнимо с умножением на 2^13 и затем на 2^9.
Best regards, Буравчик
Re[2]: k нулей
От: vadimcher  
Дата: 12.02.09 22:17
Оценка: 10 (1)
Здравствуйте, Beam, Вы писали:

B>Intel Core 2 Duo 2.67 GHz. Загрузка процессоров 100%.

B>Работает достаточно быстро. Хотелось бы увидеть результат на 4-ядернике, но у меня такого нет.

B>2^100823 contains 9 zeros ===> 0 days 00:00:00.45

B>2^559940 contains 10 zeros ===> 0 days 00:00:06.75
B>2^1148303 contains 11 zeros ===> 0 days 00:00:23.38
B>2^4036338 contains 12 zeros ===> 0 days 00:03:58.80
B>2^4036339 contains 13 zeros ===> 0 days 00:03:58.81

Я еще раз просмотрел твой код на предмет поиска нулей, и пришел к выводу, что возможны ошибки при k=2 и k>=5. Стал сравнивать результаты. Выяснилось: ошибки при k=2,3.

Для k=2, понятно. Два нуля оказались внутри 4-хзначной цифры. (Вероятность этого была достаточно маленькая, но я решил проверить, вдруг ты попал как раз в эту вероятность? Попал!) Так что и по логике, и на практике следует начинать с k=3.
Для k=3 у меня выдал 243 вместо 242. Почему? Непонятно. Я этого не ожидал.
Для k>=5. Когда один процессор обработал блок, он смотрит, какое там число стоит дальше, cur += zerosTable[ arr[index+1] ].right. Но что, если там стоит 0000, тогда надо двигать дальше, пока не встретится наконец ненулевое число! Т.е. надо что-то типа int j = 1, z; do { z = zerosTable[ arr[index+j] ].right; cur += z; } while (z == 4);
Тут проблема не только в том, что можно пропустить искомое число нулей, но и в том, что иногда шаг, с которым ты прыгаешь к следующему числу может оказаться больше, чем положено.
Верно?

А вот зайца кому, зайца-выбегайца?!
Re[3]: k нулей
От: Аноним  
Дата: 26.12.08 22:06
Оценка: 6 (1)
Здравствуйте, vadimcher, Вы писали:

V>Здравствуйте, Аноним, Вы писали:

А>>Теоретическая часть доказывается сразу. из утверждения, что степень 2 может начинаться на любую наперед заданную последовательность цифр (берем 10^k)

А>>Схема доказательства первого утверждения — 2^n начинается на число x <=> {n*ln 2} (в смысле дробная часть) лежит в неком непустом интервале. собственно, все... всюду плотность доказывается вручную... ну или гуглом по "критерий Вейля"


V>Выделенное не понял.




Ну, как я уже говорил, это вопрос с бородой. Поэтому автор поста написал схематично, опуская детали.

Между прочим, а что имелось в виду
в условиях задачи: ровно k нулей и на к-ом месте не ноль или имелось в виду как минимум к нулей? Если ровно k нулей, то через теорему Эйлера ответ получить
будет тяжело.

Теперь расшифрую Анонима.

Можно доказать более сильное утверждение: для любого натурального числа найдётся степень двойки, которая на него начинается.
Из этого утверждения всё следует.

Докажем это более сильное утверждение.
Пусть какая-то степень двойки начинается на x, тогда для некоторого m выполняется
x*10^m < 2^n <x*10^m+10^m-1.

Таким образом, задачу свелась к следующему: для данного x найти m и n, удовлетворяющие
x*10^m < 2^n <x*10^m+10^m-1
или
n*ln(2)<ln(x*10^m+10^m-1) и ln(x)+ln(10)*m < ln(2)*n

Значит, мы ищем целое число n в интервале ( ln(x)/ln(2)+ln(10)*m/ln(2), ln(x*10^m+10^m-1)/ln(2) )

При больших m ln(x*10^m+10^(m-1)) < ln(x*10^m+10^m-1), поэтому если мы найдём число n в меньшем интервале

( ln(x)/ln(2)+ln(10)*m/ln(2), ln(x*10^m+10^(m-1))/ln(2) ) = ( ln(x) / ln(2)+ln(10)*m/ln(2), m *ln(10)/ln(2)+ ln(x+1/10)/ln(2) ),

то оно подавно будет принадлежать большему.

Если обозначить очевидно иррациональное число ln(10)/ln(2) через alpha, ln(x) / ln(2) через x1, ln(x+1/10)/ln(2) через
x2, то получаем

Найти m и n такие, что

alpha *m-n лежит в (x1, x2)

А это можно доказать самому. Например, через теорему Лиувилля о приближении иррационального числа рациональной дробью.

Или из Вейля, или как-то ещё.


Что-то получилось многословно. Я помню решение в сборнике олимпиадных задач было совсем короткое...
Но задавать такие задачи детям... Есть в этом что-то садистское.
Re: k нулей
От: vadimcher  
Дата: 19.12.08 16:03
Оценка: 5 (1)
Здравствуйте, vadimcher, Вы писали:

V>Докажите, что для любого k найдется такое число n, что в [i]десятичной[i] записи числа 2^n, встречается k нулей подряд.


V>Этюд для программиста.

V>Обозначим минимальное такое n как a(k). Например, a(1)=10, т.к. 2^10=1024 -- минимальная степень двойки, содержащая один ноль (подряд? ). a(2)=53, т.к. 2^53=9007199254740992 -- минимальная степень двойки, содержащая два нуля подряд. Ну и т.д.
V>Найти a(1),...,a(7).

Все верно расчитали. Тут можно посмотреть вплоть до a(17): здесь. Внизу комментарий: некто Sacha Roscoe добавил a(15), затем через пару недель a(16), а затем еще a(17)... через 4 года.

Остается теоретическая часть вопроса.

А вот зайца кому, зайца-выбегайца?!
Re: Оптимизированная версия
От: Roman Odaisky Украина  
Дата: 22.12.08 20:02
Оценка: 5 (1)
#include <vector>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <cassert>
#include <boost/cstdint.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/foreach.hpp>

#define foreach BOOST_FOREACH
using std::size_t;

#ifndef LOG_BASE
#define LOG_BASE 5
#endif

#ifndef CZ_BITS
#define CZ_BITS 8
#endif

#ifndef DIGIT_BITS
#define DIGIT_BITS 32
#endif

typedef boost::BOOST_PP_CAT(BOOST_PP_CAT(uint_least, CZ_BITS), _t) cz_t;
typedef boost::BOOST_PP_CAT(BOOST_PP_CAT(uint_fast, DIGIT_BITS), _t) digit;
typedef std::vector<digit> bigint;

template <size_t N> struct power10;
template <>         struct power10<0> { static size_t const value = 1; };
template <size_t N> struct power10    { static size_t const value = power10<N-1>::value * 10; };

template <size_t N>
struct counter_zl;

template <>
struct counter_zl<1>
{
    static inline size_t apply(digit d)
    {
        return d == 0;
    };
};
template <size_t N>
struct counter_zl
{
    static inline size_t apply(digit d)
    {
        return (d < power10<N-1>::value) + counter_zl<N-1>::apply(d);
    };
};

//size_t const LOG_BASE = 5;
digit const BASE = power10<LOG_BASE>::value;

long long ccl = 0, cct = 0;

#ifdef CZL_TABLE
    cz_t _mdczl[BASE];
    inline size_t mdczl(digit d) { ++ccl; return _mdczl[d]; }
#else
    inline size_t mdczl(digit d)
    {
        ++ccl;
        return d >= BASE/10 ? 0 : 1 + counter_zl<LOG_BASE-1>::apply(d);
        //return counter_zl<LOG_BASE>::apply(d);
    }
#endif
cz_t _mdczt[BASE];
inline size_t mdczt(digit d) { ++cct; return _mdczt[d]; } // Map from Digits to Count of Zeros (Trailing)


int main(int argc, char** argv)
{
    assert(argc == 2);
    size_t const k = boost::lexical_cast<size_t>(argv[1]);

    std::ofstream tty("/dev/tty");

#ifdef CZL_TABLE
    _mdczl[0] = LOG_BASE;
#endif
    _mdczt[0] = 0;
    for(digit i = 1; i < BASE; ++i)
    {
#ifdef CZL_TABLE
        _mdczl[i] = mdczl(i / 10) - 1;
#endif
        _mdczt[i] = i % 10 == 0 ? 1 + mdczt(i / 10) : 0;
    }

    if(k == 0)
    {
        for(digit d = 0; d < BASE; ++d)
        {
            std::cout << std::setw(LOG_BASE) << std::setfill('0') << d << " " << mdczl(d) << " " << mdczt(d) << std::endl;
        }
        return 0;
    }

    size_t p = 0;
    bigint n;
    n.reserve(10240);
    n.push_back(1);

    while(1)
    {
        size_t czt = 0;
        for(size_t i = 0; i < n.size(); ++i)
        {
            digit const& d = n[i];
            //czt += mdczt(d);
            if(czt >= k || (czt + LOG_BASE >= k && czt + mdczt(d) >= k))
            {
                std::cout << p << std::endl;
                tty << ccl << " " << cct << std::endl;
                return 0;
            }
            czt &= d ? 0 : ~(size_t)0;
            czt += mdczl(d);
        }

        digit carry = 0;
        for(size_t i = 0; i < n.size(); ++i)
        {
            n[i] *= 2;
            n[i] += carry;
            carry = n[i] >= BASE;
            n[i] -= carry * BASE;
        }
        if(carry > 0)
        {
            n.push_back(carry);
        }

        ++p;

        if(p % 10000 == 0)
        {
            tty << "..." << p << "..." << std::endl;
        }
    }
}

Идея здесь в том, чтобы использовать 10⁵-ричную (параметр настраивается) систему счисления, и хранить в отдельной таблице количество нулей для каждой такой «цифры». В основном алгоритме нет ни единой операции деления. И еще кое-где поэкономил на спичках (например, я заменил «if(d!=0){czt=0}» на «czt &= d ? 0 : ~(size_t)0;», чтобы втолковать компилятору, что здесь нужно поставить sbb). Почерпнул немного дельных мыслей из дотнетовского варианта
Автор: Pro100Oleh
Дата: 22.12.08
, но полностью тот алгоритм не понял.

На Pentium 4 (3 ГГц, мегабайт кеша L2) считает a(8) за 6,7 с (при -DLOG_BASE=7), интеловский компилятор справляется за 6,3 с. На сервере, где Intel Q6600 и 4 МБ кеша, работает за 2,6 с. a(10) — 379 с здесь и 74 с там.

Хорошо бы запустить разные решения на одном компьютере, кое-чем померяться ;-).

Кстати, задача довольно легко параллелизуется. Как удвоение, так и поиск нулей можно поручить разным процессорам, разделив число на части. Чьи программы здесь масштабируются при наличии нескольких процессоров?
До последнего не верил в пирамиду Лебедева.
Re[6]: k нулей
От: Аноним  
Дата: 17.01.09 05:47
Оценка: 5 (1)
Здравствуйте, nikholas, Вы писали:

N>Боюсь до конца ты не доживешь


N>Для a17 надо посчитать 10^9 (кол-во строк) * 3*10^8 (~длина 2^1000000000 в десятичном представлении) / 2 знаков, у тебя считается 10^5 * 2*10^5 за 300 сек, скорость < 10^8 знаков в сек., итого тебе потребуется 10^9 * 3 * 10^8 / ( 2 * 10^8) сек = 17000 дней, даже на 100 компах пол-года


Так вот же и пытаемся придумать оптимальное решение.

Вчера сделал еще одну оптимизацию.
Теперь у меня система не десятичная а миллиардичная. Каждый знак теперь не от 0 до 9 а от 0 до 999999999!!!
Обрабатываем не массив чаров а массив интов. Подобная идея уже кем то тут описывалась... сори не помню
Конечно пришлось пожертвовать вычислениями от а1 до а8, но их и так все давно знают

ЗАТО это дало прирост в скорости пятикратно!

=====================================================
a(9) [2^100823] Time: 0:0:0:10
a(10) [2^559940] Time: 0:0:5:15
a(11) [2^1148303] Time: 0:0:16:38
a(12) [2^4036338] Time: 0:2:51:17
=====================================================
скорость 2.4 * 10^8 знаков в сек
по старому у меня а(12) считалось около 13 часов — 5 * 10^7 зн/сек
Re: k нулей
От: Ravlyk Австралия http://stitcharteasy.com
Дата: 02.02.09 18:07
Оценка: 5 (1)
Ну и я добавлю свой результат до кучи.
Реализовано на C# под .NET 3.5, скомпилировано в Release режиме, выполнено на Core 2 Duo 3.0GHz под Windows Vista.

Результат:

time=00:00:00.0220000, k=1, n=10, len=4
time=00:00:00.0230000, k=2, n=53, len=16
time=00:00:00.0230000, k=3, n=242, len=73
time=00:00:00.0230000, k=4, n=377, len=114
time=00:00:00.0240000, k=5, n=1491, len=449
time=00:00:00.0240000, k=6, n=1492, len=450
time=00:00:00.0360000, k=7, n=6801, len=2048
time=00:00:00.0750000, k=8, n=14007, len=4217
time=00:00:01.7930000, k=9, n=100823, len=30351
time=00:00:53.7840000, k=10, n=559940, len=168559
time=00:03:44.9770000, k=11, n=1148303, len=345674
time=00:45:56.7920000, k=12, n=4036338, len=1215059
time=00:45:56.7930000, k=13, n=4036339, len=1215060


Код (идея моя, но если такое уже было — значит изобрел велосипед):

Основной принцип: цифры обрабатываеются по 16 в ulong (INT64, по 4 бита на цифру). Для каждого возможного 16-циферого числа заготовлен массив с количеством нолей с начала, в середине, и в конце числа.

using System;

namespace KZerosCalculator
{
    class Program
    {
        static void Main()
        {
            DateTime statTime = DateTime.Now;

            CalculateZeros(
                delegate(int zeros, int power2, int digits)
                {
                    TimeSpan ts = DateTime.Now - statTime;
                    Console.WriteLine("time={3}, k={0}, n={1}, len={2}", zeros, power2, digits, ts);
                });
        }

        delegate void OutputResultDelegate(int zeros, int power2, int digits);

        static void CalculateZeros(OutputResultDelegate OutputMethod)
        {
            int[] leadingZerosArray;
            int[] trailingZerosArray;
            int[] separateZerosArray;

            PrepareZerosArrays(out leadingZerosArray, out trailingZerosArray, out separateZerosArray);

            ulong[] groups = new ulong[1024 * 1024];
            for (int i = 0; i < groups.Length; i++)
            {
                groups[i] = 0UL;
            }

            groups[0] = 1UL;
            int groupsCount = 1;
            int lastGroupDigitsCount = 1;

            int searchingForZeros = 1;
            int power2 = 0;

            while (groupsCount < groups.Length)
            {
                power2++;

                unchecked
                {
                    int maxFoundZeros = 0;
                    int foundZeros = 0;
                    ulong shiftFlag = 0;

                    for (int i = 0; i < groupsCount; i++)
                    {
                        // x2

                        ulong source = groups[i];

                        ulong b1 = (source & 0x1111111111111111UL);
                        ulong b2 = (source & 0x2222222222222222UL) >> 1;
                        ulong b4 = (source & 0x4444444444444444UL) >> 2;
                        ulong b8 = (source & 0x8888888888888888UL) >> 3;

                        ulong shifts = b8 | b4 & (b2 | b1);
                        ulong tens = (shifts << 3) | (shifts << 1);
                        ulong summ = (source << 1) - tens + (shifts << 4) + shiftFlag;
                        shiftFlag = shifts >> 60;

                        groups[i] = summ;

                        // Compact zeros

                        b1 = (summ & 0x1111111111111111UL);
                        b2 = (summ & 0x2222222222222222UL) >> 1;
                        b4 = (summ & 0x4444444444444444UL) >> 2;
                        b8 = (summ & 0x8888888888888888UL) >> 3;

                        ulong compact = b1 | b2 | b4 | b8;
                        compact = ((compact & 0xF0F0F0F0F0F0F0F0UL) >>  3) | (compact & 0x0F0F0F0F0F0F0F0FUL);
                        compact = ((compact & 0xFF00FF00FF00FF00UL) >>  6) | (compact & 0x00FF00FF00FF00FFUL);
                        compact = ((compact & 0xFFFF0000FFFF0000UL) >> 12) | (compact & 0x0000FFFF0000FFFFUL);
                        compact = ((compact & 0xFFFFFFFF00000000UL) >> 24) | (compact & 0x00000000FFFFFFFFUL);
                        int compactNumber = (int)compact;

                        if ((i + 1 == groupsCount) && (lastGroupDigitsCount < 16) && ((summ & (0x0FUL << (lastGroupDigitsCount * 4))) > 0UL))
                        {
                            lastGroupDigitsCount++;
                            compactNumber = (compactNumber | (0xFFFF << lastGroupDigitsCount)) & 0xFFFF;
                        }

                        // Find zeros count

                        int leadingZeros = leadingZerosArray[compactNumber] + foundZeros;
                        int separateZeros = separateZerosArray[compactNumber];
                        foundZeros = leadingZeros > separateZeros ? leadingZeros : separateZeros;

                        if (foundZeros > maxFoundZeros)
                        {
                            maxFoundZeros = foundZeros;
                        }

                        int trailingZeros = trailingZerosArray[compactNumber];
                        if (trailingZeros < 16)
                        {
                            foundZeros = trailingZeros;
                        }
                    }

                    if (shiftFlag == 1UL)
                    {
                        groups[groupsCount++] = 1UL;
                        lastGroupDigitsCount = 1;
                    }

                    if (maxFoundZeros >= searchingForZeros)
                    {
                        OutputMethod(maxFoundZeros, power2, (groupsCount - 1) * 16 + lastGroupDigitsCount);
                        searchingForZeros = maxFoundZeros + 1;
                    }
                }
            }
        }

        static void PrepareZerosArrays(out int[] leadingZerosArray, out int[] trailingZerosArray, out int[] separateZerosArray)
        {
            leadingZerosArray = new int[0x10000];
            trailingZerosArray = new int[0x10000];
            separateZerosArray = new int[0x10000];

            for (int i = 0; i < 0x10000; i++)
            {
                int number = i;
                int zeros = 0;
                bool separateGroup = false;
                int maxSepareteGroup = 0;

                leadingZerosArray[i] = 0;
                trailingZerosArray[i] = 0;
                separateZerosArray[i] = 0;

                for (int j = 0; j < 16; j++)
                {
                    if ((number & 1) == 0)
                    {
                        zeros++;
                    }
                    else
                    {
                        if (zeros > maxSepareteGroup)
                        {
                            if (separateGroup)
                            {
                                maxSepareteGroup = zeros;
                            }
                            else
                            {
                                leadingZerosArray[i] = zeros;
                            }
                        }

                        separateGroup = true;
                        zeros = 0;
                    }

                    number >>= 1;
                }

                if (zeros == 16)
                {
                    leadingZerosArray[i] = 16;
                    separateZerosArray[i] = 16;
                }
                separateZerosArray[i] = maxSepareteGroup;
                trailingZerosArray[i] = zeros;
            }
        }
    }
}
Re[2]: k нулей
От: nikholas Россия  
Дата: 12.02.09 11:10
Оценка: 5 (1)
Здравствуйте, Beam, Вы писали:

По поводу подсчета нулей:

Лучше сделать так: по числу x от 0000 до 9999 по таблице получаем zero-mask: на месте нулей — нули, на месте не-нулей — единицы (получаем число от 0 до 15)
для текущей позиции при подсчете нулей помним: максимальное число нулей найденое ранее (max, 0 — 19), число нулей на конце(curr, 0-19)
и далее по таблице [max, curr, zero-mask] получаем новые значения для max и curr
Для того чтоб не заморачиваться насчет конца числа curr может быть больше max, тогда в конце, после любого кол-ва финишных нулей, мы получаем точное значение max(главное в таблице сделать curr(19)->curr(19), а не то...).

Также лучше совместить подсчет нулей с возведением в степень — кеши и все такое

B>Еще я экспериментировал с алгоритмом nikholas (с "хитрым" прыганьем). И сделал вывод, что "простое прыганье" работает не медленнее, чем "хитрое". Причина в том, что умножение на большую степень двойки производится "столбиком". Т.е. если надо умножить некое большое число на 2^x и это число включает в себя n "разрядов", то мы должны сделать n больших умножений и потом n больших сложений. При умножении же на маленькую степень мы должны сделать одно большое умножение и одно большое сложение (переносы).


Я особо не мерял но у меня сложилось впечатление что умножение на 3-х разрядное число (с подсчетом нулей) практически не отличается по времени от умножения на одноразрядное.

И возведение в большую степень работает быстро — я прикидывал, что 2^(10^9) можно получить дней за 7-8
Re[7]: k нулей
От: Seon  
Дата: 19.12.08 11:00
Оценка: 3 (1)
Здравствуйте, Beam, Вы писали:

B>Здравствуйте, Seon, Вы писали:


S>>Моя прога посчитала а(8)


B>Поздравляю


S>>Мдя до 100000 это неделя, не меньше...


B>Может попробовать готовые библиотеки использовать?

B>Надо всего-то — работа с большими числами и поиск подстроки.
B>Уверен, что такие библиотеки для си есть.

Та тут можно проще сделать... думаю хаскел так и работает...
берем сразу десятичное число в строковом виде и удваиваем его, и проверяем нули!
это будет на несколько порядков быстрее...
Re[10]: k нулей
От: Pro100Oleh Украина  
Дата: 23.12.08 08:26
Оценка: 1 (1)
Здравствуйте, Seon, Вы писали:

S>Здравствуйте, Pro100Oleh, Вы писали:


S>1. Вы в каждом элементе храните число от 0 до 9? Или от 0 до 999999999?

S>2. Как у вас получилось вот это
PO>>a(12) = 4036338. Time 00:46:04.8292335, Length 1215059
S>при вот этом
PO>>
PO>>        public static readonly int MaxSegments = 1000000;
PO>>        m_number = new int[MaxSegments];
PO>>

S>???
S>4. В функции Check — похоже на перевод из двоичной системы в десятичную... Но я не до конца понял что там происходит.. можете пояснить?

S>В общем идея понятна в таком смысле, поправьте если не так:


S>В каждом инте храним числа от 0 до 999999999. (только мне не понятно максвалуе = 9 )

S>+ легко умножать.
S>+ колоссальная экономия памяти
S>-- тяжело искать десятичные 0. для этого надо переводить в 10-ю каждый инт, при чем потом каждое переведенное число шерстить на нули.
S>не понятно как достигнута скорость (если не брать во внимание разгон )


S>и последнее: как на вашем мегакомпьютере будет работать версия, где 1 байт хранит 1 число от 0 до 9? (по скорости)


У меня переменная длинна используемых чисел в m_numbers[]. Эта длинна равна m_segmentLength. Соответсвенно m_maxValue = 10^m_segmentLength — 1. m_k — текущее количетсво нулей, которые нужно найти. При каждом следующем m_k я вычисляю m_segmentLength (функция Rebuild()) по формуле m_segmentLength = Round(m_k / 2) — округление вверх. Идея в том, что при представленни длинного числа сегментами длинной m_segmentLength последовательность из m_k нулей обязательно заполнит один сегмент нулями полностью. Поэтому я ищю лишь нулевые сегменты, а когда нашел, то парсю его соседей чтобы найти в них нули тоже.
Pro
Re[4]: k нулей
От: vadimcher  
Дата: 25.12.08 16:47
Оценка: 1 (1)
Здравствуйте, Beam, Вы писали:

B>Здравствуйте, vadimcher, Вы писали:


V>>Вопрос 1. Доказал ли ты в итоге, что остатки повторяются (это, впрочем, очевидно), и что формулы f() и g() верны?

B>Представим 2^n в виде a*10^k + b (b — остаток от деления на 10^k).
B>Я говорю, что есть такое m при которых b содержит k нулей. В моем случае b = g(x).
B>И доказываю, что cуществует n, такое что 2^n можно представить в такой форме. В моем случае n=f(m)-1.
B>Чтобы доказать возможность представления 2^n в такой форме, я доказываю, что при заданных целых b и 2^n, вычисленных по этим формулам, частное "a" тоже будет целым.

Это все понятно. Я тебя про другое, по-моему, спрашивал.

B>>>в) (16^y — 1) делится на 5y, т.к.

V>>Здесь прокол в доказательстве. Во-первых, ты нигде не использовал, что y нечетное, а утверждение очевидно неверное для четных y. Кроме того, 16^13-1 не делится на 65 (число 13 взял наобум, может еще для каких не выполняется).
B>Я об этом говорил. y = 5^(m-1), а следовательно нечетно.
B>А пример не подходит, т.к. 13 не является степенью 5.

И где ты в своем доказательстве того, что 16^y-1 делится на 5y использовал, что y нечетное, или что оно является степенью 5? Вот твое доказательство:

16^y — 1 = (15+1)^y — 1,
т.е. получим многочлен в котором y+1 членов, один из которых 1 (мы эту единицу отнимаем),
а остальные члены являются степенью 15 (таких членов y). Значит и весь многочлен делится на 5y


А вот зайца кому, зайца-выбегайца?!
Re[9]: k нулей
От: Seon  
Дата: 19.12.08 11:22
Оценка: :)
S>>Та тут можно проще сделать... думаю хаскел так и работает...
S>>берем сразу десятичное число в строковом виде и удваиваем его, и проверяем нули!
S>>это будет на несколько порядков быстрее...

S>ДААААААА!!!!!!

S>а(9) — меньше 2х минут!!! в дэбаге !!!!
S>ща мы его....

Кароче
а(8) — до 2х секунд!
а(9) — 80 секунд!

С++ рулит! главно правильно задачу ему поставить!
а то я сначала мегаматематику подключил универсальную.... перевожу из двоичного числа в десятичное, проверяю.... ХА ХА!
Re[2]: k нулей
От: vadimcher  
Дата: 20.12.08 22:05
Оценка: :)
Здравствуйте, Skazitel, Вы писали:

S>Здравствуйте, vadimcher, Вы писали:


V>>Докажите, что для любого k найдется такое число n, что в [i]десятичной[i] записи числа 2^n, встречается k нулей подряд.


V>>Этюд для программиста.

V>>Обозначим минимальное такое n как a(k). Например, a(1)=10, т.к. 2^10=1024 -- минимальная степень двойки, содержащая один ноль (подряд? ). a(2)=53, т.к. 2^53=9007199254740992 -- минимальная степень двойки, содержащая два нуля подряд. Ну и т.д.
V>>Найти a(1),...,a(7).

S>Что-то я не понял пролемы... Первое, что я увидел — дикие мучения на тему вычисления огромных чисел...

S>Может кто-то глубже и написал, все читать не стал — долго.

S>отрицательные n решение проблемы. Вроде же очевидно все становится, нет? Огроничений на n нигде нету... в чем проблема то?


Из примеров понятно о чем речь. К тому же a(k) -- "минимальное такое n", которое, если допустить отрицательные n, не существует. У Вас образование не юридическое?

А вот зайца кому, зайца-выбегайца?!
Re[3]: k нулей
От: Skazitel  
Дата: 21.12.08 15:07
Оценка: :)
Здравствуйте, vadimcher, Вы писали:

V>Здравствуйте, Skazitel, Вы писали:


S>>Здравствуйте, vadimcher, Вы писали:


V>>>Докажите, что для любого k найдется такое число n, что в [i]десятичной[i] записи числа 2^n, встречается k нулей подряд.


V>>>Этюд для программиста.

V>>>Обозначим минимальное такое n как a(k). Например, a(1)=10, т.к. 2^10=1024 -- минимальная степень двойки, содержащая один ноль (подряд? ). a(2)=53, т.к. 2^53=9007199254740992 -- минимальная степень двойки, содержащая два нуля подряд. Ну и т.д.
V>>>Найти a(1),...,a(7).

S>>Что-то я не понял пролемы... Первое, что я увидел — дикие мучения на тему вычисления огромных чисел...

S>>Может кто-то глубже и написал, все читать не стал — долго.

S>>отрицательные n решение проблемы. Вроде же очевидно все становится, нет? Огроничений на n нигде нету... в чем проблема то?


V>Из примеров понятно о чем речь. К тому же a(k) -- "минимальное такое n", которое, если допустить отрицательные n, не существует. У Вас образование не юридическое?

Нигде не сказано => не понятно. А главное, что в первой строчке нету минимуальности И если бы мне дали только первую стоку, то точно не понятно....
Re[3]: k нулей
От: Skazitel  
Дата: 21.12.08 15:11
Оценка: :)
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, Skazitel, Вы писали:


S>>отрицательные -- n решение проблемы. Вроде же очевидно все становится, нет? Огроничений на n нигде нету... в чем проблема то?

E>Прикольно, но скучно. ВО всяком случае, в качестве этюда для программистов
Каков вопрос, таков ответ. Задачу поставили, я написал решение
Re[11]: И снова об STL
От: Seon  
Дата: 22.12.08 10:53
Оценка: :)
Здравствуйте, Roman Odaisky, Вы писали:

RO>делают одно и то же.


Ну и что же... зато запись какая!
RO>
RO>    ++*--dst;
RO>


КУЛ
Re[14]: И снова об STL
От: Roman Odaisky Украина  
Дата: 22.12.08 20:09
Оценка: -1
Здравствуйте, Erop, Вы писали:

RO>>Просто у тебя при копировании тоже элементы затираются, я решил, что тебе это так надо.

E>1) у меня ничего не затирается. Каждый элемент инициализируется ОДИН раз, за исключением тех, кому делают ++*--dst.

Вот твой код:
static void expand10times( small* buffer, int count )
{
    const small* src = buffer + 1;
    small* dst = buffer + 1 + count;
    for( int i = count * 9; i > 0; --i )
        *dst++ = *src++;
    ++*--dst;
}


Пусть count = 1:

0123456789
^^^
|||
||dst
|src
buffer

И теперь цикл возымеет такое действие: buffer[2]=buffer[1], buffer[3]=buffer[2]... т. е., вместо смещения данных первые count элементов будут размножены 8 раз.

E>2) STL не предоставляет гарантий, что std::copy будет работать именно так, в случае такого нарушения. Например, какая-нибудь реализация, может копировать в каком-то хитром порядке Скажем группами... Или таки не может?


Не предоставляет, естественно.
До последнего не верил в пирамиду Лебедева.
Re[16]: И снова об STL
От: Roman Odaisky Украина  
Дата: 22.12.08 20:26
Оценка: :)
Здравствуйте, Erop, Вы писали:

RO>>И теперь цикл возымеет такое действие: buffer[2]=buffer[1], buffer[3]=buffer[2]... т. е., вместо смещения данных первые count элементов будут размножены 8 раз.

E>9 раз.
E>Я знаю как работает мой код. Он это и должен делать, вообще-то, а не какое-то там "смещение данных" выполнять. Хотя я понимаю, что ты имеешь в виду, и мог бы, например, написать аналогичный код на memcpy, например. И тоже непереносимый.

Хм, надо было смотреть на название функции...

E>>>2) STL не предоставляет гарантий, что std::copy будет работать именно так, в случае такого нарушения. Например, какая-нибудь реализация, может копировать в каком-то хитром порядке Скажем группами... Или таки не может?

RO>>Не предоставляет, естественно.

E>Ну и хрен ли тогда советовать заменить корректный С++ цикл на некорректное использование стандартного алгоритма? :)


А хрен ли слушать всякие вредные советы? :-)
До последнего не верил в пирамиду Лебедева.
Re[5]: Оптимизированная версия
От: vadimcher  
Дата: 23.12.08 03:26
Оценка: +1
Здравствуйте, vadimcher, Вы писали:

V>Здравствуйте, Erop, Вы писали:


E>>Здравствуйте, Pro100Oleh, Вы писали:


PO>>>Распараллерировать не интересно. Здесь нужен математических подход в решении задачи, который бы позволил на порядок уменьшить сложность вычислений. Играться же в командах, чтобы выполнить оператор не за 5 тактов, а за 4 — малоэффективно (пусть и увеличится скорость работы в 2-3 раза). Возращаясь к параллельности — распараллерировать нужно не саму итерацию умножение числа 2^x на 2 и далее проверку на нули. Нужно, чтобы был один главный поток, который бы давал своим рабочим потокам задачу: проверитьвсе числа в диапазоне 2^x ... 2^(x+1000) например. Здесь бы ядра использовались в полную силу.


E>>Можно хорошо распарарллелить, на самом деле. И просто довольно. Только мне пока некогда и машин многоголовых всё равно нету.

E>>Могу отладить на двухголовой, и выложить, если есть желающие/могущие на кластере запустить...

E>>Общая идея такая, что тормоза начинаются на реально длинных числах. Скажем на числах длинною в десятки миллионов цифр. Соответственно такую задачу и надо параллелить. Параллелить надо так. Каждый процесс идёт по куску числа и всё что надо считает. Доходит до какой-то границы, скажем в миллион цифр, и отдаёт задание в очередь для следующего процесса. А сам возвращается ждать задания от предыдущего. Будет линейно масштабироваться...


V>Мне тоже подумалось сначала что-то навроде этого. Т.е. если длина n*k цифр, то n головам отдаем по k цифр на растерзание, причем следующим образом: i-я голова получает на вход цифры c (i-1)*k+1 по i*k а также перенос от правого соседа, который можно тут же вычислить (если правое число начинается с 5 или больше, то будет перенос в эту часть, если нет -- то не будет), далее умножает свою часть на два с прибавлением полученного переноса, а также игнорируя возможный перенос в левую часть (он уже учтен у соседа слева при получении задания) и возвращает вектор значений (l, lb, le), где l -- максимальная найденная строка из нулей, lb -- длина строки из нулей в начале, le -- длина строки из нулей в конце. Все, что остается, только "скомпостировать" результаты, пока головы трудятся над своей частью дальше. Далее, если грамотно организовать, то можно сначала самой левой голове выделить кусок поменьше, а остальным -- одинаковые большие. Тогда в течение многих циклов все могут трудиться над своим куском без остановок, ну а у самого левого длина куска будет расти. Как только она достигнет длины всех остальных кусков происходит синхронное перераспределение кусков.


V>К сожалению, глобально это проблемы не решит. Действительно, как уже обратили внимание, a(n) растет экспоненциально. loga(n) выглядит как прямая, допустим, что она такая и есть, по крайней мере для "видимого диапазона" это почти так (далее никто не бывал, так что остается только догадываться). Вот результат, полученный на коленке в Excel: log[a(n)+1]=n/2+1/2 (на самом деле полученные коэффициент и константа оба равны 0.497), короче a(n)=sqrt(10^(n+1)). Число цифр m в таких числах связано соотношением m-1<lg2*a(n)~0.30103*a<m, т.е.

V>m~0.3*a(n)~0.3*10^[(n+1)/2]. Т.е. при увеличении n на два, число цифр увеличивается где-то в десять раз. А значит, чтобы просчитать очередные две цифры с той же скоростью надо в десять раз больше компов (голов). Не хило. Т.е. если хотим до a(17) быстренько досчитать, то надо найти 100 добровольцев . Причем подключать их будем последовательно по мере роста числа.

V>Кстати, последнюю аппроксимацию можно проверить:

V>для n=11 дает 0.3*10^6=300000 цифр, истинное значение 345674
V>для n=12 дает 0.3*10^6.5=948683 цифр, истинное значение 1215059
V>для n=13 дает 0.3*10^7=3000000 цифр, истинное значение 1215060 -- в 2 с половиной раза меньше, но a(13) на самом деле оказалось равным a(12)+1
V>А так порядок держит вроде.

Даже так: если просчитать a(14) за приемлемое время и привлечь 100 компов с rsdn, то мы получим a(18)... И опубликуем его на сайте at&t... И прославим rsdn как Дульсинею Тобосскую во веки веков!

А вот зайца кому, зайца-выбегайца?!
Re[2]: Наконечно досчиталось до а14 !
От: nikholas Россия  
Дата: 26.01.09 18:22
Оценка: :)
Здравствуйте, Seon, Вы писали:

S>Распределенный вариант программы сегодня нашел а(14) = 2^53619497 !!!!


S>На это ушло 21 день и 2 часа!


"Еще три тысячи ведер — и ключик у нас в кармане "
Re[2]: k нулей
От: vadimcher  
Дата: 11.02.09 17:26
Оценка: +1
Здравствуйте, Beam, Вы писали:

B>Intel Core 2 Duo 2.67 GHz. Загрузка процессоров 100%.

B>Работает достаточно быстро. Хотелось бы увидеть результат на 4-ядернике, но у меня такого нет.

B>2^100823 contains 9 zeros ===> 0 days 00:00:00.45

B>2^559940 contains 10 zeros ===> 0 days 00:00:06.75
B>2^1148303 contains 11 zeros ===> 0 days 00:00:23.38
B>2^4036338 contains 12 zeros ===> 0 days 00:03:58.80
B>2^4036339 contains 13 zeros ===> 0 days 00:03:58.81

B>1. Число состоит из "цифр" от 0000 до 9999 (unsigned short). Это позволило сделать умножение на степень двойки и определение количества нулей без использования деления — на таблицах. Таблицы готовятся заранее.

B>2. Используется обычное прыганье вперед на (нужное количество нулей — текущее количество нулей).
B>3. Алгоритм многопоточный, на основе OpenMP (надо включить поддержку в VS). Многопоточность используется при умножении и вычислении количества нулей. Причем потоки все вместе работают над одним и тем же большим числом (это удалось разрулить вроде).

Вопрос: а зачем ты так делаешь
        int step = k - zeros <= 13 ? k - zeros : 13;
        multArrayC(arr, len, arr, len, step);

когда вроде можно так
        int step = k - zeros;
        while (step > 13) {
            multArrayC(arr, len, arr, len, 13);
            step -= 13;
        }
        multArrayC(arr, len, arr, len, step);

А вот зайца кому, зайца-выбегайца?!
Re: k нулей
От: Seon  
Дата: 19.12.08 07:21
Оценка:
Здравствуйте, vadimcher, Вы писали:

V>Докажите, что для любого k найдется такое число n, что в [i]десятичной[i] записи числа 2^n, встречается k нулей подряд.


V>Этюд для программиста.

V>Обозначим минимальное такое n как a(k). Например, a(1)=10, т.к. 2^10=1024 -- минимальная степень двойки, содержащая один ноль (подряд? ). a(2)=53, т.к. 2^53=9007199254740992 -- минимальная степень двойки, содержащая два нуля подряд. Ну и т.д.
V>Найти a(1),...,a(7).

С использованием "длинной" математики или без?
Re: k нулей
От: Seon  
Дата: 19.12.08 07:51
Оценка:
Здравствуйте, vadimcher, Вы писали:

V>Докажите, что для любого k найдется такое число n, что в [i]десятичной[i] записи числа 2^n, встречается k нулей подряд.


V>Этюд для программиста.

V>Обозначим минимальное такое n как a(k). Например, a(1)=10, т.к. 2^10=1024 -- минимальная степень двойки, содержащая один ноль (подряд? ). a(2)=53, т.к. 2^53=9007199254740992 -- минимальная степень двойки, содержащая два нуля подряд. Ну и т.д.
V>Найти a(1),...,a(7).

a(1) [2^10] = 1024
a(2) [2^53] = 9007199254740992
a(3) [2^242] = 7067388259113537318333190002971674063309935587502475832486424805170479104
a(4) [2^377] = 307828173409331868845930000782371982852185463050511302093346042220669701339821957901673955116288403443801781174272

вот пока что успел просчитать...
Re[2]: k нулей
От: Seon  
Дата: 19.12.08 07:52
Оценка:
Здравствуйте, Seon, Вы писали:

S>Здравствуйте, vadimcher, Вы писали:


V>>Докажите, что для любого k найдется такое число n, что в [i]десятичной[i] записи числа 2^n, встречается k нулей подряд.


V>>Этюд для программиста.

V>>Обозначим минимальное такое n как a(k). Например, a(1)=10, т.к. 2^10=1024 -- минимальная степень двойки, содержащая один ноль (подряд? ). a(2)=53, т.к. 2^53=9007199254740992 -- минимальная степень двойки, содержащая два нуля подряд. Ну и т.д.
V>>Найти a(1),...,a(7).

S>a(1) [2^10] = 1024

S>a(2) [2^53] = 9007199254740992
S>a(3) [2^242] = 7067388259113537318333190002971674063309935587502475832486424805170479104
S>a(4) [2^377] = 307828173409331868845930000782371982852185463050511302093346042220669701339821957901673955116288403443801781174272

S>вот пока что успел просчитать...



a(5) [2^1491] = 685051994344414819289601327349235507686015935162711500470230430
17169851270631488679017736106611268089166309388272338901170497165901308515144865
31038672793134353507126040839309470078654606145106745445739128933326064717862942
37233252448898816197557825091114307651395358115415022917209577261642767771202747
54519441816831362983266849142056649908740853890886083405397212467377035143021587
233073571308500000341901085017693125848012770286553757194752360448


a(6) [2^1492] = 1370103988688829638579202654698471015372031870325423000940460860
34339702541262977358035472213222536178332618776544677802340994331802617030289730
62077345586268707014252081678618940157309212290213490891478257866652129435725884
74466504897797632395115650182228615302790716230830045834419154523285535542405495
09038883633662725966533698284113299817481707781772166810794424934754070286043174
466147142617000000683802170035386251696025540573107514389504720896
Re[3]: k нулей
От: Seon  
Дата: 19.12.08 08:12
Оценка:
Здравствуйте, Seon, Вы писали:

S>Здравствуйте, Seon, Вы писали:


S>>Здравствуйте, vadimcher, Вы писали:


V>>>Докажите, что для любого k найдется такое число n, что в [i]десятичной[i] записи числа 2^n, встречается k нулей подряд.


V>>>Этюд для программиста.

V>>>Обозначим минимальное такое n как a(k). Например, a(1)=10, т.к. 2^10=1024 -- минимальная степень двойки, содержащая один ноль (подряд? ). a(2)=53, т.к. 2^53=9007199254740992 -- минимальная степень двойки, содержащая два нуля подряд. Ну и т.д.
V>>>Найти a(1),...,a(7).

S>>a(1) [2^10] = 1024

S>>a(2) [2^53] = 9007199254740992
S>>a(3) [2^242] = 7067388259113537318333190002971674063309935587502475832486424805170479104
S>>a(4) [2^377] = 307828173409331868845930000782371982852185463050511302093346042220669701339821957901673955116288403443801781174272

S>>вот пока что успел просчитать...



S>a(5) [2^1491] = 685051994344414819289601327349235507686015935162711500470230430

S>17169851270631488679017736106611268089166309388272338901170497165901308515144865
S>31038672793134353507126040839309470078654606145106745445739128933326064717862942
S>37233252448898816197557825091114307651395358115415022917209577261642767771202747
S>54519441816831362983266849142056649908740853890886083405397212467377035143021587
S>233073571308500000341901085017693125848012770286553757194752360448


S>a(6) [2^1492] = 1370103988688829638579202654698471015372031870325423000940460860

S>34339702541262977358035472213222536178332618776544677802340994331802617030289730
S>62077345586268707014252081678618940157309212290213490891478257866652129435725884
S>74466504897797632395115650182228615302790716230830045834419154523285535542405495
S>09038883633662725966533698284113299817481707781772166810794424934754070286043174
S>466147142617000000683802170035386251696025540573107514389504720896


Предположительно следующее число должно быть до 2^16380 ... ??? прога досчитала пока что до 7000
Re[4]: k нулей
От: Seon  
Дата: 19.12.08 08:20
Оценка:
Здравствуйте, Seon, Вы писали:

S>Здравствуйте, Seon, Вы писали:


S>>Здравствуйте, Seon, Вы писали:


S>>>Здравствуйте, vadimcher, Вы писали:


V>>>>Докажите, что для любого k найдется такое число n, что в [i]десятичной[i] записи числа 2^n, встречается k нулей подряд.


V>>>>Этюд для программиста.

V>>>>Обозначим минимальное такое n как a(k). Например, a(1)=10, т.к. 2^10=1024 -- минимальная степень двойки, содержащая один ноль (подряд? ). a(2)=53, т.к. 2^53=9007199254740992 -- минимальная степень двойки, содержащая два нуля подряд. Ну и т.д.
V>>>>Найти a(1),...,a(7).

S>>>a(1) [2^10] = 1024

S>>>a(2) [2^53] = 9007199254740992
S>>>a(3) [2^242] = 7067388259113537318333190002971674063309935587502475832486424805170479104
S>>>a(4) [2^377] = 307828173409331868845930000782371982852185463050511302093346042220669701339821957901673955116288403443801781174272

S>>>вот пока что успел просчитать...



S>>a(5) [2^1491] = 685051994344414819289601327349235507686015935162711500470230430

S>>17169851270631488679017736106611268089166309388272338901170497165901308515144865
S>>31038672793134353507126040839309470078654606145106745445739128933326064717862942
S>>37233252448898816197557825091114307651395358115415022917209577261642767771202747
S>>54519441816831362983266849142056649908740853890886083405397212467377035143021587
S>>233073571308500000341901085017693125848012770286553757194752360448


S>>a(6) [2^1492] = 1370103988688829638579202654698471015372031870325423000940460860

S>>34339702541262977358035472213222536178332618776544677802340994331802617030289730
S>>62077345586268707014252081678618940157309212290213490891478257866652129435725884
S>>74466504897797632395115650182228615302790716230830045834419154523285535542405495
S>>09038883633662725966533698284113299817481707781772166810794424934754070286043174
S>>466147142617000000683802170035386251696025540573107514389504720896


S>Предположительно следующее число должно быть до 2^16380 ... ??? прога досчитала пока что до 7000


ЕЕЕСТТЬЬЬ!!!!!!! Нашолсо!!!

a(7) [2^6801] = 201836873730874603496067078704951742793271571467796357102595
63287899142446307449396553194376649549544732189805453964941287117332349807961845
96898709408220563882064198527460107522879819440838558686377575813024966104312440
40472053699794021012450900678592159202221067186018047489680554937424241508712624
33034724433154210959239966119613875688017101973957888567620067154231849972166639
59935738965349992022396029669476515909241032357927107773201668849648641513488181
28121205970900852387794365773285613104276333767014551707236799842614244090868138
82789134901238252835879089500000007784845918211269876585199886468773537067916422
55363794208429618031522790966763352630862216045390677455403997741887757819822545
36179073980292378702921519952169721534896399382438243624599995559220773507782863
57407766107793804592897320742792492416740896009983541060820246839826616223053856
18725457038911592602490298629776977230236880196255981756304400152189092409917670
63637206206142133371517905248972371848199178904029181997615380773873319531937795
37420090512597084968049368790217593123843433853633480876353176069425237997545227
48363067328093980965170154587917064165748691133914573471242449819558571165600837
22808170828653631246601044196566973412839611008060079204838775879979315996716284
39148801310673164340829308511104223422136544209138120755491804122181842958700452
63903594959985540352748924356931540912889423675422225013358375870739791856320272
07406851917856357718967853749880064245078036414369677587722694034263142119385177
47337101117944085336648858912750540490583941341768853329676606213106781004672766
47853690600834991591180467771692374905527010384973782874030002217253098383774586
45395269029802127818256217492473685467008121796090793979868062532342326656709441
56564848878452893940866500287080012514525229194434984840878537328561392666125392
56584609329469478143847118157468341549543546016378221618728937408483247576125814
20865579955645654575584326885619372827808775026733088186692740211957894903835943
60483708898503857927341665254697222189001784070888784966164259274752

продолжаем считать, ищем а(8) !!!
Re: k нулей
От: Аноним  
Дата: 19.12.08 09:04
Оценка:
Здравствуйте, vadimcher, Вы писали:

V>Докажите, что для любого k найдется такое число n, что в [i]десятичной[i] записи числа 2^n, встречается k нулей подряд.


V>Этюд для программиста.

V>Обозначим минимальное такое n как a(k). Например, a(1)=10, т.к. 2^10=1024 -- минимальная степень двойки, содержащая один ноль (подряд? ). a(2)=53, т.к. 2^53=9007199254740992 -- минимальная степень двойки, содержащая два нуля подряд. Ну и т.д.
V>Найти a(1),...,a(7).

Решение на Haskell.
import Data.List
zeros n = head [p | p <- [1..], (replicate n '0') `isInfixOf` (show $ 2^p)]


Ответ:

*Main> zeros 1
10
*Main> zeros 2
53
*Main> zeros 3
242
*Main> zeros 4
377
*Main> zeros 5
1491
*Main> zeros 6
1492
*Main> zeros 7  -- 5 сек.
6801
*Main> zeros 8  -- 25 сек.
14007


zeros 9 считает уже 7 минут
Не дождался — написал, то что есть
Re[2]: k нулей
От: Seon  
Дата: 19.12.08 09:07
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, vadimcher, Вы писали:


V>>Докажите, что для любого k найдется такое число n, что в [i]десятичной[i] записи числа 2^n, встречается k нулей подряд.


V>>Этюд для программиста.

V>>Обозначим минимальное такое n как a(k). Например, a(1)=10, т.к. 2^10=1024 -- минимальная степень двойки, содержащая один ноль (подряд? ). a(2)=53, т.к. 2^53=9007199254740992 -- минимальная степень двойки, содержащая два нуля подряд. Ну и т.д.
V>>Найти a(1),...,a(7).

А>Решение на Haskell.

А>
А>import Data.List
А>zeros n = head [p | p <- [1..], (replicate n '0') `isInfixOf` (show $ 2^p)]
А>


А>Ответ:


А>
А>*Main> zeros 1
А>10
А>*Main> zeros 2
А>53
А>*Main> zeros 3
А>242
А>*Main> zeros 4
А>377
А>*Main> zeros 5
А>1491
А>*Main> zeros 6
А>1492
А>*Main> zeros 7  -- 5 сек.
А>6801
А>*Main> zeros 8  -- 25 сек.
А>14007
А>


А>zeros 9 считает уже 7 минут

А>Не дождался — написал, то что есть

От блин.... быстро!
Я а(8) считаю уже час, только до 11000 дошел
Что за кирпич?
Re[3]: k нулей
От: Beam Россия  
Дата: 19.12.08 09:26
Оценка:
Здравствуйте, Seon, Вы писали:

Аноним — это я Че-то не залогинился.

S>От блин.... быстро!

S>Я а(8) считаю уже час, только до 11000 дошел

Да это еще не быстро. После компиляции вместо 25 сек. получил около 12 сек.
А вот девятку до сих пор считает

S>Что за кирпич?

Это вопрос? Или утверждение?

А почему у Вас медленно? Что за язык?
Best regards, Буравчик
Re[4]: k нулей
От: Seon  
Дата: 19.12.08 09:37
Оценка:
Здравствуйте, Beam, Вы писали:

B>Здравствуйте, Seon, Вы писали:


B>Аноним — это я Че-то не залогинился.


S>>От блин.... быстро!

S>>Я а(8) считаю уже час, только до 11000 дошел

B>Да это еще не быстро. После компиляции вместо 25 сек. получил около 12 сек.

B>А вот девятку до сих пор считает

S>>Что за кирпич?

B>Это вопрос? Или утверждение?

я спрашиваю проц какой?

B>А почему у Вас медленно? Что за язык?


C++

самодельная математика...
Re[5]: k нулей
От: Beam Россия  
Дата: 19.12.08 09:41
Оценка:
Здравствуйте, Seon, Вы писали:

S>я спрашиваю проц какой?


Старенький — Celeron 1,7 Гц
Best regards, Буравчик
Re[2]: k нулей
От: Seon  
Дата: 19.12.08 09:49
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, vadimcher, Вы писали:


V>>Докажите, что для любого k найдется такое число n, что в [i]десятичной[i] записи числа 2^n, встречается k нулей подряд.


V>>Этюд для программиста.

V>>Обозначим минимальное такое n как a(k). Например, a(1)=10, т.к. 2^10=1024 -- минимальная степень двойки, содержащая один ноль (подряд? ). a(2)=53, т.к. 2^53=9007199254740992 -- минимальная степень двойки, содержащая два нуля подряд. Ну и т.д.
V>>Найти a(1),...,a(7).

А>Решение на Haskell.

А>
А>import Data.List
А>zeros n = head [p | p <- [1..], (replicate n '0') `isInfixOf` (show $ 2^p)]
А>


Блин...
завожу ваш пример в GHC, а мне выдает:

<interactive>:1:8: parse error on input `='
Prelude Data.List>

что это?

.... я его тока поставил. еще не шуруплю...
Re[3]: k нулей
От: Beam Россия  
Дата: 19.12.08 10:04
Оценка:
Здравствуйте, Seon, Вы писали:

S>Блин...

S>завожу ваш пример в GHC, а мне выдает:

S><interactive>:1:8: parse error on input `='

S>Prelude Data.List>

S>что это?


S>.... я его тока поставил. еще не шуруплю...


В ghci надо let добавить:
let zeros n = head [p | p <- [1..], (replicate n '0') `isInfixOf` (show $ 2^p)]
Best regards, Буравчик
Re[4]: k нулей
От: Beam Россия  
Дата: 19.12.08 10:16
Оценка:
Здравствуйте, Beam, Вы писали:

B>Да это еще не быстро. После компиляции вместо 25 сек. получил около 12 сек.

B>А вот девятку до сих пор считает

Откомпилировал с -O2, перезапустил на Core 2 duo 2,66 ГГц
Просчиталось достаточно быстро — около 13 минут

2^100823 содержит 9 нулей подряд
т.е. a(9) = 100823

Само число содержит более 30 тыс. цифр
Best regards, Буравчик
Re[5]: k нулей
От: Seon  
Дата: 19.12.08 10:27
Оценка:
Здравствуйте, Beam, Вы писали:

B>Здравствуйте, Beam, Вы писали:


B>>Да это еще не быстро. После компиляции вместо 25 сек. получил около 12 сек.

B>>А вот девятку до сих пор считает

B>Откомпилировал с -O2, перезапустил на Core 2 duo 2,66 ГГц

B>Просчиталось достаточно быстро — около 13 минут

B>2^100823 содержит 9 нулей подряд

B>т.е. a(9) = 100823

B>Само число содержит более 30 тыс. цифр


Моя прога посчитала а(8)
a(8) [2^14007] = 000033662724701763990788983568556041232924515475860246167482253
21619179440438646293915455822251957083168790275365058169103299047907279931869666
62377093412572648398352429291109496691741373642434693114609921276964706431437563
17740303484788330486266539622312618771291197421437578049234416261281431991948830
90179741345388466047083662146412684123197874626588783927450887432153639999725945
49378169730314908238265400304811308972022575532573583203776926224230466012278511
74984677774147733075916511439807221461359073816036944080183143324847649511019232
96984635532851895777542519415279887128451873722760920519590845741185967486448382
59820645499314214542369733390812009307673613200659560870763343764286818531635193
82405838588997257168342124111344349677799408957534228984890299453466158953777838
40097924417252643116512471362377442057882828953674081984516353623425224379037319
13158314106869765895203582571206420678735081975763088958817692576966922251433271
31149841861548806993656297661306254830666217985043374972571796007600033509695004
39530897238474774879513048709933824255644828908475535692390574185596520249563832
09672073543818563332071480348421085357778839875754077257992237903661156295049490
24423462714994678260166485662451281221484552628252933912156726887458639863215683
82689290803885558818429029691941206128130176681760557330308529389627853758142576
76382545605570175109866401680631746354382943764908578351235377904957117321240100
56634769360287434968435338525887286530241719991993677640545050902862773629843050
95825561795016780443117510377279218584320194755363314101420901307541167436708016
09430543302734343868858891379843570280291787641988083391041239145188428252390476
85299015379737305590546615370477003685843342861156832472323600913789940912832878
85566016456534465182459126518592693119644449085012256355113681854264441459954678
50894281995833458889586853196617094216560260672386018619055624022053207139330516
88627769755037093026916953693267238918393033938985982357071756801119765376591242
11458455114130417834512133851069724865020582695692939047342977887797639127211802
25093019437706455451364423326669224665482810369799756807523222571769398102563264
87666682763778229161999263320804088315131882440538666479961425423827165774903408
23581048791287094226656961100195042382947186191288972095842951941087700552509226
31395517758764602447212753017608500017966084109115460944900327527614098144077656
58771749968396527679993450494147364364603568492311170846895897147218139840357700
74466931864136217286041866608188000843078788274891853988171934613966449874151195
02842958034297094514467899500965183464661796159370287393574846968144253223362396
12113923325330847946073081496234993152251179378322007361257399204233807479430257
08245441473989918889084601651220873221522680115812077735603902062828357877004675
91128228637730175174058379844803659249317442480204561241926853901464468362217164
48171545043163082341788465622588806031561851549790414734688672506572506600413342
63976080502482068631084389281309416243864766635698025192159399567304996489940951
90275056743308946961671112860428556721479556486184443505975896750889095178318114
21977577331766136251206312579842703668727259377103704759588652882668040880064429
86344266907053894560793929690067357517861646226248747301028658965934924293208414
47741855589902056920020218026296531345015993803782073779255370903736253099308594
00469941205004292010189639672282673042889881215331609558146147924611385253494236
47367861213759899269886939055194622171075693421784203287916603000000003213966087
57682208184786718550580089193781283154953812210416368242984614472126184380298716
88290111756639496292102403593157001971051780815372615256408750384074488193256513
38373692432796996667155150254054735193086518231855207667453906821302360953782673
22244483246613674879928197501396293251605674916319891085983406510940406816471127
58495276169917416450646758457660169005035016907184258672323521733858132349377243
75296476337758834631167125502249848717287052323868823727498857925543131093451510
97470435550431445278068017349964361161246846150796218579004669892183711597629126
44942617389369626802994855326768788247937341632109249492575848180947430156437831
245815185340839376921637308770763013748956540802880891289897190564060230320128

ХеХ!

Мдя до 100000 это неделя, не меньше...
Re[6]: k нулей
От: Beam Россия  
Дата: 19.12.08 10:32
Оценка:
Здравствуйте, Seon, Вы писали:

S>Моя прога посчитала а(8)


Поздравляю

S>Мдя до 100000 это неделя, не меньше...


Может попробовать готовые библиотеки использовать?
Надо всего-то — работа с большими числами и поиск подстроки.
Уверен, что такие библиотеки для си есть.
Best regards, Буравчик
Re[5]: k нулей
От: Seon  
Дата: 19.12.08 10:33
Оценка:
Здравствуйте, Beam, Вы писали:

B>Здравствуйте, Beam, Вы писали:


B>>Да это еще не быстро. После компиляции вместо 25 сек. получил около 12 сек.

B>>А вот девятку до сих пор считает

B>Откомпилировал с -O2, перезапустил на Core 2 duo 2,66 ГГц

B>Просчиталось достаточно быстро — около 13 минут

B>2^100823 содержит 9 нулей подряд

B>т.е. a(9) = 100823

B>Само число содержит более 30 тыс. цифр


А можно подкорректировать Вашу программу, чтобы писало текущее значение степени, ну типа как

std::cout << p << "\r";

???
Re: k нулей
От: Seon  
Дата: 19.12.08 10:47
Оценка:
Здравствуйте, vadimcher, Вы писали:

V>Докажите, что для любого k найдется такое число n, что в [i]десятичной[i] записи числа 2^n, встречается k нулей подряд.


V>Этюд для программиста.

V>Обозначим минимальное такое n как a(k). Например, a(1)=10, т.к. 2^10=1024 -- минимальная степень двойки, содержащая один ноль (подряд? ). a(2)=53, т.к. 2^53=9007199254740992 -- минимальная степень двойки, содержащая два нуля подряд. Ну и т.д.
V>Найти a(1),...,a(7).

Обратная задача

Найти все числа, степени двойки, для которых не будет повторяться 2х нулей подряд !!
Существует ли предел, степени, больше которой 2 нуля подряд не повторяются?
Re[5]: k нулей
От: Seon  
Дата: 19.12.08 11:01
Оценка:
Здравствуйте, Beam, Вы писали:

B>Здравствуйте, Beam, Вы писали:


B>>Да это еще не быстро. После компиляции вместо 25 сек. получил около 12 сек.

B>>А вот девятку до сих пор считает

B>Откомпилировал с -O2, перезапустил на Core 2 duo 2,66 ГГц

B>Просчиталось достаточно быстро — около 13 минут

B>2^100823 содержит 9 нулей подряд

B>т.е. a(9) = 100823

B>Само число содержит более 30 тыс. цифр



Вот это число:
a(9) [2^100823] = 00000055879540930067078422327851837042530966116054800134702688
41531165354249691066749470220417094225054610947409690191397767467944539216528613
60490423936108980038523632746621405629468590257489810381244296371170163628559434
61516957475008371824333109231732637641151956046535035629140674342282097000864089
85724076969719785461519381183607314969542437423703291663136408241484749520614832
77739091220250954466768269671729318742809395471840724208254907723886310417839792
18984776896249003279151002164644487834098119065895324447891411285577726441479320
07080563879567160958513392549663832955087734073911017445769747780775477506158838
96783030326791107659503992342898808704648031964568004596527219990246575915584306
98763468956731290430457003020578677610437142662086255198813391739718975530484527
20397708520786402659707979234837333950899206687785845218835941694733241202937881
51097451245048770952853681570458885548655647530999829976293624581478248911606675
87221768675125966104322794301048127809463808979699840525114583361202210505980632
25285787430609826098636965386513045060718042339014773342787743116618274161350467
61610026032015953001886253787819756036872679802044371753833406184416856101477041
25225342823822257382311482284659148363527069567161575415889915357600827021746456
68282152108465919376275368944121894177854682456441835613925982844606724307036016
77772926326468173497169309232389097504751318745431892153261678448017520421292074
96012541997374250964923876119772147314341288284431351872211172110719638997288500
47228486438160866920979136949075392679777528267483521795584340871077431756714340
87529064916837513834584359730272996376098753229300829331946149055623692923617172
46801621069690030608001281731145856518991607416801988755685525831247092343395763
26948673729341740479958596330345654486989627695717372549526503903681518849476544
79170567064520364229371512333228947885229861102445947523416787548917769922882933
18750727135402864475822435271128831613857796479788998728638426778769938942452805
77283087131264709467926406474574880763932709367306197278539868652989544158223392
50776750450324092953251250888643722524655542688125012686294685078152391598943962
91691112225626827187938301316053686594713675117576081992173193719736469839228697
71024049561905220167524635100946347330947040881552714669224069434309188611272998
56537040271948085118397761825675828095586062206228764583234828544267864734821961
24063705343092299649326999558066129893768871984498510057819554301599303383010188
04357879879068461472706869407892414812566404773602892688873553591576708604654076
87072648198781813529534290933461426941564296522438433373596056440724346383374904
42075796892342391902685162518409260921655745799945763130472423325370480098860661
39138187807160466266487298859482076320703223544818722672394805899279081736177853
73520323899035823171638984851111206660983687902327013480940548818218458057881041
19990893998016796361014094225799121528741371787423632192109729862337214365036869
52528327935613576996590868158680906097097155433610319283746161006680227328011103
28647690233607751763686571013444709535721665803915086260404124862850734650087287
94703540775768977594314460262833619421265728398973454500978189899035108614054083
81449790787311072206507000201628801862471819173045967796956760077461490160537267
62679746111209665960627579451670248383276303060304697199584007811384228561104599
82159435827438942221724066897215475507212041765288803306140189172367008901744540
66556220403373229198744732862297809140893237727733516735734743459334110535360676
32005530913619279230639057600560888863644115731010761677729821840964530253758209
80295331503332688010781698765224228624854739534877682888096451413418878638117725
62354095951170109213686697265274924539879165049319334448786716181622864311070757
32336449229730865777748185427883519692579017494033965416193748194234130244042562
86420914358851633688869422808074078320628142167946114561149746043334692693231508
68187968046000908702317547703714332712585878367482741980254982938244773492712082
30315451246150008826744680670941913847239246083347285934976090683158850105389347
09021934112300693033943692616455423867252912510200380935820605828587640660685847
57104150091390221653526258281651043584938053065384050073227423939855306476223768
16840799111148945085819397334252042774524152244449486331344338598935786250253799
06834747661519313756357864010535422239668841058737351568504503547056182312757022
14136512433441879531961700861231648542101597602690417702446911467553652183978973
52739423851521661072645566395699781033902316164988624587446968168739927476815799
82082770414112247461368222765362643299388091763200868889247915197886395222192688
43640158419483312089577791375670777621205221251015838299272244846531060692190430
85286300560984085036257254086024733969723374320374785339076009807445375684545593
11017868365782564077386289185848717926458487095961351007944388853791403869401773
76977726367452359527845934120011962482126668849305827096760996654759437383478319
38121342175729822215459366242562178282759502733296540090244860552586311034211270
43104203948140680951105734627353501899893028405160864174683747464423948010389965
99275053082804239969832330191025444223071533403686937413325218929299810099936477
53213858201634317058435811286388768915240261040453117539268729663735125983269406
31453224948876687194831777236358300692721846663574149187433242264049965227182385
15124933301515292341627445956246328886678973890348168738652587141135510026372797
63334368781076580191625332919057073766590674416073111751651265129751534683349314
14813969420443019603972556336386328316842339852504331502485548142714287078622885
31938390589726068301639382541125254427434149412493962312573389051802513147141663
43527607945564101313346072456391967896165621830072107382710452959809641661338426
23922637364377396807279453158657327005363882135134097032524863234985558386331146
43043083682350496534548078062613388883047118431599824606702749556845524167492796
90216698229558873882624738521701835552789300586730176380709729484106777705900733
60159614170437013168531475812319117565433718403633805373994451223260997399680999
39103030744776491983991247610814319976679348252956045570014650452526420442157652
43335269657311749518352124484353325675835607287293525381790503039605962640270212
22979978257549783115760628953373298435164344834883242210552346182618810212832025
09340384600274428353166015389023985245468345728677715888458264113412753116552877
44033505687414604038798046584929244688507833486436060019478830140438610907519252
65371060371628390069936240607691081250070779108039277097479843130650581975472043
08412939586022217703247835359371572823790911166015025723275112774368302356267271
18136109663388321469565354016197475325256247145356175601729184896269825633916775
11225181192013500836188219614484269518424157765762901465911023145885530371146195
39925460921390668213062974365767618123443563874739610431327551298991173498575216
03664657265389227571229230994867617349972949559292928284485826092642237109874914
52280727206032957944576266326460394844242780023192105631136228573204054498005713
79815674258838527729100152804149328296128975104639840992545490847923671140032446
42476423785650004326021745126297133695530472597704295439682920387049970440692458
34536409220384029167005334558632487549683165848767954657168810372722484024197728
94266359275317765201958646342587489766350173810818392216487401998972554609014393
04576960339693565959518568128606215173555794076836891742777310538150658655685306
00773473597943490082253302173120257656736312169905663516971387562001846889565630
94247890538836188534365791103563875515918659395092080736112089580699503093860319
31670921820442524864841271485267197566597927634423244906855604914398608433230745
92174829241116631609011017179363594446272967649525188727000178698974217587856201
23724625948177989250297576660928180436499945896487139693826406041101835616146219
62123406469340513372610854978643264085885925549181184387239130012820254841313582
90498882701620085830637971626798808315621744270812998921446454992430116972835284
14211037923376688793812489441496383504654021879748059647967340781919829401884277
07578644412647684161093808261554347479713510724936082214893100681970131910872947
00098973064588622501278573728038722021846068875397842948278275652350007346978165
64403846455557121382866765451090746103081743640967405570391350888349352955901906
61460514725948600015595792537809659037503381656989834888900686035208515539554797
88680547227622760886601464543536085145246336186163097426754109021790246556468726
52626825973213309652963652570526170357252126107085261694232874937807593527608758
73114700803492853788698475382016976448297115424304374623720826968649573955269948
13629731531372055989132095969110696959775352692685911631742898242981563252507495
97896039089404219535290528814308329697756464909192478863532829013735900119212377
78641590935540040747999764169334346745564169624674964223357990694303001455194232
89124814819905795263207813034064568370904968125810665948488168049619452914580020
86051529759651304734023219917798514709808222291588297118092734704459803472643317
24382873339019698297306082999033296835068415491361982897465291865058750535497171
36552158502232307301882637110867968269501707794127780819257643650425539200947856
25474831637633201568582468156788691177771032616703653163859032967348337787455192
92467693639768497443720910420192259215053477568566648174011298676303469997867367
45626709054558037349154761621853777481926627317352500302389063204942748341547855
09156372774355379646104759677883389956230775175163365500622144666158511307787136
81719388222115984992245009541567925792946980693522807119135921266129581478072624
60704708026381875778972378746843427954041379169267501225631395418447713606377266
73687774375297399703385248601702498401113358402307696649869872034790183336341859
76622381396908248432125023198968141602797711370613260346810575045283623023423218
26282960069008601816286835406377116868992773356219525764624979104712469918876106
70372665433042603193704135349982214620383575659928396256528724667828944096188654
54924002236767470598676307389874674965236363081325313504665571880007965639352538
32120989386311273480290016349046967110152276449784751283841182728451200440395248
66970912525263766398574544305301945378441280174046904984450525895331921965180113
09801024928899838610396765187179327640633584443225222256535197946118332678512956
95645300437337157878308256548493241590587744055778302609854638075538660570195292
14759534698615764038181515591346296788869394784568027427424543744771496273798512
67303516177067623773840709018463037768039644607216698173851407892881674942195527
88069317744266796232814626212894315851916710428976252448241246235459595660302412
41466813274264089467282025887511394511333252463631305799922404941909746066188590
98354481674457834615845143320197338398273124429978253476080394316070657490479597
71777154309541390885423475908747841928902666579780062202750301323890592090692224
36664814663267448659742634541469832362082381688508215899269018589764340388809022
86167554467161660109509326151258434916915362633382377515777183009035128677312082
49804853956317389016894278841271204441634243342232652519116926051399641998683621
37022893205008338453148370541983264069086403359048325382564831622870982871949042
69574538484534575952909816849480883901499228307406834340811670318783593828840292
46813529459099673637522068996866256373130627346790386247448216342293438817534291
54922264094433605161186832589085149048799403209380103219601523222103535077853475
01218153077770866995757399127622406014642374267705422104922969339885722776118723
75792118097951387154125588172587411307596905026866283781696193665438771028685234
63799000400225789708715876929590702047656944025749499652662438139090243246480481
88901850279625062973773279736804280868719505098363196975313514885775461376075788
35909223533635847714511988275030657700452923447786493926013374003323290303989908
90272580344005591113783499849602487008695983102113561425837675624456323224035630
08423550832870562448548569511821077754921363120394252640492001305556660464271929
57446342893787304534974032073725706939038266820310965248948356629413049640219282
02804616132131859599206943549487029285649974604250768866892495065945630493467820
21840256544769677493002145488605195990438075583791196081858884529930336719912391
87684613563191298002734051532308454837070649488313036367067759512150362304793479
97247393684742620446700527737378009252695001383058150118618629838883848315452115
81435710744921192518559800987552759189069734615753428282368511724784793444225647
51913863291782980784853397044484545045666143875021620474014593262661772424690441
58723220772566962725364550119899667087585810337127305615244673854418969069205712
19069056466080765674992746748514583583875051640461025915763535303725904310846482
08405042280470768861850625414896364496868635449842571298091387662544543277767632
39442500199835029114874935376968788307832393062432492354436677616452693458157311
91149947397074763152145391139522037653074901978698564903755591550073270499042781
66938124048600904762533730272617792267133339916182052934909058739508839126439445
34711933148592544838041439842907400466664607625479193557732190640606722947337921
30371823934618525606909798264604561784410869637124840370588309952755482585816211
69189353039127718596837505998131204668986530615581596169366226080659218506421055
51414859278420937411856212371748648551772454287644039208775890472675618293969459
25318284080961989806623478729950952666504579417726381667871519773932893495929105
55274661596180092484046598676227493800282269375512405401336036358327996112099795
72251546575258812191631347662300608755718313525103282560213199861009851683413438
19824429991639970416300232676729128263993713223767078112276671140499159577785889
43050619108303527135310002147629264700963665635222974208733617748680654117449897
70243725622148086168722136956032705282691838186823219841541040505008173328681936
36998350016844240067472628872108409976993791329240429378254258021031781806791694
53784447936943316890280469552855806322011480429987304559538298774770768757915242
93231899414193804672619652569703246323932157853441544849234689636956995265514755
35489617332913898094299651039824548817855517094936379474213185112564855986278295
62352363109236688906035976730562107048233548917234786684090978213342314174877537
26134615736120626117112216247374737066048025823885892623336976797974543136393754
62380792472035960913951230562231576794502894865936542465387079044974463369878942
36131208316856952522421124887649941674747126623444841344830271748934147847474332
00625429469627961558231053660905982574819481674328019070281165908962096366828833
16359018153672746783846273654352464404261736012354039024145136209379077340033619
66754529125642391664109307536277684766310595819192454233362980690310965011725817
31854090046226148465347009778186080320346562527072086823017105379433497598183945
80414965641189981672911809614496884637329490867579022434560131616329914286131926
94709864301117207505043056443517950888174815099714170365511604942275313251346775
85916642800497191606313659073271860538098326537630618539938613680254360405896951
68591740556050661584257552740807974025231089693202871297435449522659505741612335
79798652777544063301929718222418580068585354400576385284506436678285276553087711
02503880817768167162863833038339911056337759002201531564365446589677398746728223
37967955860909013307082636027732996298649559027643257389703278234597880640735603
66008021206067489320334340919314033327282092414203072225957120424767476733087579
14775246630923840720263490008313423863996944870005107268670241104797898190915877
24602794409390610387717530268727496940563759741711564467137973198885634262894658
29500376434566612062621873056042395126259461488260000266841804573397051862966922
98434073959808933786428827744767173447503757005439590141662748483205327310396224
30397480501774116290822135569965213697476041184484225900415592672059371231453080
11454366303956730776901986468638284406645438781636531196503967859770987356304433
53599451617948707356142026389567529276626856797069771080493400818148841456670718
68896995971383499729263114770149262814156575929213363428089427678534787326522954
94188764350046626847136709842964674101202176101060586273322797469335759024005955
44873367423497439397828680956208467722147301986814067711998984470573545418383489
58011318945481575232060056767329014156639560810763390338451752564797918438760824
66019059273619499485788546915263149919739352212444496082484958583511047485539041
29670208133984292302192014381540241877744851912270616371743910958660007841022168
87585108006498518494643303489248493815621288279803197212840906557674186751471802
68334981673632514894910671026021508027890489037441536373385518970337937269584986
26782760721140784276705111733790080305276937132537486952695389768708934448117782
73019125371045063713416304482037795356073809793714420289251166301194309143574583
45432599757821942759139232062974882973816379801773338247216269465280123329172969
06169386484629460294353930461487065140707310194195035854976389407422629082616649
70074599758580758331758768043615519255206321201987384092372450725506029231615607
60091084548374579401335898236576730027754974249042975201843631003175525876441756
90173749217682733596445846829621725308152170932226454876309606190507830368985009
42641245189698923591353826902780793945358202482743943387525652026403154025401798
34447642402668337261943738706094698348789138859858713898090636078414775145124504
17771153831844713166057226208560098904825480360965795847046203246406542990875743
43957914398552935834340669912090156667018189997715583021811150125421221222996413
04886269280942616806324600409557398687785473638259650982395272708334124382333597
10250116320087686591887915045236970717059907169208577040678098107056357194961807
59866074484091426269231397088993950412414565089542564207375562647292630781718091
71684240737851256506890461399307488630931148652809825135031536200398459145235676
62884672697339814048478443973117143913592586216743845712493646076924918167017377
02704352939392814793755355857728216315026693935904132456486947383355248921753660
58100348062911825083045946093277841198442730970203559739501331005131960267272253
61643566548412857611332222325981860542099381686594056282829570652253230059376340
37757210316681081544436260248237409873758056755228408500261416825498962753082379
62833871126074756523387263004224599550172767779033920757276855802409968821004712
48944537436993179318372323871795165588130247945503084536325390096336399312197560
60783101453273338236463093855319390080256043286241625052784344740078769973633788
30114122335056709029129307040689607532367070881682939603267488895262917887742294
50737391687568960370956158559131345541045381855450383568525576864172552710827035
98185052253082620315349136169907950835432583946153848607808795678238767227875833
44008885866560810339385053232854285695911090061361622582611061122141460844074170
22941935571417584724023727750362162856340833452644849712768135518733877488709674
55713965046825192785519248956078766613694936053898780231294060204406770074298879
14463579773378362966339322505562962670908360558492194445819379035505497212818378
39620642866813314131145279252707011892762907711414321780594450769005893194714262
36899822042625127860878084896052174082242340669960516220160821084073371075511645
75142003462371445039188061585811963695871544620203133368408389884825856388544393
11575458523878669854821292532468431141450122669137458530241060871375404973647916
66688110074828730258695070658682720195483759193240751729244037747361178897254385
40850337037274359687991032996267730937182200413645566385807797796775525113819956
90311272495203158497950565140307659818360834123180006499390051079276024572428372
37234040507392375546501079238382615738999289913738843882283905239084640254417833
31676894229791631831466153508793169840012684905396377448352358280131121731847397
38671094848682967923129363251880410088629431579471731381923423904722150579648146
65923667426951789233453780661857141076727621789156342707156593543269155609317301
39197229453001413384779468905931504832133955427742916491569430321597195434503417
66201251188613379285563302640150716105873546541629185059850915967062103838940188
44684634962080713733833989104978330173906731635030567230656891640293276795775287
82800785466433265275507793531647923818004849954660468196721737101204877378693511
08566345967213642036775180137145751405392894693747612745692086936761369597296700
44675502820221213640165642513390700649600811342192586815072964977935772560860808
44845800869092349381926331313312938267846577368111891970838782040012495869811104
82546393974340281014458444762583068853962025783137619509008551703858486934626138
97899351688012721042470133992613415994613584278286727420433632548349559578778498
51264071649415326605371802227858429833520867856482581433195758692932549520258824
60918562742928340692541256538514608253886696699256468748991908248636001310140220
07670137700839650528536388151654993782567192257449829483096148247351963051920020
37916082291628243209892105251237200128311052927715096516024623308764823757587130
28312735631055423387499617706321650613315759254819872316158039625578161933824020
86608190828273541683281771935102602781688802039147439096612795561149547853432908
30482200741576758812960195318453397843431608733618142748789844979736961977021019
74353225683818794277371380948820157107157529477325519781033779475993760601795062
27367143869387127193558418164277379829591326591183903269609926566775573801954253
35797915215123583635069364233667624294016754197799536833659865194197906368685293
01289144269337429082329659874750574115471576321062569787941229853527393529418283
28322366127467995005168580486175625750743545390364880413573372155108349654590783
40986217074342763959973399037871462533620108311829563526497064023442723872307430
21722988507908537625766150580702503110224492809713322727370100111627213058929692
21465971941383185915242997076301112087822392857549311867549594012816461281850679
44657672379439739494363843592623834538652010057382983245961398738472329771639691
00000000034244507533626934098613499300169757059255749630558108402945405953424635
79872245231280614927808083661198895776426874863506199150914809241898138567694149
27135364555505662331751429601708742946563296974615554429205734831227817289278174
87884757005024102559541707043690575996923407205579821797575196418932551633602134
28348088883972857490874971946664397998179738460575741943137440468963370677258727
12075555625643859043878113056598956210172976319085457120362429321837789643269588
90749140819760140571743546598231659714524851876965689491414005607105876203338094
92671425128088091680426146535505730489315704121789099285457034914232467966213685
68316970318724907180863656068605692606937528733919293045449903443050757480265184
58599632354715864767568843496476624659201446149422241519085723547529411871209350
27769514193771799273259309065922815475544288077093976319109085339153903794984337
50453762850887271965295065860127620185215785627776943937323404723358022150639489
90254464171937787846003980412934044281268207616370943805332901008722384113920029
81821637403230966826736489478273072275048257253371379063006311740837755618278890
62205973535787537918527860896238662972340292850155418700620407109768653309082468
79156424673888626224308608817210441640257409256753435432479889890193472667169180
30619543341722258704454944035104228712496948245246942337490910831628464255743985
03926853078883434116972427716517056624741768666503044593767475970012314097543408
22873529888896217209100187064333805546745069645234768429688563447552641361235035
68046340952775511168480627718593954966152824250436436448088302677006140757903688
59222336157320161485126452494165009557257498211422559620616149036514953835096823
61640027461081510004425304963479947605571472325692665173763576603388522761862541
88189836025583952495651907647345155248681513412510891831801976711213949467952857
21764271851572993609591883561651826582624016515128751023256715294203426720938917
51849246004964932504250093771104291546052911924530630503812732545122024017714790
23044193772136468964948805457336199327823304462555650506353830541418657142716731
01085607327058918755362173998681582656917047648552959202296312204231541151510853
22646636302285534570135231664774833812438826896544824002604078255866823477298543
77539584774597494263267742904272477087565267397623270408962991841567350696052727
36194533473813827363603129577487609755173673505399263132898616020245659437333748
69382323915267953947243148838200402663820795402387670613938334454150730643403144
01626202762484200809046046296781147657002267994656832741967700822096269623702361
95356568293317987905892599850443093034972813936485422278771066552826450747804978
25186025344776573611000295711421455361981686799070159623604161388843759975064177
17876588098042561598769709252288866463663885497653228060067594275672586980729698
16249102506086760546772644413476381726091141854748303510896740232548705391687515
58236948640277861530432232472529221247948449986386804005220994077497081252142789
70703955473845098707334601230337772385998073877862954064827932831856674590984181
13661331751572651963002960291457888647099615390203424518423060351698121799477619
02302463247795759541860835778530285726349114387111772713337059584062714938188613
88652942063372339934359972314934591112847587065277365985585020288735134798110832
46196497946077859193584627036411163977238969101327404001996549697571875229302898
28951516918733284169994302632435690339882045224217422904601116407327052459912538
73811340436046493868950241854331372870038297340706913806982602943376757195495823
57118794845402533534634000629903598331336110895349820433389517854355794138946487
87827908244690710523667757801479971551202841745304279220212123469997546336288818
07241303501863592234782328608460001510696226339822771774263906182426210316201646
06147584738992966917828903049727120113775234577311930177901825463874373870409327
06540016899184053836556923537692195054659076131075342366967688500966366307372359
64561531626356248638651473654932620808068621498763925761669485643629052322750209
09889435461818490993162162558326381259722951411378124395051848093131540128749856
80343277167465557145862900613169390365882813792688094023557716502502426877920609
42469513142186573011018263886961071628172954175866136992855638419199373909804102
29484925428697965994874224342395759816715732457352140971743096370841863327548403
69659401070487121700451194119973832330593134301844566286816038152184689194969767
42750294990087914008615773753082508827092303263955954417422969383596387967397570
97450523552700186435865923629128874206025727135690287457615383845146728270906709
62609690314530598386052144897892286344739853793579446476250839015285276656668916
52995542393693617945410770418025503093859087686374204370377222781631158478587453
52031810664419529491643174389948629608070293239660570583349910920026549245537249
30045609371176320920396582087388210883121982269338969394461953901146881240444564
73226388853353285596154846841135953917179272482587905714883111096347493743250133
17076989805537351400264339402271902291889585679964540885785090523704796178028485
75182725487948467858644190406800743353265876540473841541726138027479842402063881
42303712873885825620054073417439503820601344114692721545953209862722787535565795
73103062545427880085106586412129232357838284449878319924530745694049466266123414
56464292201610630972533089043360640248113140840246819185457032573866631957497917
76786209565765636028123406531012917252358129391251291419015631150136196674528498
88952860666772974976800066405880567171823544904475746421526012085919168418871236
10140536318318064259805982596191271876454368133154909862826942128230967793581680
04699257721806888313394392048089674773491063160843445068300668054905824756279428
43449725392292585520338657240036178862536693026432667489813829772297199352364125
43467935706490961631417226061196351123944065243357418217758182474240463119927637
46595592344825520877451997966292732244526279710910667186096851060182618516906582
04546691809588587779378113660063074161760474882055170316276570369942818317697349
06810071109732366428050276531116525710657293658070159010127262730257749693598759
78919673694237322547681770025494834978615437024877321011337702966596320577169675
21267220639331076619821026710416154106601354496590987653569250019551487115173426
02213497829021416815059456678503481935775551134901174722796972707461511415253234
04929448879573436232253745356544815570462295192271334749523009956490879507336354
65642980745462344665710602677530142850206630300262086703331051614127813983871221
24084512498427368122561696251681964669139496180670564352989282964801635254707749
95302009752952012822440061708476235448766435884168234703991388266740914721692999
98286843328904221509437308721470608792251837271330736548925564652996513568984094
76703051536904451954082157128747503265930835856111671544051685491072449086684885
35956086606663967123679881338137069036684963098682841741974506381167334322718640
91259363670166214859564294747140257474443471359502360210218428463927018950564434
56461564541473705489905830064156392883647792046407297543824577233391999224237476
07663764149684261203895326552885772148236206726296290904982262392935578281162378
37960966480588496211956565717519064414239865765911348243556795157228852875907509
04193968994826660354419395779522237320428801285297296650408890145232582748905436
05649424158931710164139225388564058099712403938194134993437741931277264768326093
51052581834006955518392938484236561750168511227695836514175920678455118076291781
26895419778791296946789754424222998240877133347125980631768068553049925555161336
11097260312564886735043232322239289442807403044417762628287885108847289085516352
14189062921823304003847650402452717418772808062412883054665183076104903410005596
28580886860349238674592462693627188225123531284664528672794881557901284191984382
42516206527166106005572723770155797282801137662592386533678011702895027912630615
12150335016781602354561507841175266897589882431374762568544381039814906906121734
03556711903641666808845712809867560570961909589616718834796667261236828988331652
55762455089919399828243772328550064571498405289693638198605171827347028979557388
39392530713269743765076606959463988271321223893359175113978200816653963834819848
71222217830773952316182037353615141595176710117802928615667467328003970175011860
41348749862883274221516033303982122326217485700544485881117171750773599650720417
98303238594146486449450963679979199662251523726947494978383716235213852992259548
2132074535536718685190028208030449249412006825435332608
Re[8]: k нулей
От: Seon  
Дата: 19.12.08 11:14
Оценка:
Здравствуйте, Seon, Вы писали:

S>Здравствуйте, Beam, Вы писали:


B>>Здравствуйте, Seon, Вы писали:


S>>>Моя прога посчитала а(8)


B>>Поздравляю


S>>>Мдя до 100000 это неделя, не меньше...


B>>Может попробовать готовые библиотеки использовать?

B>>Надо всего-то — работа с большими числами и поиск подстроки.
B>>Уверен, что такие библиотеки для си есть.

S>Та тут можно проще сделать... думаю хаскел так и работает...

S>берем сразу десятичное число в строковом виде и удваиваем его, и проверяем нули!
S>это будет на несколько порядков быстрее...


ДААААААА!!!!!!
а(9) — меньше 2х минут!!! в дэбаге !!!!
ща мы его....
Re[2]: k нулей
От: vadimcher  
Дата: 19.12.08 15:57
Оценка:
Здравствуйте, Seon, Вы писали:

S>Здравствуйте, vadimcher, Вы писали:


V>>Докажите, что для любого k найдется такое число n, что в [i]десятичной[i] записи числа 2^n, встречается k нулей подряд.


V>>Этюд для программиста.

V>>Обозначим минимальное такое n как a(k). Например, a(1)=10, т.к. 2^10=1024 -- минимальная степень двойки, содержащая один ноль (подряд? ). a(2)=53, т.к. 2^53=9007199254740992 -- минимальная степень двойки, содержащая два нуля подряд. Ну и т.д.
V>>Найти a(1),...,a(7).

S>Обратная задача


S>Найти все числа, степени двойки, для которых не будет повторяться 2х нулей подряд !!

S>Существует ли предел, степени, больше которой 2 нуля подряд не повторяются?

Не существует. Если мы докажем (теоретически), что a(k) есть для любого k, то последовательность таких чисел уходит в бесконечность.

А вот зайца кому, зайца-выбегайца?!
Re[2]: k нулей
От: vadimcher  
Дата: 19.12.08 15:57
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, vadimcher, Вы писали:


V>>Докажите, что для любого k найдется такое число n, что в [i]десятичной[i] записи числа 2^n, встречается k нулей подряд.


V>>Этюд для программиста.

V>>Обозначим минимальное такое n как a(k). Например, a(1)=10, т.к. 2^10=1024 -- минимальная степень двойки, содержащая один ноль (подряд? ). a(2)=53, т.к. 2^53=9007199254740992 -- минимальная степень двойки, содержащая два нуля подряд. Ну и т.д.
V>>Найти a(1),...,a(7).

А>Решение на Haskell.

А>
А>import Data.List
А>zeros n = head [p | p <- [1..], (replicate n '0') `isInfixOf` (show $ 2^p)]
А>


А>Ответ:


А>
А>*Main> zeros 1
А>10
А>*Main> zeros 2
А>53
А>*Main> zeros 3
А>242
А>*Main> zeros 4
А>377
А>*Main> zeros 5
А>1491
А>*Main> zeros 6
А>1492
А>*Main> zeros 7  -- 5 сек.
А>6801
А>*Main> zeros 8  -- 25 сек.
А>14007
А>


А>zeros 9 считает уже 7 минут

А>Не дождался — написал, то что есть

Волшебный чудо-язык haskell.

А вот зайца кому, зайца-выбегайца?!
Re[11]: k нулей
От: Seon  
Дата: 19.12.08 16:08
Оценка:
Здравствуйте, Seon, Вы писали:

S>>а(8) — до 2х секунд!

S>>а(9) — 80 секунд!

S>а(10) — 2^559940 — 24 минуты и 20 секунд


а(11) — 2^1148303 — 47 минут и 16 секунд
Re: k нулей
От: Pro100Oleh Украина  
Дата: 19.12.08 18:26
Оценка:
Считал на проце Q6600 на C# .Net 3.5 sp1. Программа однопоточная, но юзалось четыре проца где-то по 25% каждый.

a(1) = 10. Time 00:00:00.0038011, Length 4
a(2) = 53. Time 00:00:00.0000592, Length 16
a(3) = 242. Time 00:00:00.0006503, Length 73
a(4) = 377. Time 00:00:00.0008813, Length 114
a(5) = 1491. Time 00:00:00.0204129, Length 449
a(6) = 1492. Time 00:00:00.0000576, Length 450
a(7) = 6801. Time 00:00:00.4025472, Length 2048
a(8) = 14007. Time 00:00:00.1214338, Length 4217
a(9) = 100823. Time 00:00:08.0502971, Length 30351
a(10) = 559940. Time 00:03:16.3552767, Length 168559
a(11) = 1148303. Time 00:10:54.2630780, Length 345674

Pro
Re[3]: k нулей
От: Erop Россия  
Дата: 19.12.08 20:25
Оценка:
Здравствуйте, vadimcher, Вы писали:

А>>zeros 9 считает уже 7 минут

А>>Не дождался — написал, то что есть

V>Волшебный чудо-язык haskell.


#include "stdafx.h"
#include <vector>
#include <assert.h>
#include <iostream>

const int logPeriod = 100 * 1000;
const int tryTo = 2 * 1000 * 1000;


class PowerOf2VeryLongNumber {
    typedef std::vector<unsigned char> TDigits;
    TDigits digits;
public:
    PowerOf2VeryLongNumber() { digits.push_back( 1 ); }

    int Mult2AndRetMax0Count()
    {
        int zerCount = 0;
        int bestZerCount = 0;
        if( digits[digits.size() - 1] != 0 )
            digits.push_back( 0 );
        int carry = 0;
        for( TDigits::iterator i = digits.begin(); i != digits.end(); ++i ) {
            int res = (*i) * 2 + carry;
            if( res > 9 ) {
                assert( res < 20 );
                carry = 1;
                *i = ( res -= 10 );
            } else {
                *i = res;
                carry = 0;
            }
            if( res == 0 ) {
                ++zerCount;
            } else {
                if( zerCount > bestZerCount ) {
                    bestZerCount = zerCount;
                }
                zerCount = 0;
            }
        }
        assert( carry == 0 );
        return bestZerCount;
    }
    template<typename TStream>
    TStream& Output( TStream& dst ) const 
    {
        for( TDigits::const_reverse_iterator i = digits.rbegin(); i != digits.rend(); ++i ) {
            dst << (int)*i;
        }
        return dst;
    }

};

template<typename TStream>
TStream& operator << ( TStream& dst, const PowerOf2VeryLongNumber& x )
{
    return x.Output( dst );
}

struct Result {
    int PowerValue;
    PowerOf2VeryLongNumber x;
};

int _tmain(int argc, _TCHAR* argv[])
{
    PowerOf2VeryLongNumber x;
    std::vector<Result> result;
    Result tmp = { 0 };
    result.push_back( tmp );
    for( int i = 1; i < tryTo; i++ ) {
        int zCount = x.Mult2AndRetMax0Count();
        bool outputProgressLog = ( i % logPeriod ) == 0;
        while( result.size() <= zCount ) {
            Result r = { i, x };
            result.push_back( r );
            outputProgressLog = true;
        }
        if( outputProgressLog ) {
            std::cout << "2^" << i << " = " << zCount << ", " << result.size() - 1 << std::endl;
        }
    }
    std::cout << "--------------------------" << std::endl;
    for( int i = 1; i < result.size(); i++ ) {
        std::cout << "a(" << i << ") = 2^" << result[i].PowerValue /*<< " = " << result[i].x */<< std::endl;
    }

    return 0;
}

9 -- меньше минуты. Написал из головы, вроде сразу заработало...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: k нулей
От: Erop Россия  
Дата: 19.12.08 20:37
Оценка:
Здравствуйте, Erop, Вы писали:

E>9 -- меньше минуты. Написал из головы, вроде сразу заработало...

10 -- 14 минут ужо...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[5]: k нулей
От: Erop Россия  
Дата: 19.12.08 21:02
Оценка:
E>>9 -- меньше минуты. Написал из головы, вроде сразу заработало...
E>10 -- 14 минут ужо...

Прикольно, что вариант
#include "stdafx.h"
#include <vector>
#include <assert.h>
#include <iostream>

const int logPeriod = 100 * 1000;
const int tryTo = 20 * 1000 * 1000;

const unsigned char lowDigit[] = { 0, 2, 4, 6, 8, 0, 2, 4, 6, 8 };
const unsigned char hiDigit[] =  { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1 };


class PowerOf2VeryLongNumber {
    typedef std::vector<unsigned char> TDigits;
    TDigits digits;
public:
    PowerOf2VeryLongNumber() { digits.push_back( 1 ); }

    int Mult2AndRetMax0Count()
    {
        int zerCount = 0;
        int bestZerCount = 0;
        if( digits[digits.size() - 1] != 0 )
            digits.push_back( 0 );
        int carry = 0;
        for( TDigits::iterator i = digits.begin(); i != digits.end(); ++i ) {
            const unsigned char curDig = lowDigit[*i] + carry;
            carry = hiDigit[*i];
            *i = curDig;
            if( curDig == 0 ) {
                ++zerCount;
                if( zerCount > bestZerCount && (i+1)!=digits.end() ) {
                    bestZerCount = zerCount;
                }
            } else {
                zerCount = 0;
            }
        }
        assert( carry == 0 );
        return bestZerCount;
    }
    template<typename TStream>
    TStream& Output( TStream& dst ) const 
    {
        for( TDigits::const_reverse_iterator i = digits.rbegin(); i != digits.rend(); ++i ) {
            dst << (int)*i;
        }
        return dst;
    }

    int Length() const { return digits.size() - ( digits[digits.size() - 1] == 0 ); }

};

template<typename TStream>
TStream& operator << ( TStream& dst, const PowerOf2VeryLongNumber& x )
{
    return x.Output( dst );
}

struct Result {
    int PowerValue;
    PowerOf2VeryLongNumber x;
};

int _tmain(int argc, _TCHAR* argv[])
{
    PowerOf2VeryLongNumber x;
    std::vector<Result> result;
    Result tmp = { 0 };
    result.push_back( tmp );
    for( int i = 1; i < tryTo; i++ ) {
        int zCount = x.Mult2AndRetMax0Count();
        bool outputProgressLog = ( i % logPeriod ) == 0;
        while( result.size() <= zCount ) {
            Result r = { i, x };
            result.push_back( r );
            outputProgressLog = true;
        }
        if( outputProgressLog ) {
            std::cout << "2^" << i << " = " << zCount << ", " << result.size() - 1 
                << ", len = " << x.Length()/* << ", " << x */<< std::endl;
        }
    }
    std::cout << "--------------------------" << std::endl;
    for( int i = 1; i < result.size(); i++ ) {
        std::cout << "a(" << i << ") = 2^" << result[i].PowerValue << ", len = " << result[i].x.Length() 
            /*<< " = " << result[i].x */<< std::endl;
    }

    return 0;
}
Не сильно шибче.

а(10) посчитался на 11-й минуте...
Возможно можно ещё разогнать, если сразу парами цифп оперировать, или, даже, 4-ками...
Может попробую. Интересно же
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[7]: k нулей
От: Beam Россия  
Дата: 19.12.08 21:37
Оценка:
Здравствуйте, Beam, Вы писали:

Код на Java с учетом идей Seon'а

public class KZeros {

    void run(int K) {
        long time = -System.currentTimeMillis();

        // храним 2^n как массив цифр (в обратном порядке)
        int MAXLEN = 100*1000*1000;
        byte[] digits = new byte[MAXLEN];

        int n = 0;     // текущее n
        digits[0] = 1; // цифры числа 2^n, в начале 2^0 = 1
        int len = 1;   // количество цифр в 2^n

        boolean found = false;
        while (!found) {
            n++;
            if (n % 1000 == 0)
                System.out.println(String.format("cur n = %d", n));

            // вычисляем новое 2^(n+1) = 2^n+2^n и заодно подсчитываем нолики
            int countZeros = 0;     // найдено нулей подряд
            byte carryFlag = 0;     // перенос из предыдущего разряда
            for (int i = 0; i < len; i++) {
                byte val = (byte) (digits[i] + digits[i] + carryFlag);
                digits[i] = (byte) (val % 10);
                carryFlag = (byte) (val / 10);
                
                countZeros = digits[i] == 0 ? countZeros + 1 : 0;
                if (countZeros == K) {
                    found = true;
                    break;
                }
            }
            // если остался флаг переноса с самого старшего разряда
            if (!found && carryFlag == 1) {
                digits[len] = 1;
                len++;
                assert len <= MAXLEN;
            }
        }
        System.out.println(String.format("a(%d) = %d", K, n));
        time += System.currentTimeMillis();
        System.out.println(String.format("Time: %1$tM:%1$tS.%1$tL", time));
    }

    static public void main(String[] args) {
        new KZeros().run(10);
    }
}


а(9) 0,5 мин
a(10) 15,5 мин
на Core 2 duo 1.87 ГГц
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Best regards, Буравчик
Re[6]: k нулей
От: Erop Россия  
Дата: 20.12.08 09:38
Оценка:
E>>>9 -- меньше минуты. Написал из головы, вроде сразу заработало...
E>>10 -- 14 минут ужо...

E>а(10) посчитался на 11-й минуте...

E>Возможно можно ещё разогнать, если сразу парами цифп оперировать, или, даже, 4-ками...
E>Может попробую. Интересно же

2^4036338, 12, len = 1215059
2^4036339, 13, len = 1215060

за ночь нашёл, потом, похоже, закончился кэш
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[12]: k нулей
От: Seon  
Дата: 20.12.08 11:02
Оценка:
Вот мой вариант.

#include <iostream>
#include <fstream>
#include <time.h>
#include <math.h>

void udv(char* arr, int& current)
{
  char ost = 0;
  for(int n = 0; n < current; ++n)
  {
    char res = arr[n] << 1;
    if (ost) res++;
    if (res > 9)
    {
      arr[n] = res - 10;
      ost = 1;
    }
    else
    {
      arr[n] = res;
      ost = 0;
    }
  }
  if (ost)
    arr[current++] = ost;
}

void write(char* arr, int size, int zeros, int current)
{
  char name[128];
  sprintf(name, "a(%d)=[2^%d].dig", zeros, current);
  std::fstream f;
  f.open(name, std::ios_base::out);
  if (f.is_open())
  {
    for (int m = size; m > 0; --m)
      f << int(arr[m - 1]);
  }
}

void test(char* arr, int& zeros, int size, int current)
{
  int z = zeros;
  for(int n = 0; n < size; ++n)
    if(arr[n])
      z = zeros;
    else
    {
      z--;
      if (z == 0)
      {
        std::cout << "\n\n\n=====================================================\na(" 
          << zeros << ") [2^" << current << "]\n";
        time_t t = time(0);
        int seconds = int(t);
        int day  = seconds / (3600 * 24);
        seconds = seconds - day * 3600 * 24;
        int hour = seconds / 3600;
        seconds = seconds - hour * 3600;
        int minutes = seconds / 60;
        seconds = seconds - minutes * 60;
        write(arr, size, zeros, current);
        std::cout << "\n" << "Time: " << day << ":" << hour << ":" << minutes << ":" 
          << seconds << "\n-----------------------------------------------------\n\n";  
        zeros++;
        return;
      }
    }
}

void save(const char* name, const char* arr, int size, int zeros, int current)
{
  std::fstream f;
  f.open(name, std::ios_base::out);
  if (f.is_open())
  {
    f.write((char*)&zeros, sizeof(int));
    f.write((char*)&size, sizeof(int));
    f.write((char*)&current, sizeof(int));
    //std::cout << "zeros=" << zeros << ", bits=" << current << ", digits=" << size << " saving... ";
    f.write(arr, size);
    //std::cout << "done.\n";
    //std::cout << "saved " << size << " - " << current << "\n";
  }
}

void load(const char* name, char* arr, int& size, int& zeros, int& current)
{
  std::fstream f;
  f.open(name, std::ios_base::in);
  if (f.is_open())
  {
    f.read((char*)&zeros, sizeof(int));
    f.read((char*)&size, sizeof(int));
    f.read((char*)&current, sizeof(int));
    std::cout << "zeros=" << zeros << ", bits=" << current << ", digits=" << size << " loading... ";
    f.read(arr, size);
    std::cout << "done.\n\n";
  }
}

int main(int argc, char* argv[])
{
  char* arr = new char[1000000000];
  arr[0] = 2;
  int size = 1;
  int zeros = 1;
  int current = 1;

  if (argc == 2)
    load(argv[1], arr, size, zeros, current);

  int to_save = 100000 / (1 + int(sqrt(sqrt(float(current)))));
  if (to_save == 0) to_save = 1;

  for(; current < 3000000000; current++)
  {
    std::cout << size << " - " << current << "\r";
    test(arr, zeros, size, current);
    udv(arr, size);
  
    to_save--;
    if (to_save == 0)
    {
      save("findbindeczero.dec", arr, size, zeros, current);
      to_save = 100000 / (1 + int(sqrt(sqrt(float(current)))));
      if (to_save == 0) to_save = 1;
      //std::cout << "next save after " << to_save << " (" << (current + to_save) << ")\n\n";
    }
  }
  delete arr;
  return 0;
}
Re[3]: k нулей
От: Seon  
Дата: 20.12.08 12:34
Оценка:
Здравствуйте, vadimcher, Вы писали:

V>Здравствуйте, Seon, Вы писали:


S>>Здравствуйте, vadimcher, Вы писали:


V>>>Докажите, что для любого k найдется такое число n, что в [i]десятичной[i] записи числа 2^n, встречается k нулей подряд.


V>>>Этюд для программиста.

V>>>Обозначим минимальное такое n как a(k). Например, a(1)=10, т.к. 2^10=1024 -- минимальная степень двойки, содержащая один ноль (подряд? ). a(2)=53, т.к. 2^53=9007199254740992 -- минимальная степень двойки, содержащая два нуля подряд. Ну и т.д.
V>>>Найти a(1),...,a(7).

S>>Обратная задача


S>>Найти все числа, степени двойки, для которых не будет повторяться 2х нулей подряд !!

S>>Существует ли предел, степени, больше которой 2 нуля подряд не повторяются?

V>Не существует. Если мы докажем (теоретически), что a(k) есть для любого k, то последовательность таких чисел уходит в бесконечность.


Почему?
Чем длинее числа, тем вероятность того что встретится два нуля подрад — увеличивается, следовательно когда то наступит момент что эта вероятность будет равна 1
Re[3]: k нулей
От: Seon  
Дата: 20.12.08 13:30
Оценка:
Здравствуйте, vadimcher, Вы писали:

V>Здравствуйте, Seon, Вы писали:


S>>Здравствуйте, vadimcher, Вы писали:


V>>>Докажите, что для любого k найдется такое число n, что в [i]десятичной[i] записи числа 2^n, встречается k нулей подряд.


V>>>Этюд для программиста.

V>>>Обозначим минимальное такое n как a(k). Например, a(1)=10, т.к. 2^10=1024 -- минимальная степень двойки, содержащая один ноль (подряд? ). a(2)=53, т.к. 2^53=9007199254740992 -- минимальная степень двойки, содержащая два нуля подряд. Ну и т.д.
V>>>Найти a(1),...,a(7).

S>>Обратная задача


S>>Найти все числа, степени двойки, для которых не будет повторяться 2х нулей подряд !!

S>>Существует ли предел, степени, больше которой 2 нуля подряд не повторяются?

V>Не существует. Если мы докажем (теоретически), что a(k) есть для любого k, то последовательность таких чисел уходит в бесконечность.



Последнее число, в котором нет двух нулей подряд — 2^2114 !
Re[7]: a(9) за пять минут
От: Erop Россия  
Дата: 20.12.08 13:32
Оценка:
Здравствуйте, Erop, Вы писали:

E>>>>9 -- меньше минуты. Написал из головы, вроде сразу заработало...

E>>>10 -- 14 минут ужо...

E>>а(10) посчитался на 11-й минуте...

E>>Возможно можно ещё разогнать, если сразу парами цифп оперировать, или, даже, 4-ками...
E>>Может попробую. Интересно же

Над парами цифр:
#include "stdafx.h"
#include <vector>
#include <assert.h>
#include <iostream>
#include <iomanip>

const int logPeriod = 10 * 1000;
const int tryTo = 20 * 1000 * 1000;
const int digitsCount = 2;
const int maxDigitsVal = 99;

typedef signed char small;

small left_z_count[maxDigitsVal + 1] = { -100 };
small right_z_count[maxDigitsVal + 2] = { -100 };

static void expand10times( small* buffer, int count )
{
    const small* src = buffer + 1;
    small* dst = buffer + 1 + count;
    for( int i = count * 9; i > 0; --i )
        *dst++ = *src++;
    ++*--dst;
}
static void fillLeft( small* dst, int start, small init_to )
{
    small* from = dst + start;
    small* to = dst + start * 10;
    while( from != to )
        *from++ = init_to;
}

static void initPartOfStaticTable( int& factor, int& left0cnt )
{
    expand10times( right_z_count, factor );
    fillLeft( left_z_count, factor, left0cnt );
    left0cnt--;
    factor *= 10;
}

static void initTables()
{
    int factor = 1;
    int leftDigCount = digitsCount - 1;
    initPartOfStaticTable( factor, leftDigCount );
    initPartOfStaticTable( factor, leftDigCount );
}


class PowerOf2VeryLongNumber {
    typedef small TDigit;
    typedef std::vector<TDigit> TDigits;
    TDigits digits;
public:
    PowerOf2VeryLongNumber() { digits.push_back( 1 ); }

    int Mult2AndRetMax0Count()
    {
        int z_count = 0;
        int best_z_count = 0;
        int carry = 0;
        for( TDigits::iterator i = digits.begin(); i != digits.end(); ++i ) {
            int newVal = *i*2+carry;
            if( newVal > maxDigitsVal ) {
                newVal -= maxDigitsVal + 1;
                carry = 1;
            } else {
                carry = 0;
            }
            *i = newVal;
            if( newVal == 0 ) {
                z_count += digitsCount;
            } else {
                z_count += right_z_count[newVal];
                if( z_count > best_z_count ) {
                    best_z_count = z_count;
                }
                z_count = left_z_count[newVal];        
            }
        }
        if( carry != 0 ) {
            digits.push_back( carry );
            if( z_count > best_z_count ) {
                best_z_count = z_count;
            }
        }
        return best_z_count;
    }
    template<typename TStream>
    TStream& Output( TStream& dst ) const 
    {
        for( TDigits::const_reverse_iterator i = digits.rbegin(); i != digits.rend(); ++i ) {
            dst << std::setw( digitsCount ) << (int)*i;
        }
        return dst;
    }

    int Length() const { return digits.size() - ( digits[digits.size() - 1] == 0 ); }

};

template<typename TStream>
TStream& operator << ( TStream& dst, const PowerOf2VeryLongNumber& x )
{
    return x.Output( dst );
}

struct Result {
    int PowerValue;
    PowerOf2VeryLongNumber x;
};

int _tmain(int argc, _TCHAR* argv[])
{
    initTables();
    
    PowerOf2VeryLongNumber x;
    std::vector<Result> result;
    Result tmp = { 0 };
    result.push_back( tmp );
    for( int i = 1; i < tryTo; i++ ) {
        int zCount = x.Mult2AndRetMax0Count();
        if( ( i % logPeriod ) == 0 ) {
            std::cout << "2^" << i << " = " << zCount << ", " << result.size() - 1 
                << ", len = " << x.Length() << "    \r";
        }
        while( result.size() <= zCount ) {
            Result r = { i, x };
            result.push_back( r );
            std::cout << "2^" << i << " = " << zCount << ", " << result.size() - 1 
                << ", len = " << x.Length() /*<< ", " << x*/ << std::endl;
        }
    }
    std::cout << "--------------------------" << std::endl;
    for( int i = 1; i < result.size(); i++ ) {
        std::cout << "a(" << i << ") = 2^" << result[i].PowerValue << ", len = " << result[i].x.Length() 
            /*<< " = " << result[i].x */<< std::endl;
    }

    return 0;
}


a(9) за пять минут
Core(TM)2 Duo, 2.66 GHz, однопоточная программа.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: k нулей
От: Erop Россия  
Дата: 20.12.08 13:33
Оценка:
Здравствуйте, Seon, Вы писали:

S>Последнее число, в котором нет двух нулей подряд — 2^2114 !

Два вопроса.
1) Какие есть ваши доказательства?
2) "2114!" -- это факториал?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[8]: И снова об STL
От: Roman Odaisky Украина  
Дата: 20.12.08 13:50
Оценка:
Ты настолько не любишь STL?

E>
E>static void expand10times( small* buffer, int count )
E>{
E>    const small* src = buffer + 1;
E>    small* dst = buffer + 1 + count;
E>    for( int i = count * 9; i > 0; --i )
E>        *dst++ = *src++;
E>    ++*--dst;

std::copy(buffer + 1, buffer + 1 + count * 9, buffer + 1 + count);
++buffer[10 * count];

E>}
E>static void fillLeft( small* dst, int start, small init_to )
E>{
E>    small* from = dst + start;
E>    small* to = dst + start * 10;
E>    while( from != to )
E>        *from++ = init_to;
E>}

std::fill(dst + start, dst + start * 10, init_to);


E>a(9) за пять минут


Мой результат похуже, выкладывать не стану. Я решил использовать 10¹⁶-ричную систему счисления, но из того ничего дельного не вышло.
До последнего не верил в пирамиду Лебедева.
Re[4]: k нулей
От: vadimcher  
Дата: 20.12.08 14:05
Оценка:
Здравствуйте, Seon, Вы писали:

S>Здравствуйте, vadimcher, Вы писали:


V>>Здравствуйте, Seon, Вы писали:


S>>>Здравствуйте, vadimcher, Вы писали:


V>>>>Докажите, что для любого k найдется такое число n, что в [i]десятичной[i] записи числа 2^n, встречается k нулей подряд.


V>>>>Этюд для программиста.

V>>>>Обозначим минимальное такое n как a(k). Например, a(1)=10, т.к. 2^10=1024 -- минимальная степень двойки, содержащая один ноль (подряд? ). a(2)=53, т.к. 2^53=9007199254740992 -- минимальная степень двойки, содержащая два нуля подряд. Ну и т.д.
V>>>>Найти a(1),...,a(7).

S>>>Обратная задача


S>>>Найти все числа, степени двойки, для которых не будет повторяться 2х нулей подряд !!

S>>>Существует ли предел, степени, больше которой 2 нуля подряд не повторяются?

V>>Не существует. Если мы докажем (теоретически), что a(k) есть для любого k, то последовательность таких чисел уходит в бесконечность.


S>Почему?

S>Чем длинее числа, тем вероятность того что встретится два нуля подрад — увеличивается, следовательно когда то наступит момент что эта вероятность будет равна 1

Я твой второй вопрос не так понял.

А вот зайца кому, зайца-выбегайца?!
Re[9]: И снова об STL
От: Erop Россия  
Дата: 20.12.08 18:53
Оценка:
Здравствуйте, Roman Odaisky, Вы писали:

RO>Ты настолько не любишь STL?

Даже ещё больлше, в отличии от функций memcpy и memset

Просто сначала этот код на другой библиотеке был. Потом я её отковырял...

RO>std::copy(buffer + 1, buffer + 1 + count * 9, buffer + 1 + count);

RO>++buffer[10 * count];

А разве так можно?


E>>a(9) за пять минут


RO>Мой результат похуже, выкладывать не стану. Я решил использовать 10¹⁶-ричную систему счисления, но из того ничего дельного не вышло.

Зато он, наверное, на хорошем STL
Выкладывай, не стесняйся.
Я сейчас опубликую более вменяемый вариант...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: С++ версии...
От: Erop Россия  
Дата: 20.12.08 19:15
Оценка:
E>9 -- меньше минуты. Написал из головы, вроде сразу заработало...

Вот, теперь попробовал несколько вариантов. Как и следовало ожидать самый быстрый работает 4-ками цифр.
Пробовал на Core(TM) Duo CPU T2450 2,00 GHz, да ещё и под вистой

Итого:
Вариант с цифрой на байт:

0:00:01 : 2^10 = 1, 1, len = 4
0:00:01 : 2^53 = 2, 2, len = 16
0:00:01 : 2^242 = 3, 3, len = 73
0:00:01 : 2^377 = 4, 4, len = 114
0:00:01 : 2^1491 = 5, 5, len = 449
0:00:01 : 2^1492 = 6, 6, len = 450
0:00:01 : 2^6801 = 7, 7, len = 2048
0:00:01 : 2^14007 = 8, 8, len = 4217
0:00:32 : 2^100823 = 9, 9, len = 30351

#include "stdafx.h"
#include <vector>
#include <assert.h>
#include <iostream>
#include <string>
#include <ctime>

const int logPeriod = 10 * 1000;
const int tryTo = 20 * 1000 * 1000;
    
const int digits_count = 4;
const int max_dig_value = 9999;

typedef signed char small_num;

int my_max( int i1, int i2 ) { return i1 > i2 ? i1 : i2; }

static int seconds_since_prog_start() { return ( clock() + CLOCKS_PER_SEC - 1 ) / CLOCKS_PER_SEC; }
static std::string time_report( int seconds = seconds_since_prog_start() )
{
    char buffer[1024];
    assert( seconds >= 0 );
    sprintf_s( buffer, "%d:%2.2d:%2.2d", ( seconds / 60 ) / 60, ( seconds / 60 ) % 60, seconds %60 );
    return buffer;
}

class CDigitsParser {
public:
    CDigitsParser( int num_, int max_dig_count = digits_count ) : 
                num( num_ ), dig_count( -1 ), left_count( max_dig_count ) 
    {
        assert( max_dig_count > 0 && num != 0 );
        shift_one_dig();
        assert( !is_processed() );
        
        right_count = shift_right_z();
        max_in_count = 0;
        shift_right_nz();
        while( num != 0 ) {
            const int in_count = shift_right_z();
            max_in_count = my_max( max_in_count, in_count );
            shift_right_nz();
        }
        assert( dig_count > 0 && dig_count <= left_count );
        left_count -= dig_count;
        assert( is_processed() );
    }
    int GetLeftCount() const { assert( is_processed()); return left_count; }
    int GetInCount() const { assert( is_processed()); return max_in_count; }
    int GetRightCount() const { assert( is_processed()); return right_count; }
    
private:
    enum { base = 10 };
    
    int num;
    int dig;
    int dig_count;
    int left_count;
    int max_in_count;
    int right_count;

    bool is_processed() const { return num == 0 && dig == 0; }
    void shift_one_dig()    
    {
        dig = num % base;
        num /= base;
        dig_count++;
    }
    int shift_right_z()
    {
        assert( !is_processed() );
        int count = 0;
        while( dig == 0 ) {
            shift_one_dig();
            count++;
        }
        return count;
    }
    
    int shift_right_nz()
    {
        int count = 0;
        while( dig != 0 ) {
            shift_one_dig();
            count++;
        }
        return count;
    }
};    //    CDigitsParser


small_num left_z_count[max_dig_value + 1] = { -100 };
small_num in_z_count[max_dig_value + 1] = { -100 };
small_num right_z_count[max_dig_value + 1] = { -100 };

void init_tables()
{
    for( int i = 1; i <= max_dig_value; ++i ) {
        CDigitsParser p( i );
        left_z_count[i] = p.GetLeftCount();
        in_z_count[i] = p.GetInCount();
        right_z_count[i] = p.GetRightCount();
    }
}


const unsigned char lowDigit[] = { 0, 2, 4, 6, 8, 0, 2, 4, 6, 8 };
const unsigned char hiDigit[] =  { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1 };


class PowerOf2VeryLongNumber {
    typedef std::vector<unsigned char> TDigits;
    TDigits digits;
public:
    PowerOf2VeryLongNumber() { digits.push_back( 1 ); }

    int Mult2AndRetMax0Count()
    {
        int zerCount = 0;
        int bestZerCount = 0;
        if( digits[digits.size() - 1] != 0 )
            digits.push_back( 0 );
        int carry = 0;
        for( TDigits::iterator i = digits.begin(); i != digits.end(); ++i ) {
            const unsigned char curDig = lowDigit[*i] + carry;
            carry = hiDigit[*i];
            *i = curDig;
            if( curDig == 0 ) {
                ++zerCount;
                if( zerCount > bestZerCount && (i+1)!=digits.end() ) {
                    bestZerCount = zerCount;
                }
            } else {
                zerCount = 0;
            }
        }
        assert( carry == 0 );
        return bestZerCount;
    }
    template<typename TStream>
    TStream& Output( TStream& dst ) const 
    {
        for( TDigits::const_reverse_iterator i = digits.rbegin(); i != digits.rend(); ++i ) {
            dst << (int)*i;
        }
        return dst;
    }

    int Length() const { return digits.size() - ( digits[digits.size() - 1] == 0 ); }

};

template<typename TStream>
TStream& operator << ( TStream& dst, const PowerOf2VeryLongNumber& x )
{
    return x.Output( dst );
}

struct Result {
    int PowerValue;
    PowerOf2VeryLongNumber x;
};

int _tmain(int argc, _TCHAR* argv[])
{
    //init_tables();    
    ///std::cout << time_report() << std::endl;    
    PowerOf2VeryLongNumber x;
    std::vector<Result> result;
    Result tmp = { 0 };
    result.push_back( tmp );
    for( int i = 1; i < tryTo; i++ ) {
        int zCount = x.Mult2AndRetMax0Count();
        if( ( i % logPeriod ) == 0 ) {
            std::cout << time_report() << " : 2^" << i << " = " << zCount << ", " << result.size() - 1 
                << ", len = " << x.Length()/* << ", " << x */<< " <-\r";
        }
        
        while( result.size() <= zCount ) {
            Result r = { i, x };
            result.push_back( r );
            std::cout << time_report() << " : 2^" << i << " = " << zCount << ", " << result.size() - 1 
                << ", len = " << x.Length()/* << ", " << x */<< "   " << std::endl;
        }
    }
    std::cout << "--------------------------" << std::endl;
    for( int i = 1; i < result.size(); i++ ) {
        std::cout << "a(" << i << ") = 2^" << result[i].PowerValue << ", len = " << result[i].x.Length() 
            /*<< " = " << result[i].x */<< std::endl;
    }

    return 0;
}


Вариант с двумя цифрами на байт:

0:00:01 : 2^10 = 1, 1, len = 4
0:00:01 : 2^53 = 2, 2, len = 16
0:00:01 : 2^242 = 3, 3, len = 73
0:00:01 : 2^377 = 4, 4, len = 114
0:00:01 : 2^1491 = 5, 5, len = 449
0:00:01 : 2^1492 = 6, 6, len = 450
0:00:01 : 2^6801 = 7, 7, len = 2048
0:00:01 : 2^14007 = 8, 8, len = 4217
0:00:18 : 2^100823 = 9, 9, len = 30351

#include "stdafx.h"
#include <vector>
#include <assert.h>
#include <iostream>
#include <string>
#include <ctime>
#include <iomanip>

const int logPeriod = 10 * 1000;
const int tryTo = 20 * 1000 * 1000;
    
typedef signed char small_num;

const int digits_count = 2;
const int max_dig_value = 99;
typedef small_num TAllDigitsNum; 


void set_if_g( int& dst, int src )
{
    if( dst < src )
        dst = src;
}

static int seconds_since_prog_start() { return ( clock() + CLOCKS_PER_SEC - 1 ) / CLOCKS_PER_SEC; }
static std::string time_report( int seconds = seconds_since_prog_start() )
{
    char buffer[1024];
    assert( seconds >= 0 );
    sprintf_s( buffer, "%d:%2.2d:%2.2d", ( seconds / 60 ) / 60, ( seconds / 60 ) % 60, seconds %60 );
    return buffer;
}

class CDigitsParser {
public:
    CDigitsParser( int num_, int max_dig_count = digits_count ) : 
                num( num_ ), dig_count( -1 ), left_count( max_dig_count ) 
    {
        assert( max_dig_count > 0 && num != 0 );
        shift_one_dig();
        assert( !is_processed() );
        
        right_count = shift_right_z();
        max_in_count = 0;
        shift_right_nz();
        while( num != 0 ) {
            const int in_count = shift_right_z();
            set_if_g( max_in_count, in_count );
            shift_right_nz();
        }
        assert( dig_count > 0 && dig_count <= left_count );
        left_count -= dig_count;
        assert( is_processed() );
    }
    int GetLeftCount() const { assert( is_processed()); return left_count; }
    int GetInCount() const { assert( is_processed()); return max_in_count; }
    int GetRightCount() const { assert( is_processed()); return right_count; }
    
private:
    enum { base = 10 };
    
    int num;
    int dig;
    int dig_count;
    int left_count;
    int max_in_count;
    int right_count;

    bool is_processed() const { return num == 0 && dig == 0; }
    void shift_one_dig()    
    {
        dig = num % base;
        num /= base;
        dig_count++;
    }
    int shift_right_z()
    {
        assert( !is_processed() );
        int count = 0;
        while( dig == 0 ) {
            shift_one_dig();
            count++;
        }
        return count;
    }
    
    int shift_right_nz()
    {
        int count = 0;
        while( dig != 0 ) {
            shift_one_dig();
            count++;
        }
        return count;
    }
};    //    CDigitsParser


small_num left_z_count[max_dig_value + 1] = { -100 };
small_num in_z_count[max_dig_value + 1] = { -100 };
small_num right_z_count[max_dig_value + 1] = { -100 };

void init_tables()
{
    for( int i = 1; i <= max_dig_value; ++i ) {
        CDigitsParser p( i );
        left_z_count[i] = p.GetLeftCount();
        in_z_count[i] = p.GetInCount();
        right_z_count[i] = p.GetRightCount();
    }
}


class PowerOf2VeryLongNumber {
    typedef TAllDigitsNum TDig;        
    typedef std::vector<TDig> TDigits;
    TDigits digits;
public:
    PowerOf2VeryLongNumber() { digits.push_back( 1 ); }

    int Mult2AndRetMax0Count()
    {
        int cur_z_count = 0;
        int best_z_count = 0;
        int carry = 0;
        for( TDigits::iterator i = digits.begin(); i != digits.end(); ++i ) {
            int dig = *i*2 + carry;
            if( dig > max_dig_value ) {
                carry = 1;
                dig -= max_dig_value + 1;
            } else {
                carry = 0;
            }
            *i = dig;
            if( dig == 0 ) {
                cur_z_count += digits_count;
            } else {
                set_if_g( best_z_count, cur_z_count + right_z_count[dig] );
                //set_if_g( best_z_count, in_z_count[dig] );    //    для больших чисел не важно...
                cur_z_count = left_z_count[dig];
            }
        }
        if( carry != 0 ) {
            digits.push_back( carry );
        }
        return best_z_count;
    }
    
    template<typename TStream>
    TStream& Output( TStream& dst ) const 
    {
        TDigits::const_reverse_iterator i = digits.rbegin();    
        dst << (int)*i;
        for( ++i; i != digits.rend(); ++i ) {
            dst << std::setw( digits_count ) << std::setfill( '0' ) << (int)*i;
        }
        return dst;
    }

    int Length() const 
    { 
        assert( digits[digits.size() - 1] != 0 );
        return digits.size() * digits_count - left_z_count[digits[digits.size() - 1]]; 
    }

};

template<typename TStream>
TStream& operator << ( TStream& dst, const PowerOf2VeryLongNumber& x )
{
    return x.Output( dst );
}

struct Result {
    int PowerValue;
    PowerOf2VeryLongNumber x;
};

int _tmain(int argc, _TCHAR* argv[])
{
    init_tables();    

    PowerOf2VeryLongNumber x;
    std::vector<Result> result;
    Result tmp = { 0 };
    result.push_back( tmp );
    for( int i = 1; i < tryTo; i++ ) {
        int zCount = x.Mult2AndRetMax0Count();
        if( ( i % logPeriod ) == 0 ) {
            std::cout << time_report() << " : 2^" << i << " = " << zCount << ", " << result.size() - 1 
                << ", len = " << x.Length()/* << ", " << x */<< " <-\r";
        }
        
        while( result.size() <= zCount ) {
            Result r = { i, x };
            result.push_back( r );
            std::cout << time_report() << " : 2^" << i << " = " << zCount << ", " << result.size() - 1 
                << ", len = " << x.Length()/** << ", " << x **/<< "   " << std::endl;
        }
    }
    std::cout << "--------------------------" << std::endl;
    for( int i = 1; i < result.size(); i++ ) {
        std::cout << "a(" << i << ") = 2^" << result[i].PowerValue << ", len = " << result[i].x.Length() 
            /*<< " = " << result[i].x */<< std::endl;
    }

    return 0;
}


Вариант с четырьмя цифрами на short:

0:00:01 : 2^10 = 1, 1, len = 4
0:00:01 : 2^53 = 2, 2, len = 16
0:00:01 : 2^242 = 3, 3, len = 73
0:00:01 : 2^377 = 4, 4, len = 114
0:00:01 : 2^1491 = 5, 5, len = 449
0:00:01 : 2^1492 = 6, 6, len = 450
0:00:01 : 2^6801 = 7, 7, len = 2048
0:00:01 : 2^14007 = 8, 8, len = 4217
0:00:10 : 2^100823 = 9, 9, len = 30351

#include "stdafx.h"
#include <vector>
#include <assert.h>
#include <iostream>
#include <string>
#include <ctime>
#include <iomanip>

const int logPeriod = 10 * 1000;
const int tryTo = 20 * 1000 * 1000;
    
typedef signed char small_num;

const int digits_count = 4;
const int max_dig_value = 9999;
typedef short TAllDigitsNum; 


void set_if_g( int& dst, int src )
{
    if( dst < src )
        dst = src;
}

static int seconds_since_prog_start() { return ( clock() + CLOCKS_PER_SEC - 1 ) / CLOCKS_PER_SEC; }
static std::string time_report( int seconds = seconds_since_prog_start() )
{
    char buffer[1024];
    assert( seconds >= 0 );
    sprintf_s( buffer, "%d:%2.2d:%2.2d", ( seconds / 60 ) / 60, ( seconds / 60 ) % 60, seconds %60 );
    return buffer;
}

class CDigitsParser {
public:
    CDigitsParser( int num_, int max_dig_count = digits_count ) : 
                num( num_ ), dig_count( -1 ), left_count( max_dig_count ) 
    {
        assert( max_dig_count > 0 && num != 0 );
        shift_one_dig();
        assert( !is_processed() );
        
        right_count = shift_right_z();
        max_in_count = 0;
        shift_right_nz();
        while( num != 0 ) {
            const int in_count = shift_right_z();
            set_if_g( max_in_count, in_count );
            shift_right_nz();
        }
        assert( dig_count > 0 && dig_count <= left_count );
        left_count -= dig_count;
        assert( is_processed() );
    }
    int GetLeftCount() const { assert( is_processed()); return left_count; }
    int GetInCount() const { assert( is_processed()); return max_in_count; }
    int GetRightCount() const { assert( is_processed()); return right_count; }
    
private:
    enum { base = 10 };
    
    int num;
    int dig;
    int dig_count;
    int left_count;
    int max_in_count;
    int right_count;

    bool is_processed() const { return num == 0 && dig == 0; }
    void shift_one_dig()    
    {
        dig = num % base;
        num /= base;
        dig_count++;
    }
    int shift_right_z()
    {
        assert( !is_processed() );
        int count = 0;
        while( dig == 0 ) {
            shift_one_dig();
            count++;
        }
        return count;
    }
    
    int shift_right_nz()
    {
        int count = 0;
        while( dig != 0 ) {
            shift_one_dig();
            count++;
        }
        return count;
    }
};    //    CDigitsParser


small_num left_z_count[max_dig_value + 1] = { -100 };
small_num in_z_count[max_dig_value + 1] = { -100 };
small_num right_z_count[max_dig_value + 1] = { -100 };

void init_tables()
{
    for( int i = 1; i <= max_dig_value; ++i ) {
        CDigitsParser p( i );
        left_z_count[i] = p.GetLeftCount();
        in_z_count[i] = p.GetInCount();
        right_z_count[i] = p.GetRightCount();
    }
}


class PowerOf2VeryLongNumber {
    typedef TAllDigitsNum TDig;        
    typedef std::vector<TDig> TDigits;
    TDigits digits;
public:
    PowerOf2VeryLongNumber() { digits.push_back( 1 ); }

    int Mult2AndRetMax0Count()
    {
        int cur_z_count = 0;
        int best_z_count = 0;
        int carry = 0;
        for( TDigits::iterator i = digits.begin(); i != digits.end(); ++i ) {
            int dig = *i*2 + carry;
            if( dig > max_dig_value ) {
                carry = 1;
                dig -= max_dig_value + 1;
            } else {
                carry = 0;
            }
            *i = dig;
            if( dig == 0 ) {
                cur_z_count += digits_count;
            } else {
                set_if_g( best_z_count, cur_z_count + right_z_count[dig] );
                set_if_g( best_z_count, in_z_count[dig] );    //    для больших чисел не важно...
                cur_z_count = left_z_count[dig];
            }
        }
        if( carry != 0 ) {
            digits.push_back( carry );
        }
        return best_z_count;
    }
    
    template<typename TStream>
    TStream& Output( TStream& dst ) const 
    {
        TDigits::const_reverse_iterator i = digits.rbegin();    
        dst << (int)*i;
        for( ++i; i != digits.rend(); ++i ) {
            dst << std::setw( digits_count ) << std::setfill( '0' ) << (int)*i;
        }
        return dst;
    }

    int Length() const 
    { 
        assert( digits[digits.size() - 1] != 0 );
        return digits.size() * digits_count - left_z_count[digits[digits.size() - 1]]; 
    }

};

template<typename TStream>
TStream& operator << ( TStream& dst, const PowerOf2VeryLongNumber& x )
{
    return x.Output( dst );
}

struct Result {
    int PowerValue;
    PowerOf2VeryLongNumber x;
};

int _tmain(int argc, _TCHAR* argv[])
{
    init_tables();    

    PowerOf2VeryLongNumber x;
    std::vector<Result> result;
    Result tmp = { 0 };
    result.push_back( tmp );
    for( int i = 1; i < tryTo; i++ ) {
        int zCount = x.Mult2AndRetMax0Count();
        if( ( i % logPeriod ) == 0 ) {
            std::cout << time_report() << " : 2^" << i << " = " << zCount << ", " << result.size() - 1 
                << ", len = " << x.Length()/* << ", " << x */<< " <-\r";
        }
        
        while( result.size() <= zCount ) {
            Result r = { i, x };
            result.push_back( r );
            std::cout << time_report() << " : 2^" << i << " = " << zCount << ", " << result.size() - 1 
                << ", len = " << x.Length()/** << ", " << x **/<< "   " << std::endl;
        }
    }
    std::cout << "--------------------------" << std::endl;
    for( int i = 1; i < result.size(); i++ ) {
        std::cout << "a(" << i << ") = 2^" << result[i].PowerValue << ", len = " << result[i].x.Length() 
            /*<< " = " << result[i].x */<< std::endl;
    }

    return 0;
}


Вариант с четырьмя цифрами на short, и без проверок цепочек нулей, не выходящих на границы цепочек (очевидно, что для k > 2 это не важно)

0:00:01 : 2^242 = 3, 3, len = 73
0:00:01 : 2^377 = 4, 4, len = 114
0:00:01 : 2^1491 = 5, 5, len = 449
0:00:01 : 2^1492 = 6, 6, len = 450
0:00:01 : 2^6801 = 7, 7, len = 2048
0:00:01 : 2^14007 = 8, 8, len = 4217
0:00:09 : 2^100823 = 9, 9, len = 30351

#include "stdafx.h"
#include <vector>
#include <assert.h>
#include <iostream>
#include <string>
#include <ctime>
#include <iomanip>

const int logPeriod = 10 * 1000;
const int tryTo = 20 * 1000 * 1000;
    
typedef signed char small_num;

const int digits_count = 4;
const int max_dig_value = 9999;
typedef short TAllDigitsNum; 


void set_if_g( int& dst, int src )
{
    if( dst < src )
        dst = src;
}

static int seconds_since_prog_start() { return ( clock() + CLOCKS_PER_SEC - 1 ) / CLOCKS_PER_SEC; }
static std::string time_report( int seconds = seconds_since_prog_start() )
{
    char buffer[1024];
    assert( seconds >= 0 );
    sprintf_s( buffer, "%d:%2.2d:%2.2d", ( seconds / 60 ) / 60, ( seconds / 60 ) % 60, seconds %60 );
    return buffer;
}

class CDigitsParser {
public:
    CDigitsParser( int num_, int max_dig_count = digits_count ) : 
                num( num_ ), dig_count( -1 ), left_count( max_dig_count ) 
    {
        assert( max_dig_count > 0 && num != 0 );
        shift_one_dig();
        assert( !is_processed() );
        
        right_count = shift_right_z();
        max_in_count = 0;
        shift_right_nz();
        while( num != 0 ) {
            const int in_count = shift_right_z();
            set_if_g( max_in_count, in_count );
            shift_right_nz();
        }
        assert( dig_count > 0 && dig_count <= left_count );
        left_count -= dig_count;
        assert( is_processed() );
    }
    int GetLeftCount() const { assert( is_processed()); return left_count; }
    int GetInCount() const { assert( is_processed()); return max_in_count; }
    int GetRightCount() const { assert( is_processed()); return right_count; }
    
private:
    enum { base = 10 };
    
    int num;
    int dig;
    int dig_count;
    int left_count;
    int max_in_count;
    int right_count;

    bool is_processed() const { return num == 0 && dig == 0; }
    void shift_one_dig()    
    {
        dig = num % base;
        num /= base;
        dig_count++;
    }
    int shift_right_z()
    {
        assert( !is_processed() );
        int count = 0;
        while( dig == 0 ) {
            shift_one_dig();
            count++;
        }
        return count;
    }
    
    int shift_right_nz()
    {
        int count = 0;
        while( dig != 0 ) {
            shift_one_dig();
            count++;
        }
        return count;
    }
};    //    CDigitsParser


small_num left_z_count[max_dig_value + 1] = { -100 };
small_num in_z_count[max_dig_value + 1] = { -100 };
small_num right_z_count[max_dig_value + 1] = { -100 };

void init_tables()
{
    for( int i = 1; i <= max_dig_value; ++i ) {
        CDigitsParser p( i );
        left_z_count[i] = p.GetLeftCount();
        in_z_count[i] = p.GetInCount();
        right_z_count[i] = p.GetRightCount();
    }
}


class PowerOf2VeryLongNumber {
    typedef TAllDigitsNum TDig;        
    typedef std::vector<TDig> TDigits;
    TDigits digits;
public:
    PowerOf2VeryLongNumber() { digits.push_back( 1 ); }

    int Mult2AndRetMax0Count()
    {
        int cur_z_count = 0;
        int best_z_count = 0;
        int carry = 0;
        for( TDigits::iterator i = digits.begin(); i != digits.end(); ++i ) {
            int dig = *i*2 + carry;
            if( dig > max_dig_value ) {
                carry = 1;
                dig -= max_dig_value + 1;
            } else {
                carry = 0;
            }
            *i = dig;
            if( dig == 0 ) {
                cur_z_count += digits_count;
            } else {
                set_if_g( best_z_count, cur_z_count + right_z_count[dig] );
                //set_if_g( best_z_count, in_z_count[dig] );    //    для больших чисел не важно...
                cur_z_count = left_z_count[dig];
            }
        }
        if( carry != 0 ) {
            digits.push_back( carry );
        }
        return best_z_count;
    }
    
    template<typename TStream>
    TStream& Output( TStream& dst ) const 
    {
        TDigits::const_reverse_iterator i = digits.rbegin();    
        dst << (int)*i;
        for( ++i; i != digits.rend(); ++i ) {
            dst << std::setw( digits_count ) << std::setfill( '0' ) << (int)*i;
        }
        return dst;
    }

    int Length() const 
    { 
        assert( digits[digits.size() - 1] != 0 );
        return digits.size() * digits_count - left_z_count[digits[digits.size() - 1]]; 
    }

};

template<typename TStream>
TStream& operator << ( TStream& dst, const PowerOf2VeryLongNumber& x )
{
    return x.Output( dst );
}

struct Result {
    int PowerValue;
    PowerOf2VeryLongNumber x;
};

int _tmain(int argc, _TCHAR* argv[])
{
    init_tables();    

    PowerOf2VeryLongNumber x;
    std::vector<Result> result;
    Result tmp = { 0 };
    result.push_back( tmp );
    for( int i = 1; i < tryTo; i++ ) {
        int zCount = x.Mult2AndRetMax0Count();
        if( ( i % logPeriod ) == 0 ) {
            std::cout << time_report() << " : 2^" << i << " = " << zCount << ", " << result.size() - 1 
                << ", len = " << x.Length()/* << ", " << x */<< " <-\r";
        }
        
        while( result.size() <= zCount ) {
            Result r = { i, x };
            result.push_back( r );
            std::cout << time_report() << " : 2^" << i << " = " << zCount << ", " << result.size() - 1 
                << ", len = " << x.Length()/** << ", " << x **/<< "   " << std::endl;
        }
    }
    std::cout << "--------------------------" << std::endl;
    for( int i = 1; i < result.size(); i++ ) {
        std::cout << "a(" << i << ") = 2^" << result[i].PowerValue << ", len = " << result[i].x.Length() 
            /*<< " = " << result[i].x */<< std::endl;
    }

    return 0;
}


Будет время -- попробую обработать переполнение кэша.
Идея такая, что как только массив "цифр" перестаёт помещаться в кэш, так сразу и приходят тормоза.
Если отказаться от хранения самих степеней двойки, для каждого k, то можно сделать хитро.
Фактически Mult2AndRetMax0Count() идёт по массиву "цифр" и меняет его, накапливая некоторое состояние (перенос, длина максимальной обнаруженной цепочки 0, длина текущей обнаруженной цепочки 0, позиция). Можно проходить по куску массива "цифр", который помещается в кэш, и накапливать массив состояний, полученных на границе куска после первого прохода, после второго и т. д. Пока кэш не закончится.
Потом можно переходить к обработке след. куска массива "цифр" и т. д. А когда дойдём до конца массива "цифр" -- узнаем несколько a(k), если повезёт...

Хотя конечно, для радикального ускорения всё этой сосиски её надо на "КУДУ" перенести. Типа массивы *_z_count затолкать в текстурную память, хранить пары "цифр" и переносов, и потом прогонять логарифмическим суммированием по всей этой штуке. Должно быть очень сильно быстрее. Раз в 1000 на хорошей карточке, наверное...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[12]: k нулей
От: Erop Россия  
Дата: 20.12.08 19:21
Оценка:
Здравствуйте, Seon, Вы писали:

S>>>а(8) — до 2х секунд!

S>>>а(9) — 80 секунд!

S>>а(10) — 2^559940 — 24 минуты и 20 секунд


S>а(11) — 2^1148303 — 47 минут и 16 секунд


0:00:01 : 2^242 = 3, 3, len = 73
0:00:01 : 2^377 = 4, 4, len = 114
0:00:01 : 2^1491 = 5, 5, len = 449
0:00:01 : 2^1492 = 6, 6, len = 450
0:00:01 : 2^6801 = 7, 7, len = 2048
0:00:01 : 2^14007 = 8, 8, len = 4217
0:00:09 : 2^100823 = 9, 9, len = 30351
0:04:24 : 2^559940 = 10, 10, len = 168559
0:18:23 : 2^1148303 = 11, 11, len = 345674

Гонял на Core(TM) Duo CPU T2450 2,00 GHz под вистой...
А ты?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: k нулей
От: Skazitel  
Дата: 20.12.08 22:01
Оценка:
Здравствуйте, vadimcher, Вы писали:

V>Докажите, что для любого k найдется такое число n, что в [i]десятичной[i] записи числа 2^n, встречается k нулей подряд.


V>Этюд для программиста.

V>Обозначим минимальное такое n как a(k). Например, a(1)=10, т.к. 2^10=1024 -- минимальная степень двойки, содержащая один ноль (подряд? ). a(2)=53, т.к. 2^53=9007199254740992 -- минимальная степень двойки, содержащая два нуля подряд. Ну и т.д.
V>Найти a(1),...,a(7).

Что-то я не понял пролемы... Первое, что я увидел — дикие мучения на тему вычисления огромных чисел...
Может кто-то глубже и написал, все читать не стал — долго.

отрицательные n решение проблемы. Вроде же очевидно все становится, нет? Огроничений на n нигде нету... в чем проблема то?
Re[2]: k нулей
От: Erop Россия  
Дата: 20.12.08 22:30
Оценка:
Здравствуйте, Skazitel, Вы писали:

S>отрицательные -- n решение проблемы. Вроде же очевидно все становится, нет? Огроничений на n нигде нету... в чем проблема то?

Прикольно, но скучно. ВО всяком случае, в качестве этюда для программистов
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: k нулей
От: Skazitel  
Дата: 21.12.08 15:09
Оценка:
Здравствуйте, vadimcher, Вы писали:

V>Здравствуйте, Skazitel, Вы писали:


S>>Здравствуйте, vadimcher, Вы писали:


V>>>Докажите, что для любого k найдется такое число n, что в [i]десятичной[i] записи числа 2^n, встречается k нулей подряд.


V>>>Этюд для программиста.

V>>>Обозначим минимальное такое n как a(k). Например, a(1)=10, т.к. 2^10=1024 -- минимальная степень двойки, содержащая один ноль (подряд? ). a(2)=53, т.к. 2^53=9007199254740992 -- минимальная степень двойки, содержащая два нуля подряд. Ну и т.д.
V>>>Найти a(1),...,a(7).

S>>Что-то я не понял пролемы... Первое, что я увидел — дикие мучения на тему вычисления огромных чисел...

S>>Может кто-то глубже и написал, все читать не стал — долго.

S>>отрицательные n решение проблемы. Вроде же очевидно все становится, нет? Огроничений на n нигде нету... в чем проблема то?


V>Из примеров понятно о чем речь. К тому же a(k) -- "минимальное такое n", которое, если допустить отрицательные n, не существует. У Вас образование не юридическое?

образование: математик, системный программист
Re[4]: Ой ли?.. :)
От: Erop Россия  
Дата: 21.12.08 15:15
Оценка:
Здравствуйте, Skazitel, Вы писали:

S>Каков вопрос, таков ответ. Задачу поставили, я написал решение


Ой ли?

Что-то я не понял пролемы... Первое, что я увидел — дикие мучения на тему вычисления огромных чисел...
Может кто-то глубже и написал, все читать не стал — долго.

Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: k нулей
От: Spiceman  
Дата: 21.12.08 15:18
Оценка:
Здравствуйте, vadimcher, Вы писали:

V>Докажите, что для любого k найдется такое число n, что в [i]десятичной[i] записи числа 2^n, встречается k нулей подряд.


Больше всего понравилось решение на Хаскеле. В одну строчку — впечатлило!
Ради интереса написал на Лиспе (DrScheme):

#lang scheme
(require srfi/40/stream)

;Поток степеней двойки. Состоит из пар: степень, показатель степени.
(define (double-stream-from n k)
  (stream-cons (cons n k)
               (double-stream-from (* 2 n) (+ k 1))))

(define pow2-stream (double-stream-from 1 0))

;Функция проверки количества нулей подряд в десятичной системе.
(define (check n k)
  (define (check-iter n k z)
    (if (= n 0)
        false
        (if (= k z)
            true
            (if (= (remainder n 10) 0)
                (check-iter (quotient n 10) k (+ z 1))
                (check-iter (quotient n 10) k 0)))))
  (check-iter n k 0))

;Поток отфильтрованных степеней двойки.
(define (filtered-pow2-stream-from n s)
  (if (check (car (stream-car s)) n)
      (stream-cons (stream-car s)
                   (filtered-pow2-stream-from (+ n 1) (stream-cdr s)))
      (filtered-pow2-stream-from n (stream-cdr s))))

(define filtered-pow2-stream (filtered-pow2-stream-from 1 pow2-stream))

;Отображение потока.
(define (display-pow2-stream s)
  (stream-for-each display-pow s))

(define (display-pow x)
  (newline)
  (display (cdr x)))

(define display-filtered-pow2-stream (display-pow2-stream filtered-pow2-stream))


Работает очень медленно. Зато функционально И что интересно, сам распараллелился на два потока — один строит степени двойки, а другой эти степени фильрует.
Лисп изучаю, если кто покритикует, буду рад.
Re[2]: k нулей
От: Аноним  
Дата: 21.12.08 15:53
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Решение на Haskell.

А>
А>import Data.List
А>zeros n = head [p | p <- [1..], (replicate n '0') `isInfixOf` (show $ 2^p)]
А>


Неужели еще никто не написал решение на J или K?
Re: И еще одна программа на C++
От: Roman Odaisky Украина  
Дата: 21.12.08 19:00
Оценка:
А вот моя версия. Подход немножко другой, используется 10¹⁶-ричная система счисления.

#include <vector>
#include <iostream>
#include <fstream>
#include <cassert>
#include <boost/lexical_cast.hpp>

using std::size_t;

typedef unsigned long long digit;
typedef std::vector<digit> bigint;

size_t const LOG_BASE = 16;
digit const power10[17] = {
    (digit)1ULL,
    (digit)10ULL,
    (digit)100ULL,
    (digit)1000ULL,
    (digit)10000ULL,
    (digit)100000ULL,
    (digit)1000000ULL,
    (digit)10000000ULL,
    (digit)100000000ULL,
    (digit)1000000000ULL,
    (digit)10000000000ULL,
    (digit)100000000000ULL,
    (digit)1000000000000ULL,
    (digit)10000000000000ULL,
    (digit)100000000000000ULL,
    (digit)1000000000000000ULL,
    (digit)10000000000000000ULL,
};
digit const BASE = power10[LOG_BASE];

bool has_k_zeros(digit const d, size_t const k, size_t& leftover)
{
    if(leftover >= k)
    {
        return true;
    }
    if(leftover > 0 && d % power10[k - leftover] == 0)
    {
        return true;
    }

    digit const factor_positive = power10[k];
    digit const factor_possible = power10[k / 2];

    for(digit i = d; i; i /= factor_possible)
    {
        if(i % factor_possible == 0)
        {
            leftover = LOG_BASE;
            for(digit j = d; j; )
            {
                if(j % factor_positive == 0)
                {
                    return true;
                }

                while(j % 10 == 0)
                {
                    j /= 10;
                    --leftover;
                }
                j /= 10;
                --leftover;
            }
            return false;
        }
    }

    leftover = LOG_BASE;
    for(size_t i = 0; i < LOG_BASE; ++i)
    {
        if(d >= power10[LOG_BASE - i - 1])
        {
            leftover = i;
            break;
        }
    }
    return false;
}

bigint& mul2(bigint& n)
{
    digit carry = 0;
    for(size_t i = 0; i < n.size(); ++i)
    {
        n[i] *= 2;
        n[i] += carry;
        if(n[i] >= BASE)
        {
            carry = n[i] / BASE;
            n[i] %= BASE;
        }
        else
        {
            carry = 0;
        }
    }
    if(carry > 0)
    {
        n.push_back(carry);
    }
    return n;
}

int main(int argc, char** argv)
{
    assert(argc == 2);
    size_t const k = boost::lexical_cast<size_t>(argv[1]);

    size_t p = 0;
    bigint n;
    n.reserve(10240);
    n.push_back(1);

    std::ofstream tty("/dev/tty");

    while(1)
    {
        {
            size_t leftover = 0;
            for(size_t i = 0; i < n.size(); ++i)
            {
                if(has_k_zeros(n[i], k, leftover))
                {
                    std::cout << p << std::endl;
                    return 0;
                }
            }
        }

        mul2(n);

        ++p;

        if(p % 10000 == 0)
        {
            tty << p << "..." << std::endl;
        }
    }
}
До последнего не верил в пирамиду Лебедева.
Re[13]: k нулей
От: Seon  
Дата: 22.12.08 07:12
Оценка:
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, Seon, Вы писали:


S>>>>а(8) — до 2х секунд!

S>>>>а(9) — 80 секунд!

S>>>а(10) — 2^559940 — 24 минуты и 20 секунд


S>>а(11) — 2^1148303 — 47 минут и 16 секунд


E>

0:00:01 : 2^242 = 3, 3, len = 73
E>0:00:01 : 2^377 = 4, 4, len = 114
E>0:00:01 : 2^1491 = 5, 5, len = 449
E>0:00:01 : 2^1492 = 6, 6, len = 450
E>0:00:01 : 2^6801 = 7, 7, len = 2048
E>0:00:01 : 2^14007 = 8, 8, len = 4217
E>0:00:09 : 2^100823 = 9, 9, len = 30351
E>0:04:24 : 2^559940 = 10, 10, len = 168559
E>0:18:23 : 2^1148303 = 11, 11, len = 345674

Гонял на Core(TM) Duo CPU T2450 2,00 GHz под вистой...

E>А ты?

Семпрон 1.8 W2003 в belownormal

a(12) — 2^4036332 11 часов 18 минут

сейчас приближается к 10 миллионам со скоростью гдето 20 чисел в секунду
Re[5]: С++ версии...
От: Seon  
Дата: 22.12.08 08:10
Оценка:
Здравствуйте, Erop, Вы писали:

E>Вариант с двумя цифрами на байт:

E>Вариант с четырьмя цифрами на short:
E>Вариант с четырьмя цифрами на short, и без проверок цепочек нулей, не выходящих на границы цепочек (очевидно, что для k > 2 это не важно)

А как на счет 8 на INT?

... а еще есть вариант 4 цифры на ИНТ, (по 1 на байт)

E>Будет время -- попробую обработать переполнение кэша.


Есть более радикальное решение:
Обрабатывать числа по частям. Ведь для удвоения нам достаточно знать цифру с которой начинать, а это всегда 1, и значение переноса из предыдущего разряда, это 1 или 0 — его запоминать в файле.

Расчитываем числа, длиной например в 1 000 000, — это приблизительно 3 200 000-я степень двойки. Продолжаем считать их например до 1000 000 000 000, запоминая в файле для каждой степени один байт, в котором 1 бит — значение переноса, остальные биты — количество нулей, которые имело число с левой стороны. Таким образом получаем файл в 1000 000 байт.

Затем мы расчитываем числа со степени 3 200 000, начиная с 1, учитывая значения переноса из файла. А при подсчете нулей, начальное количество нулей берем так же из файла.

Ресурс файла по количеству нулей — 127. То есть эта схема файла позволит рассчитать числа до 127 нулей подряд.

Этот алгоритм позволит избавить поиск чисел от зависимости на количество используемой памяти программой. И кстати легко может быть распределен между компьютерами.
1-й ищет части числа 1 000 000 000 000? второй 1 000 000 000 000, третий 1 000 000 000 000, четвертый 1 000 000 000 000.

Кто возьмется писать такую программу, просьба маленькая :
— сделать консольную программу, которая в качестве параметров принимает количество итераций, выходной файл переносов, входной файл переносов. (2 параметра — считать что перенос всегда 0)
— программа должна делать периодическое сохранение промежуточных данных (всего массива чисел), для того чтобы в любой момент можно было продолжить вычисления.
— должна позволить продолжить вычисления, получив четвертый параметр — текущее состояние



Удачи, программисты!
Re[5]: k нулей
От: Seon  
Дата: 22.12.08 08:13
Оценка:
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, Seon, Вы писали:
S>>Последнее число, в котором нет двух нулей подряд — 2^2114 !
E>Два вопроса.
E>1) Какие есть ваши доказательства?
программа обработала числа до 2^10 000 000. Вероятность появления 2х нулей подряд падала очень быстро.
Вероятность встретить 2 нуля подряд в числах такого размера вероятна равна 0.
E>2) "2114!" -- это факториал?
Нет, просто 2^2114
Re[4]: k нулей
От: Seon  
Дата: 22.12.08 08:15
Оценка:
Здравствуйте, Skazitel, Вы писали:

S>Здравствуйте, vadimcher, Вы писали:


V>>Здравствуйте, Skazitel, Вы писали:


S>>>Здравствуйте, vadimcher, Вы писали:


V>>>>Докажите, что для любого k найдется такое число n, что в [i]десятичной[i] записи числа 2^n, встречается k нулей подряд.


V>>>>Этюд для программиста.

V>>>>Обозначим минимальное такое n как a(k). Например, a(1)=10, т.к. 2^10=1024 -- минимальная степень двойки, содержащая один ноль (подряд? ). a(2)=53, т.к. 2^53=9007199254740992 -- минимальная степень двойки, содержащая два нуля подряд. Ну и т.д.
V>>>>Найти a(1),...,a(7).

S>>>Что-то я не понял пролемы... Первое, что я увидел — дикие мучения на тему вычисления огромных чисел...

S>>>Может кто-то глубже и написал, все читать не стал — долго.

S>>>отрицательные n решение проблемы. Вроде же очевидно все становится, нет? Огроничений на n нигде нету... в чем проблема то?


V>>Из примеров понятно о чем речь. К тому же a(k) -- "минимальное такое n", которое, если допустить отрицательные n, не существует. У Вас образование не юридическое?

S>Нигде не сказано => не понятно. А главное, что в первой строчке нету минимуальности И если бы мне дали только первую стоку, то точно не понятно....

По моему и из первой строки все ясно без проблем..
Не вижу проблем в постановке задачи...
Re[2]: И еще одна программа на C++
От: Seon  
Дата: 22.12.08 08:20
Оценка:
Здравствуйте, Roman Odaisky, Вы писали:

RO>А вот моя версия. Подход немножко другой, используется 10¹⁶-ричная система счисления.


А где же результаты работы?
Степени + временные интервалы?

Меня смутил ретурн вот здесь


                if(has_k_zeros(n[i], k, leftover))
                {
                    std::cout << p << std::endl;
                    return 0;
                }


Re[6]: С++ версии...
От: Seon  
Дата: 22.12.08 08:26
Оценка:
Если что,
у меня есть массиф числа 2^4036332
Re[6]: С++ версии...
От: Seon  
Дата: 22.12.08 08:34
Оценка:
Здравствуйте, Seon, Вы писали:

S>Здравствуйте, Erop, Вы писали:


E>>Вариант с двумя цифрами на байт:

E>>Вариант с четырьмя цифрами на short:
E>>Вариант с четырьмя цифрами на short, и без проверок цепочек нулей, не выходящих на границы цепочек (очевидно, что для k > 2 это не важно)

S>А как на счет 8 на INT?


S>... а еще есть вариант 4 цифры на ИНТ, (по 1 на байт)


E>>Будет время -- попробую обработать переполнение кэша.


S>Есть более радикальное решение:

S>Обрабатывать числа по частям. Ведь для удвоения нам достаточно знать цифру с которой начинать, а это всегда 1, и значение переноса из предыдущего разряда, это 1 или 0 — его запоминать в файле.

S>Расчитываем числа, длиной например в 1 000 000, — это приблизительно 3 200 000-я степень двойки. Продолжаем считать их например до 1000 000 000 000, запоминая в файле для каждой степени один байт, в котором 1 бит — значение переноса, остальные биты — количество нулей, которые имело число с левой стороны. Таким образом получаем файл в 1000 000 байт.


S>Затем мы расчитываем числа со степени 3 200 000, начиная с 1, учитывая значения переноса из файла. А при подсчете нулей, начальное количество нулей берем так же из файла.


S>Ресурс файла по количеству нулей — 127. То есть эта схема файла позволит рассчитать числа до 127 нулей подряд.


S>Этот алгоритм позволит избавить поиск чисел от зависимости на количество используемой памяти программой. И кстати легко может быть распределен между компьютерами.

S>1-й ищет части числа 1 000 000 000 000? второй 1 000 000 000 000, третий 1 000 000 000 000, четвертый 1 000 000 000 000.

S>Кто возьмется писать такую программу, просьба маленькая :

S>- сделать консольную программу, которая в качестве параметров принимает количество итераций, выходной файл переносов, входной файл переносов. (2 параметра — считать что перенос всегда 0)
S>- программа должна делать периодическое сохранение промежуточных данных (всего массива чисел), для того чтобы в любой момент можно было продолжить вычисления.
S>- должна позволить продолжить вычисления, получив четвертый параметр — текущее состояние

S>


S>Удачи, программисты!



Кстати отсюда вылезает задача о повторяемости:
Через какое количество итераций, числа 1 000 000 000 начнут повторяться, и можно будет для 1 000 000 000 использовать один и тот же файл...
Re[14]: k нулей
От: Erop Россия  
Дата: 22.12.08 08:44
Оценка:
Здравствуйте, Seon, Вы писали:

E>>

0:00:01 : 2^242 = 3, 3, len = 73
E>>0:00:01 : 2^377 = 4, 4, len = 114
E>>0:00:01 : 2^1491 = 5, 5, len = 449
E>>0:00:01 : 2^1492 = 6, 6, len = 450
E>>0:00:01 : 2^6801 = 7, 7, len = 2048
E>>0:00:01 : 2^14007 = 8, 8, len = 4217
E>>0:00:09 : 2^100823 = 9, 9, len = 30351
E>>0:04:24 : 2^559940 = 10, 10, len = 168559
E>>0:18:23 : 2^1148303 = 11, 11, len = 345674

Гонял на Core(TM) Duo CPU T2450 2,00 GHz под вистой...

E>>А ты?

S> Семпрон 1.8 W2003 в belownormal


S>a(12) — 2^4036332 11 часов 18 минут

3:47:15 : 2^4036338 = 12, 12, len = 1215059
3:47:16 : 2^4036339 = 13, 13, len = 1215060

Не совсем понятно от чего 13 не попался сразу. Короче медленно всё. Даже до известного a(17), который пол миллиард, и то бесконечно долго считать будет

S>сейчас приближается к 10 миллионам со скоростью где-то 20 чисел в секунду
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: k нулей
От: Erop Россия  
Дата: 22.12.08 08:52
Оценка:
Здравствуйте, Spiceman, Вы писали:

S>Больше всего понравилось решение на Хаскеле. В одну строчку — впечатлило!

Ну на любом языке с поддержкой длинных чисел будет коротко. Вот на С++ с соответствующей библиотекой, например
Другое дело, что будет медленно.
Кстати, чтобы было веселее, предлагаю немного изменить условие задачи — посчитать функцию a( k, base ), где base -- основание системы счисления.
Конечно для степеней двойки задача вырождается, но можно рассмотреть основание 9 или 11, например...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: k нулей
От: Seon  
Дата: 22.12.08 08:57
Оценка:
Здравствуйте, Erop, Вы писали:

E>Конечно для степеней двойки задача вырождается, но можно рассмотреть основание 9 или 11, например...


Не понял, почему вырождается?
Re[2]: И еще одна программа на C++
От: Erop Россия  
Дата: 22.12.08 09:00
Оценка:
Здравствуйте, Roman Odaisky, Вы писали:

RO>А вот моя версия. Подход немножко другой, используется 10¹⁶-ричная система счисления.


И что? Как работает?
IMHO, отдельно умножать, и отдельно подсчитывать нули очень невыгодно, так как достаточно длинное число придётся тягать в кэш дважды за тестируемую степень двойки, о хотелось бы на много степеней двойки тягать число в кэш только один раз...

Кстати, развей мои сомнения
Автор: Erop
Дата: 20.12.08
про использование std::copy. Ты ошибся или я?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: k нулей
От: Erop Россия  
Дата: 22.12.08 09:05
Оценка:
Здравствуйте, Seon, Вы писали:

S>Не понял, почему вырождается?

потому, что "2 в степени 666" в 8-ричной системе записывается как 1 с 222 нулями
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: k нулей
От: Pro100Oleh Украина  
Дата: 22.12.08 09:09
Оценка:
Здравствуйте, vadimcher, Вы писали:

V>Было бы здорово, если бы все еще свой код выкладывали. Просто интересно сравнить эффективность/простоту для разных языков.


Имхо, суть не в применяемых языках, а в алгоритме. Все приведенные здесь примеры что я пересмотрел (все не смотрел — лень) производят умножения по одной цифре. Я же использую int64 с 17 цифрами, то есть я умножаю в 17 раз быстрее.
Кстати, основная сложность не в умножении, а в проверке числа. Здесь у меня другая оптимизация, но это пока секрет .
Pro
Re[3]: И еще одна программа на C++
От: Roman Odaisky Украина  
Дата: 22.12.08 10:21
Оценка:
Здравствуйте, Seon, Вы писали:

S>А где же результаты работы? :))

S>Степени + временные интервалы? :shuffle:

~/src :) time ./kzeros 7
6801
./kzeros 7  0.12s user 0.00s system 100% cpu 0.124 total
~/src :) time ./kzeros 8
...10000...
14007
./kzeros 8  0.46s user 0.01s system 99% cpu 0.472 total


S>Меня смутил ретурн вот здесь


S>
S>                if(has_k_zeros(n[i], k, leftover))
S>                {
S>                    std::cout << p << std::endl;
S>                    return 0;
S>                }
S>

Это же return из main. Там раньше был еще return 1 на случай ненахождения результата, но я потом его убрал.
До последнего не верил в пирамиду Лебедева.
Re[4]: k нулей
От: Seon  
Дата: 22.12.08 10:58
Оценка:
Здравствуйте, Pro100Oleh, Вы писали:

PO>Здравствуйте, vadimcher, Вы писали:


V>>Было бы здорово, если бы все еще свой код выкладывали. Просто интересно сравнить эффективность/простоту для разных языков.


PO>Имхо, суть не в применяемых языках, а в алгоритме. Все приведенные здесь примеры что я пересмотрел (все не смотрел — лень) производят умножения по одной цифре. Я же использую int64 с 17 цифрами, то есть я умножаю в 17 раз быстрее.

PO>Кстати, основная сложность не в умножении, а в проверке числа. Здесь у меня другая оптимизация, но это пока секрет .

Вот вас и просят показать свой алгоритм...
Интересно как это вы в инт64 впихнули 17 цифр

вы говорите в 17 раз быстрее...

У вас на 4 кирпичах — a(11) — 10 минут
У меня на 1 кирпиче — а(11) — 47 минут

Где же тут в 17 раз быстрее? интересно
Re[5]: k нулей
От: Seon  
Дата: 22.12.08 10:59
Оценка:
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, Seon, Вы писали:


S>>Не понял, почему вырождается?

E>потому, что "2 в степени 666" в 8-ричной системе записывается как 1 с 222 нулями

ААААА. Понятно! не то подумал
Re[4]: И еще одна программа на C++
От: Seon  
Дата: 22.12.08 11:07
Оценка:
Здравствуйте, Roman Odaisky, Вы писали:

RO>
RO>~/src :) time ./kzeros 7
RO>6801
RO>./kzeros 7  0.12s user 0.00s system 100% cpu 0.124 total
RO>~/src :) time ./kzeros 8
RO>...10000...
RO>14007
RO>./kzeros 8  0.46s user 0.01s system 99% cpu 0.472 total
RO>


Мдя... медленновато.

Вы тратите много времени на перевод в 10-ю, видимо.
Мы тутачки работаем ужо сразу в десятичной.
14007 считается — 1-2 секунды.

S>>Меня смутил ретурн вот здесь

S>>
S>>                if(has_k_zeros(n[i], k, leftover))
S>>                {
S>>                    std::cout << p << std::endl;
S>>                    return 0;
S>>                }
S>>

RO>Это же return из main. Там раньше был еще return 1 на случай ненахождения результата, но я потом его убрал.

Та при чем тут 0 или 1. Зачем вываливаться из цикла как только нашли результат? Не уж-то нельзя продолжить поиск следующего числа?
Зачем потом тратить время опять на умножение сначала?
Re[12]: И снова об STL
От: Roman Odaisky Украина  
Дата: 22.12.08 11:38
Оценка:
Здравствуйте, Seon, Вы писали:

S>Ну и что же... зато запись какая! :super:

RO>>
RO>>    ++*--dst;
RO>>

С тем же успехом можно было ++dst[-1].
До последнего не верил в пирамиду Лебедева.
Re[5]: k нулей
От: Pro100Oleh Украина  
Дата: 22.12.08 12:28
Оценка:
Здравствуйте, Seon, Вы писали:

S>Здравствуйте, Pro100Oleh, Вы писали:


PO>>Здравствуйте, vadimcher, Вы писали:


V>>>Было бы здорово, если бы все еще свой код выкладывали. Просто интересно сравнить эффективность/простоту для разных языков.


PO>>Имхо, суть не в применяемых языках, а в алгоритме. Все приведенные здесь примеры что я пересмотрел (все не смотрел — лень) производят умножения по одной цифре. Я же использую int64 с 17 цифрами, то есть я умножаю в 17 раз быстрее.

PO>>Кстати, основная сложность не в умножении, а в проверке числа. Здесь у меня другая оптимизация, но это пока секрет .

S>Вот вас и просят показать свой алгоритм...

S>Интересно как это вы в инт64 впихнули 17 цифр

S>вы говорите в 17 раз быстрее...


S>У вас на 4 кирпичах — a(11) — 10 минут

S>У меня на 1 кирпиче — а(11) — 47 минут

S>Где же тут в 17 раз быстрее? интересно


В 17 раз — имеется ввиду теоретическое улутчение в операции умножения, так как я за раз умножаю 17 цифр, а не одну. Но кроме самого умножения выполняются и проверка на нули. Кстати, здесь минус моего алгоритма, так как мне приходится искать втутри многоцифренномго числа нули.
На самом деле можно использовать даже 18 цифр, потому что мы используем только умножения на два: (10е18-1)*2 < Int64.MaxValue = 9,223,372,036,854,775,807. По поводу алгоритма — чуть розже, так как с сегодняшнего дня я в отпуске, а код остался на работе.
Pro
Re[5]: k нулей
От: Pro100Oleh Украина  
Дата: 22.12.08 12:31
Оценка:
Кстати, я использую не все 17 цифр. Это связанно с эвристикой
Pro
Re[5]: И еще одна программа на C++
От: Roman Odaisky Украина  
Дата: 22.12.08 12:40
Оценка:
Здравствуйте, Seon, Вы писали:

RO>>
RO>>~/src :) time ./kzeros 7
RO>>6801
RO>>./kzeros 7  0.12s user 0.00s system 100% cpu 0.124 total
RO>>~/src :) time ./kzeros 8
RO>>...10000...
RO>>14007
RO>>./kzeros 8  0.46s user 0.01s system 99% cpu 0.472 total
RO>>


S>Мдя... медленновато. :-\


S>Вы тратите много времени на перевод в 10-ю, видимо.

S>Мы тутачки работаем ужо сразу в десятичной.
S>14007 считается 1—2 секунды.

Написано же — 0,46 с.

S>Зачем вываливаться из цикла как только нашли результат? Неужто нельзя продолжить поиск следующего числа?

S>Зачем потом тратить время опять на умножение сначала?

Чтобы не усложнять.
До последнего не верил в пирамиду Лебедева.
Re[13]: И снова об STL
От: Seon  
Дата: 22.12.08 13:00
Оценка:
Здравствуйте, Roman Odaisky, Вы писали:

RO>Здравствуйте, Seon, Вы писали:


S>>Ну и что же... зато запись какая!

RO>>>
RO>>>    ++*--dst;
RO>>>

RO>С тем же успехом можно было ++dst[-1].

А ВОТ и НЕТ!
++*--dst; — уменьшает dst!
а ++dst[-1] — НЕТ!!!!!

Re[6]: k нулей
От: Seon  
Дата: 22.12.08 13:02
Оценка:
Здравствуйте, Pro100Oleh, Вы писали:

PO>Кстати, я использую не все 17 цифр. Это связанно с эвристикой


Нифига не понятно!
Нужен КОД!
Re[7]: k нулей
От: Pro100Oleh Украина  
Дата: 22.12.08 13:04
Оценка:
Здравствуйте, Seon, Вы писали:

S>Здравствуйте, Pro100Oleh, Вы писали:


PO>>Кстати, я использую не все 17 цифр. Это связанно с эвристикой


S>Нифига не понятно!

S>Нужен КОД!

ok, потерпите часик, мне нужно написать прогу заново
Pro
Re[2]: k нулей
От: Seon  
Дата: 22.12.08 13:46
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Brute force на J:

А>
А>  zr =: 3 : '<: >./ 2 -~/\ I. ''0'' ~: ": 2 ^ x: y'
А>  (>:i.7) i.~ zr"0 i.7000
А>


О боже! похоже на смайлики
это вообще язык? или у меня проблема с кодировкой?
Re[3]: k нулей
От: Аноним  
Дата: 22.12.08 13:49
Оценка:
Здравствуйте, Seon, Вы писали:

S>О боже! похоже на смайлики

S>это вообще язык? или у меня проблема с кодировкой?

J
Re[11]: И снова об STL
От: Erop Россия  
Дата: 22.12.08 17:57
Оценка:
Здравствуйте, Roman Odaisky, Вы писали:

E>>А разве так можно?


RO>и мой код:

RO>
RO>std::copy(buffer + 1, buffer + 1 + count * 9, buffer + 1 + count);
RO>++buffer[10 * count];
RO>

RO>делают одно и то же. Меня, правда, смущает то, что диапазоны пересекаются, но результат будет один и тот же, даже если это и не то, что ты планировал.

AFAIK, ты забыл уточнить, что это так в доступной тебе реализации STL.
Вообще-то вроде как стандарт требует чтобы третий аргумент не попадал в интервал, заданный первыми двумя...
Я думал ты круто знаешь STL, поэтому и просил тебя разъяснить можно ли согласно стандарта так писать.
AFAIK, в таком случае надо использовать copy_backwards (или как-то ещё оно называется, я в STL всё время путаюсь, где backwards, а где reverse), а использование таким образом std::copy, AFAIK, это неспецифицированное поведение.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
спасибо за попытку было бы классно выяснить до конца... ):
Re[14]: И снова об STL
От: Roman Odaisky Украина  
Дата: 22.12.08 19:16
Оценка:
Здравствуйте, Seon, Вы писали:

S>>>Ну и что же... зато запись какая! :super:

RO>>>>
RO>>>>    ++*--dst;
RO>>>>

RO>>С тем же успехом можно было ++dst[-1].

S>А ВОТ и НЕТ!

S>++*--dst; — уменьшает dst!
S>а ++dst[-1] — НЕТ!!!!!

dst потом не используется нигде.
До последнего не верил в пирамиду Лебедева.
Re[12]: И снова об STL
От: Roman Odaisky Украина  
Дата: 22.12.08 19:19
Оценка:
Здравствуйте, Erop, Вы писали:

RO>>и мой код:

RO>>
RO>>std::copy(buffer + 1, buffer + 1 + count * 9, buffer + 1 + count);
RO>>++buffer[10 * count];
RO>>

RO>>делают одно и то же. Меня, правда, смущает то, что диапазоны пересекаются, но результат будет один и тот же, даже если это и не то, что ты планировал.

E>AFAIK, ты забыл уточнить, что это так в доступной тебе реализации STL. :shuffle:

E>Вообще-то вроде как стандарт требует чтобы третий аргумент не попадал в интервал, заданный первыми двумя...
E>Я думал ты круто знаешь STL, поэтому и просил тебя разъяснить можно ли согласно стандарта так писать.
E>AFAIK, в таком случае надо использовать copy_backwards (или как-то ещё оно называется, я в STL всё время путаюсь, где backwards, а где reverse:)), а использование таким образом std::copy, AFAIK, это неспецифицированное поведение. :shuffle:

Он-то требует, как для copy, так и для copy_backward: «Requires: result shall not be in the range [first, last)».

Просто у тебя при копировании тоже элементы затираются, я решил, что тебе это так надо.
До последнего не верил в пирамиду Лебедева.
Re[13]: И снова об STL
От: Erop Россия  
Дата: 22.12.08 19:49
Оценка:
Здравствуйте, Roman Odaisky, Вы писали:

RO>Просто у тебя при копировании тоже элементы затираются, я решил, что тебе это так надо.

1) у меня ничего не затирается. Каждый элемент инициализируется ОДИН раз, за исключением тех, кому делают ++*--dst.
2) STL не предоставляет гарантий, что std::copy будет работать именно так, в случае такого нарушения. Например, какая-нибудь реализация, может копировать в каком-то хитром порядке Скажем группами... Или таки не может?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: Оптимизированная версия
От: Erop Россия  
Дата: 22.12.08 20:06
Оценка:
Здравствуйте, Roman Odaisky, Вы писали:

RO>Кстати, задача довольно легко параллелизуется. Как удвоение, так и поиск нулей можно поручить разным процессорам, разделив число на части. Чьи программы здесь масштабируются при наличии нескольких процессоров?


IMHO надо сразу на "КУДУ" нести...

А вообще-то всё это очень к размеру кэша чувствительно, IMHO...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: Оптимизированная версия
От: Roman Odaisky Украина  
Дата: 22.12.08 20:10
Оценка:
Здравствуйте, Erop, Вы писали:

RO>>Кстати, задача довольно легко параллелизуется. Как удвоение, так и поиск нулей можно поручить разным процессорам, разделив число на части. Чьи программы здесь масштабируются при наличии нескольких процессоров?


E>IMHO надо сразу на "КУДУ" нести...


E>А вообще-то всё это очень к размеру кэша чувствительно, IMHO...


Воистину. У меня зависимость от LOG_BASE экстремальная, хотя казалось бы, что чем больше, тем лучше.
До последнего не верил в пирамиду Лебедева.
Re[15]: И снова об STL
От: Erop Россия  
Дата: 22.12.08 20:13
Оценка:
Здравствуйте, Roman Odaisky, Вы писали:

RO>И теперь цикл возымеет такое действие: buffer[2]=buffer[1], buffer[3]=buffer[2]... т. е., вместо смещения данных первые count элементов будут размножены 8 раз.

9 раз.
Я знаю как работает мой код. Он это и должен делать, вообще-то, а не какое-то там "смещение данных" выполнять. Хотя я понимаю, что ты имеешь в виду, и мог бы, например, написать аналогичный код на memcpy, например. И тоже непереносимый.

E>>2) STL не предоставляет гарантий, что std::copy будет работать именно так, в случае такого нарушения. Например, какая-нибудь реализация, может копировать в каком-то хитром порядке Скажем группами... Или таки не может?

RO>Не предоставляет, естественно.

Ну и хрен ли тогда советовать заменить корректный С++ цикл на некорректное использование стандартного алгоритма?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: Оптимизированная версия
От: Erop Россия  
Дата: 22.12.08 20:15
Оценка:
Здравствуйте, Roman Odaisky, Вы писали:

RO>Воистину. У меня зависимость от LOG_BASE экстремальная, хотя казалось бы, что чем больше, тем лучше.

Очевидно, что нет
Кроме того, не понятно почему ты 100 000 за "цифру" взял. Казалось бы 10 000 помещается в два байта, а 100 000 уже в 4, так что каш тратится менее эффективно...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[5]: Оптимизированная версия
От: Roman Odaisky Украина  
Дата: 22.12.08 20:25
Оценка:
Здравствуйте, Erop, Вы писали:

RO>>Воистину. У меня зависимость от LOG_BASE экстремальная, хотя казалось бы, что чем больше, тем лучше.

E>Очевидно, что нет :)
E>Кроме того, не понятно почему ты 100 000 за "цифру" взял. Казалось бы 10 000 помещается в два байта, а 100 000 уже в 4, так что каш тратится менее эффективно...

Это ни при чем.

Данные из n у меня берутся последовательно, а вот из mdczt — случайным образом, поэтому именно таблица должна полностью помещаться в кеше, не число.
До последнего не верил в пирамиду Лебедева.
Re[2]: Оптимизированная версия
От: vadimcher  
Дата: 22.12.08 21:03
Оценка:
Здравствуйте, Roman Odaisky, Вы писали:

[]
RO>Идея здесь в том, чтобы использовать 10⁵-ричную (параметр настраивается) систему счисления, и хранить в отдельной таблице количество нулей для каждой такой «цифры». В основном алгоритме нет ни единой операции деления. И еще кое-где поэкономил на спичках (например, я заменил «if(d!=0){czt=0}» на «czt &= d ? 0 : ~(size_t)0;», чтобы втолковать компилятору, что здесь нужно поставить sbb). Почерпнул немного дельных мыслей из дотнетовского варианта
Автор: Pro100Oleh
Дата: 22.12.08
, но полностью тот алгоритм не понял.


RO>На Pentium 4 (3 ГГц, мегабайт кеша L2) считает a(8) за 6,7 с (при -DLOG_BASE=7), интеловский компилятор справляется за 6,3 с. На сервере, где Intel Q6600 и 4 МБ кеша, работает за 2,6 с. a(10) — 379 с здесь и 74 с там.


Странно, в твоей предыдущей "неоптимизированной" версии a(8) считалось за 0.46 секунд...

Кстати, если сравнить твой лучший показатель для a(10) -- 1:14 с вариантом Pro100Oleh -- a(10) за 1:10, то наблюдается "сходимость". Понятно, что тест проводился на разных машинах, с разным кэшем и т.д. и т.п., но тем не менее. Интересно, возможен ли какой-то "идеологический прорыв", который позволит посчитать на персоналках a(15), a(16) и т.д., или же все упирается в GHz-ы и кэши?

Хочу отметить, что то, чего вы (вы с маленькой, т.к. "все вы") добились на этом форуме -- уже не мало. Вы можете прочитать по той ссылке, что я приводил ранее, что в то время как первые члены последовательности "безымянные", про последние члены этой последовательности уже отмечено кто и когда их получил. Так вот первые именные члены этой последовательности -- a(12) и a(13) -- уже были получены здесь за более чем приемлемое время!

А вот зайца кому, зайца-выбегайца?!
Re[2]: Оптимизированная версия
От: Pro100Oleh Украина  
Дата: 22.12.08 22:31
Оценка:
Здравствуйте, Roman Odaisky, Вы писали:

RO>Кстати, задача довольно легко параллелизуется. Как удвоение, так и поиск нулей можно поручить разным процессорам, разделив число на части. Чьи программы здесь масштабируются при наличии нескольких процессоров?


Распараллерировать не интересно. Здесь нужен математических подход в решении задачи, который бы позволил на порядок уменьшить сложность вычислений. Играться же в командах, чтобы выполнить оператор не за 5 тактов, а за 4 — малоэффективно (пусть и увеличится скорость работы в 2-3 раза). Возращаясь к параллельности — распараллерировать нужно не саму итерацию умножение числа 2^x на 2 и далее проверку на нули. Нужно, чтобы был один главный поток, который бы давал своим рабочим потокам задачу: проверитьвсе числа в диапазоне 2^x ... 2^(x+1000) например. Здесь бы ядра использовались в полную силу.
Pro
Re[3]: Оптимизированная версия
От: vadimcher  
Дата: 22.12.08 22:34
Оценка:
Здравствуйте, Pro100Oleh, Вы писали:

PO>Здравствуйте, Roman Odaisky, Вы писали:


RO>>Кстати, задача довольно легко параллелизуется. Как удвоение, так и поиск нулей можно поручить разным процессорам, разделив число на части. Чьи программы здесь масштабируются при наличии нескольких процессоров?


PO>Распараллерировать не интересно. Здесь нужен математических подход в решении задачи, который бы позволил на порядок уменьшить сложность вычислений. Играться же в командах, чтобы выполнить оператор не за 5 тактов, а за 4 — малоэффективно (пусть и увеличится скорость работы в 2-3 раза). Возращаясь к параллельности — распараллерировать нужно не саму итерацию умножение числа 2^x на 2 и далее проверку на нули. Нужно, чтобы был один главный поток, который бы давал своим рабочим потокам задачу: проверитьвсе числа в диапазоне 2^x ... 2^(x+1000) например. Здесь бы ядра использовались в полную силу.


Да, если бы, например, были какие-то верхние и нижние границы. Хотя бы рекурсивные...

А вот зайца кому, зайца-выбегайца?!
Re[3]: Оптимизированная версия
От: Roman Odaisky Украина  
Дата: 22.12.08 22:46
Оценка:
Здравствуйте, vadimcher, Вы писали:

RO>>На Pentium 4 (3 ГГц, мегабайт кеша L2) считает a(8) за 6,7 с (при -DLOG_BASE=7), интеловский компилятор справляется за 6,3 с. На сервере, где Intel Q6600 и 4 МБ кеша, работает за 2,6 с. a(10) — 379 с здесь и 74 с там.


V>Странно, в твоей предыдущей "неоптимизированной" версии a(8) считалось за 0.46 секунд...


Прошу прощения, не a(8) за 6,7 с, а a(9).
До последнего не верил в пирамиду Лебедева.
Re[4]: Оптимизированная версия
От: vadimcher  
Дата: 22.12.08 22:48
Оценка:
Здравствуйте, Roman Odaisky, Вы писали:

RO>Здравствуйте, vadimcher, Вы писали:


RO>>>На Pentium 4 (3 ГГц, мегабайт кеша L2) считает a(8) за 6,7 с (при -DLOG_BASE=7), интеловский компилятор справляется за 6,3 с. На сервере, где Intel Q6600 и 4 МБ кеша, работает за 2,6 с. a(10) — 379 с здесь и 74 с там.


V>>Странно, в твоей предыдущей "неоптимизированной" версии a(8) считалось за 0.46 секунд...


RO>Прошу прощения, не a(8) за 6,7 с, а a(9).


Да, я так и подумал...

А вот зайца кому, зайца-выбегайца?!
Re[4]: Оптимизированная версия
От: Pro100Oleh Украина  
Дата: 22.12.08 22:54
Оценка:
Здравствуйте, vadimcher, Вы писали:

V>Да, если бы, например, были какие-то верхние и нижние границы. Хотя бы рекурсивные...


Судя по этому графику есть логарифмическая зависимость степени от k. Только это нужно доказать
Pro
Re[17]: И снова об STL
От: Erop Россия  
Дата: 23.12.08 01:48
Оценка:
Здравствуйте, Roman Odaisky, Вы писали:

RO>Хм, надо было смотреть на название функции...

+1, ну вообще весь остальной код

E>>Ну и хрен ли тогда советовать заменить корректный С++ цикл на некорректное использование стандартного алгоритма?

RO>А хрен ли слушать всякие вредные советы?

Ну так я и не послушал. Зато теперь я ещё больше углубился во мнении, что прежде чем куда совать STL надо пару раз подумать
А то даже такие последовательные поклонники этой библиотеки, как ты, на ровном месте с ней лажают Куда уж нам, простым привыкшим к MFL парням?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[6]: Оптимизированная версия
От: Erop Россия  
Дата: 23.12.08 01:51
Оценка:
Здравствуйте, Roman Odaisky, Вы писали:

RO>Данные из n у меня берутся последовательно, а вот из mdczt — случайным образом, поэтому именно таблица должна полностью помещаться в кеше, не число.

Ну если в кэш помещается всё, то быстрее получится, чем, если не всё. Я так думаю, что пока всё число лезет в кэш вместе с таблицами, не имеет смысла ускорять обработку одной цифры, за счёт риска перестать помещаться в кэш...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: Оптимизированная версия
От: Erop Россия  
Дата: 23.12.08 01:59
Оценка:
Здравствуйте, Pro100Oleh, Вы писали:

PO>Распараллерировать не интересно. Здесь нужен математических подход в решении задачи, который бы позволил на порядок уменьшить сложность вычислений. Играться же в командах, чтобы выполнить оператор не за 5 тактов, а за 4 — малоэффективно (пусть и увеличится скорость работы в 2-3 раза). Возращаясь к параллельности — распараллерировать нужно не саму итерацию умножение числа 2^x на 2 и далее проверку на нули. Нужно, чтобы был один главный поток, который бы давал своим рабочим потокам задачу: проверитьвсе числа в диапазоне 2^x ... 2^(x+1000) например. Здесь бы ядра использовались в полную силу.


Можно хорошо распарарллелить, на самом деле. И просто довольно. Только мне пока некогда и машин многоголовых всё равно нету.
Могу отладить на двухголовой, и выложить, если есть желающие/могущие на кластере запустить...

Общая идея такая, что тормоза начинаются на реально длинных числах. Скажем на числах длинною в десятки миллионов цифр. Соответственно такую задачу и надо параллелить. Параллелить надо так. Каждый процесс идёт по куску числа и всё что надо считает. Доходит до какой-то границы, скажем в миллион цифр, и отдаёт задание в очередь для следующего процесса. А сам возвращается ждать задания от предыдущего. Будет линейно масштабироваться...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: Оптимизированная версия
От: vadimcher  
Дата: 23.12.08 03:10
Оценка:
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, Pro100Oleh, Вы писали:


PO>>Распараллерировать не интересно. Здесь нужен математических подход в решении задачи, который бы позволил на порядок уменьшить сложность вычислений. Играться же в командах, чтобы выполнить оператор не за 5 тактов, а за 4 — малоэффективно (пусть и увеличится скорость работы в 2-3 раза). Возращаясь к параллельности — распараллерировать нужно не саму итерацию умножение числа 2^x на 2 и далее проверку на нули. Нужно, чтобы был один главный поток, который бы давал своим рабочим потокам задачу: проверитьвсе числа в диапазоне 2^x ... 2^(x+1000) например. Здесь бы ядра использовались в полную силу.


E>Можно хорошо распарарллелить, на самом деле. И просто довольно. Только мне пока некогда и машин многоголовых всё равно нету.

E>Могу отладить на двухголовой, и выложить, если есть желающие/могущие на кластере запустить...

E>Общая идея такая, что тормоза начинаются на реально длинных числах. Скажем на числах длинною в десятки миллионов цифр. Соответственно такую задачу и надо параллелить. Параллелить надо так. Каждый процесс идёт по куску числа и всё что надо считает. Доходит до какой-то границы, скажем в миллион цифр, и отдаёт задание в очередь для следующего процесса. А сам возвращается ждать задания от предыдущего. Будет линейно масштабироваться...


Мне тоже подумалось сначала что-то навроде этого. Т.е. если длина n*k цифр, то n головам отдаем по k цифр на растерзание, причем следующим образом: i-я голова получает на вход цифры c (i-1)*k+1 по i*k а также перенос от правого соседа, который можно тут же вычислить (если правое число начинается с 5 или больше, то будет перенос в эту часть, если нет -- то не будет), далее умножает свою часть на два с прибавлением полученного переноса, а также игнорируя возможный перенос в левую часть (он уже учтен у соседа слева при получении задания) и возвращает вектор значений (l, lb, le), где l -- максимальная найденная строка из нулей, lb -- длина строки из нулей в начале, le -- длина строки из нулей в конце. Все, что остается, только "скомпостировать" результаты, пока головы трудятся над своей частью дальше. Далее, если грамотно организовать, то можно сначала самой левой голове выделить кусок поменьше, а остальным -- одинаковые большие. Тогда в течение многих циклов все могут трудиться над своим куском без остановок, ну а у самого левого длина куска будет расти. Как только она достигнет длины всех остальных кусков происходит синхронное перераспределение кусков.

К сожалению, глобально это проблемы не решит. Действительно, как уже обратили внимание, a(n) растет экспоненциально. loga(n) выглядит как прямая, допустим, что она такая и есть, по крайней мере для "видимого диапазона" это почти так (далее никто не бывал, так что остается только догадываться). Вот результат, полученный на коленке в Excel: log[a(n)+1]=n/2+1/2 (на самом деле полученные коэффициент и константа оба равны 0.497), короче a(n)=sqrt(10^(n+1)). Число цифр m в таких числах связано соотношением m-1<lg2*a(n)~0.30103*a<m, т.е.
m~0.3*a(n)~0.3*10^[(n+1)/2]. Т.е. при увеличении n на два, число цифр увеличивается где-то в десять раз. А значит, чтобы просчитать очередные две цифры с той же скоростью надо в десять раз больше компов (голов). Не хило. Т.е. если хотим до a(17) быстренько досчитать, то надо найти 100 добровольцев . Причем подключать их будем последовательно по мере роста числа.

Кстати, последнюю аппроксимацию можно проверить:
для n=11 дает 0.3*10^6=300000 цифр, истинное значение 345674
для n=12 дает 0.3*10^6.5=948683 цифр, истинное значение 1215059
для n=13 дает 0.3*10^7=3000000 цифр, истинное значение 1215060 -- в 2 с половиной раза меньше, но a(13) на самом деле оказалось равным a(12)+1
А так порядок держит вроде.

А вот зайца кому, зайца-выбегайца?!
Re[9]: k нулей
От: Seon  
Дата: 23.12.08 08:05
Оценка:
Здравствуйте, Pro100Oleh, Вы писали:

1. Вы в каждом элементе храните число от 0 до 9? Или от 0 до 999999999?
2. Как у вас получилось вот это
PO>a(12) = 4036338. Time 00:46:04.8292335, Length 1215059
при вот этом
PO>
PO>        public static readonly int MaxSegments = 1000000;
PO>        m_number = new int[MaxSegments];
PO>

???
4. В функции Check — похоже на перевод из двоичной системы в десятичную... Но я не до конца понял что там происходит.. можете пояснить?

В общем идея понятна в таком смысле, поправьте если не так:

В каждом инте храним числа от 0 до 999999999. (только мне не понятно максвалуе = 9 )
+ легко умножать.
+ колоссальная экономия памяти
-- тяжело искать десятичные 0. для этого надо переводить в 10-ю каждый инт, при чем потом каждое переведенное число шерстить на нули.
не понятно как достигнута скорость (если не брать во внимание разгон )


и последнее: как на вашем мегакомпьютере будет работать версия, где 1 байт хранит 1 число от 0 до 9? (по скорости)
Re[2]: Оптимизированная версия
От: Seon  
Дата: 23.12.08 08:58
Оценка:
Здравствуйте, Roman Odaisky, Вы писали:

RO>Хорошо бы запустить разные решения на одном компьютере, кое-чем померяться .


Вот мое решение здесь
Автор: Seon
Дата: 20.12.08
.
язык C++
Re[2]: k нулей
От: vadimcher  
Дата: 23.12.08 22:34
Оценка:
Здравствуйте, Beam, Вы писали:

B>Здравствуйте, vadimcher, Вы писали:


V>>Докажите, что для любого k найдется такое число n, что в десятичной[i] записи числа 2^n, встречается k нулей подряд.


B>Решение этой части этюда


Мне твое доказательство пока не до конца ясно. Пройдемся...

B>Т.е. имеем последовательность f(k) = 5, 22, 103, 504, 2505, 12506, 62507, 312508 ...

B>Обобщив ее получаем f(k) = 100*5^(k-3) + k
B>Как уже сказал, остатки после некоторого числа начинают повторяться.
B>Найдя эти "последние" остатки получил еще одну интересную последовательность 6, 52, 504, 5008, 50016, 500032, 5000064 ...
B>Обобщив ее получаем g(k) = 5*10^(k-1) + 2^(k-1)
B>Вот такой вот результат.
B>Попытался доказать, что это верно не только для протестированных чисел (k <= 8), но и для всех.

Вопрос 1. Доказал ли ты в итоге, что остатки повторяются (это, впрочем, очевидно), и что формулы f() и g() верны?
Впрочем, может это и не важно для твоего доказательства, т.к. как я понял, то, что ты пытаешься доказать в пункте 1, означает, что g(m) -- возможный остаток при делении [i]некоторой
степени двойки на 10^m. Этого достаточно, т.к. 10^m > g(m). Однако это может оказаться важным, если пункт 1 твоего доказательства неверен.

B>1. Докажем что, для любых целых m > 0, существует целое x, такое что 2^(f(m)-1) = x*10^m + g(m)

[]
B>в) (16^y — 1) делится на 5y, т.к.

Здесь прокол в доказательстве. Во-первых, ты нигде не использовал, что y нечетное, а утверждение очевидно неверное для четных y. Кроме того, 16^13-1 не делится на 65 (число 13 взял наобум, может еще для каких не выполняется).

B>2. Очевидно, что в последовательности g(m) мы найдем число с k нулями.

B>А значит существует такое число n, что при делении 2^n на 10^k получим остаток, содержащий k нулей.
B>Из этого следует решение этюда

Ты, видимо, имел в виду "при делении 2^n на 10^m получим остаток, сожержащий k нулей."

Тем не менее, интересный подход, и такое впечатление, что он может привести к решению.

А вот зайца кому, зайца-выбегайца?!
Re: k нулей
От: Аноним  
Дата: 24.12.08 02:55
Оценка:
Здравствуйте, vadimcher, Вы писали:

V>Докажите, что для любого k найдется такое число n, что в [i]десятичной[i] записи числа 2^n, встречается k нулей подряд.


V>Этюд для программиста.

V>Обозначим минимальное такое n как a(k). Например, a(1)=10, т.к. 2^10=1024 -- минимальная степень двойки, содержащая один ноль (подряд? ). a(2)=53, т.к. 2^53=9007199254740992 -- минимальная степень двойки, содержащая два нуля подряд. Ну и т.д.
V>Найти a(1),...,a(7).

Теоретическая часть доказывается сразу. из утверждения, что степень 2 может начинаться на любую наперед заданную последовательность цифр (берем 10^k)

Схема доказательства первого утверждения — 2^n начинается на число x <=> {n*ln 2} (в смысле дробная часть) лежит в неком непустом интервале. собственно, все... всюду плотность доказывается вручную... ну или гуглом по "критерий Вейля"
Re[3]: k нулей
От: Beam Россия  
Дата: 24.12.08 03:54
Оценка:
Здравствуйте, vadimcher, Вы писали:

V>Вопрос 1. Доказал ли ты в итоге, что остатки повторяются (это, впрочем, очевидно), и что формулы f() и g() верны?

Представим 2^n в виде a*10^k + b (b — остаток от деления на 10^k).
Я говорю, что есть такое m при которых b содержит k нулей. В моем случае b = g(x).
И доказываю, что cуществует n, такое что 2^n можно представить в такой форме. В моем случае n=f(m)-1.
Чтобы доказать возможность представления 2^n в такой форме, я доказываю, что при заданных целых b и 2^n, вычисленных по этим формулам, частное "a" тоже будет целым.

B>>в) (16^y — 1) делится на 5y, т.к.


V>Здесь прокол в доказательстве. Во-первых, ты нигде не использовал, что y нечетное, а утверждение очевидно неверное для четных y. Кроме того, 16^13-1 не делится на 65 (число 13 взял наобум, может еще для каких не выполняется).


Я об этом говорил. y = 5^(m-1), а следовательно нечетно.
А пример не подходит, т.к. 13 не является степенью 5.

B>>2. Очевидно, что в последовательности g(m) мы найдем число с k нулями.

B>>А значит существует такое число n, что при делении 2^n на 10^k получим остаток, содержащий k нулей.
B>>Из этого следует решение этюда

V>Ты, видимо, имел в виду "при делении 2^n на 10^m получим остаток, сожержащий k нулей."


Да. Именно так.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Best regards, Буравчик
Re[2]: k нулей
От: Beam Россия  
Дата: 24.12.08 06:38
Оценка:
Здравствуйте, Beam, Вы писали:

B>Здравствуйте, vadimcher, Вы писали:


V>>Докажите, что для любого k найдется такое число n, что в [i]десятичной[i] записи числа 2^n, встречается k нулей подряд.


B>Решение этой части этюда


B>Предисловие. Пытаясь найти какие-нибудь зависимости в последовательности натолкнулся на интересный результат


B>Написал программку, которая вычисляет количество возможных остатков чисел 2^n при делении их на 10^k

B>Например 1, 2, 4, 8, 16, 32, 64, 128 ... при делении на 10^1 дает остатки 1, 2, 4, 8, 6, 2, 4, 8, 6 ...
B>После некоторого числа остатки начинают повторяться (в данном случае после 6).
B>Количество возможных остатков при делении на 10 равно 5. Это 1, 2, 4, 8 и 6
B>Аналогично для деления на 100 получаем 22 остатка, при делении на 1000 получаем 103 остатка.
B>Т.е. имеем последовательность f(k) = 5, 22, 103, 504, 2505, 12506, 62507, 312508 ...
B>Обобщив ее получаем f(k) = 100*5^(k-3) + k

B>Как уже сказал, остатки после некоторого числа начинают повторяться.

B>Найдя эти "последние" остатки получил еще одну интересную последовательность 6, 52, 504, 5008, 50016, 500032, 5000064 ...
B>Обобщив ее получаем g(k) = 5*10^(k-1) + 2^(k-1)

Ой. Примеры не привел.

2^(5-1)
16

2^(22-1)
2097152

2^(103-1)
5070602400912917605986812821504

2^(504-1)
261871248631691349601055175746207932177331363683445183158663309447690703712373
96439066160738607233257207093473020480568073738052367083144426628220715008

2^(2505-1)
60132483752768192589337987035581840778837848281481388329043814365157069039734033365
71723612042541509339239323992416924164947646261625884250430516975500483783435104693
05978499434759066365745810932149966577954528288850798772444024927951838520227542350
58879180375008327907459992704354324702525063610134325603963613584257226698077210866
97965594178563342037853359202620643016368419959048118246112515022278177758493915308
05029190273917571539320710435893386487658970495023503337021002531803558460354723583
98630634564189720424240469835564945762960051260079413879992251123446696070679668135
05060724474749961684572680842562091232767971493355989701146839512474920828253732280
043454304126203636001132485604207238035424461476759780217566076674821411534921911832150016

B>1. Докажем что, для любых целых m > 0, существует целое x, такое что 2^(f(m)-1) = x*10^m + g(m)
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Best regards, Буравчик
Re[2]: k нулей
От: Seon  
Дата: 24.12.08 08:09
Оценка:
Здравствуйте, Beam, Вы писали:

Мне понравилась вот эта последовательность

B>Т.е. имеем последовательность f(k) = 5, 22, 103, 504, 2505, 12506, 62507, 312508 ...
Re[3]: k нулей
От: Beam Россия  
Дата: 24.12.08 08:44
Оценка:
Здравствуйте, Seon, Вы писали:

S>Мне понравилась вот эта последовательность


B>>Т.е. имеем последовательность f(k) = 5, 22, 103, 504, 2505, 12506, 62507, 312508 ...


Этот кусок последовательности сломается после 598, 599, ...
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Best regards, Буравчик
Re[2]: k нулей - решение на лиспе
От: Spiceman  
Дата: 24.12.08 09:31
Оценка:
Здравствуйте, Spiceman, Вы писали:

S>Больше всего понравилось решение на Хаскеле. В одну строчку — впечатлило!

S>Ради интереса написал на Лиспе (DrScheme):
S>[skip]
S>Работает очень медленно. Зато функционально И что интересно, сам распараллелился на два потока — один строит степени двойки, а другой эти степени фильрует.

Новое решение на лиспе:

#lang scheme
(require srfi/40/stream)
(require srfi/19)

;Числа представлены по основанию k в виде списка.

(define (base k)
  (if (< k 14)
      (cond ((= k 0) 1)
            ((= k 1) 10)
            ((= k 2) 100)
            ((= k 3) 1000)
            ((= k 4) 10000)
            ((= k 5) 100000)
            ((= k 6) 1000000)
            ((= k 7) 10000000)
            ((= k 8) 100000000)
            ((= k 9) 1000000000)
            ((= k 10) 10000000000)
            ((= k 11) 100000000000)
            ((= k 12) 1000000000000)
            ((= k 13) 10000000000000))
      (cond ((= k 14) 100000000000000)
            ((= k 15) 1000000000000000)
            ((= k 16) 10000000000000000)
            ((= k 17) 100000000000000000)
            ((= k 18) 1000000000000000000)
            ((= k 19) 10000000000000000000))))

;p - показатель степени двойки, b - основание системы.
(define (make-number p b)
  (define (iter n)
    (if (= n 0)
        '()
        (cons (remainder n b)
              (iter (quotient n b)))))
  (iter (expt 2 p)))

;s - список, m - знак переноса разрядов, b - основание системы.
(define (double-list s m b)
  (if (null? s)
      (if (= m 0)
          '()
          (cons m '()))
      (let ((n (* (car s) 2)))
        (let ((c (+ n m)))
          (if (>= n b)
              (cons (- c b)
                    (double-list (cdr s) 1 b))
              (cons c
                    (double-list (cdr s) 0 b)))))))

(define (order n k)
  (if (>= n (base k))
      (+ k 1)
      (order n (- k 1))))

(define (mult n p)
  (if (odd? n)
      false
      (let ((b (base p)))
        (if (= (remainder n b) 0)
            true
            false))))

;s - список, p - порядок предыдущего числа в списке, k - проверяемое число нулей.
(define (check s p k)
  (if (null? s)
      false
      (if (= (car s) 0)
          true
          (if (mult (car s) p)
              true
              (check (cdr s) (order (car s) k) k)))))

;k - проверяемое число нулей, s - текущее число, p - показатель степени двойки этого числа.
(define (start k s p)
  (if (check s k k)
      (begin ((println (cons p k))
              (start (+ k 1) (make-number (+ p 1) (base (+ k 1))) (+ p 1))))
      (start k (double-list s 0 (base k)) (+ p 1))))

(define (println x)
  (newline)
  (display x)
  (display (date->string (current-date) "~r")))

(define run (start 1 '(1) 0))


Числа представлены списком. Каждый элемент — это разряд числа в системе по основанию 10^k, где k — проверяемое число нулей.

Уже не стыдно показать результаты (виртуальный сервер Xeon 3ГГц, 384Мб):
(10 . 1)01:12:57 PM
(53 . 2)01:12:57 PM
(242 . 3)01:12:57 PM
(377 . 4)01:12:57 PM
(1491 . 5)01:12:57 PM
(1492 . 6)01:12:57 PM
(6801 . 7)01:12:57 PM
(14007 . 8)01:12:58 PM
(100823 . 9)01:14:16 PM
(559940 . 10)02:49:41 PM
Re[3]: k нулей - решение на лиспе
От: Seon  
Дата: 24.12.08 10:28
Оценка:
Здравствуйте, Spiceman, Вы писали:

А можно идею алгоритма в кратце, а то не все понятно
Все же не очень быстро...
А почему списком?
Re[5]: С++ версии...
От: Аноним  
Дата: 24.12.08 12:52
Оценка:
У меня вышла вот такая вещь...

#include <stdio.h>
#include <string.h>
#include <vector>
#include <time.h>
// constants
const unsigned int BlockSize = 1023;
// group of digits
struct digitgroup
{
  digitgroup(): binary(0L) { }
  digitgroup(unsigned int bin): binary(bin) { }
  union
  {
    struct
    {
      unsigned char digit0: 4;
      unsigned char digit1: 4;
      unsigned char digit2: 4;
      unsigned char digit3: 4;
      unsigned char digit4: 4;
      unsigned char digit5: 4;
      unsigned char digit6: 4;
      unsigned char digit7: 4;
    };
    unsigned int binary;
  };
};
// block of digits
struct digitblock
{
  // create one block using carry value
  digitblock(unsigned char carry = 0)
  {
    for (int i = 0; i < BlockSize; groups[i++].binary = 0L);
    if (carry)
    {
      count = 1;
      groups[0].digit0 = 1;
    }
    else
      count = 0;
  }
  digitgroup groups[BlockSize];
  unsigned int count;
};
// vector of pointers to digit blocks
typedef std::vector<digitblock*> digitvector;
// temporary and total execution result
struct result
{
  result(): carry(0), zeros(0), maxzeros(0) { }
  unsigned char carry;
  unsigned short zeros;
  unsigned short maxzeros;
};
// multiply one digit
inline unsigned char multiply(unsigned char digit, result& r)
{
  // multiply digit
  digit <<= 1;
  digit += r.carry;
  // check carry
  if (digit > 9)
  {
    r.carry = 1;
    digit -= 10;
  }
  else
    r.carry = 0;
  // count zeros
  if (digit)
  {
    r.maxzeros = r.zeros > r.maxzeros ? r.zeros : r.maxzeros;
    r.zeros = 0;
  }
  else
    ++r.zeros;
  // return result
  return digit;
}
// multiply one digit group by two
inline void multiply(digitgroup& part, result& r)
{
  // mult digits
  part.digit0 = multiply(part.digit0, r);
  part.digit1 = multiply(part.digit1, r);
  part.digit2 = multiply(part.digit2, r);
  part.digit3 = multiply(part.digit3, r);
  part.digit4 = multiply(part.digit4, r);
  part.digit5 = multiply(part.digit5, r);
  part.digit6 = multiply(part.digit6, r);
  part.digit7 = multiply(part.digit7, r);
}

void multiply(digitblock& dblock, result& r)
{
  // multiply all groups in block
  for (digitgroup *i = dblock.groups, *end = dblock.groups + dblock.count; i != end; multiply(*(i++), r));
  // if we have carry and some free groups in block,
  // then initialize new group and clear carry
  if (r.carry && dblock.count < (BlockSize - 1))
  {
    dblock.groups[dblock.count++].digit0 = 1;
    r.carry = 0;
  }
}

void multiply(digitvector& digits, result& r)
{
  for (digitvector::iterator i = digits.begin(), end = digits.end(); i != end; multiply(**(i++), r));
  // if carriage taken out of last block, create, initialize and process new one
  if (r.carry)
  {
    digits.push_back(new digitblock());
    multiply(*(digits.back()), r);
  }
}

size_t digitscount(const digitvector& digits)
{
  if (!digits.size())
    return 0;
  // count full blocks, each block contains BlockSize groups, each group contains 8 digits
  size_t sz = (digits.size() - 1) * BlockSize * 8;
  // count full groups in last block which can't be empty, each group contains 8 digits
  sz += (digits.back()->count - 1) * 8;
  // count active digits in last group
  digitgroup &i = digits.back()->groups[digits.back()->count - 1];
  if (i.digit7) return sz+8;
  if (i.digit6) return sz+7;
  if (i.digit5) return sz+6;
  if (i.digit4) return sz+5;
  if (i.digit3) return sz+4;
  if (i.digit2) return sz+3;
  if (i.digit1) return sz+2;
  if (i.digit0) return sz+1;
  return sz;
}

void printtime(clock_t t)
{
  size_t msecs = t % CLOCKS_PER_SEC;
  size_t secs = (t / CLOCKS_PER_SEC) % 60;
  size_t mins = (t / CLOCKS_PER_SEC / 60) % 60;
  size_t hours = t / CLOCKS_PER_SEC / 3600;
  printf("[%02u:%02u:%02u.%03u]", hours, mins, secs, msecs);
}

void checkzeros(digitvector& digits, size_t& power, size_t& border, size_t zeros)
{
  for (result r = result(); r.maxzeros < zeros;)
  {
    r = result();
    power++;
    multiply(digits, r);
    if (!(power % border))
    {
      printf("Reached %u power of 2, %u digits total\n", power, digitscount(digits));
      border *= 10;
      fflush(stdout);
    }
  }
  printtime(clock());
  printf(" a(%u) = %u, %u digits total\n", zeros, power, digitscount(digits));
  fflush(stdout);
}

int main(int argc, char** argv)
{
  digitvector digits;
  digits.push_back(new digitblock(1));
  size_t power = 0;
  size_t border = 1000;
  size_t zeros = 1;
  while(true)
    checkzeros(digits, power, border, zeros++);
}

простенько до одури, но вроде работает
слегка оптимизировал работу с памятью за счёт блоков
результаты пока такие
[00:00:00.000] a(1) = 10, 4 digits total
[00:00:00.000] a(2) = 53, 16 digits total
[00:00:00.000] a(3) = 242, 73 digits total
[00:00:00.000] a(4) = 377, 114 digits total
Reached 1000 power of 2, 302 digits total
[00:00:00.000] a(5) = 1491, 449 digits total
[00:00:00.000] a(6) = 1492, 450 digits total
[00:00:00.062] a(7) = 6801, 2048 digits total
Reached 10000 power of 2, 3011 digits total
[00:00:00.296] a(8) = 14007, 4217 digits total
Reached 100000 power of 2, 30127 digits total
[00:00:15.734] a(9) = 100823, 30375 digits total
[00:08:06.140] a(10) = 559940, 168719 digits total
Re: k нулей
От: Ovl Россия  
Дата: 24.12.08 14:46
Оценка:
на шарпе никто не выкладывал?



Found KNumber 0 with power 1
Found KNumber 1 with power 10
Found KNumber 2 with power 61
Found KNumber 3 with power 271
Found KNumber 4 with power 583
      power 1000 calculated in 28 ms
Found KNumber 5 with power 1330
Found KNumber 6 with power 1492
      power 2000 calculated in 59 ms
      power 3000 calculated in 131 ms
      power 4000 calculated in 208 ms
      power 5000 calculated in 348 ms
      power 6000 calculated in 563 ms
Found KNumber 7 with power 6802
      power 7000 calculated in 817 ms
      power 8000 calculated in 963 ms
      power 9000 calculated in 1131 ms
      power 10000 calculated in 1315 ms
      power 11000 calculated in 1518 ms
      power 12000 calculated in 1742 ms
      power 13000 calculated in 1983 ms
      power 14000 calculated in 2246 ms
Found KNumber 8 with power 14007
      power 15000 calculated in 2526 ms
      power 16000 calculated in 2830 ms
      power 17000 calculated in 3149 ms
      power 18000 calculated in 3486 ms
      power 19000 calculated in 3849 ms
      power 20000 calculated in 4227 ms
      power 21000 calculated in 4623 ms
      power 22000 calculated in 5100 ms
      power 23000 calculated in 5559 ms
      power 24000 calculated in 6021 ms
      power 25000 calculated in 6494 ms
      power 26000 calculated in 6993 ms
      power 27000 calculated in 7505 ms
      power 28000 calculated in 8284 ms
      power 29000 calculated in 8838 ms
      power 30000 calculated in 9414 ms
      power 31000 calculated in 10021 ms
      power 32000 calculated in 10633 ms
      power 33000 calculated in 11272 ms
      power 34000 calculated in 11919 ms
      power 35000 calculated in 12587 ms
      power 36000 calculated in 13273 ms
      power 37000 calculated in 13982 ms
      power 38000 calculated in 14705 ms
      power 39000 calculated in 15452 ms
      power 40000 calculated in 16214 ms
      power 41000 calculated in 17008 ms


исходник (3.5)

using System.Collections.Generic;
using System;

using BytePair = System.Collections.Generic.KeyValuePair<byte, byte>;
using System.Diagnostics;
using System.Threading;

namespace KZero
{
    class KNumber
    {
        public int MaxZeroCount;
        public int Power;

        public byte[] NumberPairs;
    }

    class Program
    {
        private static readonly BytePair[] HexAddition = new BytePair[100 + 100];
        private static readonly bool[] HexAdditionExists = new bool[100 + 100];

        private static BytePair InitializeHexAdditionValue(byte val1, byte val2)
        {
            var reminder = (byte)((val1 + val2) % 100);
            var primary = (byte)((val1 + val2 - reminder) / 100);
            return new BytePair(primary, reminder);
        }

        private static int GetHexAdditionIndex(byte val1, byte val2)
        { 
            return val1 + val2;
        }

        private static BytePair GetHexAdditionValue(byte val1, byte val2)
        {
            var index = GetHexAdditionIndex(val1, val2);
            if (HexAdditionExists[index])
                return HexAddition[index];

            HexAdditionExists[index] = true;
            return HexAddition[index] = InitializeHexAdditionValue(val1, val2);
        }

        private static BytePair TripleAdd(byte val1, byte val2, byte val3)
        {
            if (val3 == 0)
            {
                return GetHexAdditionValue(val1, val2);
            }

            var pair1 = GetHexAdditionValue(val1, val2);
            var pair2 = GetHexAdditionValue(pair1.Value, val3);

            return new BytePair((byte)(pair1.Key + pair2.Key), pair2.Value);
        }

        static void Main()
        {
            const bool PrintOutput = false;
            //InitializeHexAddition();

            var kNumber = new KNumber { MaxZeroCount = 0, Power = 0, NumberPairs = new byte[] { 1 } };
            var kNumbers = new Dictionary<int, KNumber>();

            var watch = new Stopwatch();

            while (true)
            {
                watch.Start();
                kNumber = CalculateNextKNumber(kNumber);
                watch.Stop();

                if (kNumber.Power % 1000 == 0)
                    Console.WriteLine("      power " + kNumber.Power + " calculated in " + watch.ElapsedMilliseconds + " ms");

                if (PrintOutput)
                {
                    Console.Write("Power " + kNumber.Power + " calculated in " + watch.ElapsedMilliseconds + " ms - ");

                    var tmp = (byte[])kNumber.NumberPairs.Clone();
                    Array.Reverse(tmp);
                    Array.ForEach(tmp, b => Console.Write(b < 10 ? ("0" + b) : b.ToString()));
                    Console.WriteLine();
                    
                    Thread.Sleep(100);
                }

                if (kNumbers.ContainsKey(kNumber.MaxZeroCount))
                {
                    continue;
                }

                kNumbers[kNumber.MaxZeroCount] = kNumber;
                Console.WriteLine("Found KNumber " + kNumber.MaxZeroCount + " with power " + kNumber.Power);
            }
        }

        private static KNumber CalculateNextKNumber(KNumber seed)
        {
            var nextNumberPairsLength = seed.NumberPairs[seed.NumberPairs.Length - 1] == 0
                ? seed.NumberPairs.Length
                : seed.NumberPairs.Length + 1;

            var nextNumberPairs = new byte[nextNumberPairsLength];
            var kNumber = new KNumber { Power = seed.Power + 1, MaxZeroCount = 0 };

            var append = (byte)0;
            var i = 0;

            for (; i < seed.NumberPairs.Length; i++)
            {
                var val = seed.NumberPairs[i];
                var pair = TripleAdd(val, val, append);

                append = pair.Key;

                nextNumberPairs[i] = pair.Value;
            }

            if (append > 0)
            {
                nextNumberPairs[i] = append;
            }

            if (nextNumberPairs[nextNumberPairs.Length - 1] == 0)
            {
                var tmp = new byte[nextNumberPairs.Length - 1];
                Array.Copy(nextNumberPairs, tmp, tmp.Length);
                nextNumberPairs = tmp;
            }

            kNumber.NumberPairs = nextNumberPairs;
            CalculateMaxZeroCount(kNumber);

            return kNumber;
        }

        private static void CalculateMaxZeroCount(KNumber kNumber)
        {
            var currentZeroCount = 0;

            for (var i = 0; i < kNumber.NumberPairs.Length; ++i)
            {
                switch (kNumber.NumberPairs[i])
                {
                case 0:
                    currentZeroCount += 2;
                    break;
                case 10:
                    currentZeroCount += 1;
                    UpdateKMaxZero(kNumber, currentZeroCount);
                    break;
                case 01:
                    UpdateKMaxZero(kNumber, currentZeroCount);
                    if (i != kNumber.NumberPairs.Length - 1)
                    {
                        currentZeroCount = 1;
                    }
                    break;
                default:
                    UpdateKMaxZero(kNumber, currentZeroCount);
                    currentZeroCount = 0;
                    break;
                }
            }
            UpdateKMaxZero(kNumber, currentZeroCount);
        }

        private static void UpdateKMaxZero(KNumber kNumber, int count)
        {
            if (count > kNumber.MaxZeroCount)
                kNumber.MaxZeroCount = count;
        }
    }
}
Read or Die!
Как правильно задавать вопросы
Как правильно оформить свой вопрос
Автор: anvaka
Дата: 15.05.06
Re[2]: k нулей
От: Ovl Россия  
Дата: 24.12.08 15:08
Оценка:
нет, нули считает неправильно скипаем for now
Read or Die!
Как правильно задавать вопросы
Как правильно оформить свой вопрос
Автор: anvaka
Дата: 15.05.06
Re[3]: k нулей
От: Ovl Россия  
Дата: 24.12.08 15:25
Оценка:
теперь правильно..


Found KNumber 0 with power 1, Number calculated in 3 ms is: 02
Found KNumber 1 with power 10, Number calculated in 3 ms is: 1024
Found KNumber 2 with power 53, Number calculated in 3 ms is: 9007199254740992
Found KNumber 3 with power 242, Number calculated in 3 ms is: 07067388259113537318333190...
Found KNumber 4 with power 377, Number calculated in 4 ms is: 307828173409331868845930000...
Found KNumber 5 with power 1491, Number calculated in 16 ms is: 068505199434441481928960132734923...
Found KNumber 6 with power 1492, Number calculated in 16 ms is: 1370103988688829638579202654698471015372
Found KNumber 7 with power 6801, Number calculated in 242 ms is: 20183687373087460349606707870495174...
Found KNumber 8 with power 14007, Number calculated in 1023 ms is: 33662724701763990788983568556041...
Found KNumber 9 with power 100823, Number calculated in 55332 ms is: 558795409300670784...


считалось на P4 2.6GHz, 3GB Ram

using System.Collections.Generic;
using System;

using BytePair = System.Collections.Generic.KeyValuePair<byte, byte>;
using System.Diagnostics;

namespace KZero
{
    class KNumber
    {
        public int MaxZeroCount;
        public int Power;

        public byte[] NumberPairs;
    }

    class Program
    {
        #region stuff
        private static readonly BytePair[] HexAddition = new BytePair[100 + 100];
        private static readonly bool[] HexAdditionExists = new bool[100 + 100];

        private static BytePair InitializeHexAdditionValue(byte val1, byte val2)
        {
            var reminder = (byte)((val1 + val2) % 100);
            var primary = (byte)((val1 + val2 - reminder) / 100);
            return new BytePair(primary, reminder);
        }

        private static int GetHexAdditionIndex(byte val1, byte val2)
        {
            return val1 + val2;
        }

        private static BytePair GetHexAdditionValue(byte val1, byte val2)
        {
            var index = GetHexAdditionIndex(val1, val2);
            if (HexAdditionExists[index])
                return HexAddition[index];

            HexAdditionExists[index] = true;
            return HexAddition[index] = InitializeHexAdditionValue(val1, val2);
        }

        private static BytePair TripleAdd(byte val1, byte val2, byte val3)
        {
            if (val3 == 0)
            {
                return GetHexAdditionValue(val1, val2);
            }

            var pair1 = GetHexAdditionValue(val1, val2);
            var pair2 = GetHexAdditionValue(pair1.Value, val3);

            return new BytePair((byte)(pair1.Key + pair2.Key), pair2.Value);
        }

        private static void PrintNumber(Stopwatch watch, KNumber kNumber)
        {
            Console.WriteLine("Found KNumber " + kNumber.MaxZeroCount + " with power " + kNumber.Power);
            Console.Write("Number calculated in " + watch.ElapsedMilliseconds + " ms is: ");

            var tmp = (byte[])kNumber.NumberPairs.Clone();
            Array.Reverse(tmp);
            Array.ForEach(tmp, b => Console.Write(b < 10 ? ("0" + b) : b.ToString()));
            Console.WriteLine();
        }

        #endregion stuff

        static void Main()
        {
            var kNumber = new KNumber { MaxZeroCount = 0, Power = 0, NumberPairs = new byte[] { 1 } };
            var kNumbers = new Dictionary<int, KNumber>();

            var watch = new Stopwatch();

            while (true)
            {
                watch.Start();
                kNumber = CalculateNextKNumber(kNumber);
                watch.Stop();

                if (kNumber.Power % 1000 == 0)
                    Console.WriteLine("      power " + kNumber.Power + " calculated in " + watch.ElapsedMilliseconds + " ms");

                if (kNumbers.ContainsKey(kNumber.MaxZeroCount)) {
                    continue;
                }

                kNumbers[kNumber.MaxZeroCount] = kNumber;
                PrintNumber(watch, kNumber);
            }
        }

        private static KNumber CalculateNextKNumber(KNumber seed)
        {
            var nextNumberPairs = new byte[seed.NumberPairs.Length + 1];
            var kNumber = new KNumber { Power = seed.Power + 1, MaxZeroCount = 0 };

            var append = (byte)0;
            var i = 0;

            for (; i < seed.NumberPairs.Length; i++)
            {
                var val = seed.NumberPairs[i];
                var pair = TripleAdd(val, val, append);

                append = pair.Key;

                nextNumberPairs[i] = pair.Value;
            }

            if (append > 0)
            {
                nextNumberPairs[i] = append;
            }

            if (nextNumberPairs[nextNumberPairs.Length - 1] == 0)
            {
                var tmp = new byte[nextNumberPairs.Length - 1];
                Array.Copy(nextNumberPairs, tmp, tmp.Length);
                nextNumberPairs = tmp;
            }

            kNumber.NumberPairs = nextNumberPairs;
            CalculateMaxZeroCount(kNumber);

            return kNumber;
        }

        private static void CalculateMaxZeroCount(KNumber kNumber)
        {
            var currentZeroCount = 0;

            for (var i = 0; i < kNumber.NumberPairs.Length; ++i)
            {
                switch (kNumber.NumberPairs[i])
                {
                case 0:
                    currentZeroCount += 2;
                    break;
                case 10:case 20:case 30:case 40:case 50:case 60:case 70:case 80:case 90:
                    currentZeroCount += 1;
                    UpdateKMaxZero(kNumber, currentZeroCount);
                    currentZeroCount = 0;
                    break;
                case 1:case 2:case 3:case 4:case 5:case 6:case 7:case 8:case 9:
                    UpdateKMaxZero(kNumber, currentZeroCount);
                    if (i != kNumber.NumberPairs.Length - 1)
                    {
                        currentZeroCount = 1;
                    }
                    break;
                default:
                    UpdateKMaxZero(kNumber, currentZeroCount);
                    currentZeroCount = 0;
                    break;
                }
            }
            UpdateKMaxZero(kNumber, currentZeroCount);
        }

        private static void UpdateKMaxZero(KNumber kNumber, int count)
        {
            if (count > kNumber.MaxZeroCount)
                kNumber.MaxZeroCount = count;
        }
    }
}
Read or Die!
Как правильно задавать вопросы
Как правильно оформить свой вопрос
Автор: anvaka
Дата: 15.05.06
Re[4]: k нулей - решение на лиспе
От: Spiceman  
Дата: 24.12.08 19:05
Оценка:
Здравствуйте, Seon, Вы писали:

S>Здравствуйте, Spiceman, Вы писали:


S>А можно идею алгоритма в кратце, а то не все понятно

Да вобщем-то идея примерно та же, что у Pro100Oleh-а. Представляем число в 10-ричной системе, если ищем 1 ноль, в 100-ричной системе, если ищем 2 ноля, и т.д. Число у меня список (начиная с младших разрядов) — например, 512 = (2 1 5), 1024 = (4 2 0 1), 2^53 = (92 09 74 54 92 19 07 90). В таком списке довольно просто найти k нолей подряд. Это так, если:
1. элемент списка равен 0, либо
2. элемент списка (начиная с единиц, то есть слева) меньше 10^m и следующий элемент кратен 10^m. Например, для 2^53 элемент 07 < 10 и 90 кратно 10. m подбирается минимальным.

S>Все же не очень быстро...

Ну я не спец в лиспе, не знаю библиотек и функций. Написал как смог. Спецы, думаю, оптимизировали бы лучше. Теперь попробую тоже на C#

S>А почему списком?

Так получилось
Re[5]: k нулей - решение на лиспе
От: Seon  
Дата: 25.12.08 07:14
Оценка:
Здравствуйте, Spiceman, Вы писали:

S>Здравствуйте, Seon, Вы писали:


S>>Здравствуйте, Spiceman, Вы писали:


S>>А можно идею алгоритма в кратце, а то не все понятно

S>Да вобщем-то идея примерно та же, что у Pro100Oleh-а. Представляем число в 10-ричной системе, если ищем 1 ноль, в 100-ричной системе, если ищем 2 ноля, и т.д. Число у меня список (начиная с младших разрядов) — например, 512 = (2 1 5), 1024 = (4 2 0 1), 2^53 = (92 09 74 54 92 19 07 90). В таком списке довольно просто найти k нолей подряд. Это так, если:
S>1. элемент списка равен 0, либо
S>2. элемент списка (начиная с единиц, то есть слева) меньше 10^m и следующий элемент кратен 10^m. Например, для 2^53 элемент 07 < 10 и 90 кратно 10. m подбирается минимальным.

S>>Все же не очень быстро...

S>Ну я не спец в лиспе, не знаю библиотек и функций. Написал как смог. Спецы, думаю, оптимизировали бы лучше. Теперь попробую тоже на C#

S>>А почему списком?

S>Так получилось

Принципиальный вопрос:
в вашем варианте есть перевод из 2-й в десятичную, или сразу работаете в десятичной?
умножаете 10-тичные числа или 2-ичные?
Re[2]: k нулей
От: vadimcher  
Дата: 25.12.08 16:52
Оценка:
Здравствуйте, Аноним, Вы писали:
А>Теоретическая часть доказывается сразу. из утверждения, что степень 2 может начинаться на любую наперед заданную последовательность цифр (берем 10^k)

А>Схема доказательства первого утверждения — 2^n начинается на число x <=> {n*ln 2} (в смысле дробная часть) лежит в неком непустом интервале. собственно, все... всюду плотность доказывается вручную... ну или гуглом по "критерий Вейля"


Выделенное не понял.

А вот зайца кому, зайца-выбегайца?!
Re[5]: k нулей
От: Beam Россия  
Дата: 26.12.08 14:32
Оценка:
Здравствуйте, vadimcher, Вы писали:

V>И где ты в своем доказательстве того, что 16^y-1 делится на 5y использовал, что y нечетное, или что оно является степенью 5? Вот твое доказательство:

V>

V>16^y — 1 = (15+1)^y — 1,
V>т.е. получим многочлен в котором y+1 членов, один из которых 1 (мы эту единицу отнимаем),
V>а остальные члены являются степенью 15 (таких членов y). Значит и весь многочлен делится на 5y


Да уж. Действительно. Я перечитал это еще раз и ужаснулся
Вообще я изначально доказывал это высказывание, подсчитывая количество множителей 5 в каждом члене выражения (15+1)^y — 1, где y=5^n. Потом меня "осенило", нашел более простое "доказательство" , ну т.е. то, которое я написал. Но, действительно, это не только ничего не доказывает, но и неверно в принципе. Благо, что ответ оказался все же верен.

Исправляю ошибку. Докажем, что 16^y — 1 делится на 5y, где y = 5^n.
Более простое доказательство на основе теоремы Эйлера (к сожалению, я ее не знал, ээх!).

Теорема Эйлера: a^ф(m) === 1 (mod m), ф - функция Эйлера, a и m взаимно просты
ф имеет следующее свойство: ф(p^n) = (p-1)*p^(n-1), когда p - простое

Доказать, что
16^(5^n) - 1 === 0 (mod 5*5^n))
Преобразовываем
2^(4*5^n) === 1 (mod 5^(n+1))
На основе указанного свойства ф, т.к. 5 - простое:
ф(5^(n+1)) = 4*5^n,
Отсюда:
2^(4*5^n) === 1 (mod 5^(n+1)) ч.т.д.


V>>>Вопрос 1. Доказал ли ты в итоге, что остатки повторяются (это, впрочем, очевидно), и что формулы f() и g() верны?

V>Это все понятно. Я тебя про другое, по-моему, спрашивал.

Я все-таки не совсем понял, о чем идет речь.
Что значит верны? Речь об этом?

Для любых целых k > 0, целых n>=0, при делении чисел 2^n на 10^k:
Количество возможных остатков равно f(k)
Последний неповторяющийся остаток равен g(k)


Это можно доказать.
Best regards, Буравчик
Re[6]: k нулей
От: vadimcher  
Дата: 26.12.08 17:29
Оценка:
Здравствуйте, Beam, Вы писали:

B>Исправляю ошибку. Докажем, что 16^y — 1 делится на 5y, где y = 5^n.

B>Более простое доказательство на основе теоремы Эйлера (к сожалению, я ее не знал, ээх!).

Да, именно теоремой Эйлера проще всего доказывать. Просто я хотел обратить твое внимание, что утверждение неверно не только для четных y, но и для многих нечетных, как, например, 13.

B>Я все-таки не совсем понял, о чем идет речь.

B>Что значит верны? Речь об этом?

B>
B>Для любых целых k > 0, целых n>=0, при делении чисел 2^n на 10^k:
B>Количество возможных остатков равно f(k)
B>Последний неповторяющийся остаток равен g(k)
B>


B>Это можно доказать.


Да, именно об этом. Просто в итоге ты использовал конкретные выражения для того, чтобы привести пример остатка (g(m)) при делении некоторой большой степени двойки (f(m)-1) на 10^m. Т.е., как я написал до этого, в твоем доказательстве не важно, действительно ли f() и g() выражают то, с чего ты начал. Т.е. для доказательства это не важно. Тем не менее, просто интересно.

А вот зайца кому, зайца-выбегайца?!
Re[4]: k нулей
От: vadimcher  
Дата: 27.12.08 04:58
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, vadimcher, Вы писали:

V>>Здравствуйте, Аноним, Вы писали:
А>>>Теоретическая часть доказывается сразу. из утверждения, что степень 2 может начинаться на любую наперед заданную последовательность цифр (берем 10^k)
А>>>Схема доказательства первого утверждения — 2^n начинается на число x <=> {n*ln 2} (в смысле дробная часть) лежит в неком непустом интервале. собственно, все... всюду плотность доказывается вручную... ну или гуглом по "критерий Вейля"
V>>Выделенное не понял.

Выделенное я не понял, потому как оно кажется мне неверным. А автор в ответе писал это так, как будто это очевидно. Мне нет. Потому я переспросил.

А>Ну, как я уже говорил, это вопрос с бородой. Поэтому автор поста написал схематично, опуская детали.


Ну с бородой, или нет -- я не знаю. Это мне напоминает, как когда кто-то что-то постит, и обязательно найдется кто-нибудь: "баян!". Баян (по определению ) -- шутка, которую постоянно все пересказывают, и которая уже всем уши пробаянила, а если кто-то что-то там постил три года назад, то это не баян. Не надо путать "небаянность" и "уникальность" сообщения.

Короче, для меня эта задача новая, а потому просто интересно ее красивое решение. Так, в копилку. Я пока видел здесь два таких. Оба в итоге доказываются с помощью теоремы Эйлера. Просто и красиво! Это же решение также выглядит правильным, за исключением того, что вместо того, чтобы говорить, что тут все очевидно, надо было просто аккуратнее написать, что именно доказывается. Видимо, ты как раз и расписал это ниже. Спасибо.

А>Между прочим, а что имелось в виду

А>в условиях задачи: ровно k нулей и на к-ом месте не ноль или имелось в виду как минимум к нулей? Если ровно k нулей, то через теорему Эйлера ответ получить будет тяжело.

Имелось в виду "как минимум", но вторая интерпретация тоже интересная.

А>Теперь расшифрую Анонима.

А>Можно доказать более сильное утверждение: для любого натурального числа найдётся степень двойки, которая на него начинается.
А>Из этого утверждения всё следует.
А>Докажем это более сильное утверждение.
А>Пусть какая-то степень двойки начинается на x, тогда для некоторого m выполняется
А>x*10^m < 2^n <x*10^m+10^m-1
[]
А>Если обозначить очевидно иррациональное число ln(10)/ln(2) через alpha, ln(x) / ln(2) через x1, ln(x+1/10)/ln(2) через
А>x2, то получаем
А>Найти m и n такие, что
А>alpha *m-n лежит в (x1, x2)
А>А это можно доказать самому. Например, через теорему Лиувилля о приближении иррационального числа рациональной дробью.

n-ln(10)/ln(2)*m в (ln(x)/ln(2),ln(x+1/10)/ln(2))
Это утверждение совсем не то, что было в том топике. Поэтому это не пояснение к тому, а скорее попытка решить тем же путем.

А вот зайца кому, зайца-выбегайца?!
Re[5]: k нулей
От: Аноним  
Дата: 27.12.08 22:23
Оценка:
Здравствуйте, vadimcher.
После нового года я постараюсь выложить и саму олимпиадную задачу и решение из сборника задач.

Заодно узнаем насколько она старая.
Re[7]: k нулей
От: Beam Россия  
Дата: 28.12.08 00:01
Оценка:
Здравствуйте, vadimcher, Вы писали:

V>Да, именно об этом. Просто в итоге ты использовал конкретные выражения для того, чтобы привести пример остатка (g(m)) при делении некоторой большой степени двойки (f(m)-1) на 10^m. Т.е., как я написал до этого, в твоем доказательстве не важно, действительно ли f() и g() выражают то, с чего ты начал. Т.е. для доказательства это не важно. Тем не менее, просто интересно.


B>>
B>>Для любых целых k > 0, целых n>=0, при делении чисел 2^n на 10^k:
B>>Количество возможных остатков равно f(k)
B>>Последний неповторяющийся остаток равен g(k)
B>>


1. Последний неповторяющийся остаток равен g(k) = 5*10^(k-1) + 2^(k-1)

Во-первых остатки повторяются (это очевидно и так).
Во-вторых g(k) действительно является остатком (это мы уже доказали).

Следуюший остаток после него будет 2*(5*10^(k-1) + 2^(k-1)) mod 10^k = 2^k
Минимальное n при котором остаток может быть равен 2^k равно k.
Также очевидно, что g(k) не является остатком при n < k.
Из этого следует, что минимальное n для остатка g(k) больше минимального n для остатка 2^k.

А это говорит о том, что для следующего n список остатков зациклится, а значит g(k) является последним неповторяющимся остатком.

2. Чему равно n, которое приводит к остатку g(k)?

Т.к. g() — остаток от деления 2^n на 10^k можем записать:
x*10^k + 5*10^(k-1) + 2^(k-1) = 2^n

Переносим 2^(k-1) и выносим общие множители
5*10^(k-1) * (2x+1) = 2^(k-1) * (2^(n-k+1) — 1)

Делим на 2^(k-1)
5^k (2x+1) = 2^(n-k+1) — 1

Т.е.
2^(n-k+1) === 1 (mod 5^k)

По теореме Эйлера:
a^ф(m) = 1 (mod m)
ф(5^k) = 4*5^(k-1)

Отсюда получаем:
a^(4*5^(k-1)) === 1 (mod 5^k), где a и 5^k взаимно простые

Возвращаясь к нашей степени двойки:
a^(4*5^(k-1)) = 2^(n-k+1)

Логарифмируем по основанию 2:
4*5^(k-1) * log a = n-k+1

Обозначим log a = s, откуда a = 2^s. Заметим также, что s>0 т.к. "a" не может быть 1 (не взаимно простое с 5^k)
n = s*4*5^(k-1) + k — 1, где s >= 1

Это формула n при котором получается остаток g()

3. Количество остатков f(k) = 4*5^(k-1) + k = 100*5^(k-3) + k

Теперь можно определить количество остатков от деления на 10^k
Возьмем минимальное n при котором получается последний неповторяющийся остаток g(k).
Тогда общее количество остатков будет равно n+1 (единицу прибавляем, т.к. степени начинаем считать с нуля)

В нашем случае минимальное n = 4*5^(k-1) + k — 1 (при s = 1)
Откуда f(k) = 4*5^(k-1) + k, ч.т.д.

P.S.Интересно, что остатки, стоящие самыми первыми в списке (т.е. для n < k) никогда не повторяются.
Например существует единственное число 2^n, которое при делении на 100 дает в остатке 2. Это само число 2 ,
т.е. числа вида 2^n никогда не заканчиваются на 02 и т.д.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Best regards, Буравчик
Re: k нулей
От: Seon  
Дата: 13.01.09 08:12
Оценка:
Здравствуйте, vadimcher, Вы писали:

По одному из вариантов программы (пусть не самый быстрый) на процессоре рейтинга 2000 считается 70 000 000 знаков в секунду.


число а17 — это приблизительно миллиардная степень двойки.

для расчета 2^1 000 000 000 придется обработать (1000000000 ^ 2) / (2 * 3.31) знаков. (3.31 — коэффициент ширины десятичного представления степени двойки)
итого это 151 057 401 812 688 821 знаков.
для их расчета 1-му процессору потребуется 2 157 962 883 секунд
или 599 434 часов
или 24 976 суток
или 68 лет

если на эту задачу бросить 70 процессоров, то потребуется почти год.

явно, что а17 расчитывалось, либо каким то другим способом (не удвоением), либо на каком то жутко мощном майнфрэйме
ну или на огромном количестве компов...
Re[7]: Эх, олимпиадников на вас нету...
От: Erop Россия  
Дата: 14.01.09 23:42
Оценка:
Здравствуйте, Аноним, Вы писали:

А>К сожалению, я так и не нашёл книги с решением задачи с помощью логарифмов.

Да его легко восстановить, вообще-то.

Пусть у нас есть An = 2**n;
Найдём число Q(n, k), представляющее k старших цифр An:

Это будет Q(n, k) = 2**n / 10**q(n), где q(n) = [log10( 2**n )] — k = [n log10( 2 )] — k.
(тут [х] обозначает "целая часть х")
Соотвественно, log10 Q(n, k) = log10( 2**n / 10**q(n) ) = n*log10( 2 ) — q(n) = n*log10( 2 ) + k — [n log10( 2 )]
То есть log10 Q(n, k) = k + { n log10( 2 ) }, где {x} -- это дробная часть x.

Довольно очевидно, что для любого иррационального x последовательность Bn = { n x } всюду плотна на [0, 1] (под "всюду плотна" я имею в виду, что в любой окрестности любой точки отрезка найдётся хотя бы одна точка из Bn)

Но это обозначает, что Q(n, k) принимает все значения на [10**k, 10**(k+1) — 1]...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[8]: Док-во очевидного факта про Bn
От: Erop Россия  
Дата: 14.01.09 23:55
Оценка:
E>Довольно очевидно, что для любого иррационального x последовательность Bn = { n x } всюду плотна на [0, 1] (под "всюду плотна" я имею в виду, что в любой окрестности любой точки отрезка найдётся хотя бы одна точка из Bn)

Если кому не очевидно, то вот док-во:

Рассмотрим наматывание на окружность радиуса 1/(2pi) угла в x радиан. По условию х иррационально, соответственно несоизмеримо с длинной нашей окружности, равной 1.
То есть если мы будем брать углы в Bn радиан, то ни при каких n != m не получится так, что точки Bn и Bm совпадут.
Соотвественно, мы всегда можем поставить на окружности столько разных точек, сколько нам надо.

Рассмотрим теперь диапазон углов длины 2a > 0. (скажем такой: [t0-a, t0+a]). Докажем, что в нём обязательно найдётся одна из точек Bn.

Лема 1. Найдутся два такие k < m, что расстояние от Bk до Bm на окружности будет меньше, чем 2a. Это очевидно, так как если мы возьмём первые [1 / a] + 1 точек, то где-то на окружности должно найтись две точки, на расстоянии меньшем чем 2a... Выберем ту из них, у которой меньший индекс за Bk, а ту, у которой больший за Bm.

Лема 2.
Очевидно, что длинна отрезка [Bn, Bn+k] зависит только от k, просто в силу осевой симметрии окружности

Лема 3.
Можно покрыть всю окружность точками, отстоящими друг от друга менее, чем на 2a.
Тоже очевидно. Берём пару точек из леммы 1, и с таким шагом покрываем постепенно всю окружность с шагом меньшем чем 2a

Ну, а из этого всего следует, что найдётся точка в диапазоне углов [t0-a, t0+a], для любого t0 и любого положительного a...

ЧТД.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: k нулей
От: Seon  
Дата: 16.01.09 08:36
Оценка:
Здравствуйте, nikholas, Вы писали:

А можешь посчитать сколько времени уйдет для этого алгоритма на нахождение а14 ?
Re[3]: k нулей
От: Spiceman  
Дата: 16.01.09 08:41
Оценка:
Здравствуйте, nikholas, Вы писали:

N>Аппроксимация времени — квадратичная, и до арда потребуется примерно 667*(1.000.000.000 / 4.036.338)^2 = 40.000.000 сек = 11.111 час = 462 дня


Круто! Тоже думал про такую оптимизацию, но не думал, что это даст такой прирост производительности.

Чувствую, близок день, когда RSDN BruteForce Team посчитает a(18)
Re[4]: k нулей
От: Seon  
Дата: 16.01.09 09:43
Оценка:
Здравствуйте, Spiceman, Вы писали:

S>Здравствуйте, nikholas, Вы писали:


N>>Аппроксимация времени — квадратичная, и до арда потребуется примерно 667*(1.000.000.000 / 4.036.338)^2 = 40.000.000 сек = 11.111 час = 462 дня


S>Круто! Тоже думал про такую оптимизацию, но не думал, что это даст такой прирост производительности.


S>Чувствую, близок день, когда RSDN BruteForce Team посчитает a(18)


Кстати у меня получилось сделать распределенный вариант этой задачи
Сейчас уже приближаюсь к 50 000 000. (а14)
Расчет ведется одновременно на 8 компах, при чем по моему медленному, и неоптимизированному всякими такими фичами

Задача разбивается на "квадратные" блоки, каждый из которых считает отдельный экземпляр задачи.
Текущий размер блока 100000х200000 знаков. Считается такой блок около 5 минут.
Скорость расчета прямо пропорциональна количеству компов, на которых запущена эта задача. Кого интересует могу поделиццо кодом (С++)
Re[5]: k нулей
От: Spiceman  
Дата: 16.01.09 09:58
Оценка:
Здравствуйте, Seon, Вы писали:

S>Кстати у меня получилось сделать распределенный вариант этой задачи

S>Сейчас уже приближаюсь к 50 000 000. (а14)
S>Расчет ведется одновременно на 8 компах, при чем по моему медленному, и неоптимизированному всякими такими фичами

Тоже вот хотел распределенную написать. Но после ответа nikholas, захотелось сначала прикрутить его идею.

S>Задача разбивается на "квадратные" блоки, каждый из которых считает отдельный экземпляр задачи.

S>Текущий размер блока 100000х200000 знаков. Считается такой блок около 5 минут.
S>Скорость расчета прямо пропорциональна количеству компов, на которых запущена эта задача. Кого интересует могу поделиццо кодом (С++)

У меня на C# многопроцессорный вариант — посчитал до 2^16млн за 8 часов на двухядернике.
Лучше делиться не кодом, а идеями, чтобы их можно было в свой код прикручивать.
Re[4]: k нулей
От: nikholas Россия  
Дата: 16.01.09 10:10
Оценка:
Здравствуйте, Seon, Вы писали:

S>Здравствуйте, nikholas, Вы писали:


S>А можешь посчитать сколько времени уйдет для этого алгоритма на нахождение а14 ?


а14 : 667*(53.619.497 / 4.036.338)^2 = 117705 сек = 32 часа
a15 : 667*(119.476.156 / 4.036.338)^2 = 584404 сек = 162 часа
a16 : 667*(146.226.201 / 4.036.338)^2 = 243 часа — всего 10 суток!

К меня есть идеи как распараллелить, но ускорение в 2 раза не особо поможет, а других систем под рукой нет
Re[6]: k нулей
От: Seon  
Дата: 16.01.09 11:31
Оценка:
Здравствуйте, Spiceman, Вы писали:

S>Здравствуйте, Seon, Вы писали:


S>>Кстати у меня получилось сделать распределенный вариант этой задачи

S>>Сейчас уже приближаюсь к 50 000 000. (а14)
S>>Расчет ведется одновременно на 8 компах, при чем по моему медленному, и неоптимизированному всякими такими фичами

S>Тоже вот хотел распределенную написать. Но после ответа nikholas, захотелось сначала прикрутить его идею.


S>>Задача разбивается на "квадратные" блоки, каждый из которых считает отдельный экземпляр задачи.

S>>Текущий размер блока 100000х200000 знаков. Считается такой блок около 5 минут.
S>>Скорость расчета прямо пропорциональна количеству компов, на которых запущена эта задача. Кого интересует могу поделиццо кодом (С++)

S>У меня на C# многопроцессорный вариант — посчитал до 2^16млн за 8 часов на двухядернике.

S>Лучше делиться не кодом, а идеями, чтобы их можно было в свой код прикручивать.

Легко.
Вариант мультиматериночный

Что из себя представляет это число?
Треугольник знаков.
                      1
                     11
                    111
                   1111
                  11111
                 111111
                1111111
               11111111
              111111111
             1111111111
            11111111111
           111111111111
          1111111111111
         11111111111111
        111111111111111
       1111111111111111
      11111111111111111
     111111111111111111
    1111111111111111111
   11111111111111111111
  111111111111111111111
 1111111111111111111111
11111111111111111111111


Видно, что его легко разбить на блоки вот так

                      1
                     11
                    111
                   1111
                  11111
                 322222
                3322222
               33322222
              333322222
             3333322222
            65555544444
           665555544444
          6665555544444
         66665555544444
        666665555544444
       1999998888877777
      11999998888877777
     111999998888877777
    1111999998888877777
   11111999998888877777

и так далее

После вычисления каждого блока имеем 2 файла результатов:
      1
      2
      4
      8
     16
     32
     64
    128
    256
    512
  1 024
  2 048
  4 096 
  8 192
--6 384                    
|
| 2 768 - это файл результата по ширине блока
|
|
--> 1 2 4 8 6 - это файл результата по высоте блока


Каждый из файлов будет исходными данными для следующего блока.
Вот основная идея. Можете работать

У меня файл по высоте содержит значение переноса из предыдущего разряда, а не само число, как в примере...
Кроме этого содержит максимальное количество нулей подряд из вычисленного куска числа, и количество нулей в конце этого числа — потому как число нового блока может начаться с нулей и надо знать сколько их было в предыдущем блоке.
Этот файл содержит 1 слово на каждое значение последовательности:
ABBBBBBB 0CCCCCCC
A — бит переноса из предыдущего разряда
B — максимальное количество нулей
C — количество нулей на конце блока


Разбивка вычисления на блоки — это только половина задачи.
Вторая половина — это чтобы N запущенных задач брали блоки по порядку и вычисляли:

Примерно так:
      A
     AA
    AAA
   AAAA
  AAAAA
 AAAAAA
AAAAAAA
 111111  - вычисляет экземпляр приложения I
  22222  - вычисляет экземпляр приложения II
   3333  - вычисляет экземпляр приложения III
    444  - вычисляет экземпляр приложения IV
     55  - вычисляет экземпляр приложения V
      6  - вычисляет экземпляр приложения VI


A — уже посчитанные числа
Жирным показаны текущие вычисляемые блоки
Если вот для этого примера сейчас запустить 7-й экземпляр, программа будет ожидать появления свободной задачи. Он появится как только экземпляр приложения VI перейдет к следующему левому блоку.

Сейчас у меня расчитана уже 35 000 000 степень. Так как размер блока у меня 100000х200000, то имеем уже 175 строку. Количество блоков по ширине = 105.
То есть одновременно можно запустить 105 компов.

В моем варианте программа просто натравливается на расшаренный по сети каталог с файлами результатов, захватывает 2 из них, вычисляет блок, и записывает в этот каталог результаты, затем цикл повторяется.
Но лучше сделать такой вариант: Одна программа — сервер-шедулер, занимается менеджментом заданий, остальные — клиенты: запрашивают у сервера задачи, вычисляют и отдают результаты назад.
Re[5]: k нулей
От: nikholas Россия  
Дата: 16.01.09 15:53
Оценка:
Здравствуйте, Seon, Вы писали:

S>Здравствуйте, Spiceman, Вы писали:


S>>Здравствуйте, nikholas, Вы писали:


N>>>Аппроксимация времени — квадратичная, и до арда потребуется примерно 667*(1.000.000.000 / 4.036.338)^2 = 40.000.000 сек = 11.111 час = 462 дня


S>>Круто! Тоже думал про такую оптимизацию, но не думал, что это даст такой прирост производительности.


S>>Чувствую, близок день, когда RSDN BruteForce Team посчитает a(18)


S>Кстати у меня получилось сделать распределенный вариант этой задачи

S>Сейчас уже приближаюсь к 50 000 000. (а14)
S>Расчет ведется одновременно на 8 компах, при чем по моему медленному, и неоптимизированному всякими такими фичами

S>Задача разбивается на "квадратные" блоки, каждый из которых считает отдельный экземпляр задачи.

S>Текущий размер блока 100000х200000 знаков. Считается такой блок около 5 минут.
S>Скорость расчета прямо пропорциональна количеству компов, на которых запущена эта задача. Кого интересует могу поделиццо кодом (С++)

Боюсь до конца ты не доживешь

Для a17 надо посчитать 10^9 (кол-во строк) * 3*10^8 (~длина 2^1000000000 в десятичном представлении) / 2 знаков, у тебя считается 10^5 * 2*10^5 за 300 сек, скорость < 10^8 знаков в сек., итого тебе потребуется 10^9 * 3 * 10^8 / ( 2 * 10^8) сек = 17000 дней, даже на 100 компах пол-года
Re[6]: k нулей
От: vadimcher  
Дата: 16.01.09 20:21
Оценка:
Здравствуйте, nikholas, Вы писали:

N>Боюсь до конца ты не доживешь


N>Для a17 надо посчитать 10^9 (кол-во строк) * 3*10^8 (~длина 2^1000000000 в десятичном представлении) / 2 знаков, у тебя считается 10^5 * 2*10^5 за 300 сек, скорость < 10^8 знаков в сек., итого тебе потребуется 10^9 * 3 * 10^8 / ( 2 * 10^8) сек = 17000 дней, даже на 100 компах пол-года


Ну полгода на 100 компах это уже "приемлемое" время. Будем кумекать дальше.

А вот зайца кому, зайца-выбегайца?!
Re[3]: k нулей
От: Seon  
Дата: 17.01.09 06:34
Оценка:
Здравствуйте, nikholas, Вы писали:

N>Вот результат:


N>
N>   0.000:  1 :          1 (         1)
N>   0.000:  2 :          2 (         2)
N>   0.000:  3 :        242 (       244)
N>   0.000:  4 :        377 (       296)
N>   0.000:  5 :       1491 (       518)
N>   0.000:  6 :       1492 (       522)
N>   0.000:  7 :       6801 (      1217)
N>   0.000:  8 :      14007 (      1922)
N>   0.469:  9 :     100823 (      9548)
N>  13.797: 10 :     559940 (     47855)
N>  55.641: 11 :    1148303 (     94153)
N> 667.266: 12 :    4036338 (    317876)
N> 667.281: 13 :    4036339 (    317880)
N>


N>Pentium(R)D 3.4 MHz


У меня ваша прога считалась вот так


   0.000:  1 :          1 (         1)
   0.000:  2 :          2 (         2)
   0.000:  3 :        242 (       244)
   0.000:  4 :        377 (       296)
   0.000:  5 :       1491 (       518)
   0.000:  6 :       1492 (       522)
   0.020:  7 :       6801 (      1217)
   0.060:  8 :      14007 (      1922)
   2.680:  9 :     100823 (      9548)
  77.260: 10 :     559940 (     47855)
 308.470: 11 :    1148303 (     94153)


Athlon 2300+ 1 proc
ubuntu g++
Re[4]: k нулей
От: nikholas Россия  
Дата: 17.01.09 12:27
Оценка:
Здравствуйте, Seon, Вы писали:

S>Здравствуйте, nikholas, Вы писали:


N>>Вот результат:


N>>
N>>   0.000:  1 :          1 (         1)
N>>   0.000:  2 :          2 (         2)
N>>   0.000:  3 :        242 (       244)
N>>   0.000:  4 :        377 (       296)
N>>   0.000:  5 :       1491 (       518)
N>>   0.000:  6 :       1492 (       522)
N>>   0.000:  7 :       6801 (      1217)
N>>   0.000:  8 :      14007 (      1922)
N>>   0.469:  9 :     100823 (      9548)
N>>  13.797: 10 :     559940 (     47855)
N>>  55.641: 11 :    1148303 (     94153)
N>> 667.266: 12 :    4036338 (    317876)
N>> 667.281: 13 :    4036339 (    317880)
N>>


N>>Pentium(R)D 3.4 MHz


S>У меня ваша прога считалась вот так



S>
S>   0.000:  1 :          1 (         1)
S>   0.000:  2 :          2 (         2)
S>   0.000:  3 :        242 (       244)
S>   0.000:  4 :        377 (       296)
S>   0.000:  5 :       1491 (       518)
S>   0.000:  6 :       1492 (       522)
S>   0.020:  7 :       6801 (      1217)
S>   0.060:  8 :      14007 (      1922)
S>   2.680:  9 :     100823 (      9548)
S>  77.260: 10 :     559940 (     47855)
S> 308.470: 11 :    1148303 (     94153)
S>


S>Athlon 2300+ 1 proc

S>ubuntu g++

На другой машине у меня так:
0.000: 1 : 1 ( 1)
0.002: 2 : 2 ( 2)
0.002: 3 : 242 ( 244)
0.002: 4 : 377 ( 296)
0.002: 5 : 1491 ( 518)
0.002: 6 : 1492 ( 522)
0.006: 7 : 6801 ( 1217)
0.022: 8 : 14007 ( 1922)
0.872: 9 : 100823 ( 9548)
22.653: 10 : 559940 ( 47855)

AMD Athlon64 3000+ 1.99 GHz
Visual C++ 2005 Express Edition

Видимо дело в размерах кешей
Re[7]: k нулей
От: nikholas Россия  
Дата: 17.01.09 12:29
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, nikholas, Вы писали:


N>>Боюсь до конца ты не доживешь


N>>Для a17 надо посчитать 10^9 (кол-во строк) * 3*10^8 (~длина 2^1000000000 в десятичном представлении) / 2 знаков, у тебя считается 10^5 * 2*10^5 за 300 сек, скорость < 10^8 знаков в сек., итого тебе потребуется 10^9 * 3 * 10^8 / ( 2 * 10^8) сек = 17000 дней, даже на 100 компах пол-года


А>Так вот же и пытаемся придумать оптимальное решение.


А>Вчера сделал еще одну оптимизацию.

А>Теперь у меня система не десятичная а миллиардичная. Каждый знак теперь не от 0 до 9 а от 0 до 999999999!!!
А>Обрабатываем не массив чаров а массив интов. Подобная идея уже кем то тут описывалась... сори не помню
А>Конечно пришлось пожертвовать вычислениями от а1 до а8, но их и так все давно знают

А>ЗАТО это дало прирост в скорости пятикратно!


А>=====================================================

А>a(9) [2^100823] Time: 0:0:0:10
А>a(10) [2^559940] Time: 0:0:5:15
А>a(11) [2^1148303] Time: 0:0:16:38
А>a(12) [2^4036338] Time: 0:2:51:17
А>=====================================================
А>скорость 2.4 * 10^8 знаков в сек
А>по старому у меня а(12) считалось около 13 часов — 5 * 10^7 зн/сек

Круто!

А каким способом подсчитывается кол-во нулей? 9 делений и 9 if-ов ?
Или это просто вычисление 2-в-нужной-степени?
Re[7]: k нулей
От: vadimcher  
Дата: 17.01.09 15:36
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, nikholas, Вы писали:


N>>Боюсь до конца ты не доживешь


N>>Для a17 надо посчитать 10^9 (кол-во строк) * 3*10^8 (~длина 2^1000000000 в десятичном представлении) / 2 знаков, у тебя считается 10^5 * 2*10^5 за 300 сек, скорость < 10^8 знаков в сек., итого тебе потребуется 10^9 * 3 * 10^8 / ( 2 * 10^8) сек = 17000 дней, даже на 100 компах пол-года


А>Так вот же и пытаемся придумать оптимальное решение.


А>Вчера сделал еще одну оптимизацию.

А>Теперь у меня система не десятичная а миллиардичная. Каждый знак теперь не от 0 до 9 а от 0 до 999999999!!!
А>Обрабатываем не массив чаров а массив интов. Подобная идея уже кем то тут описывалась... сори не помню
А>Конечно пришлось пожертвовать вычислениями от а1 до а8, но их и так все давно знают

А>ЗАТО это дало прирост в скорости пятикратно!


А>=====================================================

А>a(9) [2^100823] Time: 0:0:0:10
А>a(10) [2^559940] Time: 0:0:5:15
А>a(11) [2^1148303] Time: 0:0:16:38
А>a(12) [2^4036338] Time: 0:2:51:17
А>=====================================================
А>скорость 2.4 * 10^8 знаков в сек
А>по старому у меня а(12) считалось около 13 часов — 5 * 10^7 зн/сек

Код?

А вот зайца кому, зайца-выбегайца?!
Re[5]: k нулей
От: vadimcher  
Дата: 17.01.09 15:56
Оценка:
Здравствуйте, nikholas, Вы писали:

N>Здравствуйте, Seon, Вы писали:


S>>Здравствуйте, nikholas, Вы писали:


N>>>Вот результат:


N>>>
N>>>   0.000:  1 :          1 (         1)
N>>>   0.000:  2 :          2 (         2)
N>>>   0.000:  3 :        242 (       244)
N>>>   0.000:  4 :        377 (       296)
N>>>   0.000:  5 :       1491 (       518)
N>>>   0.000:  6 :       1492 (       522)
N>>>   0.000:  7 :       6801 (      1217)
N>>>   0.000:  8 :      14007 (      1922)
N>>>   0.469:  9 :     100823 (      9548)
N>>>  13.797: 10 :     559940 (     47855)
N>>>  55.641: 11 :    1148303 (     94153)
N>>> 667.266: 12 :    4036338 (    317876)
N>>> 667.281: 13 :    4036339 (    317880)
N>>>


N>>>Pentium(R)D 3.4 MHz


S>>У меня ваша прога считалась вот так



S>>
S>>   0.000:  1 :          1 (         1)
S>>   0.000:  2 :          2 (         2)
S>>   0.000:  3 :        242 (       244)
S>>   0.000:  4 :        377 (       296)
S>>   0.000:  5 :       1491 (       518)
S>>   0.000:  6 :       1492 (       522)
S>>   0.020:  7 :       6801 (      1217)
S>>   0.060:  8 :      14007 (      1922)
S>>   2.680:  9 :     100823 (      9548)
S>>  77.260: 10 :     559940 (     47855)
S>> 308.470: 11 :    1148303 (     94153)
S>>


S>>Athlon 2300+ 1 proc

S>>ubuntu g++

N>На другой машине у меня так:

N> 0.000: 1 : 1 ( 1)
N> 0.002: 2 : 2 ( 2)
N> 0.002: 3 : 242 ( 244)
N> 0.002: 4 : 377 ( 296)
N> 0.002: 5 : 1491 ( 518)
N> 0.002: 6 : 1492 ( 522)
N> 0.006: 7 : 6801 ( 1217)
N> 0.022: 8 : 14007 ( 1922)
N> 0.872: 9 : 100823 ( 9548)
N> 22.653: 10 : 559940 ( 47855)

N>AMD Athlon64 3000+ 1.99 GHz

N>Visual C++ 2005 Express Edition

N>Видимо дело в размерах кешей


У меня на лаптопе (2x1.87GHz, с наполовину задействованным процессором) Visual C++ 2008 Express дало:
   0.000:  1 :          1 (         1)
   0.000:  2 :          2 (         2)
   0.001:  3 :        242 (       244)
   0.002:  4 :        377 (       296)
   0.004:  5 :       1491 (       518)
   0.005:  6 :       1492 (       522)
   0.011:  7 :       6801 (      1217)
   0.022:  8 :      14007 (      1922)
   0.636:  9 :     100823 (      9548)
  18.600: 10 :     559940 (     47855)
  73.947: 11 :    1148303 (     94153)

А вот зайца кому, зайца-выбегайца?!
Re[8]: k нулей
От: Seon  
Дата: 19.01.09 08:21
Оценка:
Здравствуйте, nikholas, Вы писали:

N>Круто!


N>А каким способом подсчитывается кол-во нулей? 9 делений и 9 if-ов ?

N>Или это просто вычисление 2-в-нужной-степени?

3 ифа
1 деление


int zeros_left(BaseType c)
{
  int z;
  if (c < 10000)
  {
    z = 5;
    if (c < 100)
    {
      z += 2;
      if (c < 10)
        z++;
    }
    else
      if (c < 1000)
        z++;    }
  else
  {
    if (c < 1000000)
    {
      z = 3;
      if (c < 100000)
        z++;
    }
    else
    {
      if (c < 100000000)
      {
        z = 1;
        if (c < 10000000)
          z++;
      }
      else
        z = 0;
    }
  }
  return z;
}

bool zeros_right(BaseType c, int z)
{
  BaseType t;
  switch(z)
  {
  case 1:
    t = 10;
    break;
  case 2:
    t = 100;
    break;
  case 3:
    t = 1000;
    break;
  case 4:
    t = 10000;
    break;
  case 5:
    t = 100000;
    break;
  case 6:
    t = 1000000;
    break;
  case 7:
    t = 10000000;
    break;
  case 8:
    t = 100000000;
    break;
  default:
    return false;
  }
  if ((c % t) == 0)
    return true;
  return false;
}


А теперь кусок вызывающей функции

  BaseType ost = 0;
  bool z = false;
  int nz = 0;
  BaseType res;
  BaseType c;
  for(int n = 0; n < size; ++n)
  {
    c = arr[n];
    res = c << 1;
    if (ost) res++;
    if (res > 999999999)
    {
      c = res - 1000000000;
      ost = 1;
    }
    else
    {
      c = res;
      ost = 0;
    }
    if (c)
    {
      if (zeros_right(c, zeros - nz))
        z = true;
      nz = zeros_left(c);
    }
    else
      nz += 9;
    arr[n] = c;
  }
  if (ost)
    arr[size++] = ost;
  if (z)
  {
    // нашли очередное число нулей
  }
Re[9]: k нулей
От: Seon  
Дата: 19.01.09 11:53
Оценка:
Здравствуйте, Seon, Вы писали:

S>3 ифа

S>1 деление

Пардонте!
Тут пропущен 1 кейс

S>

S>bool zeros_right(BaseType c, int z)
S>{
S>  BaseType t;
S>  switch(z)
S>  {
    case 0:
      return 0;
S>  case 1:
S>    t = 10;
S>    break;
S>  case 2:
S>    t = 100;
S>    break;
S>  case 3:
S>    t = 1000;
S>    break;
S>  case 4:
S>    t = 10000;
S>    break;
S>  case 5:
S>    t = 100000;
S>    break;
S>  case 6:
S>    t = 1000000;
S>    break;
S>  case 7:
S>    t = 10000000;
S>    break;
S>  case 8:
S>    t = 100000000;
S>    break;
S>  default:
S>    return false;
S>  }
S>  if ((c % t) == 0)
S>    return true;
S>  return false;
S>}
S>
Re[9]: k нулей
От: Spiceman  
Дата: 19.01.09 12:30
Оценка:
Здравствуйте, Seon, Вы писали:

S>3 ифа

S>1 деление

Функцию "int zeros_left(BaseType c)" можно сделать так:

return (int)Math.Log10(n) + 1;

У себя в коде я разницы в скорости не увидел.

Функцию "bool zeros_right(BaseType c, int z)" можно сделать так:

return (z == 0) || ((c & Pow2[z]) == 0 && ((c >> z) % Base5[z]) == 0);

Где,
Pow2[] = {0, 1, 3, 7, 15,...}, то есть 2^n — 1.
Base5[] = {1, 5, 25, 125, 625, ...}, то есть 5^n
z — вместо степени 10 использовать показатель степени, то есть, вместо 10 использовать 1, вместо 100 — 2, вместо 1000 — 3 и т.д.
Пояснение. Число делится на 100, если делится на 4 и на 25. В данном слечае:
(c & Pow2[2]) == 0 — проверка делимости на 4,
((c >> z) % Base5[2]) == 0 — проверка делимости на 25.

Код становится менее лапшеобразным без потери скорости.
Re[10]: k нулей
От: Spiceman  
Дата: 19.01.09 12:32
Оценка:
Здравствуйте, Spiceman, Вы писали:

S>
S>return (int)Math.Log10(n) + 1;
S>


S>
S>return (z == 0) || ((c & Pow2[z]) == 0 && ((c >> z) % Base5[z]) == 0);
S>


S>Код становится менее лапшеобразным без потери скорости.


Забыл добавить. В таком виде функции инлайнятся, так как состоят из одной строчки кода с ретурном.
Re[10]: k нулей
От: Seon  
Дата: 19.01.09 13:41
Оценка:
Здравствуйте, Spiceman, Вы писали:

S>Функцию "int zeros_left(BaseType c)" можно сделать так:


Вот тут точно не скажу..
S>
S>return (int)Math.Log10(n) + 1;
S>


Вызывать функцию вычисления логарифма вместо 3-х сравнений???

S>Функцию "bool zeros_right(BaseType c, int z)" можно сделать так:


S>
S>return (z == 0) || ((c & Pow2[z]) == 0 && ((c >> z) % Base5[z]) == 0);
S>

S>Где,
S>Pow2[] = {0, 1, 3, 7, 15,...}, то есть 2^n — 1.
S>Base5[] = {1, 5, 25, 125, 625, ...}, то есть 5^n
S>z — вместо степени 10 использовать показатель степени, то есть, вместо 10 использовать 1, вместо 100 — 2, вместо 1000 — 3 и т.д.
S>Пояснение. Число делится на 100, если делится на 4 и на 25. В данном слечае:
S>(c & Pow2[2]) == 0 — проверка делимости на 4,
S>((c >> z) % Base5[2]) == 0 — проверка делимости на 25.

S>Код становится менее лапшеобразным без потери скорости.


На счет массивов — я как то про них и забыл...

тогда так

BaseType  step[] = {0, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000};

bool zeros_right(BaseType c, int z)
{
  if (z && z < 9)
  {
    if ((c % step[z]) == 0)
      return true;
  }
  return false;
}


Это еще меньше, без всяких проверок делимостей...
Re[11]: k нулей
От: Seon  
Дата: 19.01.09 13:51
Оценка:
Здравствуйте, Seon, Вы писали:

S>
S>BaseType  step[] = {0, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000};

S>bool zeros_right(BaseType c, int z)
S>{
S>  if (z && z < 9)
S>  {
S>    if ((c % step[z]) == 0)
S>      return true;
S>  }
S>  return false;
S>}
S>


Это дало еще 15 процентный прирост в скорости!!!!
Spiceman, благодарю за подсказку!
Re[3]: k нулей
От: Beam Россия  
Дата: 27.01.09 21:30
Оценка:
Здравствуйте, nikholas, Вы писали:

N>- если в N-й степени двойки есть K нулей подряд, то в N+1,N+2,N+3 — не менее (K-1), N+4,N+5,N+6 — не менее (K-2) и т.д.

N>И обратно: если в N-й степени двойки есть не более K нулей подряд, то в N-1 — не более (K+1), N-2,N-3,N-4 — не более (K+2)

Что-то я не могу понять как это может помочь.
Т.к. N у нас возрастает, то польза есть только от первого высказывания, а в нем ничего не сказано про то, что в следующих N будет нулей не больше K +- x.
А значит на сколько "прыгать" непонятно. Во втором высказывании N уменьшается, т.е. пользы нет.

Эффект "прыганья" основан на другом высказывании: если N имеет К нулей, то любое значение [N..N+a] имеет не более K+x нулей.
Вопрос в том каково может быть a и x? И здесь все не так очевидно:

Пример:
.....2015625101.....
.....4031250202..... N — 1 ноль
.....8062500404..... N+1 — 2 нуля
....16125000808..... N+2 — 3 нуля
....32250001616..... N+3 — 3 нуля
....64500003232..... N+4 — 4 нуля
...128000006464..... N+5 — 5 нулей
... << RSDN@Home 1.2.0 alpha 4 rev. 1136>>
Best regards, Буравчик
Re[4]: k нулей
От: nikholas Россия  
Дата: 27.01.09 22:28
Оценка:
Здравствуйте, Beam, Вы писали:

B>Здравствуйте, nikholas, Вы писали:


N>>- если в N-й степени двойки есть K нулей подряд, то в N+1,N+2,N+3 — не менее (K-1), N+4,N+5,N+6 — не менее (K-2) и т.д.

N>>И обратно: если в N-й степени двойки есть не более K нулей подряд, то в N-1 — не более (K+1), N-2,N-3,N-4 — не более (K+2)

B>Что-то я не могу понять как это может помочь.

B>Т.к. N у нас возрастает, то польза есть только от первого высказывания, а в нем ничего не сказано про то, что в следующих N будет нулей не больше K +- x.
B>А значит на сколько "прыгать" непонятно. Во втором высказывании N уменьшается, т.е. пользы нет.

B>Эффект "прыганья" основан на другом высказывании: если N имеет К нулей, то любое значение [N..N+a] имеет не более K+x нулей.

B>Вопрос в том каково может быть a и x? И здесь все не так очевидно:

B>Пример:

B>.....2015625101.....
B>.....4031250202..... N — 1 ноль
B>.....8062500404..... N+1 — 2 нуля
B>....16125000808..... N+2 — 3 нуля
B>....32250001616..... N+3 — 3 нуля
B>....64500003232..... N+4 — 4 нуля
B>...128000006464..... N+5 — 5 нулей

Вот именно! Количество нулей может возрастать практически +1 ноль на +1 степень! А вот убывает заметно медленнее:

...***00000 * 10^N + Y, Y< 10^N, 5 нулей
...***00000 * 10^N + 2*Y
...***00000 * 10^N + 4*Y
...***00000 * 10^N + 8*Y, не менее 4 нулей
...***00000 * 10^N + 16*Y
...***00000 * 10^N + 32*Y
...***00000 * 10^N + 64*Y не менее 3 нулей
и т.д.

Т. е. теоретически если просматривать N в убывающем порядке то можно проверять не все степени подряд, а заметно меньше.
Но, как Вы правильно заметили, N у нас возрастает.
И если прыгнуть на К степеней вперед иногда можно сразу определить, что среди этих степеней нет ни одной, количество нулей в которой превосходит уже просчитаное. Если нельзы это сразу сказать — по крайней иере можно часто можно пропустить сразу несколько степеней
Re[5]: k нулей
От: Beam Россия  
Дата: 28.01.09 08:57
Оценка:
Здравствуйте, nikholas, Вы писали:

B>>Пример:

B>>.....2015625101.....
B>>.....4031250202..... N — 1 ноль
B>>.....8062500404..... N+1 — 2 нуля
B>>....16125000808..... N+2 — 3 нуля
B>>....32250001616..... N+3 — 3 нуля
B>>....64500003232..... N+4 — 4 нуля
B>>...128000006464..... N+5 — 5 нулей

N>Вот именно! Количество нулей может возрастать практически +1 ноль на +1 степень! А вот убывает заметно медленнее:


Из этого же примера видно, что убывать нули могут с такой же скоростью!

N>И если прыгнуть на К степеней вперед иногда можно сразу определить, что среди этих степеней нет ни одной, количество нулей в которой превосходит уже просчитаное. Если нельзы это сразу сказать — по крайней иере можно часто можно пропустить сразу несколько степеней


Как? Пусть имеем N с количеством нулей 4, нам надо 8 нулей. Какое число (числа) будут проверены после N, т.е. куда будет осуществлен прыжок (прыжки)?
... << RSDN@Home 1.2.0 alpha 4 rev. 1136>>
Best regards, Буравчик
Re[2]: Наконечно досчиталось до а14 !
От: nikholas Россия  
Дата: 28.01.09 09:11
Оценка:
Здравствуйте, Seon, Вы писали:

S>Распределенный вариант программы сегодня нашел а(14) = 2^53619497 !!!!


S>На это ушло 21 день и 2 часа!


S>Одновременно эту задачу считало от 2-х до 8 компов попеременно. В среднем гдето 4-5 штук.

S>Задача без всяких оптимизаций — первоначальный вариант — десятичные числа на чарах!!

S>Продолжать считать думаю на этом варианте нет смысла — до а(15) — топать в 4 раза дольше! Ой ой ой...


S>Еще тут на одном проце оптимизированная до интов(9 десятичных цифр на 1 элемент массива — ИНТ) задача посчитала уже свыше 35 000 000. На это ушло уже 7 дней!

S>Движемся на ней до а(14), интересно же узнать, опередит ли эта оптимальная версия — распределенную..

У меня тоже досчиталось.

0 days 00:00:00.000s: 1 : 10
0 days 00:00:00.000s: 2 : 53
0 days 00:00:00.000s: 3 : 242
0 days 00:00:00.000s: 4 : 377
0 days 00:00:00.000s: 5 : 1491
0 days 00:00:00.000s: 6 : 1492
0 days 00:00:00.000s: 7 : 6801
0 days 00:00:00.000s: 8 : 14007
0 days 00:00:00.125s: 9 : 100823
0 days 00:00:03.237s: 10 : 559940
0 days 00:00:13.042s: 11 : 1148303
0 days 00:02:37.769s: 12 : 4036338
0 days 00:02:37.769s: 13 : 4036339
0 days 09:08:41.660s: 14 : 53619497

4-х головый Intel Xeon 1.6GHz, 64 бита, в среднем загрузка CPU 95%

Завтра будет A15, к понедельнику — A16
Re[3]: Наконечно досчиталось до а14 !
От: Seon  
Дата: 28.01.09 09:18
Оценка:
Здравствуйте, nikholas, Вы писали:

N>У меня тоже досчиталось.


N> 0 days 00:00:00.000s: 1 : 10

N> 0 days 00:00:00.000s: 2 : 53
N> 0 days 00:00:00.000s: 3 : 242
N> 0 days 00:00:00.000s: 4 : 377
N> 0 days 00:00:00.000s: 5 : 1491
N> 0 days 00:00:00.000s: 6 : 1492
N> 0 days 00:00:00.000s: 7 : 6801
N> 0 days 00:00:00.000s: 8 : 14007
N> 0 days 00:00:00.125s: 9 : 100823
N> 0 days 00:00:03.237s: 10 : 559940
N> 0 days 00:00:13.042s: 11 : 1148303
N> 0 days 00:02:37.769s: 12 : 4036338
N> 0 days 00:02:37.769s: 13 : 4036339
N> 0 days 09:08:41.660s: 14 : 53619497

N>4-х головый Intel Xeon 1.6GHz, 64 бита, в среднем загрузка CPU 95%


N>Завтра будет A15, к понедельнику — A16


Хе! Акромя проца еще надо указывать какой алгоритм...
Re[6]: k нулей
От: nikholas Россия  
Дата: 28.01.09 09:26
Оценка:
Здравствуйте, Beam, Вы писали:

B>Как? Пусть имеем N с количеством нулей 4, нам надо 8 нулей. Какое число (числа) будут проверены после N, т.е. куда будет осуществлен прыжок (прыжки)?


Все не так.
Мы прыгаем на 100 (к примеру), надо 8, а там 4. Значит среди 91-100 не более 7 нулей. проверяем 90 — там 3 нуля, значит среди 77-90 не более 7 нулей.
И т.д.
Проблема в том, чтобы уметь далеко прыгать, хотя как показывет практика, кол-во умножений практически не зависит от дальности каждого начального прыжка и составляет примерно 6-8% от достигнутой степени. Я пробовал прыгать на 7 — 50 и оптимальным является прыжок на 13
Re[4]: Наконечно досчиталось до а14 !
От: nikholas Россия  
Дата: 28.01.09 09:30
Оценка:
Здравствуйте, Seon, Вы писали:

S>Здравствуйте, nikholas, Вы писали:


N>>У меня тоже досчиталось.


N>> 0 days 00:00:00.000s: 1 : 10

N>> 0 days 00:00:00.000s: 2 : 53
N>> 0 days 00:00:00.000s: 3 : 242
N>> 0 days 00:00:00.000s: 4 : 377
N>> 0 days 00:00:00.000s: 5 : 1491
N>> 0 days 00:00:00.000s: 6 : 1492
N>> 0 days 00:00:00.000s: 7 : 6801
N>> 0 days 00:00:00.000s: 8 : 14007
N>> 0 days 00:00:00.125s: 9 : 100823
N>> 0 days 00:00:03.237s: 10 : 559940
N>> 0 days 00:00:13.042s: 11 : 1148303
N>> 0 days 00:02:37.769s: 12 : 4036338
N>> 0 days 00:02:37.769s: 13 : 4036339
N>> 0 days 09:08:41.660s: 14 : 53619497

N>>4-х головый Intel Xeon 1.6GHz, 64 бита, в среднем загрузка CPU 95%


N>>Завтра будет A15, к понедельнику — A16


S>Хе! Акромя проца еще надо указывать какой алгоритм...



Ну, алгоритм-то тот же самый, только многопоточный.

Каждый поток берет полученное число, умножает на 2^2000 (примерно) и проверяет этот диапазон
Диапазон проверяется прыжками.
Re[5]: Наконечно досчиталось до а14 !
От: Seon  
Дата: 28.01.09 09:44
Оценка:
Здравствуйте, nikholas, Вы писали:

N>Каждый поток берет полученное число, умножает на 2^2000 (примерно) и проверяет этот диапазон

N>Диапазон проверяется прыжками.

Так. Понятно.
А если попытаться так же сделать для нескольких компов...
То есть умножаем на большую степень, и результат сохраняем в файл. Чтобы другой комп мог его взять на обработку...
Чтобы скомпенсировать рост числа вширь, и чтобы каждая задача решалась приблизительно равное количество времени, надо каждый раз прыгать на меньшую степень.
А для того чтобы не случалось переполнение памяти, каждый такой блин можно есть по частям справа налево, например долями по 20 000 000 знаков..

А еще лучше чтобы программа сервер — делала эти длинные умножения, и хранила результаты, чтобы потом раздавать клиентам. Это лучче всего будет.
Сервак чтобы торчал в инет, и доступен для скачивания клиент.
Ну а дальше как на БОИНКЕ — раздает одну задачу 3-м разным клиентам, шифрует и так далее... Можно даже для этого заюзать движок ихний. И сделать объяву новой задачи.
Думаю за месяцок МИР расчитает до а50!
Re[6]: Наконечно досчиталось до а14 !
От: nikholas Россия  
Дата: 28.01.09 09:49
Оценка:
Здравствуйте, Seon, Вы писали:

S>Здравствуйте, nikholas, Вы писали:


N>>Каждый поток берет полученное число, умножает на 2^2000 (примерно) и проверяет этот диапазон

N>>Диапазон проверяется прыжками.

S>Так. Понятно.

S>А если попытаться так же сделать для нескольких компов...
S>То есть умножаем на большую степень, и результат сохраняем в файл. Чтобы другой комп мог его взять на обработку...
S>Чтобы скомпенсировать рост числа вширь, и чтобы каждая задача решалась приблизительно равное количество времени, надо каждый раз прыгать на меньшую степень.
S>А для того чтобы не случалось переполнение памяти, каждый такой блин можно есть по частям справа налево, например долями по 20 000 000 знаков..

S>А еще лучше чтобы программа сервер — делала эти длинные умножения, и хранила результаты, чтобы потом раздавать клиентам. Это лучче всего будет.

S>Сервак чтобы торчал в инет, и доступен для скачивания клиент.
S>Ну а дальше как на БОИНКЕ — раздает одну задачу 3-м разным клиентам, шифрует и так далее... Можно даже для этого заюзать движок ихний. И сделать объяву новой задачи.
S>Думаю за месяцок МИР расчитает до а50!

Вот только это нахрен никому не надо
Re[6]: k нулей
От: dima125 Россия html://dima125.narod.ru
Дата: 28.01.09 10:35
Оценка:
Здравствуйте, Seon, Вы писали:

E>>1) Какие есть ваши доказательства?

S>программа обработала числа до 2^10 000 000. Вероятность появления 2х нулей подряд падала очень быстро.
S>Вероятность встретить 2 нуля подряд в числах такого размера вероятна равна 0.

Ну вероятность — это не доказательство.
>>Существует ли предел, степени, больше которой 2 нуля подряд не повторяются?
Можно доказать, что не существует такого предела. Я думаю, это можно доказать даже для конкретных позиций ноликов: всегда найдётся сколь угодна большая степень n, так чтобы 2^n в 3 и 4 позиции с конца был нолик.
Как доказать:
Умножение начинается с последних цифр. Умножая любое число мы умножаем сначала последние цифры. Таким образом умножая всё большие и большие числа комбинация последних цифр повторяется циклически. И если мы нашли хоть одно число 2^n в котором встретились два нолика подряд, значит таких чисел будет сколь угодно много.
Re[7]: k нулей
От: Seon  
Дата: 28.01.09 11:53
Оценка:
Здравствуйте, dima125, Вы писали:

>если мы нашли хоть одно число 2^n в котором встретились два нолика подряд, значит таких чисел будет сколь угодно много.


Ну вот. А чисел в которых встречается только один ноль подряд будет все меньше! И очень скоро таких совсем не станет.
Re[2]: k нулей
От: Seon  
Дата: 03.02.09 07:25
Оценка:
Здравствуйте, Ravlyk, Вы писали:

R>Основной принцип: цифры обрабатываеются по 16 в ulong (INT64, по 4 бита на цифру). Для каждого возможного 16-циферого числа заготовлен массив с количеством нолей с начала, в середине, и в конце числа.


Смело

По моему с тем же успехом в инт64 можно запихнуть 18 десятичных цифр...
Re[3]: k нулей
От: Ravlyk Австралия http://stitcharteasy.com
Дата: 03.02.09 07:34
Оценка:
Здравствуйте, Seon, Вы писали:

R>>Основной принцип: цифры обрабатываеются по 16 в ulong (INT64, по 4 бита на цифру).

S>Смело

S>По моему с тем же успехом в инт64 можно запихнуть 18 десятичных цифр...

Нельзя — битов не хватит. Я использую INT64 как BCD, и именно на это оптимизированы все операции сдвигов и бинарных & и |.
Re[4]: k нулей
От: Ravlyk Австралия http://stitcharteasy.com
Дата: 03.02.09 07:37
Оценка:
Здравствуйте, Ravlyk, Вы писали:

R>Я использую INT64 как BCD, и именно на это оптимизированы все операции сдвигов и бинарных & и |.


И работает быстрее чем предложенный выше вариант с 17/18 цифрами в INT64, и 10-какаятоичная система счисления.
Хотя про вариант с прыжками вперед я прочитал позже, ато бы не выкладывал свой.
Re[5]: k нулей
От: Seon  
Дата: 03.02.09 07:44
Оценка:
Здравствуйте, Ravlyk, Вы писали:

R>Здравствуйте, Ravlyk, Вы писали:


R>>Я использую INT64 как BCD, и именно на это оптимизированы все операции сдвигов и бинарных & и |.


R>И работает быстрее чем предложенный выше вариант с 17/18 цифрами в INT64, и 10-какаятоичная система счисления.


А не факт!
Re[2]: A16
От: Seon  
Дата: 10.02.09 11:16
Оценка:
Здравствуйте, nikholas, Вы писали:

N>Здравствуйте, vadimcher, Вы писали:


N>4-х головый Intel Xeon 1.6GHz, 64 бита, в среднем загрузка CPU 95%, занимает памяти 200 MB:



N>
N>  0 days 00:00:00.000s:  1 :         10 (       586)
N>  0 days 00:00:00.000s:  2 :         53 (       586)
N>  0 days 00:00:00.000s:  3 :        242 (       586)
N>  0 days 00:00:00.000s:  4 :        377 (       586)
N>  0 days 00:00:00.015s:  5 :       1491 (       586)
N>  0 days 00:00:00.015s:  6 :       1492 (       586)
N>  0 days 00:00:00.015s:  7 :       6801 (      1456)
N>  0 days 00:00:00.015s:  8 :      14007 (      2266)
N>  0 days 00:00:00.140s:  9 :     100823 (     10009)
N>  0 days 00:00:03.468s: 10 :     559940 (     48503)
N>  0 days 00:00:13.875s: 11 :    1148303 (     94967)
N>  0 days 00:02:47.601s: 12 :    4036338 (    318504)
N>  0 days 00:02:47.601s: 13 :    4036339 (    318504)
N>  0 days 08:28:36.830s: 14 :   53619497 (   4135670)
N>  1 days 18:08:30.187s: 15 :  119476156 (   9202865)
N>  2 days 14:49:08.222s: 16 :  146226201 (  11260686)
N>


N>Дальше считать не вижу смысла, 100 дней аптайма анрил...


Вот я не понимаю....
А что? очень тяжело сделать сохранение промежуточных результатов, с возможностью их загрузки и возобновления расчета...
И программу поставить в автозапуск в беловнормале? И хай себе крутится! куда нам спешить то?
Re[3]: k нулей
От: Beam Россия  
Дата: 11.02.09 22:24
Оценка:
Здравствуйте, vadimcher, Вы писали:

V>Вопрос: а зачем ты так делаешь

V>
V>        int step = k - zeros <= 13 ? k - zeros : 13;
V>        multArrayC(arr, len, arr, len, step);
V>

V>когда вроде можно так
V>
V>        int step = k - zeros;
V>        while (step > 13) {
V>            multArrayC(arr, len, arr, len, 13);
V>            step -= 13;
V>        }
V>        multArrayC(arr, len, arr, len, step);
V>


Да, можно. Вернее даже нужно (теоретически). Поправлю.
Но, к сожалению, это мало повлияет на результат
Если интересно, вот некоторая укрупненная статистика.

При расчете до степени 4 млн. (т.е. искали до 12 нулей) с помощью прыжков мы прыгали в 95% случаев на шаг от 5 до 7 (на 6 — 44%, на 7 — 35%, на 5 — 17%).
При увеличении искомого количества нулей эти цифры смещаются в большую сторону, но очень медленно, и прыжок на 14 (и более) понадобится нам при поиске a(19), a(20)

Если мы рассмотрим все степени двойки от 0 до 4 млн. (подряд, без прыжков), то процентное отношение количества нулей в них будет такое:
4 нулей — 8%, 5 нулей — 51%, 6 нулей — 33%, 7 нулей — 4%. Т.е. 84% степеней содержат 5-6 нулей, а 95% содержат 4-7 нулей.


Насчет расчета a(18).
Если посмотреть последовательность a(), то можно увидеть, что следующий член может увеличиваться до 10 раз!
Предположим, что так оно и есть, т.е. a(18) = 10^10. В алгоритмах используется приблизительное соотношение 1 байт = 2 десятичные цифры.
Значит нам понадобится 10^10 / 2 = 5 * 10^9 байт памяти для работы с числом.
Далее. Время. У меня в программе вычисляется средняя скорость работы программы. В битах в секунду. Где биты — количество бит в обработанных степенях двойки.
т.е. для 2^n обрабатывается n бит. А для всех чисел от 2^0 до 2^n соответственно n(n+1)/2 бит. Так вот средняя скорость на двухядерниках пока не превышала 50*10^9 бит/сек (обычно 30 млрд. бит / сек). Т.е. для 10^10 * 10^10 / 2 = 10^20 / 2 / 50 / 10^9 = 10^(20 — 2 — 9) = 10^9 секунд. 30 лет.

Хотя конечно для a(18) = 1.5 млрд все не так плохо. 1 Гб памяти + пол-года. Так что попробовать можно
... << RSDN@Home 1.2.0 alpha 4 rev. 1136>>
Best regards, Буравчик
Re[2]: k нулей
От: Beam Россия  
Дата: 11.02.09 22:41
Оценка:
B>Вот и получается, что время умножения на большую степень двойки сравнимо с последовательным умножением несколько раз на маленькую степень двойки (если алгоритм учитывает, что умножение произодится только на маленькую степень). Например, время умножения на 2^22, сравнимо с умножением на 2^13 и затем на 2^9.

Кстати, если я не ошибся и это действительно так, то не все способы распараллеливания между несколькими компьютерами могут работать.
Например, не будет работать метод, в котором один компьютер подсчитывает степени от 0 до 1 млн., второй от 1 до 2 млн. и т.д., т.к. чтобы сообщить второму компьютеру число 2^(1 млн.) надо его сначала посчитать, а значит сдеолать большую часть работы.
Можно, конечно, передавать не само число, а просто степень (например 1 млн), но тогда тот компьютер должен либо опять же посчитать степени от 0 до 1 млн, либо перевести число 2^n в десятичную форму. Насколько мне известно, быстрых алгоритмов для этого не существует. Их сложность O(n^2), т.е. фактически такая же, как и при ручном расчете.

Я ничего не напутал?
... << RSDN@Home 1.2.0 alpha 4 rev. 1136>>
Best regards, Буравчик
Re[2]: k нулей
От: Seon  
Дата: 12.02.09 12:33
Оценка:
Здравствуйте, Beam, Вы писали:
B>
B>            mulTable[(i << 4) + pow].result = y % 10000;
B>            mulTable[(i << 4) + pow].carry = y / 10000;
B>


Здесь можно существенно убыстрить, если заменить деления чем нибудь более быстрым. условиями например...
Re[3]: k нулей
От: nikholas Россия  
Дата: 12.02.09 12:47
Оценка:
Здравствуйте, Seon, Вы писали:

S>Здравствуйте, Beam, Вы писали:

B>>
B>>            mulTable[(i << 4) + pow].result = y % 10000;
B>>            mulTable[(i << 4) + pow].carry = y / 10000;
B>>


S>Здесь можно существенно убыстрить, если заменить деления чем нибудь более быстрым. условиями например...


Это всего лишь инициализация таблицы

кстати, по моим ощущениям табличное "умножение" проигрывает в скорости двум делениям непосредственно в цикле(/ %)
а вот а if-ов надо стараться избегать...
Re[4]: k нулей
От: Beam Россия  
Дата: 12.02.09 13:38
Оценка:
Здравствуйте, nikholas, Вы писали:

N>Это всего лишь инициализация таблицы

Да, именно так.

N>кстати, по моим ощущениям табличное "умножение" проигрывает в скорости двум делениям непосредственно в цикле(/ %)

Я тоже так думал, но оказалась, что таблицы выигрывают около 20%. Даже по отношению к оптимизированному компилятором коду: он достаточно умен, чтобы определить, что нужен и результат и остаток, поэтому не делает два деления. Во-вторых он это деление заменяет на умножение. Но все равно таблицы быстрее. Хотя может все зависит от кэша и т.п.

N>а вот а if-ов надо стараться избегать...

Это точно.
Best regards, Буравчик
Re[3]: k нулей
От: Beam Россия  
Дата: 12.02.09 14:14
Оценка:
Здравствуйте, nikholas, Вы писали:

N>Лучше сделать так: по числу x от 0000 до 9999 по таблице получаем zero-mask: на месте нулей — нули, на месте не-нулей — единицы (получаем число от 0 до 15)

N>для текущей позиции при подсчете нулей помним: максимальное число нулей найденое ранее (max, 0 — 19), число нулей на конце(curr, 0-19)
N>и далее по таблице [max, curr, zero-mask] получаем новые значения для max и curr
N>Для того чтоб не заморачиваться насчет конца числа curr может быть больше max, тогда в конце, после любого кол-ва финишных нулей, мы получаем точное значение max(главное в таблице сделать curr(19)->curr(19), а не то...).

Отличная идея!
Мне приходила в голову похожая — я заводил таблицу [0000..9999, cur, max] = {new_cur, new_max}, но это работало долго, из-за большого размера таблицы (20*20*10000 = 4000000 = 4 Мб).
Здесь же получается таблица [0000..9999] = {mask} (10 кБ) и [max, cur, mask] = {new_cur, new_max} (20*20*16*2 = 12,8 кБ). Поэтому должно быть быстрее => внесу изменения.

N>Также лучше совместить подсчет нулей с возведением в степень — кеши и все такое


Это да. Пока что не сделал, т.к. возможна ситуация, что умножать будет нужно, а нули считать нет. Но если такое не понадобится, то объединю.

N>Я особо не мерял но у меня сложилось впечатление что умножение на 3-х разрядное число (с подсчетом нулей) практически не отличается по времени от умножения на одноразрядное.

N>И возведение в большую степень работает быстро — я прикидывал, что 2^(10^9) можно получить дней за 7-8

Я мерял, но может что-то упустил из виду. Было бы интересно увидеть твои замеры умножения. Ну хотя бы 1 млн, 5 млн, 10 млн (бех подсчета нулей). Все-таки если умножение идет "столбиком", то я реально не понимаю почему может быть быстрее
Best regards, Буравчик
Re[3]: k нулей
От: vadimcher  
Дата: 12.02.09 17:13
Оценка:
Здравствуйте, nikholas, Вы писали:

N>Также лучше совместить подсчет нулей с возведением в степень — кеши и все такое


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

А вот зайца кому, зайца-выбегайца?!
Re[3]: k нулей
От: Beam Россия  
Дата: 12.02.09 23:14
Оценка:
Здравствуйте, vadimcher, Вы писали:

V>Я еще раз просмотрел твой код на предмет поиска нулей, и пришел к выводу, что возможны ошибки при k=2 и k>=5. Стал сравнивать результаты. Выяснилось: ошибки при k=2,3.

V>Для k=2, понятно. Два нуля оказались внутри 4-хзначной цифры. (Вероятность этого была достаточно маленькая, но я решил проверить, вдруг ты попал как раз в эту вероятность? Попал!) Так что и по логике, и на практике следует начинать с k=3.
Да верно. Я просто об этом не упомянул. Для 1 и 2 это может не работать.
И это было бы ерундой, если бы не ...

V>Для k=3 у меня выдал 243 вместо 242. Почему? Непонятно. Я этого не ожидал.

Я тоже не ожидал Это реальный баг.
При подсчете он попадает на 240. Считает нули. На самом деле их там максимум 2, но также есть и по одному.
Но! Они все попадают в середину четырехзначных цифр А значит не учитываются. В итого думаем что количество нулей = 0, прыгаем на 3-0, т.е. на 3 => 240 + 3 = 243

В приниципе, такое может повториться и на других числах, хотя вероятность этого очень низкая, к тому же снижается при увеличении длины числа.

V>Для k>=5. Когда один процессор обработал блок, он смотрит, какое там число стоит дальше, cur += zerosTable[ arr[index+1] ].right. Но что, если там стоит 0000, тогда надо двигать дальше, пока не встретится наконец ненулевое число! Т.е. надо что-то типа int j = 1, z; do { z = zerosTable[ arr[index+j] ].right; cur += z; } while (z == 4);

Все таки не до конца я разрулил потоки

V>Тут проблема не только в том, что можно пропустить искомое число нулей, но и в том, что иногда шаг, с которым ты прыгаешь к следующему числу может оказаться больше, чем положено.

Да. Маловероятно, но верно => исправлю. Спасибо
... << RSDN@Home 1.2.0 alpha 4 rev. 1136>>
Best regards, Буравчик
Re[2]: A16
От: Beam Россия  
Дата: 14.02.09 21:48
Оценка:
Здравствуйте, nikholas, Вы писали:

N>Здравствуйте, vadimcher, Вы писали:


N>4-х головый Intel Xeon 1.6GHz, 64 бита, в среднем загрузка CPU 95%, занимает памяти 200 MB:


N>
N>  0 days 00:00:00.000s:  1 :         10 (       586)
N>  0 days 00:00:00.000s:  2 :         53 (       586)
N>  0 days 00:00:00.000s:  3 :        242 (       586)
N>  0 days 00:00:00.000s:  4 :        377 (       586)
N>  0 days 00:00:00.015s:  5 :       1491 (       586)
N>  0 days 00:00:00.015s:  6 :       1492 (       586)
N>  0 days 00:00:00.015s:  7 :       6801 (      1456)
N>  0 days 00:00:00.015s:  8 :      14007 (      2266)
N>  0 days 00:00:00.140s:  9 :     100823 (     10009)
N>  0 days 00:00:03.468s: 10 :     559940 (     48503)
N>  0 days 00:00:13.875s: 11 :    1148303 (     94967)
N>  0 days 00:02:47.601s: 12 :    4036338 (    318504)
N>  0 days 00:02:47.601s: 13 :    4036339 (    318504)
N>  0 days 08:28:36.830s: 14 :   53619497 (   4135670)
N>  1 days 18:08:30.187s: 15 :  119476156 (   9202865)
N>  2 days 14:49:08.222s: 16 :  146226201 (  11260686)
N>


У меня тоже посчиталось a(16).

a(14) = 53'619'497 ===> 10 час 16 мин (21% медленнее)
a(15) = 119'476'156 ===> 2 дня 00 час 36 мин (15% медленнее)
a(16) = 146'226'201 ===> 2 дня 22 час 38 мин (12% медленнее)

В принципе, результаты по времени сравнимы с предыдущим полученным a(16). Хотя и получилось немного медленнее, необходимо учитывать разницу в количестве ядер и частоте.
Т.к. архитектуры у процессоров вроде одинаковые (Core), то можно сравнивать по частоте:
4-х головый Intel Xeon 1.6GHz ~~ 1.6 * 4 = 6.4 ГГц
2-я ядерный Intel Core 2 Duo 2.67 GHz ~~ 2.67 * 2 = 5.3 ГГц
Т.е. программа на 2-ядернике должна быть на 17% медленнее. Как видно, ситуация даже лучше (15%, 12%), т.е. имеется незначительное улучшение. Но это в теории, как будет в реальности на 4-ядернике — неизвестно

N>Дальше считать не вижу смысла, 100 дней аптайма анрил...


Дальше считать действительно нет смысла. Если уж и счтать то начиная с 1 млрд., чтобы искать a(18), а так... какой смысл.
Но a(18) один компьютер будет рассчитывать от 0 до 30 лет. Чтобы максимум уменьшить хотя бы до 1 года, надо 30 компьютеров. Сомневаюсь, что на RSDN найдется столько желающих.

Тем более, мне так и не понятна эффективная схема распределения работы между компьютерами по сети.

P.S. В общем, пока я для себя эту тему закрываю. Пока не придумается какая-нибудь эвристика (из области математики) для вычислений... Интересная задачка, однако.
... << RSDN@Home 1.2.0 alpha 4 rev. 1136>>
Best regards, Буравчик
Re[3]: A16
От: vadimcher  
Дата: 15.02.09 04:36
Оценка:
Здравствуйте, Beam, Вы писали:

B>P.S. В общем, пока я для себя эту тему закрываю. Пока не придумается какая-нибудь эвристика (из области математики) для вычислений... Интересная задачка, однако.


Я не знаю, подправил ты код или нет (там было две проблемы -- число нулей между соседними процессами и поиск двух нулей, в принципе, два нуля можно и не искать, а для того, чтобы шаг не был слишком большим, просто считать, что если найденное максимальное число нулей подряд в числе меньше 2, то считать, что оно равно 2 -- это не должно никак повлиять на быстродействие, но исключит возможность перепрыгнуть через искомое число). Но я не об этом. Есть ли у тебя какая статистика по тому, сколько времени тратится на умножение, а сколько -- на поиск нулей?

А вот зайца кому, зайца-выбегайца?!
Re[4]: A16
От: Beam Россия  
Дата: 15.02.09 17:15
Оценка:
Здравствуйте, vadimcher, Вы писали:

V>Я не знаю, подправил ты код или нет (там было две проблемы -- число нулей между соседними процессами и поиск двух нулей, в принципе, два нуля можно и не искать, а для того, чтобы шаг не был слишком большим, просто считать, что если найденное максимальное число нулей подряд в числе меньше 2, то считать, что оно равно 2 -- это не должно никак повлиять на быстродействие, но исключит возможность перепрыгнуть через искомое число).

Код я поправил. Позже причешу и выложу сюда. Может кто продолжит.

V>Но я не об этом. Есть ли у тебя какая статистика по тому, сколько времени тратится на умножение, а сколько -- на поиск нулей?

Соотношение (Умножение:Поиск) очень близко к (2:1)
... << RSDN@Home 1.2.0 alpha 4 rev. 1136>>
Best regards, Буравчик
Re[3]: k нулей
От: Beam Россия  
Дата: 15.02.09 17:15
Оценка:
Здравствуйте, nikholas, Вы писали:

N>Здравствуйте, Beam, Вы писали:


N>По поводу подсчета нулей:


N>Лучше сделать так: по числу x от 0000 до 9999 по таблице получаем zero-mask: на месте нулей — нули, на месте не-нулей — единицы (получаем число от 0 до 15)

N>для текущей позиции при подсчете нулей помним: максимальное число нулей найденое ранее (max, 0 — 19), число нулей на конце(curr, 0-19)
N>и далее по таблице [max, curr, zero-mask] получаем новые значения для max и curr
N>Для того чтоб не заморачиваться насчет конца числа curr может быть больше max, тогда в конце, после любого кол-ва финишных нулей, мы получаем точное значение max(главное в таблице сделать curr(19)->curr(19), а не то...).

Попробовал я такой вариант. Работает медленнее, почему — не знаю.
... << RSDN@Home 1.2.0 alpha 4 rev. 1136>>
Best regards, Буравчик
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.