Как печатать действительно большие числа в С++

У меня есть этот код

#include <iostream>

using namespace std;

int main(int argc,char **argv) {

    unsigned long long num1 = 99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999995LL;
    unsigned long long num2 = 99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999996LL;
    unsigned long long num3 = 99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999997LL;
    unsigned long long num4 = 99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999998LL;
    unsigned long long num5 = 99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999LL;

    cout << (unsigned long long)(num1 * num2 * num3 * num4 * num5) << endl;
    return 0;
}

Как вы можете видеть, цифры огромны, но когда я занимаюсь математикой, я получаю следующее: +18446744073709551496

Во время компиляции я получаю следующие предупреждения:

warning: integer constant is too large for its type|
In function `int main(int, char**)':|
warning: this decimal constant is unsigned only in ISO C90|
...

Ответ 1

Ваш результат больше длинного длинного типа - вам нужно посмотреть BigInteger или библиотеку произвольной точности, что-то вроде gmp

Ответ 2

Эти числа не будут вписываться ни в какие типы данных С++. Если вы просто хотите их распечатать, сохраните номера в строке. Если вы хотите сделать математику, найдите произвольную математическую библиотеку точности и используйте ее.

Ответ 3

Если вы хотите, чтобы литералы были большими в вашем коде, вам придется вводить их в виде строковых литералов и загружать их в класс BigInt. Нет никакого способа выразить целые литералы, большие в исходном коде прямо сейчас (хотя С++ 0x, надеюсь, будет устранять этот недостаток).

Если вы используете библиотеку BigInteger, посмотрите функцию stringToBigUnsigned в BigIntegerUtils.hh для построения большого целого числа из строки.

#include "BigUnsigned.hh"
#include "BigIntegerUtils.hh"     

 BigUnsigned  num1 = stringToBigUnsigned (
    "99999999999999999999999999999999999999999999999999999999999999999999999999999999"
    "99999999999999999999999999999999999999999999999999999999999999999999999999999999"
    "99999999999999999999999999999999999999999999999999999999999999999999999999999999"
    "99999999999999999999999999999999999999999999999999999999999999999999999999999999"
    "99999999999999999999999999999999999999999999999999999999999999999999999999999999"
    "99999999999999999999999999999999999999999999999999999999999999999999999999999999"
    "99999999999999999999999999999999999999999999999999999999999999999999999999999999"
    "99999999999999999999999999999999999999999999999999999999999999999999999999999999"
    "99999999999999999999999999999999999999999999999999999999999999999999999999999999"
    "99999999999999999999999999999999999999999999999999999999999999999999999999999999"
    "99999999999999999999999999999999999999999999999999999999999999999999999999999999"
    "99999999999999999999999999999999999999999999999999999999999999999999999999999999"
    "99999999999999999999999999999999999995"
    );

Ответ 4

Что вы пытаетесь сделать? Вы понимаете основы двоичного и десятичного чисел? Почему 8 бит содержит только значения от 0 до 255, 12 бит 0 - 4095 и т.д.? Сколько бит требуется, чтобы удерживать номер, который вас интересует? Или лучше, насколько большой из числа вас интересует создание? И используете ли вы 9s, чтобы увеличить число? А как насчет hex 0xF... вместо этого? Если вам нужен самый большой номер без знака (в пределах одного из стандартных целых типов), почему бы и нет:

unsigned long long a, b;

a = -1;//который просто кажется неправильным смешиванием подписанного и unsigned, но он действителен, число преобразуется в unsigned перед сохранением

b = 0; В-;//делает то же, что и выше

Вам действительно нужна точность на этом уровне? Вы понимаете, что умножения могут потребовать результата в два раза больше размера каждого операнда? 0xFF * 0xFF = 0xFE01, если в этом случае вы использовали 8-битные целые числа, вы не могли бы выполнить математику. Это только ухудшается, когда вы продолжаете умножать 0xFF * 0xFF * 0xFF = 0xFD02FF.

Что вы пытаетесь сделать?


Увидев ваш ответ:

Я раньше не видел Эйлера № 8. Похоже, что это хороший вопрос для интервью, так как требуется всего несколько строк кода.


Ваш другой ответ:

Числа...

Вероятно, потому что у нас есть 10 пальцев (и, возможно, 10 пальцев), мы вырастаем с "базой 10". Наши часы имеют базовую 60 по большей части, но они были смешаны с базой 10, чтобы сделать ее более запутанной. Во всяком случае, база 10, означает для каждого заполнителя номера у вас есть одна из 10 уникальных цифр, когда вы достигаете максимума в том месте, где вы переходите на следующее место. Это все начальное школьное образование.

000
001
002
003
...
008
009
010
011
012
...

Посмотрите, как самая правая цифра имеет 10 символов (0,1,2,3,4,5,6,7,8,9), и когда она достигает последнего символа, она начинается, а одна слева от он увеличивается на единицу. Это правило справедливо для всех базовых систем нумерации.

Это верно для базы 2, за исключением наличия только двух символов: 0 и 1

000
001
010
011
100
101
...

То же самое верно для восьмеричного, но 8 символов (0,1,2,3,4,5,6,7)

000
001
002
003
004
005
006
007
010
011
012
013
...

И то же самое верно для шестнадцатеричных, 16 символов (0,1,2,3,4,5,6,7,8,9, a, b, c, d, e, f)

000
001
002
003
004
005
006
007
008
009
00a
00b
00c
00D
00E
00f
010
011
012
013
...

Я собирался войти в whys из использования двоичных файлов над другими базами (например, 10) на компьютерах. В нижней строке легко включить или выключить два состояния, или высокий, и низкий. Два состояния похожи на два символа 1 и 0 в базе 2. Попытка сохранить электронику, настроенную на более чем два состояния в пределах доступного напряжения, является жесткой, по крайней мере, она была, поддерживая ее около нуля или выше некоторого небольшого числа вольт относительно легко, поэтому цифровая электроника использует два состояния, двоичные.

Даже простая задача для человека в бинарнике длительная, простая математика второго класса по-прежнему много и нулей. Таким образом, октал стал популярным, потому что он позволял вам мыслить в группах по три бита, и вы могли бы использовать символы, которые мы знакомы с цифрами 0,1,2,3,4,5,6,7. Но группы из четырех человек, которые являются еще одной силой в 2, дают людям гораздо больше умственных вычислительных мощностей, чем восьмеричные, hex основан на 4 битах, что также является силой 2. Нам пришлось добавить больше символов в 10, которые мы заимствовали из традиционная арабская база 10, поэтому были использованы первые 6 алфавитов. Октал редко используется, если вы когда-либо использовали, вы можете сказать кому-то возраст, если они думают, что восьмеричные вместо гексагона. (Я из шестнадцатеричного поколения, но работал с теми из восьмеричного поколения, которые сражаются с гексагоном, потому что они не могут перейти от восьмеричного к двоичному в шествие в своем уме).

База 10 в компьютере похожа на среднее человеческое мышление в гексагоне. компьютеры не делают базу 10 (хорошо для ленивых людей, которых они использовали для bcd), они делают базу 2. Десятичное число 1234 на компьютере действительно 0x4D2 или 0b010011010010. Это как ценность, скажем, вы хотите добавить 1234 плюс какой-то другой номер, которому нужно это значение, которое не имеет ничего общего с символами 1, 2, 3 и 4. Но чтобы опубликовать этот ответ в stackoverflow, мы не используем номер, который мы используйте ASCII, поэтому 1234 в ascii - 0x31, 0x32, 0x33, 0x34, что важно знать для вашего решения эйлера, если 1000-разрядное число было предоставлено в виде строки ascii, которое должно было бы быть, или вам придется преобразовать его от двоичного до ascii, так как проблема является базой 10, а не базой 2. По определению.

Итак, к тому, что я спросил. Скажем, у вас было 4 бита памяти для хранения номера, сколько можно было бы сохранить число? Если вы считаете, что только основание 10, вы можете подумать, что число равно 9, потому что вы обучены думать об использовании самого большого символа в каждом месте хранения, 99999 - это самое большое число, если у вас 5 мест хранения в базе 10. Назад к четырем битам хотя самый большой символ для одного бита равен 1, поместите это число в каждое место хранения, которое вы получите 1111 (четыре). Просто взглянув на эти четыре, вы должны быть в своем уме, легко увидеть восьмеричную и шестнадцатеричную версию того же числа 17 восьмеричного или F hex. Чтобы увидеть, что десятичное значение принимает математику или в этом случае запоминание, это число равно 15 десятичным. Таким образом, самый большой четырехбитовый номер, который у вас есть, - 0xF или 15, а не 9. Как насчет 8-битного номера? 0xFF или 255 (от 2 до 8-й мощности минус один). Самый большой 16-разрядный номер? 65535 и т.д.

Итак, когда я спрашиваю, сколько бит вы пытаетесь использовать, это то, что я имею в виду. Посмотрите на этот номер 99999. Снова основание 10, вы считаете, что это самое большое число, но для компьютера это только часть пути, 99999 decimal - 0x1869F, который занимает 17 бит памяти для хранения, самый большой 17-разрядный номер, который вы можете Store - 0x1FFFF, что составляет 131071, что немного больше, чем 99999. Поэтому, когда вы хотите думать о больших числах и математике на компьютере, вы должны думать о двоичном (или шестнадцатеричном).

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

Возьмите самое большое 4-битное число 1111 (двоичное), которое равно 15 десятичным. Добавьте это с наибольшим четырехбитным номером, и вы получите 15 + 15 = 30 = 0x1E или 11110 двоичный. Таким образом, чтобы добавить два четырехбитовых номера, вам нужно пять бит, чтобы сохранить ответ. Компьютеры сохраняют бит "carry" для этого дополнительного бита. По сути, математические функции add/subtract integer в компьютере позволяют иметь N + 1 бит. Так что, если это 32-битный компьютер, у вас в основном есть 33 бита для добавления /sub math.

Проблема заключается в умножении и делении, что даже сегодня многие процессоры не поддерживают (да, многие из них не имеют fpu и только добавляют и вычитают, иногда размножаются, но деление редки). Умножьте и разделите много электроники. вы можете делать их с добавлением и вычитанием в программном обеспечении). Возьмите худший случай для четырехбитовой системы 1111 * 1111 = 11100001, поэтому для сохранения результата умножения на 4 бит потребуется 8 бит, вы быстро обнаружите, что если бы у вас была 4-битная система MOST из множителей, которые вы хотите сделать, это приведет к числу, которое невозможно сохранить в 4 биты. Поэтому, когда я увидел, что вы принимаете 64-битные целые числа (unsigned long long часто занимает 64 бит) и умножается четыре раза, это означает, что вам нужно 64 * 5 или 320-битное целое для хранения вашего ответа, вы пытались поместить этот ответ в 64 большой результат, который довольно часто, в зависимости от компилятора и компьютера, с удовольствием сделает и усечет верхние биты, оставив вас с более низкими 64 битами результата, который может легко выглядеть меньше любого из ваших операндов, что я и думал вы могли бы сделать сначала.

Плавающая точка не намного больше, чем научная нотация, но в двоичном формате, если вы хотите умножить число 1234 и 5678 с помощью научной нотации, вы должны взять 1.234 * 10 ^ 3 раза 5.678 * 10 ^ 3 и получить 7.007 * 10 ^ 6, Вы сохраняете свою точность и способны представлять более широкий диапазон чисел. Я не понимаю, как это работает в двоичном формате. Но он не работает для вашего оригинального вопроса.

Ах, последнее, что я уточнил, что я делал в своем вопросе/ответе. Отрицательные целые числа в двоичном формате. Из-за отношений между сложениями и вычитанием и базовыми системами вы можете сыграть некоторые трюки. Скажем, я хотел вычесть 1 из числа 7 (десятичный) с использованием двоичного кода. Ну нет такой вещи, как схема вычитания, вместо этого вы добавляете отрицательное число, поэтому вместо 7 - 1 это действительно 7 + (-1), это имеет значение:

0111 +???? = 0110

Какое число вы могли бы добавить к 7, чтобы получить 6... в двоичном формате?

0111 + 1111 = 0110

Отрицательные числа в двоичном выражении называются "двойным дополнением", короткий короткий ответ - "инвертировать и добавить 1". Как вы представляете минус 1 в двоичном формате? возьмите плюс один 0001, затем инвертируйте его значение, сделав те же нули и нули (также известные как дополнение) 1110, затем добавьте один 1111. Минус один - это специальное число в компьютерах (ну везде), как бы ни было сколько бит у вас есть представляется как все. Поэтому, когда вы видите, что кто-то делает это:

unsigned char a;

a = -1;

Сначала компилятор смотрит на -1 и думает... 11111 (двоичный), то он смотрит на знак равенства, а с другой стороны, о, вы хотите, чтобы все были, он видит, что у вас есть целое число со знаком и без знака, но преобразование состоит в том, чтобы просто переместить бит, чтобы вы говорили выше, что вы хотите a = 0xFF; (предполагая 8-битный без знака char).

Некоторые компиляторы могут жаловаться на то, что вы пытаетесь сохранить отрицательное число в неподписанном номере. Другие компиляторы будут смотреть на это -1 и видеть его как 32-битную или в эти дни, может быть, 64-разрядную стандартную константу со знаком, а затем, когда она оценивает равные 8-битные без знака, вы получите предупреждение о том, что вы не можете сохранить -1 в подписанном или без знака char без типа. Но если вы это сделаете:

a = 0; а -;

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

Теперь где-то друг рассказал мне книгу, которая делает двоичную математику серийно. Например, чтобы отрицать число, обычно вы делаете инвертированный и рекламный трюк, но с карандашом и бумагой некоторые могут рассказать вам другой трюк. Начиная с правой копии нули вплоть до первого включительно, затем инвертируйте после этого, так что минус 2

0010
1110

Начиная с правой копии 0, затем первой, затем инвертируйте оставшиеся биты, когда вы идете влево.

минус 6

0110
1010

минус 4

0100
1100

Предположительно, есть трюки, которые нужно добавить и вычесть (хорошо, но это легко), но также умножать и делить. Если вы делаете это последовательно, вы можете делать бесконечно длинную математику в двоичном формате с тем же alu. Если бы вы знали, как это сделать, вы можете реализовать это в программном обеспечении, и ваш оригинальный вопрос о перемножении больших констант (с предположением о сохранении всей точности) тривиальен на любом компьютере.

Ответ 5

Ответ, полученный вами, 18446744073709551496, объясняется тем, что ваш 999... 9s усечен при назначении на длинный длинный плюс многократные переполнения операций. Его детерминированный, но фактически просто случайный набор бит.

Ответ 6

unsigned int представляет собой системное слово. Сегодня это слово будет максимальным на 2 ^ 32 -1 или 2 ^ 64 - 1, в зависимости от того, является ли ваша система 32-разрядной или 64-разрядной. Вы попадаете в кепку.

Вам нужно написать класс bignum или использовать его в сети.

Почему вы все равно делаете эту проблему?

Ответ 7

Цифры не могут вписываться в диапазон unsigned long long, чтобы либо вы могли использовать библиотеку GMP, либо использовать строку для представления больших чисел, как, например, для вычисления факториала числа 50:

http://codepad.org/bkWNV0JC

#include <cmath>
#include <iostream>
using namespace std;
int main()
{
  unsigned int nd, nz;   
  unsigned char *ca;   
  unsigned int j, n=50, q, temp;
  int i;
  double p;
    p = 0.0;
    for(j = 2; j <= n; j++)
    {
      p += log10((double)j);  
    }
    nd = (int)p + 1;

    ca = new unsigned char[nd+1];
    if (!ca)
    {
      cout << "Could not allocate memory!!!";
      exit(0);
    }
    for (i = 1; (unsigned)i < nd; i++)
    {
      ca[i] = 0;
    }
    ca[0] = 1;

    p = 0.0;
    for (j = 2; j <= n; j++)
    {
      p += log10((double)j);   
      nz = (int)p + 1;        
      q = 0;                  
      for (i = 0;(unsigned) i <= nz; i++)
      {
        temp = (ca[i] * j) + q;
        q = (temp / 10);
        ca[i] = (char)(temp % 10);
      }
    }

    cout << "\nThe Factorial of " << n << " is: ";
    for( i = nd - 1; i >= 0; i--)
    {
      cout << (int)ca[i];
    }
  //  delete []ca;    
  return 0;
}