Repository navigation
BigDecimal Builtins
先看一段代码:
Consider this:
double a = 0.1 + 0.2;
runcmd("CONSOLE", "say " + a);
你以为会输出 0.3。实际会输出 0.30000000000000004。
You expect 0.3. You actually get 0.30000000000000004.
这不是 HimDSL 的 bug,是二进制浮点数的固有特性。0.1 在二进制里是无限循环小数,无法精确表示。绝大多数场景这点误差无所谓,但涉及金钱、积分、精确计数时,会累积成大问题。
This is not a HimDSL bug — it is a property of binary floating point. 0.1 has an infinite repeating representation in binary. Usually harmless, but money, points, and exact counts accumulate errors.
高精度计算的解决方案是用 BigDecimal——任意精度的十进制数。HimDSL 把它包装成五个函数。
The fix is BigDecimal — arbitrary-precision decimal numbers. HimDSL wraps five operations:
bigAdd(a, b) // a + b
bigSub(a, b) // a - b
bigMul(a, b) // a * b
bigDiv(a, b) // a / b,可指定精度
bigDivExact(a, b) // a / b,必须整除
参数和返回值都是字符串。因为 BigDecimal 不是 HimDSL 的原生类型,用字符串传递最自然。
Arguments and return values are strings. BigDecimal is not a native HimDSL type; strings carry it naturally.
string a = bigAdd("0.1", "0.2");
runcmd("CONSOLE", "say " + a); // "0.3"
结果精确,没有浮点误差。
The result is exact — no floating-point error.
参数可以是字符串或数字。推荐用字符串,避免传参时已经是浮点数:
Arguments may be strings or numbers. Prefer strings, to avoid the value already being a float:
bigAdd("0.1", "0.2") // ✓ "0.3"
bigAdd(0.1, 0.2) // 0.1 和 0.2 已经是浮点,可能带误差
返回值总是字符串。要参与其他计算,转成数字:
Returns are always strings. Convert to numbers for further computation:
double d = toDouble(bigAdd("0.1", "0.2"));
但这样又回到浮点——只在真的需要数值时才转,否则保持字符串。
But that returns to floating point — convert only when truly needed.
普通除法 0.1 / 0.3 是无限循环小数,必须指定保留几位小数:
0.1 / 0.3 is a repeating decimal; specify how many fractional digits:
bigDiv("1", "3") // "0.3333333333333333333333333333333333"(默认 34 位)
bigDiv("1", "3", 5) // "0.33333",保留 5 位小数
bigDiv("1", "3", 2) // "0.33"
第三个参数可选,默认 34 位。位数不足会四舍五入。
Third argument is optional; default 34. Truncation rounds to nearest.
bigDivExact 要求能整除,否则报错:
bigDivExact requires an exact division, or errors:
bigDivExact("6", "3") // "2"
bigDivExact("1", "3") // ✗ 报错:除不尽
使用 bigDivExact 表示"我认为这里能整除"。如果能整除,代码通过;如果条件变了不再整除,错误立即暴露。这比静默产生 34 位小数更安全。
Use bigDivExact when you expect exact division. It passes when exact, errors otherwise — safer than silently producing 34 digits.
累加玩家充值金额,需要精确到分:
Sum player payments, needing cent precision:
string total = "0";
void addPayment(string amount) {
total = bigAdd(total, amount);
}
int main() {
addPayment("19.99");
addPayment("0.01");
addPayment("5.50");
// 用 double 会得到 25.500000000000004 或类似结果
// 用 bigAdd 精确得到 "25.50"
runcmd("CONSOLE", "say 累计充值: " + total);
}
钱永远不该用 double。这是整个软件行业的老规矩。
Money should never use double. An industry-wide rule.
-
金钱、余额、交易。
-
计分、积分,特别是累加很多次的时候。
-
需要显示给用户的精确数值。
-
Money, balances, transactions.
-
Scores, points accumulated many times.
-
Precise values shown to users.
-
坐标、位置——这些本来就允许误差。
-
概率、随机数——浮点的误差可忽略。
-
性能敏感的循环——
BigDecimal比double慢得多。 -
Coordinates, positions — small errors are fine.
-
Probabilities, randomness — float error is negligible.
-
Performance-sensitive loops —
BigDecimalis far slower thandouble.
默认用 double,只有明确需要精确时才上 big*。别为了方便把所有数字都变成 BigDecimal——那会让代码变慢,也更啰嗦。
Default to double; reach for big* only when precision is required. Do not turn every number into a BigDecimal — slower and noisier.
-
double有精度问题,0.1 + 0.2不等于0.3。 -
五个函数:
bigAdd/bigSub/bigMul/bigDiv/bigDivExact。 -
参数和返回值都是字符串。
-
bigDiv默认保留 34 位,可指定精度。 -
bigDivExact要求整除,否则报错。 -
钱必须用
big*。 -
坐标、概率、性能敏感场景继续用
double。 -
doublehas precision issues;0.1 + 0.2 != 0.3. -
Five functions:
bigAdd/bigSub/bigMul/bigDiv/bigDivExact. -
Arguments and returns are strings.
-
bigDivdefaults to 34 digits; precision is configurable. -
bigDivExactrequires exact division. -
Money must use
big*. -
Coordinates, probabilities, performance-sensitive paths use
double.
下一章 [字符串函数 / String-Builtins] 是速查表,详细讲解见《字符串与字符》。
Next, [字符串函数 / String-Builtins] is a lookup, with details in Strings & Chars.
- 首页 / Home
- 安装与快速开始 / Installation & Quick Start
- 第一个脚本 / Your First Script
- 命令速查 / Command Reference
- 自动执行脚本 / Auto-run Scripts
- 定义函数 / Defining Functions
- 函数重载 / Function Overloading
- Lambda 表达式 / Lambda Expressions
- 函数式接口 / Functional Interfaces
- 选择器总览 / Selectors Overview
- 选择器过滤器 / Selector Filters
- EntityRef 引用 / EntityRef
- 占位符参考 / Placeholders Reference
- PlaceholderAPI 桥接 / PAPI Bridge
- 创建 GUI / Creating a GUI
- GUISlot 槽位 / GUISlot
- 点击回调 / Click Callbacks
- onClose 回调 / onClose Callback
- GUI 刷新 / GUI Refresh
- 数学函数 / Math Built-ins
- 高精度计算 / BigDecimal Built-ins
- 字符串函数 / String Built-ins
- 集合函数 / Collection Built-ins
- 文件 I/O / File I/O
- 命令与 sleep / Commands & sleep