Euler № 16 проекта - C# 2.0

Это ошибка в блоге. См. Doc ID 2502618.1 о поддержке Oracle.

Предлагаемые решения от поддержки Oracle:

В качестве решения примените исправление 29154575 В качестве обходного пути: отключите функцию модуля параллельного развертывания. Отключение этого режима гарантирует, что различные модули приложения будут активированы последовательно, избегая состояния гонки.

8
задан leppie 2 May 2016 в 19:31
поделиться

8 ответов

Много серия цифр. Неподписанный интервал на 32 бита составляет 32 двоичных единицы информации. Строка "12345" является серией 5 цифр. Цифры могут быть сохранены во многих отношениях: как биты, символы, элементы массива и так далее. Самый большой "собственный" тип данных в C# с полной точностью является, вероятно, десятичным типом (128 битов, 28-29 цифрами). Просто выберите свой собственный метод хранения цифр, который позволяет Вам хранить намного большие числа.

Что касается остальных, это даст Вам ключ к разгадке:

21 = 2
22 = 21 + 21
23 = 22 + 22

Пример:

The sum of digits of 2^100000 is 135178
Ran in 4875 ms

The sum of digits of 2^10000 is 13561
Ran in 51 ms

The sum of digits of 2^1000 is 1366
Ran in 2 ms

ПРЕДУПРЕЖДЕНИЕ СПОЙЛЕРА: Алгоритм и решение в C# следуют.

В основном, как сослался на число, не что иное как массив цифр. Это может быть представлено легко двумя способами:

  • Как строка;
  • Как массив символов или цифр.

