Main Content

이 번역 페이지는 최신 내용을 담고 있지 않습니다. 최신 내용을 영문으로 보려면 여기를 클릭하십시오.

수치적으로 방정식 풀기

Symbolic Math Toolbox™는 수치 방정식 솔버 및 기호 방정식 솔버를 다 제공합니다. 수치 솔버와 기호 솔버의 비교는 Select Numeric or Symbolic Solver 항목을 참조하십시오. 방정식 또는 연립방정식에는 해가 여러 개 있을 수 있습니다. 이들 해를 수치적으로 구하려면 함수 vpasolve를 사용하십시오. 다항 방정식의 경우 vpasolve는 모든 해를 반환합니다. 비다항 방정식의 경우 vpasolve는 구한 해 중 첫 번째 해를 반환합니다. 다음 예제에서는 vpasolve를 사용하여 다항 방정식과 비다항 방정식의 해를 찾고 이들 해를 임의의 정밀도까지 구하는 방법을 보여줍니다.

다항식 함수의 모든 근 구하기

vpasolve를 사용하여 함수 f(x)=6x7-2x6+3x3-8의 모든 해를 구합니다.

syms f(x)
f(x) = 6*x^7-2*x^6+3*x^3-8;
sol = vpasolve(f)
sol = 

(1.0240240759053702941448316563337-0.88080620051762149639205672298326+0.50434058840127584376331806592405i-0.88080620051762149639205672298326-0.50434058840127584376331806592405i-0.22974795226118163963098570610724+0.96774615576744031073999010695171i-0.22974795226118163963098570610724-0.96774615576744031073999010695171i0.7652087814927846556172932675903+0.83187331431049713218367239317121i0.7652087814927846556172932675903-0.83187331431049713218367239317121i)[vpa('1.0240240759053702941448316563337'); - vpa('0.88080620051762149639205672298326') + vpa('0.50434058840127584376331806592405i'); - vpa('0.88080620051762149639205672298326') - vpa('0.50434058840127584376331806592405i'); - vpa('0.22974795226118163963098570610724') + vpa('0.96774615576744031073999010695171i'); - vpa('0.22974795226118163963098570610724') - vpa('0.96774615576744031073999010695171i'); vpa('0.7652087814927846556172932675903') + vpa('0.83187331431049713218367239317121i'); vpa('0.7652087814927846556172932675903') - vpa('0.83187331431049713218367239317121i')]

이 함수는 7차 다항식이므로 vpasolve는 예상대로 이 함수의 근 7개를 반환합니다.

검색 범위와 시작점을 사용하여 비다항식 함수의 영점 찾기

함수 f(x)=e(x/7)cos(2x)의 플롯을 보면 x가 증가함에 따라 영점에서의 기울기가 증가하는 주기적인 영점들이 있습니다.

syms x
h = fplot(exp(x/7)*cos(2*x),[-2 25]);
grid on

vpasolve를 사용하여 함수 f의 영점 하나를 찾습니다. vpasolve는 복수의 해가 존재하는 경우에도 비다항 방정식의 해 하나만 반환합니다. 반복해서 호출하더라도 vpasolve는 동일한 결과를 반환합니다.

f = exp(x/7)*cos(2*x);
for k = 1:3
  vpasolve(f,x)
end
ans = -7.0685834705770347865409476123789-vpa('7.0685834705770347865409476123789')
ans = -7.0685834705770347865409476123789-vpa('7.0685834705770347865409476123789')
ans = -7.0685834705770347865409476123789-vpa('7.0685834705770347865409476123789')

복수의 해를 구하려면 옵션 'Random'true로 설정하십시오. 이렇게 하면 vpasolve가 시작점을 임의로 선택합니다. 임의의 시작점을 선택하는 알고리즘에 대한 자세한 내용은 vpasolve 페이지의 알고리즘 항목을 참조하십시오.

for k = 1:3
  vpasolve(f,x,'Random',true)
end
ans = -226.98006922186256147892598444194-vpa('226.98006922186256147892598444194')
ans = 98.174770424681038701957605727484vpa('98.174770424681038701957605727484')
ans = 52.621676947629036744249276669932vpa('52.621676947629036744249276669932')

x=10에 가까운 영점을 찾으려면 시작점을 10으로 설정하십시오.

vpasolve(f,x,10)
ans = 10.210176124166828025003590995658vpa('10.210176124166828025003590995658')

x=1000에 가까운 영점을 찾으려면 시작점을 1000으로 설정하십시오.

vpasolve(f,x,1000)
ans = 999.8118620049516981407362567287vpa('999.8118620049516981407362567287')

15x25 범위 내에 있는 영점을 찾으려면 검색 범위를 [15 25]로 설정하십시오.

vpasolve(f,x,[15 25])
ans = 21.205750411731104359622842837137vpa('21.205750411731104359622842837137')

[15 25] 범위 내에 있는 복수의 영점을 찾으려는 경우, 이전에 보여진 것처럼 호출할 때마다 동일한 결과가 반환되므로 vpasolve를 반복해서 호출할 수 없습니다. 대신, 검색 범위를 설정하고 'Random'true로 설정하십시오.

