Obliczanie Fibbonacciego od 300, z wykorzystaniem binarnego algorytmu potęgowania macierzy

0

Witam che obliczyć ciąg Fibbonacciego dla 300 i do teog mam kod:

public static double Fibonacci(double n)
        {
            if (n == 0)
                return 0;
            if (n == 1 || n == 2)
                return 1;

            double[,] A = new double[2, 2] { { 0, 1 }, { 1, 1 } };
            double[,] B = (double[,])A.Clone();
            double[,] C = new double[2, 2];

            n -= 2;

            for (double i = 1; i <= n; i++)
            {
                C[0, 0] = B[0, 0] * A[0, 0] + B[0, 1] * A[1, 0];
                C[0, 1] = B[0, 0] * A[0, 1] + B[0, 1] * A[1, 1];
                C[1, 0] = B[1, 0] * A[0, 0] + B[1, 1] * A[1, 0];
                C[1, 1] = B[1, 0] * A[0, 1] + B[1, 1] * A[1, 1];

                B = (double[,])C.Clone();
            }
            return C[1, 1];

           
        }

        private void button1_Click(object sender, EventArgs e)
        {
            MessageBox.Show(Fibonacci(Convert.ToDouble(textBox1.Text)).ToString());
            
        }

Jednak nie działa on tak jakbym chciał, gdyż dla 300 zamiast otrzymać wartość: "222232244629420445529739893461909967206666939096499764990979600", otrzymuję wartość: "22223224462942E+62"

W jaki sposób przekształcić mój kod, żeby zwracał "normalną" wartość? Z góry dziękuję za odpowiedź:)

Domyślam się, że trzeba użyć jakiegoś przekształcenia liczby zmiennoprzecinkowej na całkowitą,.. Ale nie bardzo wiem jak to dobrze zrobić :)

1
  1. "22223224462942E+62" TO JEST "222232244629420445529739893461909967206666939096499764990979600" - różnica polega tylko w wyświetlaniu!
  2. No dobra, nie jest... Ma za małą precyzję po prostu... Poszukaj czegoś o BigInt albo podobnych bibliotekach.
1

System.Numerics.BigInteger łyka takie liczby jak młody pelikan.

1

System.Numerics.BigInteger łyka takie liczby jak młody pelikan.
Ale jest dopiero w .Net 4.0. jeśli piszemy w starszej wersji, alternatywą może być java.math.BigInteger (trzeba ręcznie dodać referencję do vjslib.dll)

0

a teraz jeszce mam pytanie o zapisywanie wyników do pliku mianowicie teraz kod wygląda tak:


public static System.Numerics.BigInteger Fibonacci(double n)
        {
            if (n == 0)
                return 0;
            if (n == 1 || n == 2)
                return 1;

            System.Numerics.BigInteger[,] A = new System.Numerics.BigInteger[2, 2] { { 0, 1 }, { 1, 1 } };
            System.Numerics.BigInteger[,] B = (System.Numerics.BigInteger[,])A.Clone();
            System.Numerics.BigInteger[,] C = new System.Numerics.BigInteger[2, 2];

            n -= 2;

            FileStream plik = File.Create("c:\\dane1.txt");
            plik.Close();

            FileStream q = File.Create("c:\\dane.txt");
            q.Close();

            for (double i = 1; i <= n; i++)
            {
                C[0, 0] = B[0, 0] * A[0, 0] + B[0, 1] * A[1, 0];
                C[0, 1] = B[0, 0] * A[0, 1] + B[0, 1] * A[1, 1];
                C[1, 0] = B[1, 0] * A[0, 0] + B[1, 1] * A[1, 0];
                C[1, 1] = B[1, 0] * A[0, 1] + B[1, 1] * A[1, 1];

                B = (System.Numerics.BigInteger[,])C.Clone();

                plik = File.Open("c:\\dane1.txt", FileMode.Append);                      

                BinaryFormatter zapisywacz = new BinaryFormatter();                

                zapisywacz.Serialize(plik, i + 2 + "): " + C[1, 1]);

                plik.Close();
                

                q = File.Open("c:\\dane.txt",FileMode.Append);

                StreamWriter a = new StreamWriter(q);

                a.WriteLine(i + 2 + "): " + C[1, 1]);

                q.Close();                
            }
            return C[1, 1];        
                                 
        }

        private void button1_Click(object sender, EventArgs e)
        {
            richTextBox1.Text = (Fibonacci(Convert.ToDouble(textBox1.Text)).ToString());
            System.Diagnostics.Process.Start("c:\\dane.txt");
            System.Diagnostics.Process.Start("c:\\dane1.txt");
            
        }

dane1.txt działa poprawnie(ale wynik w formie binarnej nie jest fajny :D ˙˙˙˙ 3): 2 ˙˙˙˙ 4): 3 ˙˙˙˙ 5): 5), tylko nie wiem dlaczego dane.txt po otworzeniu jest puste... Chociaż jak zrobię breakpoint w " a.WriteLine(i + 2 + "): " + C[1, 1]);" to niby wszystko się robi jak powinno... Ktoś wie o co chodzi?:)