Как другие упомянули, хранение цифр в обратном порядке на самом деле желательно. Это делает вычисления намного легче. Я попробовал оба из вышеупомянутых методов. Я нашел строки и символьную арифметику раздражающими (это легче в C/C++; синтаксис является просто раздражающим в C#).

Первая вещь отметить состоит в том, что можно сделать это с одним массивом. Вы не должны выделять больше устройства хранения данных при каждом повторении. Как упомянуто можно найти питание 2 путем удвоения предыдущего питания 2. Таким образом, можно найти 21000 путем удвоения 1 одну тысячу раз. Удвоение может быть сделано на месте с общим алгоритмом:

carry = 0
foreach digit in array
  sum = digit + digit + carry
  if sum > 10 then
    carry = 1
    sum -= 10
  else
    carry = 0
  end if
  digit = sum
end foreach

Этот алгоритм является в основном тем же для использования строки или массива. В конце Вы просто складываете цифры. Наивная реализация могла бы добавить результаты в новый массив или строку с каждым повторением. Плохая идея. Действительно замедляет его. Как упомянуто, это может быть сделано на месте.

Но насколько большой массив должен быть? Хорошо это легко также. Математически можно преобразовать 2^a в 10^f (a), где f (a) является простым логарифмическим преобразованием и количеством цифр, Вам нужно, следующее более высокое целое число от того питания 10. Для простоты можно просто использовать:

digits required = ceil(power of 2 / 3)

который является близким приближением и достаточный.

Где можно действительно оптимизировать, это при помощи больших цифр. 32 бита подписались, интервал может сохранить число между +/-2 миллиарда (приблизительно. Хорошо 9 цифр равняются миллиарду, таким образом, можно использовать интервал на 32 бита (подписанный или неподписанный) как в основном основа один миллиард "цифр". Можно удаться, сколько ints Вы нуждаетесь, создаете тот массив, и это - все устройство хранения данных, необходимо выполнить весь алгоритм (являющийся 130ish байты) со всем сделанным на месте.

Решение следует (в довольно грубом C#):

    static void problem16a()
    {
        const int limit = 1000;
        int ints = limit / 29;
        int[] number = new int[ints + 1];
        number[0] = 2;
        for (int i = 2; i <= limit; i++)
        {
            doubleNumber(number);
        }
        String text = NumberToString(number);
        Console.WriteLine(text);
        Console.WriteLine("The sum of digits of 2^" + limit + " is " + sumDigits(text));
    }

    static void doubleNumber(int[] n)
    {
        int carry = 0;
        for (int i = 0; i < n.Length; i++)
        {
            n[i] <<= 1;
            n[i] += carry;
            if (n[i] >= 1000000000)
            {
                carry = 1;
                n[i] -= 1000000000;
            }
            else
            {
                carry = 0;
            }
        }
    }

    static String NumberToString(int[] n)
    {
        int i = n.Length;
        while (i > 0 && n[--i] == 0)
            ;
        String ret = "" + n[i--];
        while (i >= 0)
        {
            ret += String.Format("{0:000000000}", n[i--]);
        }
        return ret;
    }
15
ответ дан 5 December 2019 в 05:46
поделиться

Я решил этого прежде, и теперь я разрешил его с помощью C# 3.0.:)

Я просто записал a Multiply дополнительный метод, который берет IEnumerable<int> и множитель и возвраты IEnumerable<int>. (Каждый интервал представляет цифру и первую это младшая значащая цифра.) Затем я просто создал список с объектом {1} и умножил его на 2 1000 времена. Добавление объектов в списке просто с Sum дополнительный метод.

19 строк кода, который работает в 13 мс. на моем ноутбуке.:)

3
ответ дан 5 December 2019 в 05:46
поделиться

Притворитесь, что Вы очень молоды с квадратной бумагой. Мне, который похож на список чисел. Затем для удвоения его Вы удваиваете каждое число, затем обрабатываете любого, "несет", путем вычитания 10-х и добавления 1 к следующему индексу. Таким образом, если ответ является 1366... что-то как (полностью неоптимизированный, rot13):

hfvat Flfgrz;
hfvat Flfgrz.Pbyyrpgvbaf.Trarevp;    
pynff Cebtenz {
    fgngvp ibvq Pneel(Yvfg<vag> yvfg, vag vaqrk) {
        juvyr (yvfg[vaqrk] > 9) {
            yvfg[vaqrk] -= 10;
            vs (vaqrk == yvfg.Pbhag - 1) yvfg.Nqq(1);
            ryfr yvfg[vaqrk + 1]++;
        }
    }
    fgngvp ibvq Znva() {
        ine qvtvgf = arj Yvfg<vag> { 1 }; // 2^0
        sbe (vag cbjre = 1; cbjre <= 1000; cbjre++) {
            sbe (vag qvtvg = 0; qvtvg < qvtvgf.Pbhag; qvtvg++) {
                qvtvgf[qvtvg] *= 2;
            }
            sbe (vag qvtvg = 0; qvtvg < qvtvgf.Pbhag; qvtvg++) {
                Pneel(qvtvgf, qvtvg);
            }
        }

        qvtvgf.Erirefr();
        sbernpu (vag v va qvtvgf) {
            Pbafbyr.Jevgr(v);
        }
        Pbafbyr.JevgrYvar();

        vag fhz = 0;
        sbernpu (vag v va qvtvgf) fhz += v;
        Pbafbyr.Jevgr("fhz: ");
        Pbafbyr.JevgrYvar(fhz);
    }
}
3
ответ дан 5 December 2019 в 05:46
поделиться

Если у Вас есть рубин, можно легко вычислить "2 ** 1000" и получить его как строку. Должно быть легкое сокращение/вставка в строку в C#.

Спойлер

В Ruby: (2 ** 1000) .to_s.split (//) .inject (0) {|x, y | x+y.to_i}

1
ответ дан 5 December 2019 в 05:46
поделиться

спойлер

Если Вы хотите видеть, что решение проверяет мой другой ответ. Это находится в Java, но это очень легко к порту к C#

Вот подсказка:

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

[1,2,3,4,5,6]
+       [4,5]
_____________
[1,2,3,5,0,1]
1
ответ дан 5 December 2019 в 05:46
поделиться

Если Вы хотите сделать основное вычисление в C#, то Вам будет нужна своего рода большая целочисленная реализация (Во многом как GMP для C/C++). Программирование об использовании правильного инструмента для правильного задания. Если Вы не можете найти хорошую крупную целочисленную библиотеку для C#, это не противоречит правилам для вычисления числа на языке как Python, который уже имеет способность вычислить большие количества. Вы могли затем поместить это число в свою программу C# с помощью Вашего предпочтительного метода, и выполнить итерации по каждому символу в числе (необходимо будет сохранить его как строку). Для каждого символа преобразуйте его в целое число и добавьте его к своему общему количеству, пока Вы не достигнете конца числа. Если Вы хотели бы большое целое число, я вычислил его с Python ниже. Ответ далее снижается.

Частичный спойлер

10715086071862673209484250490600018105614048117055336074437503883703510511249361 22493198378815695858127594672917553146825187145285692314043598457757469857480393 45677748242309854210746050623711418779541821530464749835819412673987675591655439 46077062914571196477686542167660429831652624386837205668069376

Спойлер ниже!

>>> val = str(2**1000)
>>> total = 0
>>> for i in range(0,len(val)): total += int(val[i])
>>> print total











1366
2
ответ дан 5 December 2019 в 05:46
поделиться

Я решил это использование C# также, очень к моей тревоге, когда я обнаружил, что Python может сделать это в одной простой операции.

Ваша цель состоит в том, чтобы создать счетную машину с помощью массивов международных значений.

Спойлер следует

Я закончил тем, что использовал массив международных значений для моделирования счетной машины, но я представил число назад - который можно сделать, потому что проблема только просит сумму цифр, это означает, что порядок не важен.

То, что Вы по существу делаете, удваивает значение 1000 раз, таким образом, можно удвоить значение 1 сохраненный в 1-м элементе массива и затем продолжить цикличное выполнение, пока значение не более чем 10. Это - то, где необходимо будет отслеживать значение переноса. Первое питание 2, который является более чем 10, равняется 16, таким образом, элементы в массиве после 5-го повторения равняются 6 и 1.

Теперь то, когда Вы циклично выполняетесь через массив, запускающийся в 1-м значении (6), это становится 12 (таким образом, Вы сохраняете последнюю цифру и устанавливаете перенос, обдумало следующий индекс массива) - который, когда то значение удвоено, Вы получаете 2... плюс 1 для бита переноса, который равняется 3. Теперь Вы имеете 2 и 3 в Вашем массиве, который представляет 32.

Продолжает этот процесс 1000 раз, и у Вас будет массив примерно с 600 элементами, которые можно легко сложить.

4
ответ дан 5 December 2019 в 05:46
поделиться

Одна альтернатива представлению цифр как последовательность целых чисел должна представить основание системы счисления 2^32 как список целых чисел на 32 бита, который является тем, что делают многие крупные целочисленные библиотеки. Затем необходимо преобразовать число для базирования 10 для вывода. Это не получает Вас очень для этой конкретной проблемы - можно записать 2^1000 немедленно, затем иметь для деления на 10 много раз вместо того, чтобы умножиться 2 отдельно 1000 раз (или, поскольку 1000 0b1111101000. при вычислении продукта 2^8,32,64,128,256,512 использование повторило обработку на квадрат 2^8 = (((2^2) ^2) ^2))), который требует большего количества пространства и метода умножения, но является гораздо меньшим количеством операций) - ближе к нормальному большому целочисленному использованию, таким образом, можно найти это более полезным в более поздних проблемах (при попытке вычислить последние десять цифр 28433×2^ (7830457) +1 использование цифры - на международный метод и повторенное дополнение, это может занять время (хотя в этом случае Вы могли использовать arthimetic по модулю, вместо того, чтобы добавить строки миллионов цифр)).

0
ответ дан 5 December 2019 в 05:46
поделиться