直角双曲線 y=a/x

  y = a/x の直角双曲線についてのプログラムを作ってみました。
 この双曲線については特に説明は必要無いと思います。
一番最初に習う双曲線のようです。
此処でも、双曲線と直線の交点を取り上げています。
交点の座標は、連立方程式の二次式を解法すれば求められる事は他の双曲線と同じです。
 ゼロから、x1 或いはゼロからx2迄の積分は無限大になってしまう為出来ません。
x1からx2迄の範囲の積分は可能です。
積分a/x a log|X| (logは自然対数)となり log(1) = 0 となります。
x1 から x2の範囲の積分は、a (log(x2)-log(x1)) = a (log(x2/x1)) = s

左図ハンチング扇形の面積と、x2-x1の積分値が一致します。
一致することは、分割積分でも確認しました、この双曲線の特徴です。

 45°回転すれば、X2/a2 - Y2/b2 = 1 又は X2/a2 - Y2/b2 = -1 の双曲線になります。
左図のプログラムでは、-1の双曲線の値を算出しています。
弓形部の面積や弧の長さは、45°変換された双曲線の値からX2/a2 - Y2/b2 = -1 のプログラムを使用して計算してください。



プログラム

 プログラムは内容のわりに長くなっています。
グラフのパターンを整理すれば、可成り短くなると思いますが、今回は、手間を省きました。

unit Main;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, VclTee.TeeGDIPlus, Vcl.StdCtrls, VCLTee.TeEngine,
  VCLTee.Series, Vcl.ExtCtrls, VCLTee.TeeProcs, VCLTee.Chart;

type
  TForm1 = class(TForm)
    Chart1: TChart;
    Series1: TLineSeries;
    Series2: TLineSeries;
    Series3: TLineSeries;
    Series4: TPointSeries;
    Memo1: TMemo;
    Panel1: TPanel;
    Button1: TButton;
    Label1: TLabel;
    Label2: TLabel;
    LabeledEdit1: TLabeledEdit;
    LabeledEdit2: TLabeledEdit;
    LabeledEdit3: TLabeledEdit;
    Image1: TImage;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private 宣言 }
    function Datainput: boolean;
    procedure Calc;
    procedure addChartpApX;           // 交点2箇所 又は1箇所 第一象限
    procedure addChartpAmX;           // 交点2箇所 又は1箇所 第三象限
    procedure addChartmApX;           // 交点2箇所 又は1箇所 第四象限
    procedure addChartmAmX;           // 交点2箇所 又は1箇所 第二象限
    procedure addChartpAmpX;          // 交点2箇所 又は無し 第一第三象限
    procedure addChartmAmpX;          // 交点2箇所 又は無し 第二第四象限
    procedure addChartpAmBpC;         // 接線 第一象限
    procedure addChartpAmBmC;         // 接線 第三象限
    procedure addChartmApBpC;         // 接線 第二象限
    procedure addChartmApBmC;         // 接線 第四象限
    procedure GraphDraw;              // 扇型部作図部
    procedure Transform;              // 双曲線変換計算
    procedure calcarea;               // x1 - x2 間面積
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses
  Math;

var
  a, b, c: double;   // 双曲線 a/x  直線 bx+c
  x1, y1 : double;   // 交点1
  x2, y2 : double;   // 交点 2
  crossF : integer;  // 0 無し 1 接線 2,4 交点同一曲線二ヶ所 3,5 交点対象曲線

// a > 0 & b <= 0 X < 0
// 交点2箇所 又は1箇所 第三象限
procedure TForm1.addChartpAmX;
var
  maxX, maxY: double;
  MaxS, MinS: double;
  i, n: integer;
  x, dx: double;
  ys, yc : double;
begin
  // 双曲線グラフ範囲設定
  if x1 < x2 then maxX := x1 else maxX := x2;
  if y1 < y2 then maxY := y1 else maxY := y2;
  MaxS := maxY;
  if maxX < maxY then MaxS := maxX;
  MaxS := MaxS * 1.5;
  MinS := a / maxS;
  // 双曲線
  n := 1000;
  dx := (MaxS - MinS) / n;
  for i := 0 to n do begin
    x := dx * i + MinS;
    ys := a / x;
    Series1.AddXY(x, ys);
  end;
  // 直線
  x := 0;
  yc := b * x + c;
  Series2.AddXY(x, yc);
  if b <> 0 then begin
    yc := 0;
    x := -c / b;
  end
  else x := maxS;
  Series2.AddXY(x, yc);
  application.ProcessMessages;
  // 座標スケール設定用
  x := chart1.BottomAxis.Minimum;
  yc := 0;
  Series4.AddXY(x, yc);
  x := 0;
  Series4.AddXY(x, yc);
  yc := chart1.LeftAxis.Minimum;
  Series4.AddXY(x, yc);
  application.ProcessMessages;
  // b=0 交点一箇所時交点通過接線
  if b = 0 then begin
    dx := -y1 / x1;         // m
    yc := y1 - dx * x1;     // c
    x := maxS;
    ys := dx * x + yc;      // y = mx +c
    if ys > chart1.LeftAxis.Maximum then begin
      ys := chart1.LeftAxis.Maximum;
      x := (ys - yc) / dx
    end;
    Series3.AddXY(x, ys);
    x := 0;
    ys := dx * x + yc;      // y = mx + c
    if ys < chart1.LeftAxis.Minimum then begin
      ys := chart1.LeftAxis.Minimum;
      x := (ys - yc) / dx
    end;
    Series3.AddXY(x, ys);
    memo1.Lines.Add('接線 y = ' + floatTostr(dx) + ' x + ' + floatTostr(yc));
  end;
