Scala专门化用于原始类型的数值运算

前端之家收集整理的这篇文章主要介绍了Scala专门化用于原始类型的数值运算前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我写了一个简单的数学函数

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,他是尖顶的主要作者之一.

但最重要的是,即使代码是通用的,结果也非常快.

猜你在找的Scala相关文章