PDA

View Full Version : محاسبه 200 فاکتوریل؟



DelphiAmateur
جمعه 17 مرداد 1382, 22:06 عصر
با سلام
چگونه می توان!200 و اعداد بزرگتر را محاسبه کرد با توجه به اینکه هیچ یک از انواع داده ها تا این حد بزرگ نیستند؟لطفا در نوشتن این برنامه کمکم کنید
ممنون

v_shalchian
شنبه 18 مرداد 1382, 09:57 صبح
سلام
شما برای این کار می توانید یک آرایه با طول زیاد تعریف کنید که عناصر این آرایه اعداد یک رقمی باشند و با این آرایه را می توانید مثل یک عدد بسیار بزرگ برخورد کنید.فقط کافیست اعمال جمع و ضرب را روی آن تعریف کنید.

Kambiz
شنبه 18 مرداد 1382, 16:47 عصر
سلام
شما برای این کار می توانید یک آرایه با طول زیاد تعریف کنید که عناصر این آرایه اعداد یک رقمی باشند و با این آرایه را می توانید مثل یک عدد بسیار بزرگ برخورد کنید.فقط کافیست اعمال جمع و ضرب را روی آن تعریف کنید.

این روش عملی هست ولی فکر کنم زمان محاسبه، خودش یک رقم نجومی بشه. :(

DelphiAmateur
شنبه 18 مرداد 1382, 22:49 عصر
با تشکر
از راهنمایی شما ممنون ولی جواب کامل تر و دقیق تری میخواهم،
به موردی را که شما اشاره کردید فکر کرده بودم ولی جزییات بیشتری مد نظرم هست،خصوصا اگر با کد عملی همراه باشد(دلفی||C#)
با تشکر

Kambiz
یک شنبه 19 مرداد 1382, 16:50 عصر
type
TStrNum = String;

// Compares two numbers and returns the result as follow:
// if Num1 < Num2 then returns -1
// if Num1 = Num2 then returns = 0
// if Num1 > Num2 then returns +1
function Compare(const Num1, Num2: TStrNum): Integer;
begin
if Length(Num1) < Length(Num2) then
Result := -1
else if Length(Num1) > Length(Num2) then
Result := +1
else
if Num1 < Num2 then
Result := -1
else if Num1 > Num2 then
Result := +1
else
Result := 0;
end;

// Returns the addition of two numbers
function Add(const Num1, Num2: TStrNum): TStrNum;
var
Digit1, Digit2: Integer;
DigitSum, Carry: Integer;
I1, I2: Integer;
begin
Result := '';
Carry := 0;
I1 := Length(Num1);
I2 := Length(Num2);
while (I1 > 0) and (I2 > 0) do
begin
Digit1 := Ord(Num1[I1]) - Ord('0');
Digit2 := Ord(Num2[I2]) - Ord('0');
DigitSum := Digit1 + Digit2 + Carry;
Carry := 0;
if DigitSum >= 10 then
begin
DigitSum := DigitSum mod 10;
Carry := 1;
end;
Result := Chr(DigitSum + Ord('0')) + Result;
Dec(I1);
Dec(I2);
end;
while I1 > 0 do
begin
Digit1 := Ord(Num1[I1]) - Ord('0');
DigitSum := Digit1 + Carry;
Carry := 0;
if DigitSum >= 10 then
begin
DigitSum := DigitSum mod 10;
Carry := 1;
end;
Result := Chr(DigitSum + Ord('0')) + Result;
Dec(I1);
end;
while I2 > 0 do
begin
Digit2 := Ord(Num2[I2]) - Ord('0');
DigitSum := Digit2 + Carry;
Carry := 0;
if DigitSum >= 10 then
begin
DigitSum := DigitSum mod 10;
Carry := 1;
end;
Result := Chr(DigitSum + Ord('0')) + Result;
Dec(I2);
end;
if Carry <> 0 then
Result := '1' + Result;
end;

// Returns the multiply of two numbers
function Multiply(const Num1, Num2: TStrNum): TStrNum;
var
N: TStrNum;
begin
Result := '0';
N := '1';
while Compare(N, Num2) <= 0 do
begin
Result := Add(Result, Num1);
N := Add(N, '1');
end;
end;

// Returns the factorial of the given number
function Factorial(N: Cardinal): TStrNum;
var
I: Cardinal;
begin
Result := '1';
for I := 2 to N do
Result := Multiply(Result, IntToStr(I));
end;


Memo1.Text := Factorial(200);

در کد بالا اعداد به صورت رشته‌ای از حروف در نظر گرفته شده‌اند. البته در یک کد با کاربرد واقعی بدلیل سرعت کم و نیاز به حافظه بیشتر٬ چنین انتخابی می‌تواند یکی از بدترین انتخابها باشد.

در ضمن این کد فقط اعداد طبیعی را پشتیبانی می‌کند.

Kambiz
شنبه 05 مهر 1382, 20:18 عصر
کدی که در بالا نوشتم سرعتش خیلی کمه و فقط به درد اعداد مثبت می‌خوره. برای همین یک چیز یک کم بدردبخورتر نوشتم.

در فایل ضمیمه شده یونیتی حاوی یک کلاس برای نگهداری اعداد با تعداد ارقام زیاد (حداکثر <span dir=ltr>2^31</span> رقم) وجود داره که متدهایی برای انجام چهار عمل اصلی بروی اعداد مثبت و منفی و مقایسه رو در اختیار میگذاره.

یک برنامه نمونه هم برای تست کلاس و نحوه استفاده از اون داخل فایل ضمیمه هست.