0

hah sam znalazłem rozwiązanie może komuś się przyda - potrzeba było dodać "a.Flush();"

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Numerics;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

namespace WindowsFormsApplication2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        public static System.Numerics.BigInteger Fibonacci(double n)
        {
            if (n == 0)
                return 0;
            if (n == 1 || n == 2)
                return 1;

            System.Numerics.BigInteger[,] A = new System.Numerics.BigInteger[2, 2] { { 0, 1 }, { 1, 1 } };
            System.Numerics.BigInteger[,] B = (System.Numerics.BigInteger[,])A.Clone();
            System.Numerics.BigInteger[,] C = new System.Numerics.BigInteger[2, 2];

            n -= 2;

            FileStream plik = File.Create("c:\\dane1.txt");
            plik.Close();

            FileStream q = File.Create("c:\\dane.txt");
            q.Close();

            for (double i = 1; i <= n; i++)
            {
                C[0, 0] = B[0, 0] * A[0, 0] + B[0, 1] * A[1, 0];
                C[0, 1] = B[0, 0] * A[0, 1] + B[0, 1] * A[1, 1];
                C[1, 0] = B[1, 0] * A[0, 0] + B[1, 1] * A[1, 0];
                C[1, 1] = B[1, 0] * A[0, 1] + B[1, 1] * A[1, 1];

                B = (System.Numerics.BigInteger[,])C.Clone();

                plik = File.Open("c:\\dane1.txt", FileMode.Append);                      

                BinaryFormatter zapisywacz = new BinaryFormatter();                

                zapisywacz.Serialize(plik, i + 2 + "): " + C[1, 1]);

                plik.Close();
                

                q = File.Open("c:\\dane.txt",FileMode.Append);

                StreamWriter a = new StreamWriter(q);
                
                a.WriteLine(i + 2 + "): " + C[1, 1]);

                a.Flush();//BEZ TEGO NIE DZIAŁA!!

                q.Close();                
            }
            return C[1, 1];        
                                 
        }

        private void button1_Click(object sender, EventArgs e)
        {
            richTextBox1.Text = "Wartość " + textBox1.Text + " elementu ciągu Fibbonacciego wynosi: " + (Fibonacci(Convert.ToDouble(textBox1.Text)).ToString());              
            System.Diagnostics.Process.Start("c:\\dane.txt");
            System.Diagnostics.Process.Start("c:\\dane1.txt");
        }
    }
}
1

A ten zapis w pętli nie spowalnia czasem algorytmu?
Ja bym liczby z ciągu zapisywał w oddzielnej tablicy (albo budował w pamięci StringBuilder z tekstem do zapisania), a do pliku zapisał na końcu całość.

0

<user>somekind</user> masz rację :) dopiero teraz przyuważyłem, że bez zapisywania dla 50000 wynik mam w sek, ale z zapisywaniem w pętli trwa to wieki...

Spróbowałem zrobić osobną tabelę i pożniej dopiero zapisywać jej zawartość do pliku, jednak to nie zmieniło szybkości działania aplikacji.. Prosiłbym o pomoc :)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Numerics;
using System.IO;

namespace WindowsFormsApplication2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        public static System.Numerics.BigInteger Fibonacci(int n)
        {
            if (n == 0)
                return 0;
            if (n == 1 || n == 2)
                return 1;

            System.Numerics.BigInteger[,] A = new System.Numerics.BigInteger[2, 2] { { 0, 1 }, { 1, 1 } };
            System.Numerics.BigInteger[,] B = (System.Numerics.BigInteger[,])A.Clone();
            System.Numerics.BigInteger[,] C = new System.Numerics.BigInteger[2, 2];

            n -= 2;           

            FileStream plik = File.Create("c:\\dane.txt");
            plik.Close();

            System.Numerics.BigInteger[] tabelka = new System.Numerics.BigInteger[n+2];
            tabelka[0] = 1;
            tabelka[1] = 1;           

            for (int i = 1; i <= n; i++)
            {
                C[0, 0] = B[0, 0] * A[0, 0] + B[0, 1] * A[1, 0];
                C[0, 1] = B[0, 0] * A[0, 1] + B[0, 1] * A[1, 1];
                C[1, 0] = B[1, 0] * A[0, 0] + B[1, 1] * A[1, 0];
                C[1, 1] = B[1, 0] * A[0, 1] + B[1, 1] * A[1, 1];

                B = (System.Numerics.BigInteger[,])C.Clone();                               
                
                tabelka[i+1] = C[1, 1];                

                Application.DoEvents();
            }            

            for (int j = 0; j < n; j++)
            {
                plik = File.Open("c:\\dane.txt", FileMode.Append);

                StreamWriter sw = new StreamWriter(plik);

                sw.WriteLine(j + 2 + "): " + tabelka[j]);

                sw.Flush();//BEZ TEGO NIE DZIAŁA!!

                plik.Close();
            }         

            return C[1, 1];                                                         
        }

        private void button1_Click(object sender, EventArgs e)
        {
            richTextBox1.Text = "Wartość " + textBox1.Text + " elementu ciągu Fibbonacciego wynosi: " + (Fibonacci(Convert.ToInt32(textBox1.Text)).ToString());              
            System.Diagnostics.Process.Start("c:\\dane.txt");            
        }
    }
}