end;

// a > 0 & b <= 0  X > 0
// 交点2箇所 又は1箇所 第一象限
procedure TForm1.addChartpApX;
var
  maxX, maxY: double;
  MaxS, MinS: double;
  i, n: integer;
  x, dx: double;
  ys, yc : double;
begin
  // 双曲線グラフ範囲設定
  if x1 > x2 then maxX := x1 else maxX := x2;
  if y1 > y2 then maxY := y1 else maxY := y2;
  MaxS := maxY;
  if maxX > maxY then MaxS := maxX;
  MaxS := MaxS * 1.5;
  MinS := a / MaxS;
  // 双曲線
  n := 1000;
  dx := (MaxS - MinS) / n;
  for i := 0 to n do begin
    x := dx * i + MinS;
    ys := a / x;
    Series1.AddXY(x, ys);
  end;
  // 直線
  x := 0;
  yc := b * x + c;
  Series2.AddXY(x, yc);
  if b <> 0 then begin
    yc := 0;
    x := -c / b;
  end
  else x := MaxS;
  Series2.AddXY(x, yc);
  application.ProcessMessages;
  // 座標スケール設定用
  x := 0;
  yc := chart1.LeftAxis.Maximum;
  Series4.AddXY(x, yc);
  yc := 0;
  Series4.AddXY(x, yc);
  x := chart1.BottomAxis.Maximum;
  Series4.AddXY(x, yc);
  application.ProcessMessages;
  // b=0 交点一箇所時交点通過接線
  if b = 0 then begin
    dx := -y1 / x1;         // m
    yc := y1 - dx * x1;     // c
    x := 0;
    ys := dx * x + yc;      // y = mx +c
    if ys > chart1.LeftAxis.Maximum then begin
      ys := chart1.LeftAxis.Maximum;
      x := (ys - yc) / dx
    end;
    Series3.AddXY(x, ys);
    x := maxs;
    ys := dx * x + yc;      // y = mx + c
    if ys < chart1.LeftAxis.Minimum then begin
      ys := chart1.LeftAxis.Minimum;
      x := (ys - yc) / dx
    end;
    Series3.AddXY(x, ys);
    memo1.Lines.Add('接線 y = ' + floatTostr(dx) + ' x + ' + floatTostr(yc));
  end;
end;

// a < 0 & b >= 0 X < 0
// 交点2箇所 又は1箇所 第二象限
procedure TForm1.addChartmAmX;
var
  maxX, maxY: double;
  MaxS, MinS: double;
  i, n: integer;
  x, dx: double;
  ys, yc : double;
begin
  // 双曲線グラフ範囲設定
  if x1 < x2 then maxX := x1 else maxX := x2;
  if y1 < y2 then maxY := y2 else maxY := y1;
  MaxS := -maxY;
  if abs(maxX) > maxY then MaxS := maxX;
  MaxS := MaxS * 1.5;
  MinS := -a / MaxS;
  // 双曲線
  n := 1000;
  dx := (MaxS - MinS) / n;
  for i := 0 to n do begin
    x := dx * i + MinS;
    ys := a / x;
    Series3.AddXY(x, ys);
  end;
  // 直線
  x := 0;
  yc := b * x + c;
  Series2.AddXY(x, yc);
  if b <> 0 then begin
    yc := 0;
    x := -c / b;
  end
  else x := MaxS;
  Series2.AddXY(x, yc);
  application.ProcessMessages;
  // 座標スケール設定用
  x := chart1.BottomAxis.Minimum;
  yc := 0;
  Series4.AddXY(x, yc);
  x := 0;
  Series4.AddXY(x, yc);
  yc := chart1.LeftAxis.Maximum;
  Series4.AddXY(x, yc);
  application.ProcessMessages;
  // b=0 交点一箇所時交点通過接線
  if b = 0 then begin
    dx := -y1 / x1;         // m
    yc := y1 - dx * x1;     // c
    x := maxs;
    ys := dx * x + yc;      // y = mx + c
    if ys < chart1.LeftAxis.Minimum then begin
      ys := chart1.LeftAxis.Minimum;
      x := (ys - yc) / dx
    end;
    Series1.AddXY(x, ys);
    x := 0;
    ys := dx * x + yc;      // y = mx +c
    if ys > chart1.LeftAxis.Maximum then begin
      ys := chart1.LeftAxis.Maximum;
      x := (ys - yc) / dx
    end;
    Series1.AddXY(x, ys);
    memo1.Lines.Add('接線 y = ' + floatTostr(dx) + ' x + ' + floatTostr(yc));
  end;
end;

// a < 0 & b >= 0 x > 0
// 交点2箇所 又は1箇所 第四象限
procedure TForm1.addChartmApX;
var
  maxX, maxY: double;
  MaxS, MinS: double;
  i, n: integer;
  x, dx: double;
  ys, yc : double;
