الگوریتمستان - کلاس اعداد بزرگ در ++C

معرفی کلاس BigInteger برای کار با اعداد صحیح بسیار بزرگ در ++C

✤    ۲ اسفند ۱۳۸۶ - آخرین به‌روزرسانی: ۲۱ تیر ۱۴۰۳

یکی از دغدعه‌های مهم برخی از افرادی که در حوزه‌هایی مانند رمزنگاری برنامه‌نویسی می‌کنند کار با اعداد بسیار بزرگ صحیح است. در چنین حوزه‌هایی نیاز زیادی به عملیات ریاضی روی اعداد بزرگ وجود دارد. تا کنون کلاس‌ها و توابع زیادی روی اینترنت برای حل این مشکل از طرف برنامه‌نویسان معرفی شده است. آنچه که در اینجا معرفی می‌کنم، کلاسی است برای امکان تعریف اعداد بسیار بزرگ که توسط خودم نوشته شده است.

  

class BigInteger

{

  friend BigInteger BigAbs(const BigInteger &);

  

  friend BigInteger operator + (long long , const BigInteger &);

  friend BigInteger operator + (string , const BigInteger &);

  friend BigInteger operator - (long long , const BigInteger &);

  friend BigInteger operator - (string , const BigInteger &);

  friend BigInteger operator * (long long , const BigInteger &);

  friend BigInteger operator * (string , const BigInteger &);

  friend BigInteger operator / (long long , const BigInteger &);

  friend BigInteger operator / (string , const BigInteger &);

  friend BigInteger operator % (long long , const BigInteger &);

  friend BigInteger operator % (string , const BigInteger &);

  friend BigInteger operator ^ (long long , const BigInteger &);

  friend BigInteger operator ^ (string , const BigInteger &);

  friend bool operator == (long long , const BigInteger &);

  friend bool operator == (string , const BigInteger &);

  friend bool operator != (long long , const BigInteger &);

  friend bool operator != (string , const BigInteger &);

  friend bool operator < (long long , const BigInteger &);

  friend bool operator < (string , const BigInteger &);

  friend bool operator > (long long , const BigInteger &);

  friend bool operator > (string , const BigInteger &);

  friend bool operator <= (long long , const BigInteger &);

  friend bool operator <= (string , const BigInteger &);

  friend bool operator >= (long long , const BigInteger &);

  friend bool operator >= (string , const BigInteger &);

  friend ostream & operator << (ostream &out, const BigInteger &);

  friend istream & operator >> (istream &in, BigInteger &r);

private:

  char *data;

  unsigned size;

  bool sign;

  void reverse(string &str);

public:

  BigInteger();

  BigInteger(long long);

  BigInteger(string);

  BigInteger(const BigInteger &);

  ~BigInteger();

  bool isValid();

  unsigned length();

  string toString();

  int operator [ ] (unsigned index) const;

  BigInteger operator = (long long);

  BigInteger operator = (string);

  BigInteger operator = (const BigInteger &);

  BigInteger operator + (long long) const;

  BigInteger operator + (string) const;

  BigInteger operator + (const BigInteger &) const;

  BigInteger operator + () const;

  BigInteger operator += (long long);

  BigInteger operator += (string);

  BigInteger operator += (const BigInteger &);

  BigInteger operator - (long long) const;

  BigInteger operator - (string) const;

  BigInteger operator - (const BigInteger &) const;

  BigInteger operator - () const;

  BigInteger operator -= (long long);

  BigInteger operator -= (string);

  BigInteger operator -= (const BigInteger &);

  BigInteger operator * (long long) const;

  BigInteger operator * (string) const;

  BigInteger operator * (const BigInteger &) const;

  BigInteger operator *= (long long);

  BigInteger operator *= (string);

  BigInteger operator *= (const BigInteger &);

  BigInteger operator / (long long) const;

  BigInteger operator / (string) const;

  BigInteger operator / (const BigInteger &) const;

  BigInteger operator /= (long long);

  BigInteger operator /= (string);

  BigInteger operator /= (const BigInteger &);

  BigInteger operator % (long long) const;

  BigInteger operator % (string) const;

  BigInteger operator % (const BigInteger &) const;

  BigInteger operator %= (long long);

  BigInteger operator %= (string);

  BigInteger operator %= (const BigInteger &);

  BigInteger operator ^ (long long) const;

  BigInteger operator ^ (string) const;

  BigInteger operator ^ (const BigInteger &) const;

  BigInteger operator ^= (long long);

  BigInteger operator ^= (string);

  BigInteger operator ^= (const BigInteger &);

  BigInteger operator ++ ();

  BigInteger operator ++ (int);

  BigInteger operator -- ();

  BigInteger operator -- (int);