for k = 1:3
  vpasolve(f,x,[15 25],'Random',true)
end
ans = 21.205750411731104359622842837137vpa('21.205750411731104359622842837137')
ans = 21.205750411731104359622842837137vpa('21.205750411731104359622842837137')
ans = 16.493361431346414501928877762217vpa('16.493361431346414501928877762217')

'Random'은 시작점을 임의로 선택하므로, 연속된 호출에서 동일한 해가 구해질 수도 있습니다.

지정된 검색 범위에서 모든 영점 찾기

지정된 허용오차 내에서 주어진 탐색 범위 내에 있는 f의 모든 영점을 체계적으로 찾는 함수 findzeros를 생성합니다. 이 함수는 입력값으로 주어진 탐색 범위에서부터 시작하여 vpasolve를 호출하고 영점 하나를 찾습니다. 그런 다음 이 영점의 값을 기준으로 검색 범위를 둘로 분할한 후 새로운 검색 범위를 입력값으로 사용하여 자기 자신을 재귀적으로 호출함으로써 더 많은 영점을 찾습니다.

다음은 이 함수를 각 부분별로 설명한 것입니다.

입력값 3개와 출력값 1개를 갖는 함수를 선언합니다. 첫 번째 입력값은 함수이고, 두 번째 입력값은 범위이며, 선택적으로 세 번째 입력값에는 영점과 영점으로부터 생성된 상한 및 하한 사이의 오차를 지정할 수 있습니다.

function sol = findzeros(f,range,err)

선택적인 허용오차 인수를 지정하지 않으면 findzeroserr0.001로 설정합니다.

if nargin < 2
  err = 1e-3;
end

vpasolve를 사용하여 검색 범위 내에서 영점 하나를 찾습니다.

sol = vpasolve(f,range);

vpasolve가 영점을 찾지 못하면 종료합니다.

if(isempty(sol))
  return

vpasolve는 영점을 찾으면 검색 범위를 이 영점 위에 그리고 아래에 하나씩, 2개의 검색 범위로 분할합니다.

else
  lowLimit = sol-err;
  highLimit = sol+err;

아래의 검색 범위를 사용하여 findzeros를 호출합니다. findzeros가 영점을 반환할 경우, 값을 해 배열에 복사하고 정렬합니다.

  temp = findzeros(f,[range(1) lowLimit],1);
  if ~isempty(temp)
    sol = sort([sol temp]);
  end

위의 검색 범위를 사용하여 findzeros를 호출합니다. findzeros가 영점을 반환할 경우, 값을 해 배열에 복사하고 정렬합니다.

  temp = findzeros(f,[highLimit range(2)],1);
  if ~isempty(temp)
    sol = sort([sol temp]);
  end
  return
end
end

전체 함수 findzeros는 다음과 같습니다. 이 함수를 현재 폴더에 findzeros.m으로 저장합니다.

function sol = findzeros(f,range,err)
if nargin < 3
  err = 1e-3;
end
sol = vpasolve(f,range);
if(isempty(sol))
  return
else
  lowLimit = sol-err;
  highLimit = sol+err;
  temp = findzeros(f,[range(1) lowLimit],1);
  if ~isempty(temp)
    sol = sort([sol temp]);
  end
  temp = findzeros(f,[highLimit range(2)],1);
  if ~isempty(temp)
    sol = sort([sol temp]);
  end
  return
end
end

findzeros를 검색 범위 [15 25]를 사용해 호출하여 디폴트 허용오차 내에서 이 범위 내에 있는 f(x) = exp(x/7)*cos(2*x)의 모든 영점을 찾습니다.

syms f(x)
f(x) = exp(x/7)*cos(2*x);
sol = findzeros(f,[15 25])'
sol = 

(16.49336143134641450192887776221718.06415775814131112116019945385719.63495408493620774039152114549721.20575041173110435962284283713722.77654673852600097885416452877624.347343065320897598085486220416)[vpa('16.493361431346414501928877762217'); vpa('18.064157758141311121160199453857'); vpa('19.634954084936207740391521145497'); vpa('21.205750411731104359622842837137'); vpa('22.776546738526000978854164528776'); vpa('24.347343065320897598085486220416')]

임의의 정밀도로 해 구하기

digits를 사용하여 vpasolve에서 반환되는 해의 정밀도를 설정합니다. 기본적으로 vpasolve는 유효 숫자 32개 정밀도까지의 해를 반환합니다.

f = exp(x/7)*cos(2*x);
vpasolve(f)
ans = -7.0685834705770347865409476123789-vpa('7.0685834705770347865409476123789')

digits를 사용하여 정밀도를 유효 숫자 64개로 늘립니다. digits를 수정할 때는 현재 값을 복원할 수 있도록 먼저 저장해 두어야 합니다.

digitsOld = digits;
digits(64)
vpasolve(f)
ans = -7.068583470577034786540947612378881489443631148593988097193625333-vpa('7.068583470577034786540947612378881489443631148593988097193625333')

