Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > IT форум > Помощь студентам
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 21.10.2010, 18:42   #1
Relrin
Пользователь
 
Регистрация: 28.12.2007
Сообщений: 18
По умолчанию Умножение больших чисел

Суть задачи в том, чтобы найти произведение двух 50-значных чисел. Попытка через 3 массива выйти (два для оперирования с числами, и третий для хранения результата) пока не привели к полной решаемости задачи. Какие-то числа считает правильно, какие-то не совсем так (например, 2*3=6 правильно считает, а скажем 15*3=35, что не правильно). Помогите пожайлуйста

Код:
Var
   buf        : integer;           //полученное число, в результате умножения
   des        : integer;           //счетчик "десяток"
   n,m        : integer;           //счетчики длины строки
   i,j,q      : integer;           //переменные для работы со строкой и массивами
   x1,x2      : string;            //сюда вводим числа в виде строк
   c,d: array[1..50]   of integer; //массивы для хранения и оперирования с числами 
   res: array[1..2500] of integer; //результат вычислений

begin
   write('Введите первое число: ');
   readln(x1);
   n:=length(x1);
   write('Введите второе число: ');
   readln(x2);
   m:=length(x2);
   //перенос первого числа в массив
   i:=1;
     repeat
      val(x1[i],c[i],q);
      i:=succ(i);
     until i>n;
   //перенос второго числа в массив  
   i:=1;
     repeat
      val(x2[i],d[i],q);
      i:=succ(i);
     until i>m;
   //умножение двух чисел (умножение "столбиком") 
   for i:=1 to length(x1) do
   begin
     for j:=1 to length(x2) do
     begin
      buf:=c[i]*d[j]+des+res[i+j-1];
      res[i+j-1]:=buf mod 10;
      des:=buf div 10;
     end;
    res[i+j]:=des;
   end;
   //вывод полученного числа 
   if res[1]=0 then
   for i:=2 to length(x1)-length(x2)+1 do write(res[i])
    else 
   for i:=1 to length(x1)-length(x2)+1 do write(res[i]);
   readln;
end.

Последний раз редактировалось Relrin; 21.10.2010 в 18:44.
Relrin вне форума Ответить с цитированием
Старый 21.10.2010, 18:45   #2
Sparky
Участник клуба
 
Аватар для Sparky
 
Регистрация: 15.05.2009
Сообщений: 1,222
По умолчанию

эм вот когда писала длинную вещественную арифметику, может поможет
Код:
public:
			int chislo[count];	//число
			bool znak;	//знак числа + true, - false
			int por;	//порядок числа
			int len;	//длина числа
Код:
longfloat operator *(longfloat a,longfloat b)
{
//=============================================================================================================
//			вычисление знака после умножения	
//=============================================================================================================
	bool z;	//знак в итоге
	if((a.znak && b.znak)||(!a.znak && !b.znak))
		z=true;
	else
		z=false;
//=============================================================================================================
//			инициализация результирующего числа
//=============================================================================================================
	longfloat new_float;
	for(int i=0;i<count;i++)
		new_float.chislo[i]=0;

	new_float.por=1; ///
	new_float.len=1;
	new_float.znak=true;
	a.znak=true;
	b.znak=true;

//=============================================================================================================
//		проверка одного из чисел на 0		
//=============================================================================================================
	bool flag1=true;	//показывает состоит ли первое число из 0
	bool flag2=true;	//показывает состоит ли второе число из 0

	for(int i=0;i<count;i++)
	{
		if(a.chislo[i]!=0)
			flag1=false;
		if(b.chislo[i]!=0)
			flag2=false;
	}

	if(flag1 || flag2)
	{
		new_float.por = 1;
		new_float.len = 1;
		new_float.znak=true;
		return new_float;
	}

	else
	{
//=============================================================================================================
//			вычисление порядка нового числа	
//=============================================================================================================
		int drobn=(a.len-a.por)+(b.len-b.por);
		if (b.len>a.len)
			swap(a,b);
//=============================================================================================================
//			умножение
//=============================================================================================================
		int mark=2;
		for(int j=count-1;j>=(count-b.len);j--)
		{
			for(int k=0;k<b.chislo[j];k++)
				new_float=new_float+a;
			int i=count-a.len-mark;
			for(i;i<count-1;i++)
			{
				a.chislo[i]=a.chislo[i+1];
				a.chislo[i+1]=0;
			}
			mark++;
		}
		new_float.por=new_float.len-drobn;
		if (new_float.por==0)
		{
			new_float.por=1;
			new_float.len++;
		}
//=============================================================================================================
//			обновление знака			
//=============================================================================================================
		new_float.znak=z;
		del(new_float);
		return new_float;
	}

}
Единственное, что ограничивает полет мысли программиста-компилятор
Sparky вне форума Ответить с цитированием
Старый 21.10.2010, 19:46   #3
Aries
Пользователь
Пользователь
 