begin
  // 双曲線グラフ範囲設定
  if x1 > x2 then maxX := x1 else maxX := x2;
  if y1 > y2 then maxY := y2 else maxY := y1;
  MaxS := - maxY;
  if maxX > abs(maxY) then MaxS := maxX;
  MaxS := MaxS * 1.5;
  MinS := -a / maxS;
  // 双曲線
  n := 1000;
  dx := (MaxS - MinS) / n;
  for i := 0 to n do begin
    x := dx * i + MinS;
    ys := a / x;
    Series3.AddXY(x, ys);
  end;
  // 直線
  x := 0;
  yc := b * x + c;
  Series2.AddXY(x, yc);
  if b <> 0 then begin
    yc := 0;
    x := -c / b;
  end
  else x := MaxS;
  Series2.AddXY(x, yc);
  application.ProcessMessages;
  // 座標スケール設定用
  x := 0;
  yc := chart1.LeftAxis.Minimum;
  Series4.AddXY(x, yc);
  yc := 0;
  Series4.AddXY(x, yc);
  x := chart1.BottomAxis.Maximum;
  Series4.AddXY(x, yc);
  application.ProcessMessages;
  // b=0 交点一箇所時交点通過接線
  if b = 0 then begin
    dx := -y1 / x1;         // m
    yc := y1 - dx * x1;     // c
    x := 0;
    ys := dx * x + yc;      // y = mx +c
    if ys < chart1.LeftAxis.Minimum then begin
      ys := chart1.LeftAxis.Minimum;
      x := (ys - yc) / dx
    end;
    Series1.AddXY(x, ys);
    x := maxS;
    ys := dx * x + yc;      // y = mx + c
    if ys > chart1.LeftAxis.Maximum then begin
      ys := chart1.LeftAxis.Maximum;
      x := (ys - yc) / dx
    end;
    Series1.AddXY(x, ys);
    memo1.Lines.Add('接線 y = ' + floatTostr(dx) + ' x + ' + floatTostr(yc));
  end;
end;

// a > 0 & b > 0
// 交点2箇所 又は無し 第一第三象限
procedure TForm1.addChartpAmpX;
var
  maxX, maxY: double;
  MaxS, MinS: double;
  i, n: integer;
  x, dx: double;
  ys, yc : double;
begin
  // 双曲線グラフ範囲設定
  if abs(x1) > abs(x2) then maxX := x1 else maxX := x2;
  if abs(y1) > abs(y2) then maxY := y1 else maxY := y2;
  MaxS := maxY;
  if abs(maxX) > abs(maxY) then MaxS := maxX;
  if abs(MaxS) < 10 then MaxS := sqrt(abs(MaxS)) * 5
                    else MaxS := abs(MaxS) * 1.5;
  minS := a / MaxS;
  // 双曲線
  n := 1000;
  dx := (MaxS - MinS) / n;
  for i := 0 to n do begin
    x := dx * i + MinS;
    ys := a / x;
    Series1.AddXY(x, ys);
  end;
  for i := n downto 0 do begin
    x := dx * i - MaxS;
    ys := a / x;
    Series3.AddXY(x, ys);
  end;
  application.ProcessMessages;
  // 直線
  x := chart1.BottomAxis.Minimum;
  yc := b * x + c;
  if yc < chart1.LeftAxis.Minimum then begin
    yc := chart1.LeftAxis.Minimum;
    x := (yc - c) / b;
  end;
  Series2.AddXY(x, yc);
  x := chart1.BottomAxis.Maximum;
  yc := b * x + c;
  if yc > chart1.LeftAxis.Maximum then begin
    yc := chart1.LeftAxis.Maximum;
    x := (yc - c) / b;
  end;
  Series2.AddXY(x, yc);
end;

// a < 0 & b < 0
// 交点2箇所 又は無し 第二第四象限
procedure TForm1.addChartmAmpX;
var
  maxX, maxY: double;
  MaxS, MinS: double;
  i, n: integer;
  x, dx: double;
  ys, yc : double;
begin
  // 双曲線グラフ範囲設定
  if abs(x1) > abs(x2) then maxX := x1 else maxX := x2;
  if abs(y1) > abs(y2) then maxY := y1 else maxY := y2;
  MaxS := maxY;
  if abs(maxX) > abs(maxY) then MaxS := maxX;
  if abs(MaxS) < 10 then MaxS := sqrt(abs(MaxS)) * 5
                    else MaxS := abs(MaxS) * 1.5;
  minS := -a / MaxS;
  // 双曲線
  n := 1000;
  dx := (MaxS - MinS) / n;
  for i := 0 to n do begin
    x := dx * i + MinS;
    ys := a / x;
    Series1.AddXY(x, ys);
  end;
  for i := n downto 0 do begin
    x := dx * i - MaxS;
    ys := a / x;
    Series3.AddXY(x, ys);
  end;
  application.ProcessMessages;
  // 直線
  x := chart1.BottomAxis.Minimum;
  yc := b * x + c;
  if yc > chart1.LeftAxis.Maximum then begin
    yc := chart1.LeftAxis.Maximum;
    x := (yc - c) / b;
  end;
  Series2.AddXY(x, yc);
  x := chart1.BottomAxis.Maximum;
  yc := b * x + c;
  if yc < chart1.LeftAxis.Minimum then begin
    yc := chart1.LeftAxis.Minimum;
    x := (yc - c) / b;
  end;
  Series2.AddXY(x, yc);
