fix(m01): 값 식 작은 수를 유효숫자 4 자리로 · 200 원 미만 단가도 (PLAN 5장 4바퀴)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V1MKKZKpUHTPKb513FneU8
This commit is contained in:
2026-09-24 11:31:18 +09:00
co-authored by Claude Sonnet 5
parent 0a6bac5056
commit 0d81acc7d3
2 changed files with 23 additions and 3 deletions
+12 -3
View File
@@ -33,10 +33,13 @@ _CALC_ERRORS = (mf.FormulaError, ArithmeticError, KeyError, TypeError, ValueErro
def fmt(value) -> str:
"""화면에 보이는 자릿수 그대로 — 소수 넷째 자리까지 · 뒤 0 은 떼고 · 천 단위 쉼표."""
"""보이는 자릿수 — 소수 넷째 자리·유효숫자 4 자리 중 많은 쪽 · 뒤 0 뗌 · 천 단위 쉼표."""
if not isinstance(value, Decimal):
return str(value)
cut = value.quantize(PLACES) if value.as_tuple().exponent < -4 else value
places = max(4, 3 - value.adjusted()) if value else 4 # 0.00167 → 0.001667
cut = value
if value.as_tuple().exponent < -places:
cut = value.quantize(Decimal(1).scaleb(-places))
sign, digits = ("-", -cut) if cut < 0 else ("", cut)
whole, _, rest = f"{digits.normalize():f}".partition(".")
if "E" in whole or "e" in whole: # 아주 큰 수 — 지수 꼴을 펴서 씀
@@ -51,6 +54,12 @@ def fmt_money(value) -> str:
return fmt(value)
def fmt_price(value) -> str:
"""단가 — 정수로 보이되 200 원 미만은 반올림 오차가 커서 유효숫자로."""
small = isinstance(value, Decimal) and abs(value) < 200
return fmt(value) if small else fmt_money(value)
# ── 식을 글로 — 값 꼴과 이름 꼴 ────────────────────────────────────────
def render(node, env: dict, master, depth: int = 0) -> str:
"""식 한 마디 → 값 꼴 글. 값이 정해지는 마디(요소 · 찾기 · 로직 · 이름)는 그 수로 바뀜."""
@@ -377,7 +386,7 @@ def _line_text(item: dict, line: dict, env: dict, master, part: str | None) -> s
qty = _times(render(mf.parse(item["수량"]), env, master), item, env, master)
money = line["비목"][part] if part else line["금액"]
price = line["단가"] if part is None or line["수량"] == 0 else money / line["수량"]
return f"{fmt_money(price)} * {qty} = {fmt_money(money)}"
return f"{fmt_price(price)} * {qty} = {fmt_money(money)}"
def _line_names(item: dict, line: dict, env: dict, master, part: str | None, name_of: dict) -> str: