آیا الگوریتمی برای محاسبه شماره فیبوناچی نهم در زمان زیر خطی وجود دارد؟
می توان استدلال کرد که این مربوط به الگوریتم ها است ، زیرا OP مرجع مبهم به پیچیدگی الگوریتمی است. من هنوز هم کنجکاو خواهم بود که چه الگوریتم.
دو پاسخ زیر فرمول صحیح دارند. در مورد اینکه آیا این سوال مربوط به برنامه نویسی است: این بخشی از علوم کامپیوتر است. دستگاه مورد استفاده برای استخراج فرمول به عنوان "توابع تولید" شناخته می شود و نقش مهمی در تجزیه و تحلیل الگوریتم دارد.
anazheglov: در حالی که تولید توابع مفید هستند ، برای استخراج فرم بسته برای دنباله فیبوناچی لازم نیست.
شما مشکلی دارید که می خواهید به هر دلیلی حل کنید و می خواهید آن را به طور کارآمد انجام دهید. گاهی اوقات بینش مورد نیاز یک اجرای جدید ، بعضی اوقات یک الگوریتم و گاهی اوقات ریاضیات خواهد بود. نیازی به فریب اوضاع نیست زیرا هر بار که دومی اتفاق می افتد "مربوط به برنامه نویسی نیست".
اندازه نتیجه در n خطی است. بنابراین چنین الگوریتم وجود ندارد. البته که هیچ یک از پاسخ های خوب زیر را که شماره های فیبوناچی را با استفاده از عملیات حسابی O (log n) محاسبه نمی کند ، باطل نمی کند.
16 پاسخ 16
به دنبال مراجعه به Pillsy به ماتریس اکتشاف ، به گونه ای که برای ماتریس
افزایش ماتریس به قدرت با استفاده از ضرب مکرر بسیار کارآمد نیست.
دو رویکرد برای نمایش ماتریس تقسیم و فاتح است که در مراحل O (LN N) یا تجزیه مقادیر ویژه ای که زمان ثابت است ، بازده می کند ، اما ممکن است به دلیل دقت نقطه شناور ، خطاها را معرفی کند.
اگر می خواهید یک مقدار دقیق بیشتر از دقت اجرای نقطه شناور خود داشته باشید ، باید بر اساس این رابطه از رویکرد O (LN N) استفاده کنید:
تجزیه مقادیر ویژه در M ، دو ماتریس U و λ را پیدا می کند به گونه ای که λ مورب است و یک ماتریس مورب λ را به قدرت n بالا می برد ، یک موضوع ساده برای بالا بردن هر عنصر در λ به n است ، بنابراین این به O (1 می دهد (1)) روش افزایش M به قدرت n. با این حال ، مقادیر موجود در λ احتمالاً عدد صحیح نیستند ، بنابراین برخی از خطا رخ می دهد.
تعریف λ برای ماتریس 2x2 ما
برای یافتن هر λ ، ما حل می کنیم
با استفاده از فرمول درجه دوم
اگر پاسخ جیسون را خوانده اید ، می توانید ببینید که این کجا قرار است طی شود.
حل برای eigenvectors x1و x2:
این بردارها به شما می دهند:
وارونه کردن شما
بنابراین u-1 توسط
بنابراین بررسی عقل نگه داشته می شود.
اکنون ما همه چیز را برای محاسبه m n داریم1,2:
که با فرمول داده شده در جای دیگر موافق است.
شما می توانید آن را از یک رابطه عود استخراج کنید ، اما در محاسبات مهندسی و شبیه سازی محاسبه مقادیر ویژه و ویژه ماتریس های بزرگ یک فعالیت مهم است ، زیرا به ثبات و هارمونیک سیستم های معادلات می دهد ، و همچنین اجازه می دهد تا ماتریس به قدرت بالا برسد.
این کپی از کتاب جبر گیلبرت استرانگ یا از کتاب خوب دیگر جبر خطی است.
alinsoar این کپی نشده بود ، اما به عنوان یک تمرین برای بررسی انجام شد ، من هنوز هم می توانم لین A را به خاطر بسپارم ، با اشاره ای به یادداشت های دوره دانشگاه آزاد و ویکی پدیا.
من دوره L جبر را با گیلبرت استرانگ گذراندم و در آنجا یکسان بود. کاملاً ، مشکل بیان بازگشت از طریق تجزیه ماتریس کلاسیک است و می توانید در هر کتاب / دوره خوب در متن پیدا کنید.
شماره فیبوناچی n توسط
با فرض اینکه عملیات ریاضی بدوی ( + ، - ، * و /) o (1) می توانید از این نتیجه برای محاسبه شماره فیبوناچی n در زمان O (log n) زمان (o (log n) به دلیل نمایندگی در استفاده کنید. فرمول).
json من شما را رعایت نکرده ام ، اما دیگران ممکن است این کار را انجام دهند زیرا پاسخ شما نشان می دهد که شماره فیبوناچی نهم را می توان در زمان O (log n) محاسبه کرد ، که نادرست است. کد شما در حال محاسبه تقریب است. کد شما حداقل O (n) با دقت دلخواه خواهد بود ، زیرا طول پاسخ o (n) است.
peterallenwebb: فرمول ارائه شده تقریب نیست. شماره فیبرچی نهم برابر با کف Phi^n / sqrt (5) + 1/2 است که phi = (1 + sqrt (5)) / 2. این یک واقعیت است. دوم ، من این نکته را درک می کنم که دیگران در مورد طول جواب O (n) می پردازند اما من به پاسخ خود اظهار نظر کردم با فرض اینکه عملیات ریاضی بدوی زمان ثابت می گیرد (می دانم که آنها نیستند مگر اینکه شما ورودی ها را محدود کنید). حرف من این است که ما می توانیم شماره فیبوناچی نهم را در عملیات حسابی O (log n) پیدا کنیم.
jason: با فرض اینکه اظهارات O (1) نیز کل الگوریتم O (1) را ایجاد می کند. این خوب خواهد بود ، با این حال ، پخش (1) نیست و هیچ یک از عملیات ریاضی بدوی دیگر نیست. به طور خلاصه ، فرمول خوب است ، اما نتیجه را در زمان زیر خطی محاسبه نمی کند.
jason: فرمول تقریب نیست ، اما کد یک تقریب است (به جز در اجرای C# خیالی که در آن Math. pow (...) دارای دقت نامتناهی است ، در این صورت کد O (n) است).
jason: nope. کد خود را در N = 1000 اجرا کنید (که برای آن شماره Fibonacci 43466. 849228875 دارای 209 رقم است) و به من بگویید که آیا همه رقم ها را به درستی دریافت می کنید. برای اینکه Math. floor به درستی قسمت عدد صحیح را بدست آورد ، بسیاری از رقم ها باید توسط Math. pow دقیق محاسبه شوند. در حقیقت ، در اجرای C ++ من ، حتی 16 رقمی F_ = 130496954492865 به طور نادرست محاسبه می شود ، حتی اگر عدد صحیح 130496954492865 را می توان دقیقاً (با طولانی طولانی) نشان داد و اگر C# بیشتر از این رقم می خورد.
اگر شماره دقیق را می خواهید (که "bignum" است ، به جای یک int/float) ، پس من می ترسم
غیر ممکنه!
همانطور که در بالا گفته شد ، فرمول اعداد فیبوناچی:
FIB n چند رقم است؟
numdigits (fib n) = log (fib n) = log (phi n /√5) = log phi n - log √5 = n * log phi - log √5
numdigits (fib n) = n * const + const
این o (n)
از آنجا که نتیجه درخواست شده از O (n) است ، نمی توان آن را در زمان کمتر از O (n) محاسبه کرد.
اگر فقط رقم های پایین تر پاسخ را می خواهید ، پس از آن می توان با استفاده از روش بازنمایی ماتریس در زمان زیر خطی محاسبه کرد.
yairchu: اگر من آن را به درستی درک کردم ، اجازه دهید این را دوباره بیان کنم. در تئوری محاسبه FIB_N نیاز به محاسبه ارقام n دارد ، بنابراین برای هرگونه دلخواه N ، زمان (n) زمان می برد. با این حال ، اگر fib_n< sizeof(long long) then we can calculate fib_n in O(log n) time since the machine architecture is providing a parallel mechanism of setting the bits. (For example, int i = -1; requires setting 32-bits but on a 32-bit machine all the 32 bits can be set in constant time.
Sumit: اگر فقط می خواهید از نتایج متناسب با 32 بیت پشتیبانی کنید ، می توانید برای این 48 نتیجه اول این سریال یک جدول جستجو داشته باشید. این بدیهی است که o (1) ، اما: انجام تجزیه و تحلیل بزرگ برای یک n محدود احمقانه است ، زیرا همیشه می توانید هر چیزی را در عامل ثابت گنجانید. بنابراین پاسخ من به ورودی بی حد و مرز اشاره دارد.
yairchu: آیا می توانید منطق خود را برای یک مثال مشهور مانند O (n*log n) برای مرتب سازی مبتنی بر مقایسه یک دنباله از اعداد n که در آن هر شماره دارای رقم O (log n) است ، نشان دهید؟
این درست یا نادرست بسته به آنچه شما قصد "زمان" را به معنای آن دارید. برای مرتب سازی (یا نگاه جدول هش) ، "زمان" به معنای تعداد مقایسه ها است. در سؤال می تواند به معنای عملیات حسابی باشد. در این پاسخ به معنای چیزی مانند عملیات رقمی است.
اعداد صحیح در واقع یک نمایش محدود در پایه SQRT (2) خواهند داشت ، اما فقط در رقم های عجیب و غریب صفر خواهد بود ، یعنی معادل پایه 2وادیک مورد که ممکن است PHI پایه را بخواهید در هنگام تبدیل سیگنال های مداوم به آنالوگ ، در ADC ها قرار دارد. AFAIK این کاربرد "صنعتی" پایه PHI است ، جایی که از آن برای کاهش دانه درشت هنگام گرد کردن سیگنال استفاده می شود. هرچند شخصاً ، من از رمزگذاری های پایه PHI و فیبوناچی به عنوان روشی مناسب برای کار با فیبوناچی هرکدام از گروه های بند بند استفاده کردم.
یکی از تمرینات موجود در SICP در مورد این است که پاسخی را در اینجا شرح داده است.
به سبک ضروری ، برنامه چیزی شبیه به
MoniRulislammilon اگر حتی (تعداد) صحیح باشد. دنباله با صفر شروع می شود (شماره Zeroth Fibonacci صفر است): 0،1،2،2،3،5،8،13.
اظهار نظر دیر هنگام ، اما متغیرهای P و A قبل از استفاده برای محاسبه Q و B بازنویسی می شوند. برای جلوگیری از این مسئله ، شرایط را از قبل محاسبه و تغییر ترتیب P و Q تکالیف: |qq = q · q |q = 2 · p · q + qq |P = P · P + QQ |واد|aq = a · q |a = b · q + aq + a · p |b = b · p + aq |واد
شما می توانید این کار را با نمایش ماتریس اعداد صحیح انجام دهید. اگر ماتریس دارید
سپس (m ^ n) [1 ، 2] برابر با شماره فیبوناچی n است ، اگر [] یک اشتراک ماتریس باشد و ^ ماتریس است. برای یک ماتریس با اندازه ثابت ، نمایش به یک قدرت انتگرال مثبت می تواند در زمان O (log n) به همان روش با اعداد واقعی انجام شود.
ویرایش: البته ، بسته به نوع پاسخی که می خواهید ، ممکن است بتوانید با یک الگوریتم زمان ثابت از بین بروید. مانند سایر فرمول ها ، تعداد فیبوناچی n به صورت نمایی با n رشد می کند. حتی با وجود اعداد صحیح 64 بیتی ، فقط به یک جدول جستجوی 94 وارد نیاز خواهید داشت تا کل دامنه را بپوشانید.
ویرایش دوم: انجام نمایی ماتریس با Eigendecomposition ابتدا دقیقاً معادل راه حل Jdunkerly در زیر است. مقادیر ویژه این ماتریس (1 + SQRT (5))/2 و (1 - SQRT (5))/2 است.
روش پیشنهادی برای محاسبات در اعداد صحیح (احتمالاً با حسابی طولانی) مناسب است. رویکرد با تجزیه Eigen جالب نیست: اگر به محاسبات عدد صحیح احتیاج ندارید ، از پاسخ جیسون از فرمول استفاده کنید.
Konstantin فرمول از پاسخ جیسون نتیجه ای است که توسط Eigen Decomposition داده شده است ، بنابراین شما با خود متناقض هستید.
@Pete Kirkham این فرمول را می توان با چندین روش به دست آورد: معادله ویژگی ها، تجزیه ویژه، اثبات با استقرا. من مطمئن نیستم که تجزیه ویژه ساده ترین است. در هر صورت شناخته شده است و استفاده فوری از آن آسان تر است
شما می توانید با استفاده از این واقعیت که |1 - phi|^n / sqrt(5) نیاز به محاسبه دو نمایی را ندارید< 1/2 when n is a nonnegative integer.
برای نمونه های واقعا بزرگ، این تابع بازگشتی کار می کند. از معادلات زیر استفاده می کند:
شما به کتابخانه ای نیاز دارید که به شما امکان می دهد با اعداد صحیح بزرگ کار کنید. من از کتابخانه BigInteger از https://mattmccutchen. net/bigint/ استفاده می کنم.
با آرایه ای از اعداد فیبوناچی شروع کنید. از fibs[0]=0، fibs[1]=1، fibs[2]=1، fibs[3]=2، fibs[4]=3 و غیره استفاده کنید. در این مثال، من از آرایهای از 501 اول استفاده میکنم.(شمارش 0). می توانید 500 عدد اول فیبوناچی غیر صفر را در اینجا پیدا کنید: http://home. hiwaay. net/~jalison/Fib500. html. برای قرار دادن آن در قالب مناسب کمی ویرایش لازم است، اما خیلی سخت نیست.
سپس می توانید هر عدد فیبوناچی را با استفاده از این تابع (در C) پیدا کنید:
من این را برای عدد 25000 فیبوناچی و موارد مشابه تست کردم.
این کد چندان کارآمد نیست. تصور کنید که آرایه fibs[] فقط اندازه 10 است و شما Fib(101) را صدا می زنید. Fib (101) Fib (51) و Fib (50) را صدا می کند. Fib(51) Fib(26) و Fib(25) را صدا می کند. Fib(50) Fib(25) و Fib(24) را صدا می کند. پس فیب(25) دو بار خوانده شد که ضایع است. حتی با فیب های تا 500 هم همین مشکل را با فیب (100000) خواهید داشت.
در اینجا نسخه بازگشتی من است که بارها log(n) را تکرار می کند. من فکر می کنم که خواندن آن به صورت بازگشتی ساده تر است:
کار می کند زیرا می توانید fib(n)، fib(n-1) را با استفاده از fib(n-1)، fib(n-2) اگر n فرد باشد و اگر n زوج باشد، می توانید fib(n)، fib را محاسبه کنید.(n-1) با استفاده از fib(n/2)، fib(n/2-1).
حالت پایه و حالت فرد ساده هستند. برای بدست آوردن حالت زوج، با a, b, c به عنوان مقادیر متوالی فیبوناچی (مثلاً 8،5،3) شروع کنید و آنها را در یک ماتریس با a = b+c بنویسید. اطلاع:
از آن، می بینیم که ماتریسی از سه عدد فیبوناچی اول، ضربدر ماتریسی از هر سه عدد فیبوناچی متوالی، برابر است با ماتریس بعدی. پس می دانیم که:
ساده کردن سمت راست منجر به حالت زوج می شود.
من می خواهم در اینجا تاکید کنم که شما می خواهید F(2n) و F(2n+1) را در تابع F(n) و F(n-1) محاسبه کنید. شما نشان ندادید که می خواهید چه کاری انجام دهید.
محاسبه نقطه ثابت نادرست است. کد سی شارپ جیسون پاسخ نادرستی برای n = 71 (308061521170130 به جای 308061521170129) و بیشتر می دهد.
برای پاسخ صحیح ، از یک سیستم جبر محاسباتی استفاده کنید. Sympy چنین کتابخانه ای برای پایتون است. یک کنسول تعاملی در http://live. sympy. org/ وجود دارد. این عملکرد را کپی و چسباند
شاید دوست داشته باشید که PHI را بازرسی کنید.
در اینجا یک لاینر وجود دارد که F (n) را با استفاده از عدد صحیح اندازه o (n) ، در عملیات حسابی O (log n) محاسبه می کند:
استفاده از عدد صحیح اندازه O (n) منطقی است ، زیرا این قابل مقایسه با اندازه پاسخ است.
برای درک این موضوع ، بگذارید Phi نسبت طلایی (بزرگترین راه حل برای x^2 = x+1) و f (n) باشد ، شماره n'th fibonacci ، جایی که f (0) = 0 ، f (1) = f(2) = 1
اکنون ، phi^n = f (n-1) + f (n) phi.
اثبات توسط القاء: phi^1 = 0 + 1*phi = f (0) + f (1) phi. و اگر phi^n = f (n-1) + f (n) phi ، سپس phi^(n + 1) = f (n-1) phi + f (n) phi^2 = f (n-1)phi + f (n) (phi + 1) = f (n) + (f (n) + f (n-1)) phi = f (n) + f (n + 1) phi. تنها مرحله پیچیده در این محاسبه ، آن است که جایگزین Phi^2 توسط (1+PHI) می شود ، که به این دلیل است که PHI نسبت طلایی است.
همچنین تعداد فرم (a+b*phi) ، که در آن a ، b عدد صحیح است تحت ضرب بسته است.
اثبات: (p0+p1*phi) (q0+q1*phi) = p0q0+(p0q1+q1p0) phi+p1q1*phi^2 = p0q0+(p0q1+q1p0) phi+p1q1*(phi+1) = (P0Q0+P1Q1)+(P0Q1+Q1P0+P1Q1)*PHI.
با استفاده از این نمایندگی ، می توان عملیات عدد صحیح O (log n) را با استفاده از Exponentiation با استفاده از مربع محاسبه کرد. نتیجه F (n-1)+f (n) phi خواهد بود ، که از آن می توان شماره فیبوناچی NTH را خواند.
توجه داشته باشید که اکثر این کد یک عملکرد استاندارد توسط مربع است.
برای رسیدن به تک لاینری که این پاسخ را شروع می کند ، می توان توجه داشت که نمایندگی PHI توسط یک عدد صحیح بزرگ X ، می توان (A+B*PHI) (C+D*PHI) را به عنوان عملکرد عدد صحیح انجام داد (A+BX) (c+dx) modulo (x^2-x-1). سپس عملکرد POW را می توان با عملکرد استاندارد Python POW جایگزین کرد (که به راحتی شامل یک آرگومان سوم Z است که نتیجه Modulo z را محاسبه می کند. X انتخاب شده 2 است
جدا از تنظیم دقیق با رویکردهای ریاضی ، یکی از بهترین راه حل بهینه (من معتقدم) استفاده از یک فرهنگ لغت برای جلوگیری از محاسبات تکراری است.
ما با فرهنگ لغت بی اهمیت (دو مقدار اول توالی فیبوناچی) شروع می کنیم و دائماً مقادیر فیبوناچی را به فرهنگ لغت اضافه می کنیم.
برای اولین 100000 مقادیر فیبوناچی (Intel Xeon CPU E5-2680 @ 2. 70 گیگاهرتز ، رم 16 گیگابایتی ، ویندوز 10-64 بیت ، حدود 0. 7 ثانیه طول کشید.
این در زمان خطی است ، اما این سؤال به طور خاص می پرسد که چگونه می توان به زمان زیر خطی رسید (که با استفاده از یک نوع راه حل بسته ممکن است).
الگوریتم تقسیم و فاتح را اینجا ببینید
پیوند دارای کد شبه برای قدرت ماتریس است که در برخی از پاسخ های دیگر برای این سؤال ذکر شده است.
برای دریافت پاسخ دقیق می توانید از معادله ریشه دوم عجیب و غریب استفاده کنید. دلیلش این است که $\sqrt(5)$ در پایان می افتد، فقط باید ضرایب را با فرمت ضرب خود پیگیری کنید.
من به برخی از روشهای محاسبه فیبوناچی با پیچیدگی زمانی کارآمد برخورد کردهام که در زیر برخی از آنها آمده است:
روش 1 - برنامه نویسی پویا اکنون در اینجا زیرساخت معمولاً شناخته شده است، بنابراین من مستقیماً به راه حل می پردازم -
یک نسخه بهینه شده فضا از بالا را می توان به صورت زیر انجام داد -
Method 2- ( Using power of the matrix ,> )
This an O(n) which relies on the fact that if we n times multiply the matrix M = ,>به خودش (به عبارت دیگر توان (M, n ) را محاسبه می کند)، سپس عدد فیبوناچی (n+1) را به عنوان عنصر در سطر و ستون (0، 0) در ماتریس حاصل می گیریم. این راه حل زمان O(n) خواهد داشت.
نمایش ماتریس عبارت بسته زیر را برای اعداد فیبوناچی به دست می دهد: ماتریس فیبوناچی
این را می توان برای کار در پیچیدگی زمانی O(Logn) بهینه کرد. برای بدست آوردن توان (M, n) در روش قبلی می توانیم ضرب بازگشتی انجام دهیم.
روش 3 (زمان O(log n)) در زیر یک فرمول عود جالب دیگر وجود دارد که می توان از آن برای یافتن عدد فیبوناچی n در زمان O(log n) استفاده کرد.
اگر n زوج باشد، k = n/2: F(n) = [2*F(k-1) + F(k)]*F(k)
اگر n فرد باشد، k = (n + 1)/2 F(n) = F(k)*F(k) + F(k-1)*F(k-1) این فرمول چگونه کار می کند؟فرمول را می توان از معادله ماتریس فوق بدست آورد. فیبوناتریس
با گرفتن دترمینال در هر دو طرف، (-1)n = Fn+1Fn-1 - Fn2 به دست می آوریم، علاوه بر این، از آنجایی که AnAm = An+m برای هر ماتریس مربع A، هویت های زیر را می توان به دست آورد (آنها از دو ضریب مختلف به دست می آیند. محصول ماتریس)
FmFn + Fm-1Fn-1 = Fm+n-1
با قرار دادن n = n+1،
FmFn+1 + Fm-1Fn = Fm+n
F2n-1 = Fn2 + Fn-12
F2n = (Fn-1 + Fn+1)Fn = (2Fn-1 + Fn)Fn (منبع: ویکی)
برای به دست آوردن فرمول برای اثبات، کافی است موارد زیر را انجام دهیم اگر n زوج باشد، می توانیم k = n/2 اگر n فرد باشد، می توانیم k = (n+1)/2 قرار دهیم.
روش 4 - استفاده از فرمول در این روش مستقیماً فرمول nام سری فیبوناچی را پیاده سازی می کنیم. زمان O(1) فضای O(1) Fn =<[(√5 + 1)/2] ^ n>/ √5