end;

// a > 0 & b < 0  c > 0
// 接線 第一象限
procedure TForm1.addChartpAmBpC;
var
  i, n: integer;
  MaxS, MinS: double;
  x, dx, ys: double;
  yc: double;
begin
  // 双曲線グラフ範囲設定
  MaxS := x1;
  if y1 > x1 then MaxS := y1;
  if abs(MaxS) < 10 then MaxS := sqrt(abs(MaxS)) * 5
                    else MaxS := abs(MaxS) * 1.5;
  minS := a / MaxS;
  // 双曲線
  n := 1000;
  dx := (MaxS - MinS) / n;
  for i := 0 to n do begin
    x := dx * i + MinS;
    ys := a / x;
    Series1.AddXY(x, ys);
  end;
  // 直線
  yc := 0;
  x := -c / b;
  Series2.AddXY(x, yc);
  x := 0;
  yc := b * x + c;
  Series2.AddXY(x, yc);
end;

// a > 0 & b < 0  c < 0
// 接線 第三象限
procedure TForm1.addChartpAmBmC;
var
  i, n: integer;
  MaxS, MinS: double;
  x, dx, ys: double;
  yc: double;
begin
  // 双曲線グラフ範囲設定
  MaxS := abs(x1);
  if abs(y1) > abs(x1) then MaxS := y1;
  if abs(MaxS) < 10 then MaxS := sqrt(abs(MaxS)) * 5
                    else MaxS := abs(MaxS) * 1.5;
  minS := a / MaxS;
  // 双曲線
  n := 1000;
  dx := (MaxS - MinS) / n;
  for i := 0 to n do begin
    x := dx * i - MaxS;
    ys := a / x;
    Series1.AddXY(x, ys);
  end;
  application.ProcessMessages;
  // 直線
  yc := 0;
  x := -c / b;
  Series2.AddXY(x, yc);
  x := 0;
  yc := b * x + c;
  Series2.AddXY(x, yc);
end;

// a < 0 & b > 0  c > 0
// 接線 第二象限
procedure TForm1.addChartmApBpC;
var
  i, n: integer;
  MaxS, MinS: double;
  x, dx, ys: double;
  yc: double;
begin
  // 双曲線グラフ範囲設定
  MaxS := abs(x1);
  if abs(y1) > abs(x1) then MaxS := y1;
  if abs(MaxS) < 10 then MaxS := sqrt(abs(MaxS)) * 5
                    else MaxS := abs(MaxS) * 1.5;
  minS := -a / MaxS;
  // 双曲線
  n := 1000;
  dx := (MaxS - MinS) / n;
  for i := 0 to n do begin
    x := dx * i - MaxS;
    ys := a / x;
    Series1.AddXY(x, ys);
  end;
  application.ProcessMessages;
  // 直線
  yc := 0;
  x := -c / b;
  Series2.AddXY(x, yc);
  x := 0;
  yc := b * x + c;
  Series2.AddXY(x, yc);
end;

// a < 0 & b > 0  c < 0
// 接線 第四象限
procedure TForm1.addChartmApBmC;
var
  i, n: integer;
  MaxS, MinS: double;
  x, dx, ys: double;
  yc: double;
begin
  // 双曲線グラフ範囲設定
  MaxS := abs(x1);
  if abs(y1) > abs(x1) then MaxS := y1;
  if abs(MaxS) < 10 then MaxS := sqrt(abs(MaxS)) * 5
                    else MaxS := abs(MaxS) * 1.5;
  minS := -a / MaxS;
  // 双曲線
  n := 1000;
  dx := (MaxS - MinS) / n;
  for i := 0 to n do begin
    x := dx * i + minS;
    ys := a / x;
    Series1.AddXY(x, ys);
  end;
  application.ProcessMessages;
  // 直線
  x := 0;
  yc := b * x + c;
  Series2.AddXY(x, yc);
  yc := 0;
  x := -c / b;
  Series2.AddXY(x, yc);
end;

// Imageに作図 同一象限交点二箇所の場合
// 扇型作図
// 扇型部の面積計算
procedure TForm1.GraphDraw;
var
  i, n: integer;
  xbase, ybase: integer;
  ximax, yimax: integer;
  dx, dy, x, y: double;
  axmax, aymax: double;
  axmin, aymin: double;
  xi, yi      : integer;
  dxx, dx2    : double;
  ds, s       : double;
