Pocitanie PI, vlakna

Created: 2010-12-09 - 08:15

// 1) Create a new windows application with a default name
// 2) Copy from here evrithing (except from these green comments)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{

    partial class Form1: Form
    {

        private System.Windows.Forms.Label label1;
        private System.Windows.Forms.NumericUpDown decimalPlacesNumericUpDown;
        private System.Windows.Forms.Button calcButton;
        private System.Windows.Forms.TextBox resultsTextBox;
        private System.Windows.Forms.Panel panel1;
        private System.Windows.Forms.StatusStrip progressStatusStrip;
        private System.Windows.Forms.ToolStripStatusLabel calcToolStripStatusLabel;
        private System.Windows.Forms.ToolStripProgressBar calcToolStripProgressBar;
        private System.ComponentModel.BackgroundWorker backgroundWorker;
        private System.Windows.Forms.ToolStripStatusLabel digitsSoFarToolStripStatusLabel;

        public Form1()
        {
            InitializeComponent();
            ini2();
        }

        void ini2()
        {
            this.label1 = new System.Windows.Forms.Label();
            this.decimalPlacesNumericUpDown = new System.Windows.Forms.NumericUpDown();
            this.calcButton = new System.Windows.Forms.Button();
            this.resultsTextBox = new System.Windows.Forms.TextBox();
            this.panel1 = new System.Windows.Forms.Panel();
            this.progressStatusStrip = new System.Windows.Forms.StatusStrip();
            this.calcToolStripStatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
            this.digitsSoFarToolStripStatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
            this.calcToolStripProgressBar = new System.Windows.Forms.ToolStripProgressBar();
            this.backgroundWorker = new System.ComponentModel.BackgroundWorker();
            ((System.ComponentModel.ISupportInitialize)(this.decimalPlacesNumericUpDown)).BeginInit();
            this.panel1.SuspendLayout();
            this.progressStatusStrip.SuspendLayout();
            this.SuspendLayout();
            //
            // label1
            //
            this.label1.AutoSize = true;
            this.label1.Location = new System.Drawing.Point(12, 12);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(60, 13);
            this.label1.TabIndex = 0;
            this.label1.Text = "Digits of Pi:";
            //
            // decimalPlacesNumericUpDown
            //
            this.decimalPlacesNumericUpDown.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
                        | System.Windows.Forms.AnchorStyles.Right)));
            this.decimalPlacesNumericUpDown.Location = new System.Drawing.Point(80, 9);
            this.decimalPlacesNumericUpDown.Maximum = new decimal(new int[] {
            1000001,
            0,
            0,
            0});
            this.decimalPlacesNumericUpDown.Name = "decimalPlacesNumericUpDown";
            this.decimalPlacesNumericUpDown.Size = new System.Drawing.Size(409, 20);
            this.decimalPlacesNumericUpDown.TabIndex = 1;
            this.decimalPlacesNumericUpDown.Value = new decimal(new int[] {
            500,
            0,
            0,
            0});
            //
            // calcButton
            //
            this.calcButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this.calcButton.Location = new System.Drawing.Point(495, 7);
            this.calcButton.Name = "calcButton";
            this.calcButton.Size = new System.Drawing.Size(75, 23);
            this.calcButton.TabIndex = 2;
            this.calcButton.Text = "Calculate";
            this.calcButton.Click += new System.EventHandler(this.calcButton_Click);
            //
            // resultsTextBox
            //
            this.resultsTextBox.BackColor = System.Drawing.Color.White;
            this.resultsTextBox.Dock = System.Windows.Forms.DockStyle.Fill;
            this.resultsTextBox.Location = new System.Drawing.Point(0, 38);
            this.resultsTextBox.Multiline = true;
            this.resultsTextBox.Name = "resultsTextBox";
            this.resultsTextBox.ReadOnly = true;
            this.resultsTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
            this.resultsTextBox.Size = new System.Drawing.Size(583, 263);
            this.resultsTextBox.TabIndex = 1;
            //
            // panel1
            //
            this.panel1.Controls.Add(this.decimalPlacesNumericUpDown);
            this.panel1.Controls.Add(this.label1);
            this.panel1.Controls.Add(this.calcButton);
            this.panel1.Dock = System.Windows.Forms.DockStyle.Top;
            this.panel1.Location = new System.Drawing.Point(0, 0);
            this.panel1.Name = "panel1";
            this.panel1.Size = new System.Drawing.Size(583, 38);
            this.panel1.TabIndex = 0;
            //
            // progressStatusStrip
            //
            this.progressStatusStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
            this.calcToolStripStatusLabel,
            this.digitsSoFarToolStripStatusLabel,
            this.calcToolStripProgressBar});
            this.progressStatusStrip.Location = new System.Drawing.Point(0, 301);
            this.progressStatusStrip.Name = "progressStatusStrip";
            this.progressStatusStrip.Size = new System.Drawing.Size(583, 22);
            this.progressStatusStrip.TabIndex = 2;
            //
            // calcToolStripStatusLabel
            //
            this.calcToolStripStatusLabel.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
            this.calcToolStripStatusLabel.Name = "calcToolStripStatusLabel";
            this.calcToolStripStatusLabel.Size = new System.Drawing.Size(568, 17);
            this.calcToolStripStatusLabel.Spring = true;
            this.calcToolStripStatusLabel.Text = "Ready";
            this.calcToolStripStatusLabel.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
            //
            // digitsSoFarToolStripStatusLabel
            //
            this.digitsSoFarToolStripStatusLabel.Name = "digitsSoFarToolStripStatusLabel";
            this.digitsSoFarToolStripStatusLabel.Size = new System.Drawing.Size(0, 17);
            //
            // calcToolStripProgressBar
            //
            this.calcToolStripProgressBar.Name = "calcToolStripProgressBar";
            this.calcToolStripProgressBar.Size = new System.Drawing.Size(100, 16);
            this.calcToolStripProgressBar.Step = 1;
            this.calcToolStripProgressBar.Visible = false;
            //
            // backgroundWorker
            //
            this.backgroundWorker.WorkerReportsProgress = true;
            this.backgroundWorker.WorkerSupportsCancellation = true;
            this.backgroundWorker.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker_DoWork);
            this.backgroundWorker.ProgressChanged += new System.ComponentModel.ProgressChangedEventHandler(this.backgroundWorker_ProgressChanged);
            this.backgroundWorker.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker_RunWorkerCompleted);
            //
            // AsyncCalcPiForm
            //
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(583, 323);
            this.Controls.Add(this.resultsTextBox);
            this.Controls.Add(this.progressStatusStrip);
            this.Controls.Add(this.panel1);
            this.MinimumSize = new System.Drawing.Size(249, 180);
            this.Name = "AsyncCalcPiForm";
            this.Text = "Digits of Pi";
            ((System.ComponentModel.ISupportInitialize)(this.decimalPlacesNumericUpDown)).EndInit();
            this.panel1.ResumeLayout(false);
            this.panel1.PerformLayout();
            this.progressStatusStrip.ResumeLayout(false);
            this.progressStatusStrip.PerformLayout();
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        //////////
        void ShowProgress(string pi, int totalDigits, int digitsSoFar)
        {
            // Make sure we're on the UI thread
            Debug.Assert(this.InvokeRequired == false);

            // Display progress in UI
            this.resultsTextBox.Text = pi;
            this.calcToolStripProgressBar.Maximum = totalDigits;
            this.calcToolStripProgressBar.Value = digitsSoFar;
        }

        class CalcPiUserState
        {
            public readonly string Pi;
            public readonly int TotalDigits;
            public readonly int DigitsSoFar;

            public CalcPiUserState(string pi, int totalDigits, int digitsSoFar)
            {
                this.Pi = pi;
                this.TotalDigits = totalDigits;
                this.DigitsSoFar = digitsSoFar;
            }
        }

        void CalcPi(int digits)
        {
            StringBuilder pi = new StringBuilder("3", digits + 2);

            // Report initial progress
            this.backgroundWorker.ReportProgress(0,
              new CalcPiUserState(pi.ToString(), digits, 0));

            if (digits > 0)
            {
                pi.Append(".");

                for (int i = 0; i < digits; i += 9)
                {
                    int nineDigits = NineDigitsOfPi.StartingAt(i + 1);
                    int digitCount = Math.Min(digits - i, 9);
                    string ds = string.Format("{0:D9}", nineDigits);
                    pi.Append(ds.Substring(0, digitCount));

                    // Report continuing progress
                    this.backgroundWorker.ReportProgress(0,
                      new CalcPiUserState(pi.ToString(), digits, i + digitCount));

                    // Check for cancelation
                    if (this.backgroundWorker.CancellationPending) { return; }
                }
            }
        }

        void calcButton_Click(object sender, EventArgs e)
        {
            // Don't process if cancel request pending
            // (Should not be called, since we disabled the button...)
            if (this.backgroundWorker.CancellationPending) { return; }

            // If worker thread currently executing, cancel it
            if (this.backgroundWorker.IsBusy)
            {
                this.calcButton.Enabled = false;
                this.backgroundWorker.CancelAsync();
                return;
            }

            // Set calculating UI
            this.calcButton.Text = "Cancel";
            this.calcToolStripProgressBar.Visible = true;
            this.calcToolStripStatusLabel.Text = "Calculating...";

            // Begin calculating pi asynchronously
            this.backgroundWorker.RunWorkerAsync(
              (int)this.decimalPlacesNumericUpDown.Value);
        }

        void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            //throw new Exception("Ooops!");

            // Track start time
            DateTime start = DateTime.Now;

            CalcPi((int)e.Argument);

            // Indicate cancelation
            if (this.backgroundWorker.CancellationPending)
            {
                e.Cancel = true;
            }

            // Return elapsed time
            DateTime end = DateTime.Now;
            TimeSpan elapsed = end - start;
            e.Result = elapsed;
        }

        void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            // Show progress
            CalcPiUserState progress = (CalcPiUserState)e.UserState;
            ShowProgress(
              progress.Pi, progress.TotalDigits, progress.DigitsSoFar);
        }

        void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            // Reset progress UI
            this.calcButton.Text = "Calculate";
            this.calcButton.Enabled = true;
            this.calcToolStripStatusLabel.Text = "Ready";
            this.calcToolStripProgressBar.Visible = false;

            // Was the worker thread cancelled?
            if (e.Cancelled)
            {
                this.resultsTextBox.Text = "Canceled";
                return;
            }

            // Show elapsed time
            TimeSpan elapsed = (TimeSpan)e.Result;
            MessageBox.Show("Elapsed: " + elapsed.ToString());
        }

    }
}
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////