1

Ale czemu za każdym razem otwierasz plik i zamykasz? Otwórz ten plik raz, flusha też daj raz, a tylko StreamWriter.WriteLine w pętli.

0

Mam kolejne zapytanie otóż chciałbym, żeby oprócz obliczenia wartości np dla 5000 mozna bylo wyswietlac jedna z obliczonych wartosci (przeciez w pamieci zostala utworzona tabelka z wartosciami), jednak mam problem z dokonianiem tego...

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Numerics;
using System.IO;

namespace WindowsFormsApplication2
{
    public partial class Form1 : Form
    {
        int poszukiwana;
        public System.Numerics.BigInteger[] tab;          

        public Form1()
        {
            InitializeComponent();
        }

        public static System.Numerics.BigInteger Fibonacci(int n)
        {            
            if (n == 0)
                return 0;
            if (n == 1 || n == 2)
                return 1;

            System.Numerics.BigInteger[,] A = new System.Numerics.BigInteger[2, 2] { { 0, 1 }, { 1, 1 } };
            System.Numerics.BigInteger[,] B = (System.Numerics.BigInteger[,])A.Clone();
            System.Numerics.BigInteger[,] C = new System.Numerics.BigInteger[2, 2];

            n -= 2;           

            FileStream plik = File.Create("c:\\dane.txt");
            plik.Close();

            System.Numerics.BigInteger[] tabelka = new System.Numerics.BigInteger[n+2];
            tabelka[0] = 1;
            tabelka[1] = 1;            

            for (int i = 1; i <= n; i++)
            {
                C[0, 0] = B[0, 0] * A[0, 0] + B[0, 1] * A[1, 0];
                C[0, 1] = B[0, 0] * A[0, 1] + B[0, 1] * A[1, 1];
                C[1, 0] = B[1, 0] * A[0, 0] + B[1, 1] * A[1, 0];
                C[1, 1] = B[1, 0] * A[0, 1] + B[1, 1] * A[1, 1];

                B = (System.Numerics.BigInteger[,])C.Clone();                             
                                
                tabelka[i+1] = C[1, 1];                
               
                Application.DoEvents();
            }

            if (n >= 10000)
            {
                plik = File.Open("c:\\dane.txt", FileMode.Append);

                StreamWriter sw = new StreamWriter(plik);

                for (int j = 0; j < 1000; j++)
                {  
                    sw.WriteLine(j + 1 + "): " + tabelka[j]);                    
                }

                sw.WriteLine("");

                sw.WriteLine("Poszukiwany to: " + tabelka[n + 1]);

                sw.Flush();//BEZ TEGO NIE DZIAŁA!!

                plik.Close();
            }
            else
            {
                plik = File.Open("c:\\dane.txt", FileMode.Append);

                StreamWriter sw = new StreamWriter(plik);

                for (int j = 0; j < n+1; j++)
                {   
                    sw.WriteLine(j + 1 + "): " + tabelka[j]);                                        
                }

                sw.WriteLine("");

                sw.WriteLine("Poszukiwany to: " + tabelka[n + 1]);

                sw.Flush();//BEZ TEGO NIE DZIAŁA!!

                plik.Close();
            }
            tab = tabelka; ---> nie da się tak zrobić bo "Error	1	An object reference is required for the non-static field, method, or property WindowsFormsApplication2.Form1.tab"

            return C[1, 1];                                                         
        }
        
        private void button1_Click(object sender, EventArgs e)
        {
            richTextBox1.Text = "Wartość " + textBox1.Text + " elementu ciągu Fibbonacciego wynosi: " + (Fibonacci(Convert.ToInt32(textBox1.Text)).ToString());              
            System.Diagnostics.Process.Start("c:\\dane.txt");
            poszukiwana = Convert.ToInt32(textBox1.Text);
            BtnPokaz.Enabled = true;
            textBox2.Enabled = true;
            label1.Text += poszukiwana;
            
        }

        private void button2_Click(object sender, EventArgs e)
        {
            MessageBox.Show(tab[Convert.ToInt32(textBox2.Text)].ToString());
        }
    }
}

co mam zrobic zeby zmiennej globalej 'tab' przypisac zawartosc tabeli 'tabelka' utworzonej wewnątrz funkcji 'public static System.Numerics.BigInteger Fibonacci(int n)'? :)

0
  1. tab to nie jest zmienna globalna.
  2. Metoda Fibbonacci powinna zwracać tablicę obliczonych liczb.
  3. Do zapisu do pliku powinna być oddzielna metoda.
  4. Do wyświetlania wartości oddzielna metoda.

1 użytkowników online, w tym zalogowanych: 0, gości: 1