Программа умножает двоичные числа в дополнительном коде. Но умножает неправильно. Помогите пожалуйста найти проблему
var temp,i,j: longint; n,n2,res:longint; s,s2,sim,sim2:string; alf:set of char; ch:char; p,p2,s1,s22,por,pr,apr,step,k:longint; a,b:longint; apr2:longint; arr: array[1..10] of string; c,c2:boolean; begin c:=false; c2:=false; alf:=['0'..'9']; Write('vvedite pervoe chislo: '); Readln(s); Write('vvedite vtoroe chislo: '); Readln(s2); n:=length(s); n2:=length(s2); sim:='';p:=0; sim2:=''; p2:=0; For i:=1 to n do begin {vudelenie cifr iz 1 stroki} If s[i] in alf then sim:=sim+s[i]; If s[i]='-' then c:=true; end; For j:=1 to n2 do begin {vudelenie cifr iz 2 stroki} If s2[j] in alf then sim2:=sim2+s2[j]; If s2[j]='-' then c2:=true; end; For i:=1 to length(sim) do begin {perevod iz stroki v chislo (1)} s1:=ord(sim[i])-ord('0'); p:=p*10+s1; end; For j:=1 to length(sim2) do begin {perevod iz stroki v chislo (2)} s22:=ord(sim2[j])-ord('0'); p2:=p2*10+s22; end; Writeln('chisla: ',p,' ',p2); a:=0; step:=1;n:=1; While p>=2 do begin {perevod iz 10i ss v 2ss (1)} pr:=p div 2; apr:=p-pr*2; a:=a+apr*step; p:=pr; step:=step*10; n:=n+1; If p=1 then a:=step+a; end; Writeln('dvoichnoe predstavlenie 1 chsla: ',a); step:=1; b:=0; por:=1; {perevod iz 10i ss v 2ss (2)} While p2>=2 do begin pr:=p2 div 2; apr:=p2-pr*2; b:=b+apr*step; p2:=pr; step:=step*10; If p2=1 then b:=step+b; por:=por+1; end; Writeln('dvoichnoe predstavlenie 2 chisla: ',b); Writeln('kolichestvo cifr 1: ',n); Writeln(' 2: ',por); If c=true then begin apr:=a; pr:=a; a:=0; k:=1; {perevod 1go chisla v dopolnitelnui kod} For i:=1 to n do begin apr:=pr mod 10; pr:=pr div 10; If apr=0 then apr2:=1; If apr=1 then apr2:=0; a:=a+apr2*k; k:=k*10; end; k:=a mod 10; If k=1 then begin apr:=0; a:=(a div 10)*10+apr; end; If k=0 then begin k:=1; a:=(a div 10)*10+apr; end;
end; { If c=false then a:=p;} Writeln('v dopolnit kode 1: ',a); If c2=true then begin apr:=b; pr:=b; b:=0; k:=1; {perevod 2go chisla v dopolnitelnui kod} For j:=1 to por do begin apr:=pr mod 10; pr:=pr div 10; If apr=0 then apr2:=1; If apr=1 then apr2:=0; b:=b+apr2*k; k:=k*10; end; k:=b mod 10; If k=1 then begin apr:=0; b:=(b div 10)*10+apr; end; If k=0 then begin k:=1; b:=(b div 10)*10+apr; end; end; { If c2=false then b:=p2;} Writeln('v dopolnit kode 2: ',b); res:=0; {ymnozenie} k:=0; n:=1; While k<=64 do begin temp:=n and b; if temp<>0 then res:=res+a; a:=a shl 1; n:=n*2; k:=k+1; end; writeln('rezyltat v dopolnitelnom kode: ',res); readln; end.
Федосеев Павел
24.03.2012 20:54
происходит переполнение разрядной сетки переменной n. Если ограничить множители 8-ю битами, т.е. диапазоном (-128...+127), то
While k<=64 do begin <---- k<8 temp:=n and b; if temp<>0 then res:=res+a; a:=a shl 1; n:=n*2; <--- n:=n shl 1; k:=k+1; end;
В дополнительный код неправильно переводит отрицательные числа. Опять же, если ограничиться 8-ю битами, то число (-210)=-102=1111 11102. Алгоритм такой: все 8 бит исходного числа инвертируешь и прибавляешь 1. (-210)=-102=1111 11012 доп+1=1111 11102 доп При умножении двух чисел нужно умножать их модули, а потом с учётом знака результата переводить или не переводить в дополнительный код.
Если не сложно, немного реструктурируй код: ввод строки, преобразования в двоичный, в дополнительный коды вынеси в процедуры или функции.
А ещё, приведи исходную постановку задачи.
olven
24.03.2012 21:04
Цитата(Федосеев Павел @ 24.03.2012 17:54)
происходит переполнение разрядной сетки переменной n. Если ограничить множители 8-ю битами, т.е. диапазоном (-128...+127), то
While k<=64 do begin <---- k<8 temp:=n and b; if temp<>0 then res:=res+a; a:=a shl 1; n:=n*2; <--- n:=n shl 1; k:=k+1; end;
В дополнительный код неправильно переводит отрицательные числа. Опять же, если ограничиться 8-ю битами, то число (-210)=-102=1111 11102. Алгоритм такой: все 8 бит исходного числа инвертируешь и прибавляешь 1. (-210)=-102=1111 11012 доп+1=1111 11102 доп При умножении двух чисел нужно умножать их модули, а потом с учётом знака результата переводить или не переводить в дополнительный код.
Если не сложно, немного реструктурируй код: ввод строки, преобразования в двоичный, в дополнительный коды вынеси в процедуры или функции.
спасибо большое. поняла. правда 8 бит это немало? мне нужно переводить именно длинные числа... попробовала для длинных не совсем то что нужно выдает...
Krjuger
24.03.2012 21:13
Привидите пример и резальтат.
Федосеев Павел
24.03.2012 21:16
Можно взять и больше, но дополнительный код для отрицательных чисел будет длиннее. Так для 16 разрядов -210=1111 1111 1111 11102 доп. для длинных чисел применяют другой тип хранения чисел - массив или строку. И соответственно определяют в виде процедур все операции над числами (+, -, *, /). Имея простые операции уже и реализуют все остальные вычисления. На форуме должны быть примеры.
Приведи исходный текст задания.
olven
24.03.2012 21:22
Цитата(Krjuger @ 24.03.2012 18:13)
Привидите пример и резальтат.
любые числа. диапозон дб Longint -2147483648..2147483647 . 25 и 26 вводимые. результат в двоичн. дополнит. 10010001010
Добавлено через 5 мин. пользователь должен ввести любое десятичное число. программа перевести его в дополнительный код и перемножить. независимо отрицателньое оно или положительное. результат выдается в десятичном же числе. Умножаются длинные целые числа
Федосеев Павел
24.03.2012 22:30
Я не могу понять смысл задания.
Вот описание работы с длинными положительными целыми числами.
Добавим к тем реализациям дополнительное поле "знак" и сможем работать и с отрицательными.
Но как к ним прикрутить дополнительный код?
olven
24.03.2012 22:37
Цитата(Федосеев Павел @ 24.03.2012 19:30)
Я не могу понять смысл задания.
Вот описание работы с длинными положительными целыми числами.
Добавим к тем реализациям дополнительное поле "знак" и сможем работать и с отрицательными.
Но как к ним прикрутить дополнительный код?
смотрела эту тему.. всё что поняла из кода это то что они там кажется столбиком перемножают... мне необходдимо по алгоритму. сложил - сдвинул, сложил-сдвинул.. как я и пыталась
Федосеев Павел
24.03.2012 23:33
Я не могу понять смысл задания.
Как прикрутить дополнительный код? ------------------------------------------------------------------------ Может быть речь идёт о типе LongInt? Т.е. всё - и мнгожители и произведение умещается в тип LongInt? Тогда решение задания получается таким: 1. Ввод 1-го числа в виде строки s1. Далее просто преобразование строки в число LongInt (забываем про встроенные возможности языка). 2. Преобразование s1 в беззнаковое (пока) число c1 (типа LongInt) и знак sign1 (boolean) 3. Если c1 должно быть отрицательным, то c1:=(NOT c1)+1. Вернее здесь будет чуть иначе, но это детали. Тоже самое и со вторым числом. Потом умножаем c1 на c2 и выводим результат средствами языка (writeln).
Кажется, что я подменяю условие...
olven
24.03.2012 23:40
Цитата(Федосеев Павел @ 24.03.2012 20:33)
Я не могу понять смысл задания.
Как прикрутить дополнительный код? ------------------------------------------------------------------------ Может быть речь идёт о типе LongInt? Т.е. всё - и мнгожители и произведение умещается в тип LongInt? Тогда решение задания получается таким: 1. Ввод 1-го числа в виде строки s1. Далее просто преобразование строки в число LongInt (забываем про встроенные возможности языка). 2. Преобразование s1 в беззнаковое (пока) число c1 (типа LongInt) и знак sign1 (boolean) 3. Если c1 должно быть отрицательным, то c1:=(NOT c1)+1. Вернее здесь будет чуть иначе, но это детали. Тоже самое и со вторым числом. Потом умножаем c1 на c2 и выводим результат средствами языка (writeln).
Кажется, что я подменяю условие...
там нет ограничений каким способом. главное чтобы выполнялись условия, то что ты написал это просто мой метод я пыталась решить это так, но для длинных чисел он не работает, из твоих слов поняла, что нужно писать по другому, представлять формат в виде строк или массива. но как это делают я без понятия. пытаюсь разобраться
Федосеев Павел
25.03.2012 0:22
Ага, значит в оригинальном условии задачи фраза "дополнительный код" не упоминалась?
olven
25.03.2012 0:43
Цитата(Федосеев Павел @ 24.03.2012 21:22)
Ага, значит в оригинальном условии задачи фраза "дополнительный код" не упоминалась?
упоминалась,иначе я б не стала столько мучиться.... я думаю может нужно просто если положит числа то в двоичном прямом коде перемножить. а если отриц то перевести в дополнительный и там попробовать?
olven
31.03.2012 18:56
Длинная арифметика попробовала умножение описанноездесь. оно тоэе не работает для длинных... ии я что то не понимаю? почему при числах больше 10 переводя в двоичный код результат выдается неверный?
Федосеев Павел
31.03.2012 21:48
Приведи пример, на котором возникла ошибка (и данные и программу). Сейчас я попробовал умножение из модуля dlinna - показал верный результат. Никаких дополнительных преобразований в двоичный код там не предполагается. В модуле есть штатные средства визуализации - WriteLong. Ты уже столько сил затратила на изучение различныных форматов данных... Может стоит уточнить у преподавателя, что требуется от учебной программы?
Цитата
любые числа. диапозон дб Longint -2147483648..2147483647 . 25 и 26 вводимые. результат в двоичн. дополнит. 10010001010
Добавлено через 5 мин. пользователь должен ввести любое десятичное число. программа перевести его в дополнительный код и перемножить. независимо отрицателньое оно или положительное. результат выдается в десятичном же числе. Умножаются длинные целые числа
Если взять это за основу, то получается, что требуется "забыть" о существовании штатных Write и Read, и самостоятельно пересоздать их. Затем "забыть" о существовании типа longint и создать свои процедуры для работы с ним. Вот без реализации умножения и деления (по-сути с чего начался топик):
TYPE TLongBin = LongInt;
VAR LongBin_Error : Integer;
PROCEDURE LongBin_Add ( m1, m2 : TLongBin; VAR Res : TLongBin); BEGIN END;
PROCEDURE LongBin_Sub ( m1, m2 : TLongBin; VAR Res : TLongBin); BEGIN END;
PROCEDURE LongBin_Mul ( m1, m2 : TLongBin; VAR Res : TLongBin); BEGIN Res:=m1*m2; END;
PROCEDURE LongBin_Div (m1, m2 : TLongBin; VAR Res : TLongBin); BEGIN END;
PROCEDURE LongBin_Read (VAR Num : TLongBin); VAR s : String; i, start : Integer; Sign : BOOLEAN; BEGIN ReadLn(s); Sign:=(s[1]='-'); if Sign then start:=2 else start:=1; for i:=start to Length(s) do begin if NOT (s[i] in ['0'..'9']) then begin LongBin_Error:=1; Exit; end; Num:=Num*10; Num:=Num+(Ord(s[i])-Ord('0')) end; {если число отрицательное, то преобразуем в дополнительный код} if Sign then begin Num:=NOT(Num)+1; end; END;
PROCEDURE LongBin_WriteD( Num : TLongBin); BEGIN Write(Num); END;
PROCEDURE LongBin_WriteB( Num : TLongBin); VAR i : Integer; s : String; Mask : TLongBin; BEGIN Mask:=1; for i:=1 to (SizeOf(TLongBin)*8-1) do Mask:=Mask shl 1; s:=''; for i:=1 to SizeOf(TLongBin)*8 do begin if (Mask AND Num)<>0 then s:=s+'1' else s:=s+'0'; Mask:=Mask shr 1; end; Write(s); END;
----------------------------- Добавлю во вложении исправленный вариант. В нём реализовано сложение, вычитание и умножение. Если реализовать деление, то можно корректно оформить и вывод в десятичном виде. Тогда размер длинных чисел можно будет не ограничивать 4 байтами.Нажмите для просмотра прикрепленного файла
olven
2.04.2012 0:01
спасибо большое, попробую разобраться.... по моему я уже сама запуталась...
olven
24.04.2012 1:21
скажите пожалуйста можно ли добавить в программу часть которая показывает это умножение?
Федосеев Павел
24.04.2012 12:38
А что нужно показать? В процедуре LongBin_Mul простое умножение в столбик (правда, желательно ввести проверку на переполнение разрядной сетки - но ведь это всего лишь пример). Далее в программе приводится пример использования этой процедуры "LongBin_Mul(c1, c2, c3);", где c1, c2 - первый и второй множители, а c3 - их произведение.
olven
24.04.2012 16:11
Цитата(Федосеев Павел @ 24.04.2012 9:38)
А что нужно показать? В процедуре LongBin_Mul простое умножение в столбик (правда, желательно ввести проверку на переполнение разрядной сетки - но ведь это всего лишь пример). Далее в программе приводится пример использования этой процедуры "LongBin_Mul(c1, c2, c3);", где c1, c2 - первый и второй множители, а c3 - их произведение.
как они перемножаются пошагово,показать как осуществляется умножение в дополнительном коде,допустим человеку который не умеет этого делать, как то так сказали. можно еще вопрос о функции hi() и lo() как они выделяют байты?
Федосеев Павел
24.04.2012 17:59
1) hi/lo - hi - возвращает старший байт слова (для типа word) или старшее слово (для типа longint). В контексте данной процедуры - старший байт слова (word). - lo - аналогично hi, только возвращает младшую часть. В нашем случае младший байт слова. 2) В процедуре умножения в дополнительном коде как такового нет. В самом начале процедуры выясняются знаки множителей (Sign1 и Sign2) и вычисляется знак результата (SignRes). Далее берётся модуль каждого множителя (LongBin_Abs) и перемножаются именно модули (положительные числа). После перемножения, если нужно (SignRes == TRUE) результат делается отрицательным - переводится в дополнительный код. В принципе, при умножении в столбик мы тоже так и поступаем - умножаем модули чисел и определяем знак результата. 3) Если будет достаточно показать входные числа, затем их абсолютные значения, абсолютное, а затем и знаковое значение произведения, то см. в аттаче. Если требуется показать всё умножение столбиком, то там слишком много переделывать.
olven
24.04.2012 20:33
Цитата(Федосеев Павел @ 24.04.2012 14:59)
1) hi/lo - hi - возвращает старший байт слова (для типа word) или старшее слово (для типа longint). В контексте данной процедуры - старший байт слова (word). - lo - аналогично hi, только возвращает младшую часть. В нашем случае младший байт слова. 2) В процедуре умножения в дополнительном коде как такового нет. В самом начале процедуры выясняются знаки множителей (Sign1 и Sign2) и вычисляется знак результата (SignRes). Далее берётся модуль каждого множителя (LongBin_Abs) и перемножаются именно модули (положительные числа). После перемножения, если нужно (SignRes == TRUE) результат делается отрицательным - переводится в дополнительный код. В принципе, при умножении в столбик мы тоже так и поступаем - умножаем модули чисел и определяем знак результата. 3) Если будет достаточно показать входные числа, затем их абсолютные значения, абсолютное, а затем и знаковое значение произведения, то см. в аттаче. Если требуется показать всё умножение столбиком, то там слишком много переделывать.
плохо.. ладно, понятно.. спасибо
Федосеев Павел
24.04.2012 22:46
olven, я немного поторопился, гворя о невозможности демонстрации умножения в столбик. Вот изменения. Т.к. умножение производится байтами - оно получается как бы в 256-ричной системе.
olven
29.04.2012 22:28
выводить нужно не совсем это.... нужно вообще показать как осущетвляется умножение в дополнительном коде пошагово.... сложение сдвиг... и так до конца
Федосеев Павел
30.04.2012 0:07
Прикольно - ваш препод знает толк в извращениях. К чему это я... Например. у нас 4-х байтовое число. прои умножении указанным образом имеем 32 слагаемых (для отображения на экран), плюс обрамление... В общем на экране в 25 строк не поместится. Следующее задание - вывод результата в файл или пауза для ожидания нажатия на клавишу?
{сдвиг влево на один разряд} PROCEDURE LongBin_SHL(VAR a : TArrayBin); VAR i, CarryPrev, CarryCurr : Integer; BEGIN CarryPrev:=0;{предыдущий байт при сдвиге не дал перенос} CarryCurr:=0;{текущий байт при сдвиге не дал перенос} for i:=1 to CLongLen do begin CarryCurr:=(a[i] AND $80); {бит, который будет переноситься в следующий байт} {$ifopt R+} {временно отключим контроль переполнения} {$R-} {$define ReqSet_OptR} {$endif} a[i]:=a[i] SHL 1; {$ifdef ReqSet_OptR} {$R+} {$undef ReqSet_OptR} {$endif} if CarryPrev<>0 then a[i]:=(a[i] OR 1); CarryPrev:=CarryCurr; end; END; {Умножение по принципу сложение-сдвиг} PROCEDURE LongBin_NewMul( a, b : TArrayBin; VAR Res : TArrayBin; Log : BOOLEAN); VAR i, j : Integer; Mask : Byte; Zero : TArrayBin; {равно нулю - для вывода на экран} BEGIN if Log then begin LongBin_WriteB(a); WriteLn; WriteLn('x'); LongBin_WriteB(b); WriteLn; WriteLn('-------------------------------------'); end;
FillChar(Res, Sizeof(Res), 0); Zero:=Res; for i:=1 to CLongLen do begin {цикл по всем байтам числа b} Mask:=1; for j:=1 to 8 do begin {цикл по всем битам числа b} if Log then begin if (Mask AND b[i])<>0 then LongBin_WriteB(a) else LongBin_WriteB(Zero); WriteLn; end; if (Mask AND b[i])<>0 then LongBin_Add(Res, a, Res); LongBin_SHL(a); {$ifopt R+} {временно отключим контроль переполнения} {$R-} {$define ReqSet_OptR} {$endif} Mask:=Mask SHL 1; {$ifdef ReqSet_OptR} {$R+} {$undef ReqSet_OptR} {$endif} end; end; if Log then begin WriteLn('-------------------------------------'); LongBin_WriteB(Res); WriteLn; end; END;
Умножение я реализовал как википедии "http://en.wikipedia.org/wiki/Two's_complement" - с отсечением "лишних" разрядов.
olven
30.04.2012 1:23
она говорила лучше в файл записывать всё т.к. не умещается на экране как выи сказали. да скорее всего у меня просто руки кривые, препод не виноват. задача есть задача...
Федосеев Павел
30.04.2012 1:28
Нормальные руки. Ну в файл-то легко отправить.
olven
30.04.2012 1:33
да, отправлю думаю. только не поняла. какое количество раз оно показывает сложение и сдвиги.. у меня слишком много получилось что то
Федосеев Павел
30.04.2012 1:37
Лог умножения, как видно из листинга примерно такой 111110001010 x 101010010101 ----------------- 010101010101 010101010101 ........всего 32 разряда, значит 32 слагаемых ----------------- 101010100101 - это результат
Итого 3+32+1+1=36 строк
olven
30.04.2012 1:42
спасибо большое
Федосеев Павел
30.04.2012 1:44
Знаешь, чтобы не переделывать всё, можно сделать перенаправление вывода с экрана в файл.
это в самом первом if Log Assign(output, 'Log.txt'); rewrite(output);
а это в последних строках последнего if Log Close(output) Assign(output) rewrite(output)
olven
30.04.2012 1:51
так странно, он так не записывает. пустой файл
Добавлено через 3 мин. я исправила, немного по другому, записывает=)
Федосеев Павел
30.04.2012 1:56
Сейчас проверил на TP7 и FPC2.4.2 Файл создаётся. Приаттачу свой вариант, но это не для преподавателя - я в нём просто тестировал процедурки. ---------------- Опоздал я с репликой!
Ну и хорошо, что работает!!!
olven
30.04.2012 2:08
в файле запись сдигов всего лишь?
Федосеев Павел
30.04.2012 2:14
Да. Только лог умножения. Но если перенаправить вывод в теле основной программы. то можно получить и весь лог.
Вообще-то такое решение - костыль. Если по хорошему, то нужно было делать процедуры не вывода на экран и ввода с клавиатуры, а преобразования числа в строку и строки в число. А потом уже решать, что делать со строками - на экран или в файл.
olven
30.04.2012 2:22
понятно.. там вроде как и для длминных чисел не весь лог помещается
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.