Разделение массива. Как лучше всего разделить два числа, хранящиеся в массиве?

У меня есть два массива (дивиденд, делитель):

dividend[] = {1,2,0,9,8,7,5,6,6};
divisor[] = {9,8};

Мне нужен результат (дивиденд/делитель) как:

quotient[] = {1,2,3,4,5,6,7};

Я сделал это, используя вычитание массива:

  • вычитать делитель из делимого до тех пор, пока делимое не станет равным 0 или меньше делителя, каждый раз увеличивая частное на 1,

но это занимает огромное время. Есть лучший способ сделать это?


person josh    schedule 23.07.2010    source источник
comment
Я не совсем уверен, что понимаю - как вы получаете массив частных из предоставленного вами примера делимого и делителя? Будут ли ваши массивы дивидендов и массивы делителей иметь разную длину? Если да, то как вы сопоставляете, какой элемент массива из вашего массива делителей совпадает с вашим массивом дивидендов?   -  person Adam McKee    schedule 24.07.2010
comment
@Adam: очевидно, он делит 120987566 на 98, что дает 1234567. Проблема в том, что отдельные десятичные цифры хранятся в массивах. Как Джеймс предлагает ниже, он может просто реализовать полное деление, как учили в начальной школе.   -  person Paul R    schedule 24.07.2010


Ответы (7)


Есть лучший способ сделать это?

Вы можете использовать полное деление.

person James McNellis    schedule 23.07.2010

Делайте длинное деление.

Имейте временное хранилище размером, равным делителю плюс один, и инициализируйте его нулем:

accumulator[] = {0,0,0};

Теперь запустите цикл:

  1. Сдвиньте каждую цифру частного на одну позицию влево.
  2. Сдвиньте каждую цифру аккумулятора на одну позицию вправо.
  3. Возьмите следующую цифру делимого, начиная с самого старшего конца, и сохраните ее в наименее значимом разряде аккумулятора.
  4. Вычислите accumulator / divisor и установите младший разряд частного в результат. Установите аккумулятор на остаток.

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

person Nietzche-jou    schedule 23.07.2010
comment
Что вызывает связанный с этим вопрос, как вы вычисляете аккумулятор/делитель? - person Drew Hall; 24.07.2010
comment
Используйте повторные вычитания, но с этим методом вы сделаете около 40 вместо 1 234 567 из них. - person Nietzche-jou; 24.07.2010
comment
Я точно не помню трюк, но Кнут показывает способ сделать это с не более чем двумя вычитаниями (вместо 40 здесь) на цифру частного. TAOCP том. 2 я думаю. - person Drew Hall; 24.07.2010

Кроме этого, рассматривали ли вы возможность использования класса BigInt (или эквивалентного в вашем языке), который уже сделает это за вас?

person Lie Ryan    schedule 23.07.2010
comment
Я думаю, что класс BigInt применим только к Java, а в С++ я не знаю ничего, что служит этой цели. - person josh; 24.07.2010
comment
Как насчет библиотеки GNU MP Bignum — gmplib.org. GMP is a free library for arbitrary precision arithmetic, operating on signed integers, rational numbers, and floating point numbers - person dsolimano; 24.07.2010
comment
Да, и есть также библиотека OpenSSL BigNum. - person caf; 24.07.2010

Вы можете использовать длинное деление http://en.wikipedia.org/wiki/Long_division

person Tauquir    schedule 24.07.2010

Вы можете использовать алгоритм деления в длину или более общий Полиномиальное длинное деление.

person Lie Ryan    schedule 23.07.2010

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

в псевдокоде:

int dividend_number
foreach i in dividend
    dividend_number *= 10
    dividend_number += i

int divisor_number
foreach i in divisor
    divisor_number *= 10
    divisor_number += i

int answer = dividend_number / divisor_number;
person dsolimano    schedule 23.07.2010
comment
Это может легко вызвать переполнение. Если бы ОП мог это сделать, он, вероятно, вообще не использовал бы массивы. - person IVlad; 24.07.2010
comment
да, это правда, я работаю с числами, имеющими 100 цифр. - person josh; 24.07.2010
comment
Я думаю, дело в том, что числа в массиве представляют собой BigInts, то есть они потенциально могут быть намного больше, чем могут поместиться в целое число. - person Drew Hall; 24.07.2010
comment
А, думал, это академическое упражнение. Похоже, тогда он должен использовать что-то вроде GMP, не так ли? - person dsolimano; 24.07.2010

Ну вот! А делитель. В — делитель. C — целое частное, R — остальное. Каждое "огромное" число является вектором, сохраняющим большое число. В массиве huge[0] мы сохраняем количество цифр, которое имеет число, а затем число запоминается в обратном порядке. Допустим, у нас есть число 1234, тогда основной вектор будет:

v[0]=4; //number of digits
v[1]=4;
v[2]=3;
v[3]=2;
v[4]=1;

....

SHL(H,1) does: H=H*10;
SGN(A,B) Compares the A and B numbers
SUBSTRACT(A,B) does: A=A-B;
DIVIDHUGE: makes the division using the mentioned procedures...

void Shl(Huge H, int Count)
/* H <- H*10ACount */
{ 
  memmove(&H[Count+1],&H[1],sizeof(int)*H[0]);
  memset(&H[1],0,sizeof(int)*Count);
   H[0]+=Count;
}
    int Sgn(Huge H1, Huge H2) {
      while (H1[0] && !H1[H1[0]]) H1[0]--;
      while (H2[0] && !H2[H2[0]]) H2[0]--;

      if (H1[0] < H2[0]) {
        return -1;
      } else if (H1[0] > H2[0]) {
        return +1;
      }

      for (int i = H1[0]; i > 0; --i) {
        if (H1[i] < H2[i]) {
          return -1;
        } else if (H1[i] > H2[i]) {
          return +1;
        }
      }
      return 0;
    }

        void Subtract(Huge A, Huge B)
        /* A <- A-B */
        { int i, T=0;

          for (i=B[0]+1;i<=A[0];) B[i++]=0;
          for (i=1;i<=A[0];i++)
            A[i]+= (T=(A[i]-=B[i]+T)<0) ? 10 : 0;
          while (!A[A[0]]) A[0]--;
        }


            void DivideHuge(Huge A, Huge B, Huge C, Huge R)
            /* A/B = C rest R */
            { int i;

              R[0]=0;C[0]=A[0];
              for (i=A[0];i;i--)
                { Shl(R,1);R[1]=A[i];
                  C[i]=0;
                  while (Sgn(B,R)!=1)
                    { C[i]++;
                      Subtract(R,B);
                    }
                }
              while (!C[C[0]] && C[0]>1) C[0]--;
            }
person XCS    schedule 01.08.2010