Python으로 검증하기
- 식 하나를 SymPy 유도에서부터 페이지와 테스트까지 따라갑니다.
- 두 계산을 상대 차이(relative difference)로 비교하고, 반올림으로는 실패하지 않고 실제 실수는 통과하지 못하는 허용오차(tolerance)를 고릅니다.
- 이 사이트의 검사를 자신의 컴퓨터에서 실행합니다.
원본은 하나, 구현은 둘
섹션 제목: “원본은 하나, 구현은 둘”이 사이트의 모든 식은 packages/pe-core/equations/equations.yaml에 한 번씩, 기호와
테스트와 인용을 갖춘 SymPy 식으로 들어 있습니다. Python 패키지 python/pe_core는
이 파일을 바탕으로 동작합니다.
- 가능한 경우
python/pe_core/derive/의 스크립트가 회로의 평형 방정식(balance equation)을 SymPy로 한 단계씩 풀어 식을 기본 원리에서 유도합니다. 유도 과정 페이지는 코드가 계산한 그대로 그 단계를 보여 주며, pytest는 각 결과가 카탈로그의 식과 같은지 확인합니다. python scripts/gen_equations.py는 페이지에 보이는 LaTeX와 테스트 벡터(test vector), 곧 각 식의 자체 테스트와 SymPy로 계산한 무작위 입력을 만듭니다. CI는 이를 다시 실행해 조금이라도 다르면 실패합니다.
페이지와 도구가 쓰는 TypeScript 엔진은 같은 파일에서 생성하지 않고 손으로 따로 쓴 계산 함수를 가지고 있습니다. 한쪽의 실수가 다른 쪽으로 복사되지 않게 하기 위해서입니다. vitest는 모든 계산 함수를 테스트 벡터와 비교합니다.
두 수 비교하기
섹션 제목: “두 수 비교하기”두 계산은 상대 차이로 비교합니다.
- 상대 차이
- 기준값
- 검사할 값
가정, 표기 규약, 출처
- 가정
- 정의
- 비고
- 볼트를 밀리볼트로 바꾸듯 물리량의 배율을 바꿔도 상대 차이는 달라지지 않으므로, 하나의 허용오차를 모든 물리량에 쓸 수 있습니다(켈빈에 대한 섭씨처럼 영점이 옮겨 가는 단위는 예외). 기준값이 0이면 정의되지 않고, 0에 가까우면 작은 절대 차이가 큰 상대 차이가 됩니다. 이 사이트는 같은 식의 TypeScript와 Python 계산에 1e-9를, 식에 대한 시뮬레이션에 1 % 또는 2 %를 요구합니다
- 출처
- Higham 2002, Sec. 1.2 (Relative Error and Significant Digits)
- 수식 id
num.rel_diff· equations.yaml 항목
상대 차이는 볼트를 밀리볼트로 바꾸듯 물리량의 배율을 바꿔도 달라지지 않으므로, 하나의 허용오차를 모든 양에 쓸 수 있습니다. 기준값이 0이면 정의되지 않고 [Higham 2002, Sec. 1.2], 0에 가까우면 작은 차이를 부풀리므로 그곳에서는 척도와 비교합니다. 올바른 두 프로그램이라도 비트까지 같은 결과를 내지는 않을 수 있습니다. 연산마다 결과를 반올림하고, 그 결과는 연산 순서에 따라 달라지기 때문입니다. 반올림 한 번이 수를 바꾸는 양은 그 수의 크기에 대한 비율로 많아야 수치 형식의 단위 반올림 오차(unit roundoff)입니다.
- 단위 반올림 오차(unit roundoff)
- 밑(이진수는 2)
- 정밀도(가수의 자릿수)
가정, 표기 규약, 출처
- 가정
- 형식에서 가장 가까운 수로 반올림(IEEE 754의 기본값)
- 비고
- 실수를 형식에서 가장 가까운 수로 반올림하면 값은 (정규 범위에서) 최대 원래 값의 이 비율만큼 바뀝니다. JavaScript의 수와 Python의 float가 쓰는 IEEE 754 배정밀도(binary64)는 밑이 2, 정밀도가 53자리이므로 입니다. Higham은 정밀도를 로 씁니다
- 출처
- Higham 2002, Ch. 2 (Floating Point Arithmetic: the unit roundoff, Sec. 2.1, and its value in IEEE double precision)
- 수식 id
num.unit_roundoff· equations.yaml 항목
이 사이트는 한 식에 대한 TypeScript와 Python 계산이 10억분의 1 안에서 맞기를 요구합니다. 이는 단위 반올림 오차의 수백만 배이므로, 계산이 오차를 키우지 않는 한 반올림은 통과합니다. 거의 같은 두 수를 빼는 상쇄(cancellation)가 오차를 키우는 대표적인 경우입니다 [Higham 2002, Sec. 1.7]. 그래도 이 허용오차는 잘못된 상수나 빠진 인수 같은 실제 실수보다 훨씬 작습니다. 시뮬레이션을 그 식과 비교할 때는 허용오차가 더 느슨합니다. 식이 회로를 이상화하기 때문입니다. 식은 리플을 작다고 보며 [Erickson & Maksimović 2020, Ch. 2], SPICE 라이브러리의 스위치와 다이오드는 이상에 가까울 뿐입니다. SPICE 라이브러리의 값은 각 양의 주기 동안 최대 크기 대비 1 % 안에서 이상적인 식과 맞아야 하고, 브라우저 시뮬레이터의 변환비와 리플은 2 % 안에서 맞아야 합니다.
다른 솔버와의 교차 검사
섹션 제목: “다른 솔버와의 교차 검사”scripts/spice_crosscheck.py는 브라우저 시뮬레이터의 회로를 시뮬레이터의 식이 아니라
회로도로부터 넷리스트로 다시 작성해 ngspice로 실행합니다 [ngspice – open source SPICE simulator]. CI는
시뮬레이터를 ngspice의 결과와 비교합니다. 각 값은 주기 동안 그 양의 최대 크기 대비
0.5 % 안에서, SPICE 부품이 더하는 몫만큼의 작은 여유를 두고 맞아야 하며, 각 피크-피크
값은 2 % 안에서 맞아야 합니다.
풀이 예제
섹션 제목: “풀이 예제”시뮬레이션한 변환비를 이상적인 변환비와 비교하고, JavaScript의 수와 Python의 float가 쓰는 IEEE 754 배정밀도(binary64)의 단위 반올림 오차를 구합니다.
| 기호 | 값 | 구하는 방법 |
|---|---|---|
| 검사할 값 | 0.496 | 주어진 값 |
| 기준값 | 0.5 | 주어진 값 |
| 밑(이진수는 2) | 2 | 주어진 값 |
| 정밀도(가수의 자릿수) | 53 | 주어진 값 |
| 상대 차이 | 0.008 | 기준값에 대한 값의 상대 차이 |
| 단위 반올림 오차(unit roundoff) | 1.11e-16 | 부동소수점 형식의 단위 반올림 오차 |
변환비는 이상적인 값과 0.008만큼 달라, 라이브러리의 1 % 안에 듭니다. 단위 반올림 오차는 1.11e-16이므로, 10억분의 1이라는 허용오차에는 수백만 번의 반올림이 들어갈 여유가 있습니다.
직접 해 보기
섹션 제목: “직접 해 보기”▶ 수식 탐색기에서 열기: 기준값에 대한 값의 상대 차이
초기값을 가져온 예제 num-parity
검사할 값을 바꿔 봅니다. 상대 차이는 기준값 양쪽에서 직선으로 커지고, 기준값에서만 0이 됩니다.
벤치 실습
섹션 제목: “벤치 실습”벤치에서 멀티미터로 컨버터의 입력 전압과 출력 전압을 재고, 그 비가 이상적인 변환비와 얼마나 다른지 Python으로 상대 차이를 계산한 뒤, 그 차이를 설명할 수 있는 것들을 적습니다. 다이오드의 전압 강하, 스위치와 권선의 저항, 리플 등입니다. 그런 다음 부하를 바꿔 그중 어느 것이 전류와 함께 커지는지 봅니다.
주의할 점
섹션 제목: “주의할 점”- 기준값이 0에 가까우면 상대 차이는 의미가 없습니다. 라이브러리의 검사처럼 한 주기 동안의 최대 크기 같은 척도와 비교합니다.
- 코드를 공유하는 두 구현은 그 실수도 공유합니다. 생성한 계산 함수는 원본 파일이 틀린 곳에서도 그 파일과 맞아 버립니다.
- 부동소수점(floating-point) 수는 같은지를 비교하지 않습니다. binary64에서 0.1 + 0.1 + 0.1은 0.3이 아닙니다. 허용오차 안에 드는지로 비교합니다 (단위 반올림 오차).
더 알아보기
섹션 제목: “더 알아보기”- 도구 SymPy: Solve Equations
SymPy로 방정식이나 연립방정식을 기호에 대해 푸는 방법. 이 사이트의 유도 스크립트도 이 방법으로 평형 방정식을 풉니다. - 기술 기사 Floating-Point Arithmetic: Issues and Limitations
컴퓨터에서 0.1 + 0.1 + 0.1이 0.3이 아닌 이유, 연산마다 최대 2**53분의 1의 반올림 오차가 더해질 수 있는 이유, 그리고 결과를 같은지가 아니라 허용오차 안에 드는지로 비교하는 이유.
이 사이트에 보이는 식은 어디에서 옵니까?
정답과 해설
정답: B 생성기가 그 항목에서 LaTeX와 테스트 벡터를 만들고, 커밋된 파일이 생성 결과와 다르면 CI가 실패합니다.
TypeScript 계산 함수를 equations.yaml에서 생성하지 않고 손으로 쓰는 이유는 무엇입니까?
정답과 해설
정답: A 생성한 코드는 원본이 틀린 곳에서도 원본과 맞아 버립니다. 독립된 구현은 스스로 테스트 벡터와 맞아야 합니다.
시뮬레이션한 변환비 0.495를 이상적인 0.5와 비교합니다. 상대 차이는 얼마입니까?
정답과 해설
정답: D 차이 0.005를 기준값 0.5로 나누면 0.01, 곧 1 %입니다.
binary64의 단위 반올림 오차는 약 1.1e-16입니다. 일치 검사의 허용오차가 단위 반올림 오차가 아니라 10억분의 1인 이유는 무엇입니까?
정답과 해설
정답: B 10억분의 1은 단위 반올림 오차의 수백만 배이므로 반올림 오차를 키우지 않는 계산에서 반올림은 통과하지만, 잘못된 상수나 인수는 훨씬 큽니다.
기준값이 0에 가까우면 상대 차이를 쓸 수 없는 이유는 무엇입니까?
정답과 해설
정답: A 그곳에서는 라이브러리의 검사처럼 한 주기 동안의 최대 크기 같은 척도와 비교합니다.
Python에서 0.1 + 0.1 + 0.1 == 0.3의 값은 무엇입니까?
정답과 해설
정답: C 0.1은 이진수로 정확하지 않으며, 셋을 더해 반올림한 0.30000000000000004는 0.3 바로 옆의 배정밀도 수입니다. 허용오차 안에 드는지로 비교합니다.
이 사이트의 예제, 프리셋, 연습 문제에 나오는 수치는 교육용으로 만든 어림수(합성 값)이며, 실제 설계의 데이터가 아닙니다.