begin
  image1.Canvas.Pen.Color := clSkyblue;
  image1.Canvas.Pen.Style := psSolid;
  image1.Canvas.Pen.Width := 2;
  // Axisの最小値最大値
  axmin := chart1.BottomAxis.Minimum;
  axmax := chart1.BottomAxis.Maximum;
  aymin := chart1.LeftAxis.Minimum;
  aymax := chart1.LeftAxis.Maximum;
  if (a > 0) and (b < 0) and (c > 0) then begin     // 第一象限
    // 座標値の最小値最大値
    xbase := Series4.CalcXPos(1);
    ybase := Series4.CalcYPos(0);
    ximax := Series4.CalcXPos(2);
    yimax := Series4.CalcYPos(1);
    // 交点と原点間線引き
    dx := (ximax - xbase) / (axmax - axmin);
    dy := (yimax - ybase) / (aymax - aymin);
    xi := round(x1 * dx) + xbase;
    yi := round((aymax - y1) * dy) + ybase;
    image1.Canvas.MoveTo(xi, yi);
    image1.Canvas.lineTo(xbase, yimax);
    xi := round(x2 * dx) + xbase;
    yi := round((aymax - y2) * dy) + ybase;
    image1.Canvas.MoveTo(xi, yi);
    image1.Canvas.lineTo(xbase, yimax);
    // 塗りつぶし
    n := (xi - xbase) div 4;
    if n < 2 then n := 2;
    dxx := x2 / n;
    image1.Canvas.Pen.Width := 1;
    for i := 1 to n - 1 do begin
      x := i * dxx;
      y := y2 / x2 * x;
      xi := round(x * dx) + xbase;
      yi := round((aymax - y) * dy) + ybase;
      image1.Canvas.MoveTo(xi, yi);
      if x < x1 then y := y1 / x1 * x
                else y := a / x;
      yi := round((aymax - y) * dy) + ybase;
      image1.Canvas.lineTo(xi, yi);
    end;
    // x1, x2 位置の線
    image1.Canvas.Pen.Width := 2;
    image1.Canvas.Pen.Color := clRed;
    xi := round(x1 * dx) + xbase;
    yi := round((aymax - y1) * dy) + ybase;
    image1.Canvas.MoveTo(xi, yi);
    image1.Canvas.lineTo(xi, yimax);
    image1.Canvas.TextOut(xi - 5, yimax,'x1');
    xi := round(x2 * dx) + xbase;
    yi := round((aymax - y2) * dy) + ybase;
    image1.Canvas.MoveTo(xi, yi);
    image1.Canvas.lineTo(xi, yimax);
    image1.Canvas.TextOut(xi - 5, yimax,'x2');
    // 面積計算
    n := (xi - xbase) * 100;
    if n < 100 then n := 100;
    dxx := x2 / n;
    dx2 := dxx / 2;
    s := 0;
    for i := 0 to n - 1 do begin
      x := i * dxx + dx2;
      y := y2 / x2 * x;
      if x < x1 then dy := y1 / x1 * x
                else dy := a / x;
      ds := (dy - y) * dxx;
      s := s + ds;
    end;
    memo1.Lines.Add('扇部分割面積計算 = ' + floatTostr(s));
    ds := ln(x2 / x1) * abs(a);
    memo1.Lines.Add('扇部対数面積計算 = ' + floatTostr(ds));
  end;
  if (a > 0) and (b < 0) and (c < 0) then begin     // 第三象限
    // 座標値の最小値最大値
    xbase := Series4.CalcXPos(0);
    ybase := Series4.CalcYPos(0);
    ximax := Series4.CalcXPos(1);
    yimax := Series4.CalcYPos(2);
    // 交点と原点間線引き
    dx := (ximax - xbase) / (axmax - axmin);
    dy := (yimax - ybase) / (aymax - aymin);
    xi := round((x1 - axmin) * dx) + xbase;
    yi := round((aymax - y1) * dy) + ybase;
    image1.Canvas.MoveTo(xi, yi);
    image1.Canvas.lineTo(ximax, ybase);
    xi := round((x2 - axmin) * dx) + xbase;
    yi := round((aymax - y2) * dy) + ybase;
    image1.Canvas.MoveTo(xi, yi);
    image1.Canvas.lineTo(ximax, ybase);
    // 塗りつぶし
    n := (ximax - xi) div 4;
    if n < 2 then n := 2;
    dxx := x2 / n;
    image1.Canvas.Pen.Width := 1;
    for i := 1 to n - 1 do begin
      x := i * dxx;
      y := y2 / x2 * x;
      xi := round((x - axmin) * dx) + xbase;
      yi := round((aymax - y) * dy) + ybase;
      image1.Canvas.MoveTo(xi, yi);
      if x > x1 then y := y1 / x1 * x
                else y := a / x;
      yi := round((aymax - y) * dy) + ybase;
      image1.Canvas.lineTo(xi, yi);
    end;
    // x1, x2 位置の線
    image1.Canvas.Pen.Width := 2;
    image1.Canvas.Pen.Color := clRed;
    xi := round((x1 - axmin)* dx) + xbase;
    yi := round((aymax - y1) * dy) + ybase;
    image1.Canvas.MoveTo(xi, yi);
    image1.Canvas.lineTo(xi, ybase);
    image1.Canvas.TextOut(xi - 5, ybase - 20,'x1');
    xi := round((x2 - axmin) * dx) + xbase;
    yi := round((aymax - y2) * dy) + ybase;
    image1.Canvas.MoveTo(xi, yi);
    image1.Canvas.lineTo(xi, ybase);
    image1.Canvas.TextOut(xi - 5, ybase - 20,'x2');
    // 面積計算
    n := (ximax - xi) * 100;
    if n < 100 then n := 100;
    dxx := x2 / n;
    dx2 := dxx / 2;
    s := 0;
    for i := 0 to n - 1 do begin
      x := i * dxx + dx2;
      y := y2 / x2 * x;
      if x > x1 then dy := y1 / x1 * x
                else dy := a / x;
      ds := (dy - y) * dxx;
      s := s + ds;
    end;
    memo1.Lines.Add('扇部分割面積計算 = ' + floatTostr(s));
    ds := ln(x2 / x1) * abs(a);
    memo1.Lines.Add('扇部対数面積計算 = ' + floatTostr(ds));
  end;
  if (a < 0) and (b > 0) and (c > 0) then begin     // 第二象限
    // 座標値の最小値最大値
    xbase := Series4.CalcXPos(0);
    ybase := Series4.CalcYPos(2);
    ximax := Series4.CalcXPos(1);
    yimax := Series4.CalcYPos(1);
    // 交点と原点間線引き
    dx := (ximax - xbase) / (axmax - axmin);
    dy := (yimax - ybase) / (aymax - aymin);
    xi := round((x1 - axmin) * dx) + xbase;
    yi := round((aymax - y1) * dy) + ybase;
    image1.Canvas.MoveTo(xi, yi);
    image1.Canvas.lineTo(ximax, yimax);
    xi := round((x2 - axmin) * dx) + xbase;
    yi := round((aymax - y2) * dy) + ybase;
    image1.Canvas.MoveTo(xi, yi);
    image1.Canvas.lineTo(ximax, yimax);
    // 塗りつぶし
    n := (ximax - xi) div 4;
    if n < 2 then n := 2;
    dxx := x2 / n;
    image1.Canvas.Pen.Width := 1;
    for i := 1 to n - 1 do begin
      x := i * dxx;
      y := y2 / x2 * x;
      xi := round((x - axmin) * dx) + xbase;
      yi := round((aymax - y) * dy) + ybase;
      image1.Canvas.MoveTo(xi, yi);
      if x > x1 then y := y1 / x1 * x
                else y := a / x;
      yi := round((aymax - y) * dy) + ybase;
      image1.Canvas.lineTo(xi, yi);
    end;
    // x1, x2 位置の線
    image1.Canvas.Pen.Width := 2;
    image1.Canvas.Pen.Color := clRed;
    xi := round((x1 - axmin)* dx) + xbase;
    yi := round((aymax - y1) * dy) + ybase;
    image1.Canvas.MoveTo(xi, yi);
    image1.Canvas.lineTo(xi, yimax);
    image1.Canvas.TextOut(xi - 5, yimax,'x1');
    xi := round((x2 - axmin) * dx) + xbase;
    yi := round((aymax - y2) * dy) + ybase;
    image1.Canvas.MoveTo(xi, yi);
    image1.Canvas.lineTo(xi, yimax);
    image1.Canvas.TextOut(xi - 5, yimax,'x2');
    // 面積計算
    n := (ximax - xi) * 100;
    if n < 100 then n := 100;
    dxx := x2 / n;
    dx2 := dxx / 2;
    s := 0;
    for i := 0 to n - 1 do begin
      x := i * dxx + dx2;
      y := y2 / x2 * x;
      if x > x1 then dy := y1 / x1 * x
                else dy := a / x;
      ds := (y - dy) * dxx;
      s := s + ds;
    end;
    memo1.Lines.Add('扇部分割面積計算 = ' + floatTostr(s));
    ds := ln(x2 / x1) * abs(a);
    memo1.Lines.Add('扇部対数面積計算 = ' + floatTostr(ds));
  end;
  if (a < 0) and (b > 0) and (c < 0) then begin     // 第四象限
    // 座標値の最小値最大値
    xbase := Series4.CalcXPos(1);
    ybase := Series4.CalcYPos(1);
    ximax := Series4.CalcXPos(2);
    yimax := Series4.CalcYPos(0);
    // 交点と原点間線引き
    dx := (ximax - xbase) / (axmax - axmin);
    dy := (yimax - ybase) / (aymax - aymin);
    xi := round((x1 - axmin) * dx) + xbase;
    yi := round((aymax - y1) * dy) + ybase;
    image1.Canvas.MoveTo(xi, yi);
    image1.Canvas.lineTo(xbase, ybase);
    xi := round((x2 - axmin) * dx) + xbase;
    yi := round((aymax - y2) * dy) + ybase;
    image1.Canvas.MoveTo(xi, yi);
    image1.Canvas.lineTo(xbase, ybase);
    // 塗りつぶし
    n := (xi - xbase) div 4;
    if n < 2 then n := 2;
    dxx := x2 / n;
    image1.Canvas.Pen.Width := 1;
    for i := 1 to n - 1 do begin
      x := i * dxx;
      y := y2 / x2 * x;
      xi := round((x - axmin) * dx) + xbase;
      yi := round((aymax - y) * dy) + ybase;
      image1.Canvas.MoveTo(xi, yi);
      if x < x1 then y := y1 / x1 * x
                else y := a /x;
      yi := round((aymax - y) * dy) + ybase;
      image1.Canvas.lineTo(xi, yi);
    end;
    // x1, x2 位置の線
    image1.Canvas.Pen.Width := 2;
    image1.Canvas.Pen.Color := clRed;
    xi := round((x1 - axmin)* dx) + xbase;
    yi := round((aymax - y1) * dy) + ybase;
    image1.Canvas.MoveTo(xi, yi);
    image1.Canvas.lineTo(xi, ybase);
    image1.Canvas.TextOut(xi - 5, ybase - 20,'x1');
    xi := round((x2 - axmin) * dx) + xbase;
    yi := round((aymax - y2) * dy) + ybase;
    image1.Canvas.MoveTo(xi, yi);
    image1.Canvas.lineTo(xi, ybase);
    image1.Canvas.TextOut(xi - 5, ybase - 20,'x2');
    // 面積計算
    n := (xi - xbase) * 100;
    if n < 100 then n := 100;
    dxx := x2 / n;
    dx2 := dxx / 2;
    s := 0;
    for i := 0 to n - 1 do begin
      x := i * dxx + dx2;
      y := y2 / x2 * x;
      if x < x1 then dy := y1 / x1 * x
                else dy := a / x;
      ds := (y - dy) * dxx;
      s := s + ds;
    end;
    memo1.Lines.Add('扇部分割面積計算 = ' + floatTostr(s));
    ds := ln(x2 / x1) * abs(a);
    memo1.Lines.Add('扇部対数面積計算 = ' + floatTostr(ds));
  end;
  chart1.BackImage.Bitmap := Image1.Picture.Bitmap;
