算額(その50)
山形県米沢市小野川町 小野川薬師堂 明治10年(1877)4月
http://www.wasan.jp/yamagata/onogawa.html
四辺形の中に円が 4 個入っている。甲円,乙円の径を 25, 18 としたとき,丁円の径を求めよ。
一度にまとめて方程式を解こうとすると解けない(単に計算時間がかかっているだけか?)ので,分割して解く。
まず,甲円,乙円,丙円を同定しよう。記号を以下のように定める。
using SymPy
@syms r3::positive; # 丙円の半径
@syms x1::positive, y2::positive; # 甲円の中心 X 座標,乙円の中心 Y 座標
eq1 = (x1 - 18)^2 + (25 - y2)^2 - 43^2
eq2 = (x1 - r3)^2 + (25 - r3)^2 - (25 + r3)^2
eq3 = (18 - r3)^2 + (y2 - r3)^2 - (18 + r3)^2
res = solve([eq1, eq2, eq3], (r3, x1, y2))
2-element Vector{Tuple{Sym, Sym, Sym}}:
(-43*sqrt(1609 - 1020*sqrt(2))/14 - 15*sqrt(3218 - 2040*sqrt(2))/7 + 30*sqrt(2) + 103/2, sqrt(1609 - 1020*sqrt(2))/2 + 15*sqrt(2) + 53/2, -sqrt(1609/4 - 255*sqrt(2)) + 15*sqrt(2) + 67/2)
(15*sqrt(3218 - 2040*sqrt(2))/7 + 43*sqrt(1609 - 1020*sqrt(2))/14 + 30*sqrt(2) + 103/2, -sqrt(1609 - 1020*sqrt(2))/2 + 15*sqrt(2) + 53/2, sqrt(1609/4 - 255*sqrt(2)) + 15*sqrt(2) + 67/2)
一番目の解が適切である。
println("r3 = $(res[1][1].evalf())")
println("x1 = $(res[1][2].evalf())")
println("y2 = $(res[1][3].evalf())")
r3 = 15.1902798290461
x1 = 54.1649893584910
y2 = 48.2614175127018
次に,甲円と乙円の四角形の斜辺との接点座標を (X1, Y1), (X2, Y2) と置き,これを求める。
@syms X1::positive, Y1::positive, X2::positive, Y2::positive
eq11 = (X2 - 18)^2 + (Y2 - y2)^2 - 18^2
eq12 = (X1 - x1)^2 + (Y1 - 25)^2 - 25^2
eq13 = (Y1 - 25)/(X1 - x1) - (Y2 - y2)/(X2 - 18)
eq14 = (Y1 - 25)/(X1 - x1) * (Y2 - Y1)/(X2 - X1) + 1;
res = solve([eq11, eq12, eq13, eq14], (X1, Y1, X2, Y2));
4 組の解が得られるが,4 番目のものだけが適切である。
names = ["X1", "Y1", "X2", "Y2"]
for i = 1:4
println("$(names[i]) = $(res[4][i])")
end
X1 = (x1^3 - 36*x1^2 + x1*y2^2 - 50*x1*y2 + 774*x1 + 25*y2*sqrt(x1^2 - 36*x1 + y2^2 - 50*y2 + 900) - 625*sqrt(x1^2 - 36*x1 + y2^2 - 50*y2 + 900) + 3150)/(x1^2 - 36*x1 + y2^2 - 50*y2 + 949)
Y1 = 25*(x1^2 + x1*sqrt(x1^2 - 36*x1 + y2^2 - 50*y2 + 900) - 36*x1 + y2^2 - 43*y2 - 18*sqrt(x1^2 - 36*x1 + y2^2 - 50*y2 + 900) + 774)/(x1^2 - 36*x1 + y2^2 - 50*y2 + 949)
X2 = 18*(x1^2 - 43*x1 + y2^2 + y2*sqrt(x1^2 - 36*x1 + y2^2 - 50*y2 + 900) - 50*y2 - 25*sqrt(x1^2 - 36*x1 + y2^2 - 50*y2 + 900) + 1075)/(x1^2 - 36*x1 + y2^2 - 50*y2 + 949)
Y2 = (x1^2*y2 - 36*x1*y2 + 18*x1*sqrt(x1^2 - 36*x1 + y2^2 - 50*y2 + 900) + y2^3 - 50*y2^2 + 1075*y2 - 324*sqrt(x1^2 - 36*x1 + y2^2 - 50*y2 + 900) - 3150)/(x1^2 - 36*x1 + y2^2 - 50*y2 + 949)
最後に丁円の中心から四辺形の斜辺までの距離を求める。
SymPy の Point, Line を使い,直線までの距離を求めるが,
ここでも,SymPy の結果そのものを使うと solve() で結果を求められないので,いままでの結果を数値化して用いる。
function distance(x1, y1, x2, y2, x0, y0)
p1, p2 = sympy.Point(x1, y1), sympy.Point(x2, y2)
l = sympy.Line(p1, p2)
l.distance(sympy.Point(x0, y0))
end;
r3 = 15.1902798290461
x1 = 54.1649893584910
y2 = 48.2614175127018
X1 = (x1^3 - 36*x1^2 + x1*y2^2 - 50*x1*y2 + 774*x1 + 25*y2*sqrt(x1^2 - 36*x1 + y2^2 - 50*y2 + 900) - 625*sqrt(x1^2 - 36*x1 + y2^2 - 50*y2 + 900) + 3150)/(x1^2 - 36*x1 + y2^2 - 50*y2 + 949)
Y1 = 25*(x1^2 + x1*sqrt(x1^2 - 36*x1 + y2^2 - 50*y2 + 900) - 36*x1 + y2^2 - 43*y2 - 18*sqrt(x1^2 - 36*x1 + y2^2 - 50*y2 + 900) + 774)/(x1^2 - 36*x1 + y2^2 - 50*y2 + 949)
X2 = 18*(x1^2 - 43*x1 + y2^2 + y2*sqrt(x1^2 - 36*x1 + y2^2 - 50*y2 + 900) - 50*y2 - 25*sqrt(x1^2 - 36*x1 + y2^2 - 50*y2 + 900) + 1075)/(x1^2 - 36*x1 + y2^2 - 50*y2 + 949)
Y2 = (x1^2*y2 - 36*x1*y2 + 18*x1*sqrt(x1^2 - 36*x1 + y2^2 - 50*y2 + 900) + y2^3 - 50*y2^2 + 1075*y2 - 324*sqrt(x1^2 - 36*x1 + y2^2 - 50*y2 + 900) - 3150)/(x1^2 - 36*x1 + y2^2 - 50*y2 + 949)
println("X1 = $X1; Y1 = $Y1; X2 = $X2; Y2 = $Y2")
X1 = 64.08580382962593; Y1 = 47.94727522450802; X2 = 25.142986419217163; Y2 = 64.78345567434756
@syms r4::positive
eq00 = distance(X1, Y1, X2, Y2, r4, r4) - r4;
solve(eq00) としても 'NotImplementedError' になり解を求めることができない。その原因は方程式中に長精度整数があるからのようだ。
eq00 |> println
-r4 + sqrt((11095289145632785833731051*r4/21266540642722116155792165 - 11720727187202811618008367911717774033/425330812854442323115843300000000000)^2 + (25663886212278315131969678*r4/21266540642722116155792165 - 13555275798104253130313974902537196837/212665406427221161557921650000000000)^2)
長精度整数らしいがどうも精度に問題があるらしい。そこで,この整数どもを big"整数" として完璧な長精度整数にする。
eq01 = -r4 + sqrt((big"93910527328635730934895117268"*r4/big"179999999999999212286276676385" - big"3100132341015136856051026453265830392636969" /big"112499999999999507678922922740625000000000")^2 + (big"217219132900722712058838648021" *r4/big"179999999999999212286276676385" - big"28682963588788462898433683777226651524373897" /big"449999999999998030715691690962500000000000")^2);
eq01 |> println
-r4 + 69.44170763477157031724744552587294112975879397332431357713551885112604322531*Abs(0.01893276580611329111115986244784178445485447675151318541196915535528237519342*r4 - 1)
これで,r4 = 30 が求められる。2通りの解が得られるが 220.643479932700 は不適切解である。
solve(eq01) |> println
Sym[30.0000000000000, 220.643479932700]
なお,算額では「甲円と乙円の径を掛け,2倍して,平方根を取る」としている。
確かに sqrt(25 * 18 * 2) = 30 となる。なぜだ...
using Plots
function circle(ox, oy, r, color=:red; beginangle=0, endangle=360)
θ = beginangle:0.1:endangle
x = r.*cosd.(θ)
y = r.*sind.(θ)
plot!(ox .+ x, oy .+ y, color=color, linewidth=0.5)
end;
function point(x, y, string="", color=:green, position=:left, vertical=:top; mark=true)
mark && scatter!([x], [y], color=color, markerstrokewidth=0)
annotate!(x, y, text(string, 10, position, color, vertical))
end;
function draw(more=false)
#pyplot(size=(500, 500), grid=false, aspectratio=1, label="", fontfamily="IPAMincho")
gr(size=(500, 500), grid=false, aspectratio=1, label="", fontfamily="IPAMincho")
y(x) = (Y2-Y1)/(X2-X1)*(x-X2)+Y2
p = plot()
(r3, x1, y2) = (-43*sqrt(1609 - 1020*sqrt(2))/14 - 15*sqrt(3218 - 2040*sqrt(2))/7 + 30*sqrt(2) + 103/2, sqrt(1609 - 1020*sqrt(2))/2 + 15*sqrt(2) + 53/2, -sqrt(1609/4 - 255*sqrt(2)) + 15*sqrt(2) + 67/2)
X1 = (x1^3 - 36*x1^2 + x1*y2^2 - 50*x1*y2 + 774*x1 + 25*y2*sqrt(x1^2 - 36*x1 + y2^2 - 50*y2 + 900) - 625*sqrt(x1^2 - 36*x1 + y2^2 - 50*y2 + 900) + 3150)/(x1^2 - 36*x1 + y2^2 - 50*y2 + 949)
Y1 = 25*(x1^2 + x1*sqrt(x1^2 - 36*x1 + y2^2 - 50*y2 + 900) - 36*x1 + y2^2 - 43*y2 - 18*sqrt(x1^2 - 36*x1 + y2^2 - 50*y2 + 900) + 774)/(x1^2 - 36*x1 + y2^2 - 50*y2 + 949)
X2 = 18*(x1^2 - 43*x1 + y2^2 + y2*sqrt(x1^2 - 36*x1 + y2^2 - 50*y2 + 900) - 50*y2 - 25*sqrt(x1^2 - 36*x1 + y2^2 - 50*y2 + 900) + 1075)/(x1^2 - 36*x1 + y2^2 - 50*y2 + 949)
Y2 = (x1^2*y2 - 36*x1*y2 + 18*x1*sqrt(x1^2 - 36*x1 + y2^2 - 50*y2 + 900) + y2^3 - 50*y2^2 + 1075*y2 - 324*sqrt(x1^2 - 36*x1 + y2^2 - 50*y2 + 900) - 3150)/(x1^2 - 36*x1 + y2^2 - 50*y2 + 949)
println("r3 = $r3; x1 = $x1; y2 = $y2")
println("X1 = $X1; Y1 = $Y1; X2 = $X2; Y2 = $Y2")
circle(x1, 25, 25)
circle(18, y2, 18, :blue)
circle(r3, r3, r3, :green)
r4 = 30
circle(r4, r4, r4, :magenta)
if more
point(r4, r4, "(r4,r4)", :red, :center)
point(x1, 25, "(x1,25)", :red, :center)
point(18, y2, "(18,y2)", :red, :center)
point(r3, r3, "(r3,r3)", :red, :center)
point(X1, Y1, " (X1,Y1)", :blue)
point(X2, Y2, " (X2,Y2)", :blue)
end
plot!([0, x1+25, x1+25, 0, 0], [0, 0, y(x1+25), y(0), 0], color=:black, lw=0.5)
display(p)
end;
r3 = 15.190279829046077; x1 = 54.16498935849101; y2 = 48.26141751270184
X1 = 64.08580382962599; Y1 = 47.947275224508004; X2 = 25.142986419217173; Y2 = 64.78345567434759