直角双曲線 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.rectangular_hyperbola.zip
各種プログラム計算例に戻る