// NineDigitsOfPiAt.cs

/*
 * Computation of the n'th decimal digit of pi with very little memory.
 * Written by Fabrice Bellard on January 8, 1997.
 * Ported to C# by Chris Sells on May 5, 2002.
 *
 * We use a slightly modified version of the method described by Simon
 * Plouffe in "On the Computation of the n'th decimal digit of various
 * transcendental numbers" (November 1996). We have modified the algorithm
 * to get a running time of O(n^2) instead of O(n^3log(n)^3).
 *
 * This program uses mostly integer arithmetic. It may be slow on some
 * hardwares where integer multiplications and divisons must be done
 * by software.
 */

public class NineDigitsOfPi
{

    public static int StartingAt(int n)
    {
        int av = 0;
        int vmax = 0;
        int N = (int)((n + 20) * Math.Log(10) / Math.Log(2));
        int num = 0;
        int den = 0;
        int kq = 0;
        int kq2 = 0;
        int t = 0;
        int v = 0;
        int s = 0;
        double sum = 0.0;

        for (int a = 3; a <= (2 * N); a = next_prime(a))
        {
            vmax = (int)(Math.Log(2 * N) / Math.Log(a));
            av = 1;

            for (int i = 0; i < vmax; ++i) av = av * a;

            s = 0;
            num = 1;
            den = 1;
            v = 0;
            kq = 1;
            kq2 = 1;

            for (int k = 1; k <= N; ++k)
            {
                t = k;
                if (kq >= a)
                {
                    do
                    {
                        t = t / a;
                        --v;
                    }
                    while ((t % a) == 0);

                    kq = 0;
                }

                ++kq;
                num = mul_mod(num, t, av);

                t = (2 * k - 1);
                if (kq2 >= a)
                {
                    if (kq2 == a)
                    {
                        do
                        {
                            t = t / a;
                            ++v;
                        }
                        while ((t % a) == 0);
                    }

                    kq2 -= a;
                }

                den = mul_mod(den, t, av);
                kq2 += 2;

                if (v > 0)
                {
                    t = inv_mod(den, av);
                    t = mul_mod(t, num, av);
                    t = mul_mod(t, k, av);
                    for (int i = v; i < vmax; ++i) t = mul_mod(t, a, av);
                    s += t;
                    if (s >= av) s -= av;
                }
            }

            t = pow_mod(10, n - 1, av);
            s = mul_mod(s, t, av);
            sum = (sum + (double)s / (double)av) % 1.0;
        }

        return (int)(sum * 1e9);
    }

