gpt4 book ai didi

performance - Int 和 BigInt 的 Scala 通用数学函数与 @specialized(Int)

转载 作者:行者123 更新时间:2023-12-04 03:00:02 24 4
gpt4 key购买 nike

我是 scala 的新手,我想知道是否可以定义适用于 BigIntInt 的通用数学函数以及 Int 函数的参数将被视为原语(函数体中没有任何装箱和拆箱)。

所以,例如我可以做类似的事情

def foo[@specialized(Int) T: Numeric](a: T, b: T) = {
val n = implicitly[Numeric[T]]
import n._
//some code with the use of operators '+-*/'
a * b - a * a + b * b * b
}

//works for primitive Int
val i1 : Int = 1
val i2 : Int = 2
val i3 : Int = foo(i1, i2)

//works for BigInt
val b1 : BigInt = BigInt(1)
val b2 : BigInt = BigInt(2)
val b3 : BigInt = foo(b1, b2)

foo 中,我可以对原始 intsBigInts 使用所有数学运算符(这是我需要的)。但是,函数 foo(Int, Int) 编译为以下内容:

 public int foo$mIc$sp(int a, int b, Numeric<Object> evidence$1) {
Numeric n = (Numeric)Predef..MODULE$.implicitly(evidence$1);
return BoxesRunTime.unboxToInt((Object)n.mkNumericOps(n.mkNumericOps(n.mkNumericOps((Object)BoxesRunTime.boxToInteger((int)a)).$times((Object)BoxesRunTime.boxToInteger((int)b))).$minus(n.mkNumericOps((Object)BoxesRunTime.boxToInteger((int)a)).$times((Object)BoxesRunTime.boxToInteger((int)a)))).$plus(n.mkNumericOps(n.mkNumericOps((Object)BoxesRunTime.boxToInteger((int)b)).$times((Object)BoxesRunTime.boxToInteger((int)b))).$times((Object)BoxesRunTime.boxToInteger((int)b))));
}

而不是普通的:

//this is what I really need and expect from `@specialized(Int)`
public int foo$mIc$sp(int a, int b) {
return a * b - a * a + b * b * b;
}

这使得 @specialized(Int) 无用,因为所有这些(非)装箱和不必要的调用 n.mkNumericOps(...) 的性能低得令人无法接受。

那么,有没有一种方法可以实现像 foo 这样的泛型函数,它将编译为原始类型的“原样”代码?

最佳答案

问题是 Numeric typeclass 不是特化的。

如果您想进行高性能的通用数学运算,我强烈推荐 spire数学图书馆。

它有一个非常精细的数学类型类层次结构,而不仅仅是数字。

下面是您的示例使用 spire 时的样子:

import spire.implicits._ // typeclass instances etc.
import spire.syntax._ // syntax such as +-*/
import spire.algebra._ // typeclassses such as Field

def foo[@specialized T: Field](a: T, b: T) = {
//some code with the use of operators '+-*/'
a * b - a * a + b * b * b
}

这里你是说必须有一个Field T.Field 的实例指的是 algebraic concept .

Spire 是高度模块化的:

  • spire.algebra 包含许多众所周知的代数概念,例如群、域等,编码为 scala 类型类

  • spire.syntax 包含向类型类实例可用的类型添加运算符和其他语法的隐式转换

  • spire.implicits 包含 spire.algebra 中类型类的实例,用于 JVM 原语等常见类型。

这就是您需要三个导入的原因。

关于性能:如果您的代码是专用的,并且您正在使用基元,那么性能将与直接使用基元完全相同。

下面是专门用于 Int 的 foo 方法的代码:

public int foo$mIc$sp(int, int, spire.algebra.Field<java.lang.Object>);
Code:
0: aload_3
1: aload_3
2: aload_3
3: iload_1
4: iload_2
5: invokeinterface #116, 3 // InterfaceMethod spire/algebra/Field.times$mcI$sp:(II)I
10: aload_3
11: iload_1
12: iload_1
13: invokeinterface #116, 3 // InterfaceMethod spire/algebra/Field.times$mcI$sp:(II)I
18: invokeinterface #119, 3 // InterfaceMethod spire/algebra/Field.minus$mcI$sp:(II)I
23: aload_3
24: aload_3
25: iload_2
26: iload_2
27: invokeinterface #116, 3 // InterfaceMethod spire/algebra/Field.times$mcI$sp:(II)I
32: iload_2
33: invokeinterface #116, 3 // InterfaceMethod spire/algebra/Field.times$mcI$sp:(II)I
38: invokeinterface #122, 3 // InterfaceMethod spire/algebra/Field.plus$mcI$sp:(II)I
43: ireturn

请注意,没有装箱,调用接口(interface)调用将由 JVM 内联。

关于performance - Int 和 BigInt 的 Scala 通用数学函数与 @specialized(Int),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41180154/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com