我写了一个简单的数学函数:
def clamp(num: Double,min: Double,max: Double) = if (num < min) min else if (num > max) max else num
这很简单,直到我需要与Long类型相同的功能.我用类型参数和专业化来概括它:
import Ordering.Implicits._ def clamp[@specialized N: Ordering](num: N,min: N,max: N) = if (num < min) min else if (num > max) max else num
它工作,但我发现字节码在引擎盖下进行了大量的装箱和拆箱:
public boolean clamp$mZc$sp(boolean num,boolean min,boolean max,Ordering<Object> evidence$1) { return Ordering.Implicits..MODULE$.infixOrderingOps(BoxesRunTime.BoxToBoolean(num),evidence$1).$greater(BoxesRunTime.BoxToBoolean(max)) ? max : Ordering.Implicits..MODULE$.infixOrderingOps(BoxesRunTime.BoxToBoolean(num),evidence$1).$less(BoxesRunTime.BoxToBoolean(min)) ? min : num; } public byte clamp$mBc$sp(byte num,byte min,byte max,Ordering<Object> evidence$1) { return Ordering.Implicits..MODULE$.infixOrderingOps(BoxesRunTime.BoxToByte(num),evidence$1).$greater(BoxesRunTime.BoxToByte(max)) ? max : Ordering.Implicits..MODULE$.infixOrderingOps(BoxesRunTime.BoxToByte(num),evidence$1).$less(BoxesRunTime.BoxToByte(min)) ? min : num; } public char clamp$mCc$sp(char num,char min,char max,Ordering<Object> evidence$1) { return Ordering.Implicits..MODULE$.infixOrderingOps(BoxesRunTime.Boxtocharacter(num),evidence$1).$greater(BoxesRunTime.Boxtocharacter(max)) ? max : Ordering.Implicits..MODULE$.infixOrderingOps(BoxesRunTime.Boxtocharacter(num),evidence$1).$less(BoxesRunTime.Boxtocharacter(min)) ? min : num; }
有没有更好的方法来进行无拳击的广义算术运算?
解决方法
spire project绝对是寻找高性能数值抽象的最佳选择.它的所有类型类都专门用于常见类型,如long,double,float,int.
这是使用spire类型类的方法:
import spire.algebra._ import spire.implicits._ def clamp[@specialized T:Order](a: T,min: T,max: T) = if(a < min) min else if(a > max) max else a
这里是专门的字节码(长版本),使用:scala REPL中的javap提取:
public long clamp$mJc$sp(long,long,spire.algebra.Order<java.lang.Object>); descriptor: (JJJLspire/algebra/Order;)J flags: ACC_PUBLIC Code: stack=5,locals=8,args_size=5 0: aload 7 2: lload_1 3: lload_3 4: invokeinterface #96,5 // InterfaceMethod spire/algebra/Order.lt$mcJ$sp:(JJ)Z 9: ifeq 16 12: lload_3 13: goto 35 16: aload 7 18: lload_1 19: lload 5 21: invokeinterface #99,5 // InterfaceMethod spire/algebra/Order.gt$mcJ$sp:(JJ)Z 26: ifeq 34 29: lload 5 31: goto 35 34: lload_1 35: lreturn
正如你所看到的,它正在调用spire.algebra.Order的gt方法的长专用版本,所以没有涉及到拳击.
您还可以注意到,从运算符(<和>)到类型类方法调用的转换不会出现在代码中.这背后的机制非常精细.请参阅Erik Osheim的这篇blog post,他是尖顶的主要作者之一.
但最重要的是,即使代码是通用的,结果也非常快.