From 6aeadb84b8ba35acfa0ee84fc8b97921ef805068 Mon Sep 17 00:00:00 2001 From: Joywayer Date: Mon, 3 Aug 2026 11:05:51 +0800 Subject: [PATCH] =?UTF-8?q?fix(shop):=20PriceFormula=20=E5=A4=A7=E8=B4=AD?= =?UTF-8?q?=E4=B9=B0=E6=AC=A1=E6=95=B0=E6=BA=A2=E5=87=BA=E9=9D=99=E9=BB=98?= =?UTF-8?q?=E5=A1=8C=E9=99=B7=E4=B8=BA=201=EF=BC=9B=E5=90=8C=E6=AD=A5?= =?UTF-8?q?=E8=AE=A1=E5=88=92=E6=96=87=E6=A1=A3=E6=AE=8B=E7=95=99=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit geometric 曲线在 purchased 较大时(如 n=300,base=60 growth=1.15)raw 虽仍是合法有限 double(约 9.7e19),但已超出 int64 安全范围,roundi() 对此行为未定义/环绕,经 maxi(...,1) 静默塌陷成 1——方向与「买得越多越 贵」相反,且零诊断。仅判断 is_finite(raw) 测不出这种情况(double 本身 溢出为 INF 要到 n≈5077 才发生,晚于 int64 溢出很多),故改为 `not is_finite(raw) or raw > 9.0e15` 双重判据,触发时 push_error 并钳 到统一上限,不再依赖具体常数断言(新增用例只断言单调性与「不再塌陷回 归」)。 同时补齐 docs_dev/plans/2026-07-31-shelf-c-attribute-shop.md:64 遗漏的 `PriceFormula.Curve` → `PriceFormula.PriceCurve` 同步(enum 部分先前已 改,返回类型标注漏改),并全仓复核确认无其它残留。 Co-Authored-By: Claude Opus 5 --- docs_dev/plans/2026-07-31-shelf-c-attribute-shop.md | 2 +- scripts/domain/price_formula.gd | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/docs_dev/plans/2026-07-31-shelf-c-attribute-shop.md b/docs_dev/plans/2026-07-31-shelf-c-attribute-shop.md index e152cca..83689c4 100644 --- a/docs_dev/plans/2026-07-31-shelf-c-attribute-shop.md +++ b/docs_dev/plans/2026-07-31-shelf-c-attribute-shop.md @@ -61,7 +61,7 @@ Expected: `Switched to a new branch 'feat/shelf-c-attribute-shop'` **Interfaces:** - Consumes: 无(零依赖) -- Produces: `PriceFormula.compute(spec: Dictionary, purchased: int) -> int`;`PriceFormula.curve_from_string(s: String) -> PriceFormula.Curve`;`enum PriceCurve { GEOMETRIC, LINEAR, FLAT }` +- Produces: `PriceFormula.compute(spec: Dictionary, purchased: int) -> int`;`PriceFormula.curve_from_string(s: String) -> PriceFormula.PriceCurve`;`enum PriceCurve { GEOMETRIC, LINEAR, FLAT }` > 纯函数,**先写断言、看它失败、再实现**。断言经 `execute_editor_script` 执行(项目无测试框架)。 diff --git a/scripts/domain/price_formula.gd b/scripts/domain/price_formula.gd index a7622a5..630fa3e 100644 --- a/scripts/domain/price_formula.gd +++ b/scripts/domain/price_formula.gd @@ -42,4 +42,14 @@ static func compute(spec: Dictionary, purchased: int) -> int: raw = base _: raw = base * pow(growth, float(n)) + # raw 可能在两个不同的地方失控:pow() 把 double 本身推到 INF(n 极大,如 geometric + # n≈5077+),或者 raw 仍是合法有限 double,但早已超出 int64 可安全表示的范围(如 + # geometric n=300 时 raw≈9.7e19——finite 但 > INT64_MAX≈9.22e18)。后者 is_finite() + # 测不出来,roundi() 对超范围 float 的行为是未定义/环绕,曾亲测把它环绕成极小/负值, + # 再经 maxi(...,1) 静默塌陷成 1——方向与"买得越多越贵"完全相反。故用同一个安全阈值 + # 9.0e15(远小于 INT64_MAX,远超任何合理金币量)同时兼答两种情况。 + const _PRICE_CLAMP: float = 9.0e15 + if not is_finite(raw) or raw > _PRICE_CLAMP: + push_error("PriceFormula: 价格溢出(base=%f growth=%f purchased=%d),已钳到上限" % [base, growth, n]) + raw = _PRICE_CLAMP return maxi(roundi(raw), 1)