다음으로, 해의 정밀도를 유효 숫자 16개로 변경합니다.

digits(16)

검색 범위를 사용하여 다변량 방정식 풀기

다음과 같은 연립방정식이 있다고 가정해 보겠습니다.

z=10(cos(x)+cos(y))z=x+y2-0.1x2yx+y-2.7=0

0x2.50x2.5에 대해 방정식을 플로팅하면 3개의 곡면이 2개의 점에서 교차하는 것을 볼 수 있습니다. 플롯을 더 잘 시각화하려면 view를 사용하십시오. 컬러맵 값을 스케일링하려면 caxis를 사용하십시오.

syms x y z
eqn1 = z == 10*(cos(x) + cos(y));
eqn2 = z == x+y^2-0.1*x^2*y;
eqn3 = x+y-2.7 == 0;
equations = [eqn1 eqn2 eqn3];
fimplicit3(equations)
axis([0 2.5 0 2.5 -20 10])
title('System of Multivariate Equations')
view(69, 28)
caxis([-15 10])

vpasolve를 사용하여 곡면이 교차하는 점을 찾습니다. 함수 vpasolve는 구조체를 반환합니다. 해의 x, y, z 값에 액세스하려면 구조체의 요소를 참조하십시오.

sol = vpasolve(equations);
[sol.x sol.y sol.z]
ans = (2.3697477224547980.33025227754520212.293354376823228)[vpa('2.369747722454798'), vpa('0.3302522775452021'), vpa('2.293354376823228')]

해 공간의 특정 영역을 검색하려면 변수에 대해 검색 범위를 지정하십시오. 범위 0x1.51.5y2.5를 지정하면 vpasolve 함수는 아래 표시된 경계 내 영역을 검색합니다.

vpasolve를 사용하여 이 검색 범위에 대한 해를 구합니다. z의 검색 범위를 생략하려면 세 번째 검색 범위를 [NaN NaN]으로 설정하십시오.

vars = [x y z];
range = [0 1.5; 1.5 2.5; NaN NaN];
sol = vpasolve(equations, vars, range);
[sol.x sol.y sol.z]
ans = (0.91062661725633361.7893733827436663.964101572135625)[vpa('0.9106266172563336'), vpa('1.789373382743666'), vpa('3.964101572135625')]

복수의 해를 구하려면 'Random' 옵션을 true로 설정하십시오. 이렇게 하면 vpasolve가 실행할 때마다 임의의 시작점을 사용합니다. 'Random' 옵션을 탐색 범위와 함께 사용하면 vpasolve가 특정 탐색 범위 내에서 임의의 시작점을 사용하도록 할 수 있습니다. 'Random'은 시작점을 임의로 선택하므로, 연속된 호출에서 동일한 해가 구해질 수도 있습니다. 두 해를 모두 찾으려면 vpasolve를 반복적으로 호출하십시오.

clear sol
range = [0 3; 0 3; NaN NaN];
for k = 1:5
  temp = vpasolve(equations,vars,range,'Random',true);
  sol(k,1) = temp.x;
  sol(k,2) = temp.y;
  sol(k,3) = temp.z;
end
sol
sol = 

(2.3697477224547980.33025227754520212.2933543768232282.3697477224547980.33025227754520212.2933543768232282.3697477224547980.3302522775452022.2933543768232280.91062661725633361.7893733827436663.9641015721356250.91062661725633361.7893733827436663.964101572135625)[vpa('2.369747722454798'), vpa('0.3302522775452021'), vpa('2.293354376823228'); vpa('2.369747722454798'), vpa('0.3302522775452021'), vpa('2.293354376823228'); vpa('2.369747722454798'), vpa('0.330252277545202'), vpa('2.293354376823228'); vpa('0.9106266172563336'), vpa('1.789373382743666'), vpa('3.964101572135625'); vpa('0.9106266172563336'), vpa('1.789373382743666'), vpa('3.964101572135625')]

방정식을 플로팅합니다. scatter3을 사용하여 이 두 해를 노란색 X 마커로 표시되는 산점도 플롯으로 겹쳐 놓습니다. 플롯을 더 잘 시각화하려면 alpha를 사용하여 두 개의 곡면을 투명하게 만드십시오. caxis를 사용하여 플롯 값의 컬러맵을 스케일링하고, view를 사용하여 시선을 바꿉니다.

vpasolve는 아래와 같이 방정식에 의해 형성된 곡면의 교차점에서 해를 구합니다.

clf
ax = axes;
h = fimplicit3(equations);
h(2).FaceAlpha = 0;
h(3).FaceAlpha = 0;
axis([0 2.5 0 2.5 -20 10])
hold on
scatter3(sol(:,1),sol(:,2),sol(:,3),600,'yellow','X','LineWidth',2)
title('Randomly Found Solutions in Specified Search Range')
cz = ax.Children;
caxis([0 20])
view(69,28)
hold off

마지막으로, 추후 계산을 위해 digits의 이전 값을 복원합니다.

digits(digitsOld)