توان‌رسانی دودویی

توان‌رسانی دودویی الگوریتمی سریع برای محاسبهٔ توان‌های بزرگ اعداد است.

الگوریتم عادی توان‌رسانی برای محاسب از مرتبهٔ زمانی است که برای b های بزرگ الگوریتم ناکارآمدی است. یک مثال از ناکارآمدی این الگوریتم یافتن وارون ضربی اعداد در پیمانه اعداد بزرگ است.الگوریتم توان‌رسانی دودویی مرتبه زمانی اجرای تابع را از خطی به لگاریتمی کاهش می‌دهد.

الگوریتم اصلی ویرایش

این الگوریتم بر پایهٔ این دو تساوی ساده بنا شده است:

اگر   زوج باشد  

اگر   فرد باشد  

بنابراین می‌توان با ارائهٔ تابع  دو تساوی بالا را به شکل یک رابطه بازگشتی درآورد.

 

کد الگوریتم ویرایش

کد این الگوریتم به زبان برنامه‌نویسی پایتون به این صورت است:

def power(a,b):
    if b == 0:
        return 1
    c = power(a,b//2)
    c *= c
    if b % 2 == 1:
        c *= a
    return c

کد الگوریتم به زبان ++C برای اعداد طبیعی اینگونه است. باید توجه داشت با توجه به محدودیت ظرفیت int و long long در++C و بزرگ بودن احتمالی خروجی تابع بهتر است یک پارامتر ورودی دیگری به عنوان mod به تابع داده شود تا باقی ماندهٔ  بر آن را به عنوان خروجی تابع تعریف کنیم:

int power(int a, int b, int mod)
{
    if (b == 0)
        return 1;

    long long c = power(a, b/2, mod);
    c = (c * c) % mod;

    if (b % 2 == 1)
        c = (c * a) % mod;

    return c;
}

باید دقت شود که متغیر داخلی c را باید حتماً از نوع long long تعریف کرد حتی اگر تمامی ورودی‌ها و خروجی‌ها int باشند؛ زیرا ضرب دو یا چند متغیر int ممکن است از محدودهٔ int بیرون بزند و جواب غیرقابل قبولی تولید شود.

تحلیل زمانی الگوریتم ویرایش

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

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

کاربردها ویرایش

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

منابع ویرایش