  bool operator == (long long) const;

  bool operator == (string) const;

  bool operator == (const BigInteger &) const;

  bool operator != (long long) const;

  bool operator != (string) const;

  bool operator != (const BigInteger &) const;

  bool operator < (long long) const;

  bool operator < (string) const;

  bool operator < (const BigInteger &) const;

  bool operator > (long long) const;

  bool operator > (string) const;

  bool operator > (const BigInteger &) const;

  bool operator <= (long long) const;

  bool operator <= (string) const;

  bool operator <= (const BigInteger &) const;

  bool operator >= (long long) const;

  bool operator >= (string) const;

  bool operator >= (const BigInteger &) const;

};

کلاس BigInteger به زبان ++C از عملیات مقدماتی ضرب، جمع، تفریق، تقسیم، باقیمانده و توان رسانی پشتیبانی می‌کند. اگر کد کلاس را بررسی کنید متوجه می‌شوید که اکثر توابع کلاس برای نوع داده long long و کلاس string سربارگذاری شده‌اند تا کاربر بتواند از طریق این دو مجموعه هم با کلاس در ارتباط باشد. همچنین عملگرهای >> و << برای ورودی و خروجی جریان سربارگذاری شده است.

به عنوان نمونه:

#include <iostream>

#include "BigInteger.h"

using namespace std;

int main()

{

  BigInteger a = 1, b(2), c, d, e, f;

  cin >> c >> d;

  e = c * d + "1364";

  f = ++b * e ^ 3;

  cout << a << "\t" << b << "\t" << e << "\t" << f;

  return 0;

}

این کلاس چند تابع ویژه دارد:

  • تابع BigAbs قدرمطلق عدد را محاسبه می‌کند.
  • تابع isValid معتبر بودن عدد را بررسی می‌کند.
  • تابع length طول عدد را بر می‌گرداند.
  • تابع toString رشته‌ای را که شامل عدد مورد نظر است تولید می‌کند.