end;

// 双曲線と直線の交点計算
procedure TForm1.Calc;
var
  a0, b0, c0: double;
  rt, e: double;
begin
  a0 := b;
  b0 := c;
  c0 := -a;
  x1 := 0;
  y1 := 0;
  x2 := 0;
  y2 := 0;
  crossF := 0;              // 交点なし
  // 二次方程式の解法
  rt := b0 * b0 - 4 * a0 * c0;
  if rt < 0 then begin
     Memo1.Lines.Add('交点無し');
     exit;
  end;
  if rt = 0 then begin
     Memo1.Lines.Add('接線');
     x1 := (-b0 / 2 / a0);
     y1 := b * x1 + c;
     x2 := x1;
     y2 := y1;
     crossF := 1;           // 接線
     Memo1.Lines.Add('x, y = ' + floattostr(x1) + ', ' + floattostr(y1));
     exit;
  end;
  if rt > 0 then begin
    if b <> 0 then Memo1.Lines.Add('交点二ヶ所')
              else Memo1.Lines.Add('交点一ヶ所');
    if (a > 0) and (b <= 0) then crossF := 2; // 第一第三象限交点二箇所
    if (a > 0) and (b > 0)  then crossF := 3; // 第二第四象限交点二箇所
    if (a < 0) and (b >= 0) then crossF := 4; // 第一三象限交差
    if (a < 0) and (b < 0)  then crossF := 5; // 第二四象限交差

    e := sqrt(rt);
    if a0 <> 0 then begin
      x1 := (-b0 + e) / 2 / a0;
      x2 := (-b0 - e) / 2 / a0;
      if abs(x1) > abs(x2) then begin
        rt := x1;
        x1 := x2;
        x2 := rt;
      end;
      y1 := b * x1 + c;
      y2 := b * x2 + c;
    end
    else begin
      y1 := c;
      y2 := c;
      x1 := a / y1;
      x2 := a / y2;
    end;
    Memo1.Lines.Add('交点 x1, y1 = ' + floattostr(x1) + ', ' + floattostr(y1));
    Memo1.Lines.Add('交点 x2, y2 = ' + floattostr(x2) + ', ' + floattostr(y2));
  end;
