Haskell中的*运算符是否由+运算符组合实现?
Haskell中
*运算符的工作逻辑 *不是有全局统一实现的内置运算符,它是Num类型类中定义的方法,签名为Num a => a -> a -> a,具体运算逻辑完全由参与运算的值所属类型对应的Num实例决定,不存在“默认生成一连串+完成乘法”的内置规则。
- 对于固定宽度的基础数值类型(包括
Int、Word、Float、Double以及各类固定位宽的有/无符号整数类型),*会在编译阶段直接被映射为CPU原生支持的硬件乘法指令,运行时和C等语言的原生乘法性能完全一致,根本不会走重复加法的逻辑。硬件乘法指令通常仅需1到数个时钟周期就能完成计算,换成重复加法反而是严重的性能劣化,编译器不会做这种反向优化。 - 对于任意精度大整数类型
Integer,乘法实现也和重复加法无关:- 当两个
Integer的取值都落在机器字长范围内时,同样直接调用硬件乘法指令计算 - 当数值超过机器字长时,会根据数值规模选择适配的高效大数乘法算法:小规模用竖式乘法,中规模用Karatsuba分治乘法,极大规模会用基于快速傅里叶变换的乘法算法,时间复杂度远低于重复加法的O(n)。如果真用重复加法实现,两个1e18量级的大数相乘需要执行1e18次加法,计算时间会长到完全不可用。
- 当两个
- 只有用户自定义
Num实例的场景下,才可能出现*完全基于+实现的情况,最常见的是教学场景里的皮亚诺自然数示例:
data Nat = Zero | Succ Nat instance Num Nat where -- 加法定义 Zero + n = n Succ m + n = Succ (m + n) -- 乘法递归定义,完全依赖加法 Zero * _ = Zero Succ m * n = n + m * n -- 其余Num类型类要求的方法实现省略
这种写法只是特定类型的自主实现选择,和Haskell语言本身的*运算符逻辑没有关系。
补充一点:编译器后端优化时,偶尔会把其中一个操作数是小常量的乘法替换为移位+少量加法的组合(比如n * 5优化为(n shiftL 2) + n),但这是跨语言通用的编译优化手段,既不是*运算符本身的实现逻辑,也不会生成大量重复的加法操作。
内容的提问来源于stack exchange,提问作者Connor
相关产品推荐
相关产品推荐