Аватар для Aries
 
Регистрация: 23.04.2009
Сообщений: 39
По умолчанию

Раз 15*3=35, то получается, что умножает только единицу на тройку и результат складывается с последним числом.
-Вы верите в Бога?
-У меня нет фактов, подтверждающих его существование.
Aries вне форума Ответить с цитированием
Старый 21.10.2010, 20:29   #4
Don Karleone
Форумчанин
 
Регистрация: 05.04.2010
Сообщений: 410
По умолчанию

Вот книга, если я не ошибаюсь, там рассматривается эта тема. Может тебе поможет.
Вложения
Тип файла: rar С.Окулов Программирование в алгоритмах.rar (3.00 Мб, 85 просмотров)
ICQ: 593-013-807
Don Karleone вне форума Ответить с цитированием
Старый 21.10.2010, 20:48   #5
evg_m
Старожил
 
Регистрация: 20.04.2008
Сообщений: 5,526
По умолчанию

Цитата:
Раз 15*3=35, то получается, что умножает только единицу на тройку и результат складывается с последним числом.
скорее не учитывет перенос.
15
3
-----
15 потеряли вот эту единицу
3
-----
35
программа — запись алгоритма на языке понятном транслятору
evg_m вне форума Ответить с цитированием
Старый 21.10.2010, 20:51   #6
Relrin
Пользователь
 
Регистрация: 28.12.2007
Сообщений: 18
По умолчанию

Сейчас осталась маленькая накладка. Когда например считаю число, скажем 3*4, то в результате выходит 12, но выводит только 2, как добавить недостающий знак? (Внизу код умножения)
Подсчеты типа 3*15, 125*4, и т.д. считает правильно!
Код:
   for i:=length(x1) downto 1 do
   begin
     for j:=length(x2) downto 1 do
     begin
      buf:=c[i]*d[j]+des;
        if buf>9 then
        begin
         res[i+j-1]:=buf mod 10;
         des:=buf div 10;
        end
         else
         begin
          res[i+j-1]:=buf;
          des:=0;
         end;    
     end;
   end;

Последний раз редактировалось Relrin; 21.10.2010 в 20:59.
Relrin вне форума Ответить с цитированием
Старый 21.10.2010, 21:45   #7
evg_m
Старожил
 
Регистрация: 20.04.2008
Сообщений: 5,526
По умолчанию

после цикла тоже надо проверять des и сохранять при необходимости
программа — запись алгоритма на языке понятном транслятору
evg_m вне форума Ответить с цитированием
Старый 22.10.2010, 00:10   #8
Kingdom_Reborn
Форумчанин
 
Регистрация: 21.10.2010
Сообщений: 130
Смех Элементарно

Да задача то элементарная! Я на первом курсе решал задачу деления двух длинных чисел. И решение проверялось на тестах, все тесты прошли.

Вот по поводу умножения (на Delphi 7):

Код:
const
  MaxLen = 1000;
  BASE = 10000;
  BASE_DIG = 4;

type
  TLong = record
    Length: Integer;
    Coef: Array[0..MaxLen] of Integer;
  end;

// Обнуляет число типа TLong
procedure Zero(var A: TLong);
begin
  FillChar(A.Coef, SizeOf(A.Coef), 0);
  A.Length := 1;
end;

// возвращает произведение длинного числа на короткое
function Mul(const A: TLong; const B: Longint): TLong;
overload;
var
  C: TLong;
  I: Integer;
begin
  Zero(C);
  for I := 0 to A.Length - 1 do
    C.Coef[I] := A.Coef[I] * B;
  for I := 0 to A.Length - 1 do
  begin
    Inc(C.Coef[I + 1], C.Coef[I] div BASE);
    C.Coef[I] := C.Coef[I] mod BASE;
  end;
  C.Length := A.Length;
  if C.Coef[A.Length] <> 0 then Inc(C.Length);
  Mul := C;
