仓颉 Decimal 高精度数值比较实战:六种比较运算符与 compare 方法全解析 编程语言语言运行时标准库垃圾回收并发编程【免费下载链接】cangjie_runtime仓颉编程语言运行时与标准库。项目地址https://gitcode.com/Cangjie/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 : ComparableDecimal Hashable ToString即它同时实现了Comparable、Hashable与ToString三个接口。其中ComparableT接口定义于 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.cjcompare结果为Ordering.LT时为true大于decimal.cjcompare结果为Ordering.GT时为true小于等于decimal.cjcompare结果为Ordering.GT时为false其余为true大于等于decimal.cjcompare结果为Ordering.LT时为false其余为true等于decimal.cjcompare结果为Ordering.EQ时为true!不等于decimal.cjcompare结果为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.cjfunc ailgnBigValue(val: BigInt, diffScale: Int64): BigInt { if (diffScale 0) { return val } return val * tenPowerN(diffScale) }它通过将无标度值乘以10^diffScale实现标度统一。例如比较1.0value10, scale1与1.00value100, scale2时标度差为 -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.mdDecimal、BigInt的完整成员清单与逐项说明含compare、hashCode、parse等方法的参数与异常约定math_numeric_package_overview.mdstd.math.numeric包的总体能力介绍与函数/枚举/结构体索引。如需深入源码比较相关的全部实现集中在 decimal.cj运算符与compare算法与 comparable.cjOrdering枚举与Comparable接口默认实现两个文件中可结合阅读以形成对 Decimal 比较语义的完整认知。赞分享编程语言语言运行时标准库垃圾回收并发编程【免费下载链接】cangjie_runtime仓颉编程语言运行时与标准库。项目地址https://gitcode.com/Cangjie/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上一篇Draggable 源码解析MouseSensor 鼠标传感器的默认配置、API 与工作原理下一篇Transmission 下载速度缓慢从网络到源码的 10 步完整排查指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考