# 목표값 찾기

## Content

목표값 찾기는 가상 분석의 단일 변수 역분석 도구입니다.
종속 수식 셀이 지정된 숫자 결과를 생성하는 데 필요한 하나의 입력 셀 값을 결정합니다. 입력값 변화에 따라 결과가 어떻게 달라지는지 평가하는 대신, 목표값 찾기는 목표 결과에서 시작하여 해당 결과를 만족하는 입력값을 반복 계산하여 찾습니다.
목표값 찾기는 원하는 결과는 알고 있지만 필요한 입력값은 모를 때 유용합니다.

## 개념적 모델

목표값 찾기는 세 가지 요소를 기반으로 동작합니다.

* 변경 셀(Changing cell) – 조정할 입력값입니다.
* 수식 셀(Formula cell) – 변경 셀에 종속된 수식을 포함하는 셀입니다.
* 목표 결과(Desired result) – 수식 셀이 계산해야 하는 숫자 값입니다.

해를 찾으면 변경 셀은 계산된 값으로 업데이트됩니다.
해를 찾지 못하면 원래 값이 복원됩니다.
목표값 찾기는 하나의 변수에 대해서만 해를 구합니다.

## 기본 프로그래밍 사용법

목표값 찾기는 [`GC.Spread.Sheets.CalcEngine.goalSeek`](/spreadjs/api/modules/GC.Spread.Sheets.CalcEngine#goalseek) 메서드를 사용하여 프로그래밍 방식으로 호출할 수 있습니다.

```javascript
// 대출 금액: 10000
// 기간: 18개월
sheet.setValue(0, 1, 10000);
sheet.setValue(1, 1, 18);
sheet.setFormatter(2, 1, "0%");
sheet.setFormula(3, 1, "-PMT(B3/12, B2, B1)");

// B4가 600이 되도록 B3 계산
GC.Spread.Sheets.CalcEngine.goalSeek(
  sheet, 2, 1,   // 변경 셀 (B3)
  sheet, 3, 1,   // 수식 셀 (B4)
  600            // 목표 결과
);
```

기본값:

* 최대 반복 횟수: 200
* 허용 오차: 0.001

해를 찾으면 `true`, 그렇지 않으면 `false`를 반환합니다(비동기 시나리오에 대해서는 아래 실행 모델 참조).

## 고급 반복 제어

목표값 찾기는 선택적 `options` 매개변수를 통해 고급 반복 제어를 지원합니다. 이를 통해 수렴 동작, 정밀도 및 실행 중 관찰을 세밀하게 제어할 수 있습니다.

### 수렴 제어

다음 옵션을 사용하여 수치 계산 동작을 조정할 수 있습니다.

* `maximumIterations` — 반복 횟수 제한
* `tolerance` — 수식 결과와 목표 결과 간 허용 가능한 차이

예제:

```javascript
GC.Spread.Sheets.CalcEngine.goalSeek(
  sheet, 2, 1,
  sheet, 3, 1,
  600,
  {
    maximumIterations: 500,
    tolerance: 1e-8
  }
);
```

고정밀 금융 또는 엔지니어링 시나리오에서는 더 엄격한 허용 오차를 사용하세요.

### 각 반복 단계 관찰

`callback` 옵션을 사용하면 내부 반복 과정을 관찰할 수 있습니다.
콜백은 다음 정보를 포함한 단계 정보를 전달받습니다.

* 현재 반복 인덱스
* 현재 변경 셀 값
* 현재 수식 결과
* 현재까지 유효한 해를 찾았는지 여부

예제:

```javascript
GC.Spread.Sheets.CalcEngine.goalSeek(
  sheet, 2, 1,
  sheet, 3, 1,
  600,
  {
    callback: (info) => {
      console.log(
        `iter=${info.currentIteration}, ` +
        `x=${info.currentValue}, ` +
        `f(x)=${info.currentFormulaResult}, ` +
        `succeeded=${info.succeeded}`
      );
    }
  }
);
```

이를 통해 다음이 가능합니다.

* 로깅 및 진단
* 교육용 시연
* 수렴 과정의 실시간 시각화

### 조기 종료 및 비동기 제어

콜백이 `true`를 반환하면 목표값 찾기는 즉시 중지되고 현재 값을 유지합니다.
콜백은 비동기 함수일 수도 있습니다. Promise를 반환하면 목표값 찾기는 다음 반복으로 진행하기 전에 Promise가 완료될 때까지 대기합니다.

예제:

```javascript
GC.Spread.Sheets.CalcEngine.goalSeek(
  sheet, 2, 1,
  sheet, 3, 1,
  600,
  {
    callback: async (info) => {
      await new Promise(r => setTimeout(r, 100));
      if (Math.abs(info.currentFormulaResult / 600 - 1) < 1e-10) {
        return true; // 조기 종료
      }
    }
  }
);
```

이를 통해 다음이 가능합니다.

* 수렴 과정 애니메이션
* 대화형 중지 로직
* 동적 허용 오차 전략

## 실행 모델

### 반환 값

* `boolean` — 동기 실행 시 반환
* `Promise` — 다음 경우 반환
    * 점진적 계산이 활성화된 경우 또는
    * 비동기 콜백이 제공된 경우

Promise는 해를 찾으면 `true`, 그렇지 않으면 `false`로 확인됩니다.

### 화면 갱신(Paint) 동작

* 동기 실행의 경우 성능 향상을 위해 SpreadJS가 내부적으로 `suspendPaint` / `resumePaint`를 사용합니다.
* Promise 기반 실행의 경우 화면 갱신이 자동으로 중지되지 않습니다. 필요한 경우 직접 `suspendPaint`를 호출할 수 있습니다.

### 계산 모드 처리

통합 문서의 계산 모드가 `auto`가 아니면 목표값 찾기는 실행 중 일시적으로 `auto`로 전환하고 완료 후 원래 모드로 복원합니다.

## 동작 제약 사항

* 목표 결과는 유한한 숫자 값이어야 합니다.
* 목표값 찾기에 사용되는 수식은 동기적으로 계산되어야 합니다.
* 비동기 수식은 지원되지 않습니다.
* 목표값 찾기는 동적 배열의 확장 셀(Spilled Cell)을 지원합니다.
* Promise 기반 시나리오에서는 `SJS.TABLE`을 지원합니다.
* 런타임 API 호출은 실행 취소를 지원하지 않습니다.
    Designer UI에서는 목표값 찾기 작업에 대한 실행 취소를 지원합니다.
* 협업 시나리오:
    * 런타임 API는 반복 과정 중 임시 업데이트를 전송합니다.
    * Designer는 확인 후 최종 결과만 전송합니다.

해를 찾지 못하면 변경 셀의 원래 값이 복원됩니다.

## 알고리즘 참고 사항

SpreadJS는 자체 수치 계산 전략을 사용합니다.

* 먼저 할선법(Secant Method)을 시도합니다.
* 필요한 경우 이분법(Bisection Method)으로 전환합니다.

구현 방식의 차이로 인해 결과가 Microsoft Excel과 다를 수 있습니다.
Excel이 검색 전략의 한계로 인해 해를 찾지 못하는 경우에도 SpreadJS는 성공적으로 수렴할 수 있습니다.