end;

// X^2/a^2 - Y^2/b^2 = -1 への変換
// (45°角度変換)
procedure TForm1.Transform;
var
  Q0, Q1, X01, Y01: double;
  r2a, b0, c0: double;
begin
  memo1.Lines.Add('');
  memo1.Lines.Add('双曲線変換 X^2/a''^2 - Y^2/b''^2 = -1    y = αx+c''');
  r2a := sqrt(abs(a) * 2);  // √2 * √a
  Q0 := arctan(b);
  if a > 0 then Q1 := Q0 + pi / 4
           else Q1 := Q0 - pi / 4;
  memo1.Lines.Add('a'' = ' + floatTostr(r2a));
  memo1.Lines.Add('b'' = ' + floatTostr(r2a));
  if (abs(b) = 1) and (a * b > 0) then  begin // 直線が垂直になる場合
    c0 := sin(pi / 4) * abs(c);   // 垂直線の位置絶対値
    if a > 0  then begin          // aの値とcの値で符号設定
      if c > 0 then c0 := -c0;
    end
    else
      if c < 0 then c0 := -c0;
    memo1.Lines.Add('直線垂直 X'' = ' + floatTostr(c0));
  end
  else begin                                  // 直線が垂直でない場合
    b0 := tan(Q1);
    X01 := c / sqrt(2);
    Y01 := c / sqrt(2);
    if a > 0 then c0 := Y01 + b0 * X01
             else c0 := Y01 - b0 * X01;
    memo1.Lines.Add('α = ' + floatTostrF(b0, ffFixed, 15,13));
    memo1.Lines.Add('c'' = ' + floatTostr(c0));
  end;
end;

// x2 - x1 間面積
procedure TForm1.calcarea;
var
  i, n:       integer;
  x, y:       double;
  dx, dx2:    double;
  ds, s, sl:  double;
  l1, l2 :    double;
  an:         double;
  x1n, x2n:   double;
