Составить программу вычисления числа размещений из N элементов по M, без использования готовых функций
Нужно использовать строковый тип данных(числа перевести в строку), т.к. числовой тип не сможет решить задачу при N>10000 и M>100 это будет выход из границ. Либо другим способом чтобы n и m при вводе были такими как описано выше.
Помогите пожалуйста написать программу на Pascal. Ответ необходимо записать в txt файл в котором будет ответ (огромное число).
Материал к задаче:
В теории чисел могут понадобится вычисления с большими целыми числами. При этом очень важным является сохранение всех значащих цифр. Имеющиеся во всех языках программирования числовые типы имеют ограниченную длину разрядной сетки. При ее превышении происходит либо округление, либо просто отбрасывание последующих цифр. Реализовать операции с многоразрядными числами без потери значащих цифр можно двумя способами. а) Запоминать каждое число в массиве. При этом, каждый элемент массива будет хранить одну цифру числа. б) Запоминать числа в виде строк. Рассмотрим второй способ. В этом случае необходимо реализовать базовые алгебраические операции над числами-строками – сложение, вычитание, умножение, целочисленное деление и вычисление остатка от целочисленного деления. При разработке программ, работающих с длинными числами целесообразно эти базовые операции реализовать в виде отдельных функций и затем уже использовать их в основной программе. Алгоритмы реализации просто повторяют алгоритмы вычислений «столбиком», которые осваиваются в младших классах начальной школы. Например, для операции сложения: В цикле, начиная с последнего символа (цифры) и кончая первым
- каждая пара символов преобразуется в числа - х1 и х2;
- эти числа складываются
- при этом переменная р следит за тем, что не была сумма предыдущей пары чисел больше 9. Если «да», то к х добавляется 1;
- если х больше 9, то в качестве результата сложения берется вторая цифра, а переменная р принимает значение “True” (один в уме);
- если х меньше 10, переменная р принимает значение “False”; По окончании цикла, если «в уме» еще что-то есть, впереди к результату добавляется 1. Если есть возможность выбора между языками программирования, то лучше выбирать Паскаль – уж слишком неуклюжи операции со строками в Бейсике (хотя все это дело вкуса и привычки). Итак, пусть имеются два длинных числа, представленных в виде строк. Тогда программная реализация операций сложения и вычитания в виде функции может выглядеть следующим образом (Паскаль).
{ Выравнивание длин чисел }
Procedure Equel(Var s1,s2:string;Var l:integer);
Var i,l1,l2:integer;
begin
l1:=Length(s1);
l2:=Length(s2);
If l1>l2 then begin
l:=l1;
For i:=1 to l-l2 do s2:='0'+s2
end
else begin
l:=l2;
For i:=1 to l-l1 do s1:='0'+s1
end
end;
{ Сложение }
Function Plus(a,b:string):string;
Var i,k,l:integer;
x,x1,x2:integer;
s,c:string;
p:boolean;
begin
Equel(a,b,l);
p:=False;
s:='';
For i:=l Downto 1 do
begin
Val(a[i],x1,k);
Val(b[i],x2,k);
x:=x1+x2;If p then x:=x+1;
If x>9 then p:=True else p:=False;
x:=x mod 10;
Str(x,c);
s:=c+s
end;
If p then s:='1'+s;
Plus:=s
end;
{ Вычитание }
Function Minus(a,b:string):string;
Var i,k,l:integer;
x,x1,x2:integer;
s,c:string;
p:boolean;
begin
Equel(a,b,l);
p:=False;
s:='';
For i:=l Downto 1 do
begin
Val(a[i],x1,k);
Val(b[i],x2,k);
If p then x1:=x1-1;
If x1<x2 then begin x1:=x1+10;p:=True end
else p:=False;
x:=x1-x2;
Str(x,c);
s:=c+s
end;
While (s[1]='0') and (Length(s)>1) do Delete(s,1,1);
Minus:=s
end;
Здесь понадобилась еще одна функция - выравнивание длин складываемых (вычитаемых) чисел. При этом к более короткому числу впереди добавляется нужное количество нулей. В принципе уже этих функций достаточно для реализации всех остальных алгебраических операций, т. к. операцию умножения можно заменить многократным сложением, а деление - многократным вычитанием. Например, решить задачу об изобретателе шахмат. В качестве вознаграждения за свое изобретение он потребовал на первую клетку положить одно зернышко, на вторую – два, на третью – четыре, на четвертую восемь и т. д. Спрашивается, сколько ему необходимо выдать зерна, если одно зернышко весит 1 г? Программная реализация
Uses Crt;
Var a,b:string;
i:integer;
Procedure Equel …
…
…
Function Plus …
…
…
Begin
ClrScr;
a:='1'; {Количество зерен в клетке }
b:=a; {Общее количество зерен }
For i:=1 to 63 do
begin
a:=Plus(a,a); {Умножение на 2 }
b:=Plus(b,a) {Сложение с остальными }
end;
Insert(',',b,Length(b)-5); {Перевод в тонны – вставка запятой }
Writeln(b+' тонн');
Readkey
end.
Результат – 18446744073709,551615 тонн.
Однако реализация умножения через сложение (деление через вычитание) работает слишком медленно в случае больших сомножителей (или(делимых). Поэтому эти операции все-таки лучше реализовать по школьным алгоритмам. Тем более что они должны использоваться практически во всех заданиях.
Реализация перемножения столбиком (PascalABC).
// Умножение числа на одну цифру
Function MultiOne(a:string;b:integer):string;
Var i,j:integer;
s,s1:string;
x:integer;
begin
s:='';
For i:=Length(a) Downto 1 do begin
x:=StrToInt(a[i]);
x:=x*b;
s1:=IntToStr(x);
For j:=1 to (Length(a)-i) do s1:=s1+'0';
s:=Plus(s,s1)
end;
MultiOne:=s
end;
// Перемножение
Function Multi(a,b:string):string;
Var i,j:integer;
s1,s:string;
begin
s:='';
For i:=Length(b) Downto 1 do begin
s1:=MultiOne(a,StrToInt(b[i]));
For j:=1 to (Length(b)-i) do s1:=s1+'0';
s:=Plus(s,s1)
end;
Multi:=s
end;
Ответы (1 шт):
Не чистый паскаль, а PascalABC.Net, но без использования .Net библиотек. Старалась по крайней мере.
Ваш код был не рабочий, пришлось исправлять, дополнять, оптимизировать. Надеюсь это тот результат, который хотели получить.
// Возвращает n-ую с конца цифру или 0
function GetFromRight(s: string; n: integer): integer;
begin
var l := Length(s);
if (n > l) or (n <= 0) then Result := 0 else Result := StrToInt(s[l - n + 1]);
end;
// Убираем лишние нули вначале
function RemoveLeftZeros(s: string): string;
begin
while (Length(s) > 1) and (s[1] = '0') do Delete(s, 1, 1);
Result := s;
end;
function Plus(a, b: string): string;
begin
var ten := 0; //признак изменения десятков
var res := '';
for var i := 1 to max(Length(a), Length(b)) do
begin
var x := GetFromRight(a, i) + GetFromRight(b, i) + ten;
ten := x div 10;
res := IntToStr(x mod 10) + res;
end;
if ten > 0 then res := IntToStr(ten) + res;
Result := RemoveLeftZeros(res);
end;
function Minus(a, b: string): string;
begin
var ten := False;
var res := '';
for var i := 1 to max(Length(a), Length(b)) do
begin
var xa := GetFromRight(a, i);
var xb := GetFromRight(b, i);
if ten then xa := xa - 1;
ten := xa < xb;
if ten then xa := xa + 10;
res := IntToStr(xa - xb) + res;
end;
if ten then Result := '-' + Minus(b, a) else Result := RemoveLeftZeros(res);
end;
// Умножение числа на одну цифру
function Multiply(a: string; n: integer): string;
begin
n := n mod 10; // на всякий пожарный
var res := '';
var ten := 0;
for var i := Length(a) downto 1 do
begin
var x := StrToInt(a[i]) * n + ten;
ten := x div 10;
res := IntToStr(x mod 10) + res;
end;
if ten > 0 then res := IntToStr(ten) + res;
Result := RemoveLeftZeros(res);
end;
// Yмножение
function Multiply(a, b: string): string;
begin
var res := '';
for var i := Length(b) downto 1 do
begin
var s1 := Multiply(a, StrToInt(b[i]));
for var j := 1 to (Length(b) - i) do
s1 := s1 + '0';
res := Plus(res, s1);
end;
Result := RemoveLeftZeros(res);
end;
procedure Test();
begin
for var a := 0 to 110 do
begin
PrintLn('a = ', a);
for var b := 10200 to 10345 do
begin
var sa := IntToStr(a);
var sb := IntToStr(b);
var t := plus(sa, sb);
if t <> IntToStr(a + b) then WriteLnFormat('{0} + {1} = {2} | {3}', a, b, a + b, t);
t := minus(sa, sb);
if t <> IntToStr(a - b) then WriteLnFormat('{0} - {1} = {2} | {3}', a, b, a - b, t);
if a < 10 then begin
t := Multiply(sb, a);
if t <> IntToStr(a * b) then WriteLnFormat('{0} * {1} = {2} | {3} ', b, a, a * b, t);
end;
t := Multiply(sa, sb);
if t <> IntToStr(a * b) then WriteLnFormat('{0} * {1} = {2} | {3}: ', a, b, a * b, t);
end;
end;
end;
//задачя о зернах на шахматной доске
function WheatAndChessboardProblem(): string;
begin
var current_cell := '01'; //Количество зерен на клетке
var sum := current_cell; //Общее количество зерен
for var i := 2 to 64 do
begin
current_cell := Multiply(current_cell, 2); //Умножение на 2
sum := Plus(sum, current_cell); //Сложение с остальными
end;
var ves := Multiply(sum, '65'); // одно зёрнышко пшеницы имеет массу 0,065 грамма
Insert('.', ves, Length(ves) - 9 + 1); // Перевод в тонны, делим на 1е9
Result := sum + ' зерен' + chr(13) + ves + ' тонн пшеницы';
end;
//Количество размещений без повторений = n * (n-1) * (n-2) * ... * (n-m+1) = n!/(n-m)!
function CountPermutations(n: string; m: integer): string;
begin
var A := '01';
for var i := 0 to m - 1 do
begin
var x := Minus(n, IntToStr(i));
A := Multiply(A, x);
end;
Result := 'A = ' + A;
end;
begin
// Test();
WriteAllText('result.txt', WheatAndChessboardProblem());
WriteAllText('result.txt', CountPermutations('2343', 292));
end.
Вывод:
18446744073709551615 зерен
1199038364791.120854975 тонн пшеницы
и
A = 5621020464221928081622596846312979894386396770390213138833519820801312892717218260705821410899957656193532367187812625175169950728458223021700671049119063882650289310073663931121529174633862319495473968748420439049798273258619051330907291415548617057214205215113540305221124312373237470322114930522810430007231900870006888557940326348641980146874452760708096917684962292294038928239614281031440555480320270358118366277307373773731746329635734415141151648443101133481615732096247619289444695068418921081554005451949797687871362483531092377657996760178567103420740723160785502249941837483511681488579247893487183598849265463814419823980261412706260621769699366046977852327732061227636668451747633024873964924955658921192743966188915442852068289253728160682403345773402505230975019974271304498395650496962625556368227828940477698331245097688884413644819470388094010547057574302724450437205988785290815628902400000000000000000000000000000000000000000000000000000000000000000000000