기술 · 실용 가이드
Decimal.quantize의 InvalidOperation? 정밀도 변경 전에 결과 자릿수를 확인하세요
Decimal 정밀도는 소수점 이하가 아닌 계수 전체의 자릿수입니다. 격리 시험으로 올림, 0 채우기, 비유한 입력을 구분합니다.

quantize의 InvalidOperation은 입력 소수 자릿수가 아니라 필요한 결과의 용량 때문일 수 있습니다. 정밀도를 높이거나 트랩을 끄기 전에 피연산자와 실제 컨텍스트부터 보존하세요.
1. 예외 이름뿐 아니라 연산을 기록하세요
전체 추적 정보, 두 Decimal 피연산자와 출처를 보존합니다. 실패 지점의 repr(value), value.as_tuple(), repr(quantum), getcontext().prec, rounding, Emin, Emax, traps와 기존 flags를 기록하세요. 라이브러리가 별도 context를 전달하는지도 확인합니다. 다른 곳에서 확인한 DefaultContext가 실제 설정은 아닐 수 있습니다.
생성과 양자화를 구분하세요. float로 만든 Decimal은 그 부동소수점 값을 보존하며 원래 십진 텍스트를 복구하지 않습니다. 입력 계약이 텍스트라면 원문을 우선합니다. 잘못된 텍스트, 지원 범위 초과, 이후 quantize 실패를 하나의 정밀도 설정으로 처리하지 마세요.
2. 올림과 0 채우기 후의 자릿수를 계산하세요
정밀도는 소수점 이하가 아닌 계수 전체 자릿수입니다. CPython 3.12.14와 ROUND_HALF_EVEN 시험에서 Decimal('9.995').quantize(Decimal('0.01'))는 정밀도 3에서 실패하고 4에서 10.00을 반환했습니다. 결과는 네 자리가 필요합니다. 정수 한 자리와 소수 두 자리만 계산하면 올림을 놓칩니다.
Decimal('1.23').quantize(Decimal('0.0001'))는 정밀도 3에서 실패하고 5에서 1.2300을 반환했습니다. 값이 같아도 필수 후행 0은 용량을 차지합니다. 지원 크기, 요청 지수와 올림 가능성으로 작업 정밀도를 정하고 지수 상하한도 확인하세요. 만능 정밀도 값은 없습니다.
3. 무효 값을 숨기지 말고 변경을 격리하세요
유한 데이터 정책은 먼저 value.is_finite()와 quantum.is_finite()를 확인합니다. 같은 시험에서 조용한 NaN은 예외 없이 NaN으로 전파됐지만 sNaN과 Infinity를 유한 quantum으로 양자화하면 InvalidOperation이 발생했습니다. 예외만 처리하는 파이프라인은 비유한 결과를 받아들일 수 있습니다.
InvalidOperation 트랩을 끄자 정밀도 3의 9.995 실패가 NaN과 해당 플래그로 바뀌었습니다. 10.00이 들어가게 된 것은 아닙니다. with localcontext() as ctx에서 검토한 정밀도·반올림·트랩 정책만 설정하고 외부 컨텍스트를 보존하세요. 라이브러리가 내부에서 설정을 대체한다면 문서화된 동작을 조사합니다.
4. 값·지수·신호를 함께 검증하세요
격리 컨텍스트에서 대상 연산 직전에 flags를 지우고 직후에 읽으세요. 유한 출력 계약이라면 result.is_finite(), 기대 값, result.as_tuple().exponent와 quantum 지수의 일치를 요구합니다. Inexact와 Rounded 허용 여부도 명시합니다. 시험의 10.00은 두 플래그를 설정했고 1.2300의 0 채우기는 둘 다 설정하지 않았습니다. 예외 없음은 정확한 연산과 다릅니다.
실제 앱 규칙으로 정상 입력, 정수 경계 올림, 0 채우기, 음수, 0, 최대 지원 크기와 거부할 특수 값을 재시험하세요. 합성 시험 8개는 본문 분기와 외부 정밀도 복원을 확인했을 뿐 운영 데이터·재무 규칙·외부 라이브러리를 검증하지 않았습니다. 계속 실패하면 피연산자·컨텍스트·플래그를 보존해 해당 분기를 진단하세요.
