用Delphi快速计算斐波那契(Fibonacci)数列中的第n个数

本程序使用矩阵快速幂运算方式来提高运行速度,计算到第1亿个数都没有问题。

程序中使用了rvelthuis的Delphi BigNumbers,可到下面的地址下载: 

GitHub - rvelthuis/DelphiBigNumbers: BigInteger and BigDecimal for Delphi

用Delphi快速计算斐波那契(Fibonacci)数列中的第n个数

unit uMain;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
  Vcl.StdCtrls, Vcl.ComCtrls;

type
  TForm1 = class(TForm)
    RichEditResult: TRichEdit;
    ButtonCalc: TButton;
    EditNum: TEdit;
    EditTime: TEdit;
    Label1: TLabel;
    Label2: TLabel;
    procedure ButtonCalcClick(Sender: TObject);
  private
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses uMatrix2;

procedure TForm1.ButtonCalcClick(Sender: TObject);
var
  M: TMatrix2;
  Delta: TDateTime;
begin
  EditTime.Text := '';
  RichEditResult.Text  := '';
  Application.ProcessMessages;
  M.Init(1,1,1,0);
  Delta := Now();
  M := M.Pow(StrToInt(EditNum.Text));
  Delta := Now() - Delta;
  EditTime.Text := FormatDateTime('n:s.zzz', Delta);
  RichEditResult.Text := M.Value[1,2].ToString;
end;

end.
object Form1: TForm1
  Left = 0
  Top = 0
  Caption = 'Form1'
  ClientHeight = 582
  ClientWidth = 960
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  Position = poScreenCenter
  DesignSize = (
    960
    582)
  PixelsPerInch = 96
  TextHeight = 13
  object Label1: TLabel
    Left = 362
    Top = 554
    Width = 48
    Height = 13
    Caption = #35745#31639#32791#26102
  end
  object Label2: TLabel
    Left = 720
    Top = 555
    Width = 43
    Height = 13
    Caption = #31532'N'#20010#25968
  end
  object RichEditResult: TRichEdit
    Left = 8
    Top = 8
    Width = 944
    Height = 532
    Anchors = [akLeft, akTop, akRight, akBottom]
    Font.Charset = GB2312_CHARSET
    Font.Color = clWindowText
    Font.Height = -11
    Font.Name = 'Tahoma'
    Font.Style = []
    Lines.Strings = (
      '')
    ParentFont = False
    ScrollBars = ssVertical
    TabOrder = 0
    Zoom = 100
  end
  object ButtonCalc: TButton
    Left = 877
    Top = 549
    Width = 75
    Height = 25
    Anchors = [akRight, akBottom]
    Caption = 'calc'
    TabOrder = 1
    OnClick = ButtonCalcClick
  end
  object EditNum: TEdit
    Left = 768
    Top = 551
    Width = 89
    Height = 21
    Anchors = [akRight, akBottom]
    TabOrder = 2
    Text = '10'
  end
  object EditTime: TEdit
    Left = 416
    Top = 551
    Width = 89
    Height = 21
    TabOrder = 3
  end
end
unit uMatrix2;

interface

uses Vcl.Dialogs, System.SysUtils, Velthuis.BigIntegers;

type
  BigInt =  BigInteger;

  TMatrix2 = record
    Value: array[1..2, 1..2] of BigInt;
  public
    class operator Multiply(const A, B: TMatrix2): TMatrix2;
    class operator Add(const A, B: TMatrix2): TMatrix2;
    class operator Equal(const A, B: TMatrix2): Boolean;
    class operator Implicit(const aValue: UInt64): TMatrix2;
    function Pow(N: UInt64): TMatrix2;
    function ToString: String;
    procedure Init(const A, B, C, D: BigInt);
  end;

implementation

function TMatrix2.Pow(N: UInt64): TMatrix2;
var
  Base: TMatrix2;
begin
  if N = 0 then
    Result := 1
  else if N = 1 then
    Result := Self
  else
  begin
    Result := 1;
    Base   := Self;
    while N > 0 do
    begin
      if (N and 1) > 0 then
        Result := Result * Base;
      Base := Base * Base;
      N := (N shr 1);
    end;
  end;
end;

class operator TMatrix2.Implicit(const aValue: UInt64): TMatrix2;
begin
  Result.Value[1, 1] := aValue;
  Result.Value[1, 2] := 0;
  Result.Value[2, 1] := 0;
  Result.Value[2, 2] := aValue;
end;

class operator TMatrix2.Equal(const A, B: TMatrix2): Boolean;
var
  I, J: Integer;
begin
  Result := True;
  for I := 1 to 2 do
  begin
    for J := 1 to 2 do
    begin
      if A.Value[I, J] <> B.Value[I, J] then
      begin
        Result := False;
        Exit;
      end;
    end;
  end;
end;

class operator TMatrix2.Add(const A, B: TMatrix2): TMatrix2;
var
  I, J: Integer;
begin
  for I := 1 to 2 do
  begin
    for J := 1 to 2 do
    begin
      Result.Value[I, J] := A.Value[I, J] + B.Value[I, J];
    end;
  end;
end;

class operator TMatrix2.Multiply(const A, B: TMatrix2): TMatrix2;
var
  I, J: Integer;
begin
  for I := 1 to 2 do
  begin
    for J := 1 to 2 do
    begin
      Result.Value[I, J] := A.Value[I, 1] * B.Value[1, J] +
                            A.Value[I, 2] * B.Value[2, J]
    end;
  end;
end;

function TMatrix2.ToString: String;
begin
  Result := Format('[[%s, %s], [%s, %s]]',
            [Value[1, 1].ToString, Value[1, 2].ToString,
             Value[2, 1].ToString, Value[2, 2].ToString]);
end;

procedure TMatrix2.Init(const A, B, C, D: BigInt);
begin
  Value[1, 1] := A;
  Value[1, 2] := B;
  Value[2, 1] := C;
  Value[2, 2] := D;
end;

end.

上一篇:JavaScript实现距离过去多久、刚刚、分钟、小时、天、月、时间


下一篇:猜拳游戏