end;

// возвращает произведение двух длинных чисел
function Mul(const A, B: TLong): TLong;
overload;
var
  C: TLong;
  I, J: Integer;
  temp, carry: Integer;
begin
  Zero(C);
  for I := 0 to A.Length - 1 do
  begin
    carry := 0;
    for J := 0 to B.Length - 1 do
    begin
      temp := A.Coef[I] * B.Coef[J] + C.Coef[I + J] + carry;
      carry := temp div BASE;
      C.Coef[I + J] := temp - carry * BASE;
    end;
    C.Coef[I + B.Length] := carry;
  end;
  I := A.Length + B.Length - 1;
  while (I > 0) and (C.Coef[I] = 0) do
    Dec(I);
  C.Length := I + 1;
  Mul := C;
end;

// конвертация строки в число типа TLong
function Convert(S: String): TLong;
var
  I, K, d: Integer;
  _S: String;
  C: TLong;
begin
  Zero(C);
  d := Length(S);
  while d mod BASE_DIG <> 0 do  // добавляем нули слева
  begin
    S := '0' + S;
    Inc(d);
  end;
  K := 0;
  _S := '';
  for I := d downto 1 do
  begin
    _S := Concat(S[I], _S);
    if (I - 1) mod BASE_DIG = 0 then
    begin
      C.Coef[K] := StrToInt(_S);
      Inc(K);
      _S := '';
    end;
  end;
  C.Length := K;
  Convert := C;
end;

// печать длинного числа
procedure Print(const A: TLong);
var
  I: Integer;
  d: Integer;
begin
  for I := A.Length - 1 downto 0 do
  begin
    if I <> A.Length - 1 then
    begin
      d := Length(IntToStr(A.Coef[I]));
      if d < BASE_DIG then
        while d <> BASE_DIG do
        begin
          Write('0');
          Inc(d)
        end;
    end;
    Write(A.Coef[I]);
  end;
  WriteLn;
end;
Как пользоваться, думаю, понимаете - берёте длинное число как строку, конвертируете с помощью процедуры Convert в TLong, а потом передаёте в функции...

P. S. Размеры чисел могут быть огроменные (см. MaxLen и BASE).

Последний раз редактировалось Kingdom_Reborn; 22.10.2010 в 00:17.
Kingdom_Reborn вне форума Ответить с цитированием
Старый 22.10.2010, 07:07   #9
Utkin
Старожил
 
Аватар для Utkin
 
Регистрация: 04.02.2009
Сообщений: 17,351
По умолчанию

Главная проблема - Ваши числа по настоящему большие. Если мне надо хранить сто знаков - Ваш массив займет 1000. Это не было бы такой проблемой, если бы все числа были бы нужного размера. Но основная фишка в том, что числа часто имеет разное число разрядов и хранить лишние нули непозволительная роскошь .
Юзайте динамические массивы, для человеческой реализации. Был бы я преподом, поставил незачет.
Маньяк-самоучка
Utkin появился в результате деления на нуль.
Осторожно! Альтернативная логика
Utkin вне форума Ответить с цитированием
Старый 22.10.2010, 08:34   #10
Serge_Bliznykov
Старожил
 
Регистрация: 09.01.2008
Сообщений: 26,229
По умолчанию

Цитата:
Юзайте динамические массивы, для человеческой реализации. Был бы я преподом, поставил незачет.
Далеко не всё так однозначно, коллега.
1) динамические массивы появились только в Delphi, а в том же Pascal их просто не было.
2) динамические массивы (в общем случае) медленнее, чем статические (правда, основные затраты времени там тратятся на изменение длины массива, но и в работе они тоже медленнее)
3) заданное ограничение вполне оправдано. Тем более исходя из задания.
4) и, последнее, зачем усложнять учебную задачу?
Serge_Bliznykov вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
сложение больших чисел SacReD_89 Общие вопросы C/C++ 21 25.04.2010 16:42
Описание больших чисел через дэк whatever Помощь студентам 3 04.04.2010 19:49
С# Сложение больших чисел SL1CK Помощь студентам 4 23.11.2009 21:07
алгоритм сравнения больших чисел со сдвигом WOLFak Паскаль, Turbo Pascal, PascalABC.NET 0 29.12.2008 22:36
Библиотека больших чисел на Delphi Victor1987 Помощь студентам 10 11.04.2008 08:25