begin
  an := abs(a);
  x1n := abs(x1);
  x2n := abs(x2);
  n := round((x2n - x1n) * 5000);
  dx := (x2n - x1n) / n;
  dx2 := dx / 2;
  s := 0;
  for i := 0 to n - 1 do begin
    x := i * dx + dx2 + x1n;
    y := an / x;
    ds := y * dx;
    s := s + ds;
  end;
  memo1.Lines.Add('x2-x1分割面積= ' + floatTostr(s));
  l1 := an * ln(x1n);
  l2 := an * ln(x2n);
  sl := l2 - l1;
  memo1.Lines.Add('x2-x1     面積 = ' + floatTostr(sl));
end;

// データー入力処理
function TForm1.Datainput: boolean;
var
  ch : integer;
begin
  Result := False;
  val(LabeledEdit1.Text, a, ch);
  if ch <> 0 then begin
    application.MessageBox('双曲線 a の値に間違いがあります。','注意',0);
    exit;
  end;
  if a = 0 then begin
    application.MessageBox('a の値がゼロです、ゼロでは計算出来ません。','注意',0);
    exit;
  end;
  val(LabeledEdit2.Text, b, ch);
  if ch <> 0 then begin
    application.MessageBox('直線 b の値に間違いがあります。','注意',0);
    exit;
  end;
  val(LabeledEdit3.Text, c, ch);
  if ch <> 0 then begin
    application.MessageBox('直線 c の値に間違いがあります。','注意',0);
    exit;
  end;
  Result := True;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  if not Datainput then exit;
  Button1.Enabled := False;
  image1.Canvas.Brush.Style := bsSolid;
  image1.Canvas.Brush.Color := clWhite;
  image1.Canvas.FillRect(rect(0, 0, image1.Width,image1.Height));
  chart1.BackImage.Bitmap := Image1.Picture.Bitmap;
  Memo1.Clear;
  Series1.Clear;                  // y=a/x
  Series2.Clear;                  // y=bx + c
  Series3.Clear;                  // y=a/x
  Series4.Clear;                  // スケール
  Calc;                           // 計算
  if crossF = 0 then begin        // 交点なし
    x1 := a / 5;
    x2 := a * 5;
    y1 := x2;
    y2 := x1;
    if a > 0 then addChartpAmpX
             else addChartmAmpX;
  end;
  if crossF = 2 then
    if x1 > 0 then addChartpApX         // 第一象限交点二箇所
              else addChartpAmX;        // 第三象限交点二箇所
  if crossF = 4 then
    if x1 > 0 then addChartmApX         // 第二象限交点二箇所
              else addChartmAmX;        // 第四象限交点二箇所
  if crossF = 3 then addChartpAmpX;     // 第一第三象限交差
  if crossF = 5 then addChartmAmpX;     // 第二第四象限交差
  if crossF = 1 then begin              // 接線
    if (a > 0) and (b < 0) and (c > 0) then addChartpAmBpC; // 第一象限接線
    if (a > 0) and (b < 0) and (c < 0) then addChartpAmBmC; // 第三象限接線
    if (a < 0) and (b > 0) and (c > 0) then addChartmApBpC; // 第二象限接線
    if (a < 0) and (b > 0) and (c < 0) then addChartmApBmC; // 第四象限接線
  end;
  application.ProcessMessages;
  if ((crossF = 2) or (crossF = 4)) and (b <> 0) then begin
    image1.Canvas.Font.Size := 11;
    calcarea;                       // x2 - x1 面積
    GraphDraw;                      // 面積計算と作図
  end;
  Transform;                        // 双曲線変換計算
  Button1.Enabled := True;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  tb : Tbitmap;
begin
  Image1.Width := Chart1.Width;
  Image1.Height := Chart1.Height;
  tb := Tbitmap.Create;
  tb.Width := Chart1.Width;
  tb.Height := Chart1.Height;
  Image1.Picture.Bitmap := tb;
  Image1.Visible := False;
  Memo1.Clear;
  Memo1.Font.Size := 11;
  Series1.Clear;                  // y=a/x
  Series2.Clear;                  // y=bx + c
  Series3.Clear;                  // y=a/x
  Series4.Clear;                  // y=a/x
  Series4.AddXY(0, 5);
  Series4.AddXY(0, 0);
  Series4.AddXY(5, 0);
  Panel1.Caption := '';
  LabeledEdit1.Font.Size := 11;
  LabeledEdit1.Alignment := taCenter;
  LabeledEdit1.EditLabel.Font.Size := 11;
  LabeledEdit1.EditLabel.Caption := 'a';
  LabeledEdit1.Text := '1';
  LabeledEdit2.Font.Size := 11;
  LabeledEdit2.Alignment := taCenter;
  LabeledEdit2.EditLabel.Font.Size := 11;
  LabeledEdit2.EditLabel.Caption := 'b';
  LabeledEdit2.Text := '-1';
  LabeledEdit3.Font.Size := 11;
  LabeledEdit3.Alignment := taCenter;
  LabeledEdit3.EditLabel.Font.Size := 11;
  LabeledEdit3.EditLabel.Caption := 'c';
  LabeledEdit3.Text := '5';

  Label1.Font.Style := [fsBold];
  Label1.Font.Size := 11;
  Label1.Caption := '双曲線' + #13#10 + 'y = a/x';
  Label2.Font.Style := [fsBold];
  Label2.Font.Size := 11;
  Label2.Caption := '直線' + #13#10 + 'y = bx + c';
  Button1.Caption := '計 算';
  tb.Free;
end;

end.
download rectangular_hyperbola.zip

 

各種プログラム計算例に戻る