در ضمن عملگر [] هم برای دسترسی سریع به ارقام عدد سربارگذاری شده است. به عنوان نمونه [a[0 و [a[2 به ترتیب یکان و صدگان عدد a را نشان می‌دهند. در صورتی که اندیس وارد شده خارج از اندازه عدد باشد مقدار 1- برگشت داده می‌شود.

نکته قابل توجه در این کلاس سربارگذاری سه عملگر تقسیم (خارج قسمت)، باقیمانده و توان است. برای پیاده‌سازی تقسیم و باقیمانده اعداد بزرگ سعی کردم بهینه‌ترین الگوریتم ممکن را پیاده سازی کنم، تا زمان محاسبه بیهینه شود.

این نکته را هم به خاطر داشته باشید که اگر مقسوم یا مقسوم علیه یا هر دو منفی باشند، نتیجه محاسبات کمی‌فرق خواهد کرد. به این مثال ساده توجه کنید:

9 = 1 * 5 + 4    =>    9 / 5 = 1 , 9 % 5 = 4

-9 = -2 * 5 + 1    =>    -9 / 5 = -2 , -9 % 5 = 1

9 = -1 * -5 + 4    =>    9 / -5 = -1 , 9 % -5 = 4

-9 = 2 * -5 + 1    =>    -9 / -5 = 2 , -9 % -5 = 1

عملگر توان هم که با عملگر ^ پیاده‌سازی شده، به این خاطر است که از الگوریتم بهینه‌تری نسبت به توان رسانی معمولی استفاده کرده‌ام. در حالت عادی محاسبه توان nام عدد از مرتبه‌ی $O(n)$ است. اما الگوریتمی‌که دراین کلاس به کار رفته از مرتبه‌ی   $O(log\;n)$    است که باعث کاراتر شدن محاسبات می‌شود.

از جمله کاربردهای چنین کلاسی ضرب اعداد بزرگ در هم است. به عنوان مثال، برنامه‌ی زیر فاکتوریل عدد 1000 را - تقریبا 2600 رقم!!! - به راحتی حساب می‌کند:

#include <iostream>

#include "BigInteger.h"

using namespace std;

int main()

{

  unsigned i;

  BigInteger f = 1;

  for(i = 2 ; i <= 1000 ; i++)

    f *= i;

  cout << " 1000! = " << f << endl;

  return 0;

}

از دوستان عزیزی که قصد استفاده از این کلاس را دارند خواهشمندم نظرات خود را در مورد آن بیان کنند و اگر مشکلی در محاسبات مشاهده شد، حتما اطلاع دهید تا اصلاح شود. همینطور در صورتی هم که برای محاسبات مختلف الگوریتم بهینه‌تری سراغ دارید یا توابع دیگری را برای اضافه کردن به کلاس مد نظر دارید، مطرح کنید.

کد کلاس در این ریپازیتوری منتشر شده است.


نسخه‌ی اولیه‌ی این نوشته از وب‌سایت برنامه‌نویسی و طراحی الگوریتم به الگوریتمستان منتقل شده است.

تا کنون ۲ امتیاز ثبت شده
نوشته لایک نداشت؟
 
به اشتراک گذاری نوشته

amasoudfam.ir/l/m1lsw

اشتراک‌گذاری در LinkedIn     اشتراک‌گذاری در Twitter     ارسال با Telegram

نام: *  
پست الکترونیک (محرمانه):
پیام: *  
•  jingile
۳ اسفند ۱۳۸۶، ساعت ۱۴:۰۶

عالی بود.

•  shirin
۳ اسفند ۱۳۸۶، ساعت ۱۷:۲۰

merc agha masoud alie bud

• نادر ریحانی پور
۳ اسفند ۱۳۸۶، ساعت ۲۱:۵۶

تشکر عزیز

برای من که خیلی آموزنده بود.

• محمد
۳ اسفند ۱۳۸۶، ساعت ۲۲:۵۲

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

مسعود اقدسی‌فام
۴ اسفند ۱۳۸۶، ساعت ۰۰:۴۷

کدوم سوال محمد جان؟ مطمئنید جای درستی نظر دادین!؟!؟!؟

•  سارا
۲۳ اردیبهشت ۱۳۸۷، ساعت ۰۹:۵۷

باعرض سلام و خسته نباشید خدمت شما آقای اقدسی فام

من مرتبا مطالبی که شما در سایت قرار می دهید ، را دنبال می کنم . از این مطالب و نکات استفاده می کنم. از زحمات و زمانی که شما برای این کار اختصاص می دهید ، بسیار ممنونم. امیدوارم همیشه موفق و موءید باشید.

•  مهناز جون
۱۴ خرداد ۱۳۸۷، ساعت ۲۱:۵۶

سلام

آقا مسعود خواهش می کنم تو نوشتن جمع دو عدد بسیار بزرگ با پشته کمکم کنین

•  سعید
۱۹ تیر ۱۳۸۷، ساعت ۱۴:۵۴

سلام؛ خسته نباشی آقا مسعود. واقعا کلاس باکلاسی نوشتی، ولی 2 تا سوال داشتم: 1- بنظرم اپراتور - تو بعضی موارد مشکل داره مثلا 123 رو از 321 کم کن ؛ البته این اشکال همه جا نیست ولی من موارد دیگه ای هم دیدم. فکر می کنم اشاره گر result خراب میشه. 2- اپراتورهای friend رو واسه چی تعریف کردین؟ ممنون اگه حداقل جواب دومی رو بدین. چون بدون اونا هم کلاس کامله . ضمنا اگه اجازه بدی میخوام با بعضی تغییرات کلاسو برگردونم به #C

• سعید
۱۹ تیر ۱۳۸۷، ساعت ۱۵:۱۵

آقا مسعود یادم رفت بگم من این کد رو دیروز گرفتم و (با اجازتون) با کمی تغییرات برگردوندم به C++ Builder چون تو محاسبات لازمش داشتم. اگه خواستین براتون میفرستم ولی چون نمیدونستم friend ها به چه دردی میخوردن حذفشون کردم. این کلاس خیلی کمکم کرد اگه شما هم (جسارت نشه) الگوریتمی (مثلا کروسکال و پریم و ماتریسها و ...) خواستین من تو TC اکثرشون رو پیاده کردم میتونیم با هم همفکری کنیم. ممنون

مسعود اقدسی‌فام
۲۰ تیر ۱۳۸۷، ساعت ۱۶:۵۹

سعید جان خیلی خیلی ممنون از تذکرت.

اشکال مربوط به تفریق برطرف شد. باز هم اگر موردی دیدی خواهش دارم اطلاع بدی تا بررسی کنم.

در مورد توابع دوست هم قبلا مطلب آموزشی گذاشتم که کاربردش رو کامل تشریح می کنه. مطمئن باشید لازم بوده که گذاشتمشون! شما بدون این توابع نمی تونید عملگرهای ورودی - خروجی رو سربارگذاری کنید. یا اینکه نمی تونید عددی مثل a رو از عدد 5 کم کنید که a یک شی از کلاس اعداد بسیار بزرگ هستش. امتحان کنید. باز هم اگه مشکلی بود در خدمت هستم.

در مورد الگوریتمها کروسکال و پریم و . . . هم سر فرصت ان شاء الله اگر نیاز باشه در خدمتتون خواهیم بود.

مجددا ممنونم.

موفق باشید.

• سعید
۲۴ تیر ۱۳۸۷، ساعت ۱۴:۲۳

آقا مسعود من جسارت نکردم، گفتم که میخواستم بدونم و کاربرد friend رو فراموش کردم. ضمنا میشه بگید کجای اپراتور تفریق رو تغییر دادید یا لینکش کجاست؟

•  سعید
۲۴ تیر ۱۳۸۷، ساعت ۱۵:۵۰

ضمنا من میخواستم اپراتورهای کلاس شما رو بصورت template بنویسم تا اینقدر توابع overload نداشته باشم. یک تست هم نوشتم ولی نمیتونم اینجا بفرستم، ارسال که میزنم error میده چطوری یه تکه برنامه واستون بفرستم؟

مسعود اقدسی‌فام
۲۴ تیر ۱۳۸۷، ساعت ۱۷:۳۶

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

مسعود اقدسی‌فام
۲۴ تیر ۱۳۸۷، ساعت ۱۷:۳۷

راستی مگه #C سربارگذاری عملگرها رو داره؟

•  سعید
۲۵ تیر ۱۳۸۷، ساعت ۰۸:۰۳

بله #C هم سربارگذاری عملگرها رو داره. اول یه گله بکنم آقا مسعود : من یه سوال از آقای کیانی در مورد Authenticate شدن سرویس گیرنده های وب پرسیدم و چون قسمت مرتبطی در این مورد پیدا نکردم تو قسمت بررسی معماری MVC که احساس کردم مرتبط ترین جا ممکنه باشه پیام گذاشتم ولی ایشون با عرض پوزش پیام من رو حذف کردن. فکر نمیکنید یه خبری بدن بهتره؟ ضمنا من چطوری باید با شما کد تبادل کنم؟ [اینجا نمی شه کد فرستاد] میتونم به آدرس میل تون attach کنم؟

public static implicit operator BigInteger(uint value)

{

return (new BigInteger((ulong)value));

}

مسعود اقدسی‌فام
۲۵ تیر ۱۳۸۷، ساعت ۰۸:۱۴

سعید جان من با آقای کیانی در این مورد صحبت کردم. حذف پیام رو با هماهنگی ایشون بنده انجام دادم. شما برای پرسیدن سوالهایی که مرتبط با مطالب سایت نیستن می تونید از آدرس ایمیلهای ما استفاده کنید. در مورد سوال شما من اطلاعاتی ندارم. آدرس آقای کیانی هم در پروفایلشون هست.

مسعود اقدسی‌فام
۲۵ تیر ۱۳۸۷، ساعت ۰۸:۵۹

اگر پروفایلشون رو پیدا نکردید این آدرس ایمیل ایشون: rkiani88@yahoo.com

•  مرضیه
۲۱ بهمن ۱۳۸۷، ساعت ۱۲:۲۶

کلاسی برای ماتریس 3*3 که توانایی محاسبه دترمینان و ماتریس معکوس را داشته باشد

•  masoud
۱۷ اسفند ۱۳۸۷، ساعت ۰۹:۰۳

با سلام

1 سوال داشتم :

>> فرق Int و Short int چیه در مبحث کلمات توصیف گر ؟

از آنجایی که هر دو بازه ای متشابه اند !

( هر دو 2 بایت حافظه اشغال می کنند و دارای محدوده (32767- _32767+) یکسانی هستند؟!!!

اگر می شود پاسخ دهید. بنده دانشجوی کاردانی در گلستان(علی آباد کتول) هستم ولی خودم از گنبد هستم و تا حالا هیچ استادی نتونسته جواب بده!

با تشکر

• مسعود
۱۷ اسفند ۱۳۸۷، ساعت ۰۹:۱۲

عجب دوره زمونه ای شده ؟

اونجور که فهمیدم آدم درسته علمش می ره بالا ولی یکم باید به اخلاق توجه کرد، علم بدون اخلاق ارزش نداره!

چند نفر پستشون رو با سلام شروع کردند ؟!!!

عجب(درست یک ششم) !!!

با تشکر

مسعود اقدسی‌فام
۱۷ اسفند ۱۳۸۷، ساعت ۲۱:۲۷

مسعود جان سلام

در مورد سلام دادن دیگران ترجیح می دم نظری ندم. نمی تونم به راحتی شما قضاوت کنم.

در مورد تفاوتهای int و short int:

در نسخه های قدیمی هر دو دو بایت هستند. اما در نسخه های به روز این زبان، int چهار بایت شده. اینها یک سری اسم گذاری ها برای دسته بندی هستند. حالا اینکه فلسفه پس زمینه اون چی بوده، من هم دقیقا نمی دونم.

اگر اطلاعاتی به دست آوردم، اطلاع می دم.