- 编程语言
- 语言运行时
- 标准库
- 垃圾回收
- 并发编程
【免费下载链接】cangjie_runtime
仓颉编程语言运行时与标准库。
本文面向使用仓颉标准库std.math.numeric包的开发者,系统讲解高精度十进制数Decimal的大小比较能力。你将掌握> < == != <= >=六种比较运算符的语义与运行结果、compare()方法返回的Ordering三态枚举,并通过源码级分析理解 Decimal 比较"先比量级、再对齐标度"的底层原理,从而在金融计算、精度敏感场景中正确选择比较方式。
一、Decimal 类型与比较能力概览
Decimal是仓颉标准库std.math.numeric包中用于表示任意精度有符号十进制数的结构体,用于承载基础浮点类型无法精确表达的数值。从 API 文档 math_numeric_package_overview.md 可以看到,该包通过BigInt(任意精度二进制有符号整数)与Decimal(任意精度十进制数)两个核心类型,为基础类型可表达范围之外提供扩展能力。
在类型体系上,Decimal声明为:
public struct Decimal <: Comparable<Decimal> & Hashable & ToString即它同时实现了Comparable、Hashable与ToString三个接口。其中Comparable<T>接口(定义于 comparable.cj)约定了compare(other: T): Ordering方法以及> < <= >=四个运算符,并基于compare给出==、<等方法的默认实现。这意味着 Decimal 的大小比较最终都会汇聚到compare这一个核心方法上——这也是理解本文所有示例的关键。
二、官方示例:比较运算符与 compare 方法的完整演示
官方文档 decimal_compare_opration.md 给出了最直观的入门示例:初始化两个Decimal对象后,分别用六种比较运算符和compare方法输出比较结果。
import std.math.numeric.* main() { let decimal1 = Decimal.parse("12345.6789") let decimal2 = Decimal.parse("987.654321") // 比较运算符 println("${decimal1} > ${decimal2} = ${decimal1 > decimal2}") println("${decimal1} < ${decimal2} = ${decimal1 < decimal2}") println("${decimal1} == ${decimal2} = ${decimal1 == decimal2}") println("${decimal1} != ${decimal2} = ${decimal1 != decimal2}") println("${decimal1} <= ${decimal2} = ${decimal1 <= decimal2}") println("${decimal1} >= ${decimal2} = ${decimal1 >= decimal2}") // compare 函数返回 Ordering 类型 println("${decimal1}.compare(${decimal2}) = ${decimal1.compare(decimal2)}") return 0 }运行结果:
12345.6789 > 987.654321 = true 12345.6789 < 987.654321 = false 12345.6789 == 987.654321 = false 12345.6789 != 987.654321 = true 12345.6789 <= 987.654321 = false 12345.6789 >= 987.654321 = true 12345.6789.compare(987.654321) = Ordering.GT对结果的解读要点如下:
- 六种运算符互相自洽:
>为true时,<、==、<=均为false,而!=、>=为true,与数学上全序关系的直觉完全一致。 compare返回三态结果:Ordering.GT表示当前对象大于入参,对应>与>=为真;另有Ordering.LT(小于)与Ordering.EQ(等于)两种取值。- 字符串解析构造:示例通过
Decimal.parse("12345.6789")从字符串构造 Decimal,这是官方推荐的方式。根据 math_numeric_package_structs.md 中static func parse(String)的说明,parse默认采用精度值 0(即无限精度)进行构建,字符串需满足"可选符号 + 数值部分 + 可选指数部分"的格式(支持e/E科学计数法),因此"12345.6789"会被精确解析为 value = 123456789、scale = 4 的 Decimal。
三、比较运算符的语义与源码实现
在 decimal.cj 中,六个比较运算符全部定义在Decimal结构体内,且实现高度一致——它们都只是对compare返回的Ordering做一次模式匹配:
| 运算符 | 语义 | 源码实现(行号) | 实现逻辑 |
|---|---|---|---|
< | 小于 | decimal.cj | compare结果为Ordering.LT时为true |
> | 大于 | decimal.cj | compare结果为Ordering.GT时为true |
<= | 小于等于 | decimal.cj | compare结果为Ordering.GT时为false,其余为true |
>= | 大于等于 | decimal.cj | compare结果为Ordering.LT时为false,其余为true |
== | 等于 | decimal.cj | compare结果为Ordering.EQ时为true |
!= | 不等于 | decimal.cj | compare结果为Ordering.EQ时为false,其余为true |
例如>的源码为:
public operator func >(d: Decimal): Bool { return match (this.compare(d)) { case Ordering.GT => true case _ => false } }这种"运算符统一委托compare"的设计带来的直接好处是:无论使用哪种比较方式,比较结果必然一致,不会出现a > b与b.compare(a)结论矛盾的情况。这也与 Comparable 接口 的设计理念相呼应——该接口正是用compare作为唯一抽象方法,其余运算符都围绕它给出默认实现。
四、compare 方法:Ordering 三态返回值与五步比较算法
compare方法位于 decimal.cj,签名如下:
public func compare(d: Decimal): Ordering返回值类型Ordering定义于 comparable.cj,是一个只有三个成员的枚举:
public enum Ordering { LT | GT | EQ }Ordering.LT:当前对象小于入参;Ordering.GT:当前对象大于入参;Ordering.EQ:当前对象等于入参。
对应关系在 math_numeric_package_structs.md 中也有明确说明。因此示例中12345.6789.compare(987.654321)打印Ordering.GT,与12345.6789 > 987.654321为true相互印证。
从源码结构看,compare的比较算法共分五个阶段:
- 双方均为 0 的直接判定:若
this.sign == 0且d.sign == 0,直接返回Ordering.EQ,无需进入后续数值计算。 - 符号不同的快速判定:当
this.sign * d.sign <= 0时(一正一负,或一方为 0),根据sign的大小直接返回GT或LT。例如正数恒大于负数,0 介于两者之间。 - 同号时先比量级:计算
precision - scale(即整数部分的十进制位数)。precision是无标度整数值的有效数字位数,scale是小数位标度。若整数位数不同,则量级大者胜出——这正是示例中12345.6789(整数部分 5 位)大于987.654321(整数部分 3 位)的直接原因。 - 量级相同时对齐标度:计算标度差
diffScale,若为 0 则直接比较无标度整数值this.value.compare(d.value)。 - 标度对齐后逐位比较:当
diffScale > 0时,将标度更小的数的无标度值放大10^diffScale倍再比较,即this.value.compare(ailgnBigValue(d.value, diffScale))。
其中第 5 步使用的辅助函数ailgnBigValue定义于 decimal.cj:
func ailgnBigValue(val: BigInt, diffScale: Int64): BigInt { if (diffScale <= 0) { return val } return val * tenPowerN(diffScale) }它通过将无标度值乘以10^diffScale实现标度统一。例如比较1.0(value=10, scale=1)与1.00(value=100, scale=2)时,标度差为 -1,则把前者放大 10 倍得到 100,再与后者比较。可以推断:只要两个 Decimal 表示的数值相同,即使标度(小数位数)不同,compare也会返回Ordering.EQ,即1.0 == 1.00为真。这与二进制浮点数"0.1 + 0.2 != 0.3"的近似比较有本质区别——Decimal 全程使用无标度整数(BigInt)与 10 的幂运算完成比较,不经过任何浮点转换,因此比较结果精确且可预期。
五、实战进阶:相等性、哈希与精度场景
在实际工程中,Decimal 比较还有几个值得注意的进阶点。
5.1 相等性与哈希保持一致
Decimal同时实现了Comparable与Hashable,可用于集合与哈希容器。为保证"相等对象哈希值必相同",hashCode()在计算前先调用removeTrailingZeros()去掉无标度值的尾部零,再以31 * value.hashCode() + scale计算哈希(见 decimal.cj)。这意味着1.0与1.00不仅==为真,哈希值也一致,可以安全地作为HashMap、HashSet的键使用。
5.2 比较不受"精度限制"影响
通过roundWithPrecision(10, roundingMode: HalfEven)等接口可以为运算指定结果精度与舍入规则(舍入模式RoundingMode枚举定义于 math_enum.cj,包含Ceiling、Down、Floor、HalfEven、HalfUp、Up六种)。而从compare的源码看,比较过程只使用当前对象的实际无标度值与标度,与对象是否带精度限制无关,因此比较结果始终基于真实数值,不会因精度设置而被扭曲。
5.3 与 BigInt 比较能力的对应
同属std.math.numeric包的BigInt也提供同样的比较能力:BigInt.compare(other: BigInt): Ordering返回Ordering.LT/GT/EQ,其运算符与compare的对应关系与 Decimal 完全一致,可参考配套文档 bigInt_compare_opration.md。由于 Decimal 的无标度值正是由 BigInt 承载,两者在比较语义上保持了统一。
六、深入学习路径
围绕 Decimal 的比较与运算,仓库中还提供了完整的示例与 API 文档,建议按以下顺序阅读:
- decimal_basic_arithmetic.md:涵盖通过
Decimal(BigInt.parse("987654321"), 6)构造(表示987654321 × 10⁻⁶)、四则运算、divWithPrecision与divAndMod的完整示例; - decimal_basic_prop.md:演示
sign、scale、value、precision四个基本属性的查询,以及roundWithPrecision指定精度与舍入模式的用法; - math_numeric_package_structs.md:
Decimal、BigInt的完整成员清单与逐项说明,含compare、hashCode、parse等方法的参数与异常约定; - math_numeric_package_overview.md:
std.math.numeric包的总体能力介绍与函数/枚举/结构体索引。
如需深入源码,比较相关的全部实现集中在 decimal.cj(运算符与compare算法)与 comparable.cj(Ordering枚举与Comparable接口默认实现)两个文件中,可结合阅读以形成对 Decimal 比较语义的完整认知。
- 编程语言
- 语言运行时
- 标准库
- 垃圾回收
- 并发编程
【免费下载链接】cangjie_runtime
仓颉编程语言运行时与标准库。
相关推荐
仓颉 BigInt 大小比较实战指南:比较运算符、compare 与 Ordering 详解
仓颉 BigInt 大小比较实战指南:比较运算符、compare 与 Ordering 详解 本文以 std.math.numeric 包中的 BigInt 大
编程语言语言运行时标准库垃圾回收并发编程仓颉编程语言 BigInt 大小比较详解:比较运算符、compare 方法与 Ordering 枚举实战
仓颉编程语言 BigInt 大小比较详解:比较运算符、compare 方法与 Ordering 枚举实战 导读 本文基于仓颉编程语言标准库 std.math.n
文档知识库教程OpenHarmony仓颉编程语言 Decimal 高精度小数大小比较实战指南
仓颉编程语言 Decimal 高精度小数大小比较实战指南 本指南聚焦仓颉标准库 std.math.numeric 包中的 Decimal 类型,围绕 Decim
文档知识库教程OpenHarmony
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考