    private static int mul_mod(long a, long b, int m)
    {
        return (int)((a * b) % m);
    }

    // return the inverse of x mod y
    private static int inv_mod(int x, int y)
    {
        int q = 0;
        int u = x;
        int v = y;
        int a = 0;
        int c = 1;
        int t = 0;

        do
        {
            q = v / u;

            t = c;
            c = a - q * c;
            a = t;

            t = u;
            u = v - q * u;
            v = t;
        }
        while (u != 0);

        a = a % y;
        if (a < 0) a = y + a;

        return a;
    }

    // return (a^b) mod m
    private static int pow_mod(int a, int b, int m)
    {
        int r = 1;
        int aa = a;

        while (true)
        {
            if ((b & 0x01) != 0) r = mul_mod(r, aa, m);
            b = b >> 1;
            if (b == 0) break;
            aa = mul_mod(aa, aa, m);
        }

        return r;
    }

    // return true if n is prime
    private static bool is_prime(int n)
    {
        if ((n % 2) == 0) return false;

        int r = (int)(Math.Sqrt(n));
        for (int i = 3; i <= r; i += 2)
        {
            if ((n % i) == 0) return false;
        }

        return true;
    }

    // return the prime number immediately after n
    private static int next_prime(int n)
    {
        do
        {
            n++;
        }
        while (!is_prime(n));

        return n;
    }
}