2015-08-16 30 views
4

的數字操作我寫了一個函數做簡單的數學:斯卡拉專業化爲基本類型

def clamp(num: Double, min: Double, max: Double) = 
    if (num < min) min else if (num > max) max else num 

這是非常簡單的,直到我需要用長型相同的功能。我與類型參數化和專業化概括它:

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; 
} 

有沒有更好的方式來做到廣義算術運算沒有拳擊?

回答

3

spire project絕對是尋找高性能數值抽象的好地方。它的所有類型類都專用於常用類型,如long,double,float,int。

下面是使用你的方法塔尖類型類:

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 

這裏是專門的字節碼(long版本),提取使用:javap的從斯卡拉REPL:

public long clamp$mJc$sp(long, 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,這是Spire的主要作者之一。

但底線是結果是非常快的,即使代碼是通用的。

0

據我所知,沒有辦法做到這一點,因爲scala標準庫使用@specialized非常罕見,特別是Ordering不是專門的。

即使這是你仍然有開銷呼籲Ordering.Implicits..MODULE$.infixOrderingOps。因此,類型上下文需要高級別的幫助來實現這種低級別的優化。

因此,我只看到了代碼生成的一些方法,而無需額外開銷就可以進行廣義算術運算。

2

這不是對問題的直接回答,更多的是評論,但它比評論長,我認爲格式化會很有用。

spire project的靈感來源於要求能夠通過數學運算進行抽象,以便能夠以最小的開銷編寫廣義的數學代碼。

該項目肯定會在benchmarks(如上一篇文章中提到的那個)中與本地函數非常接近。

這本同時使用專業化,還附加宏的組合來重新編寫代碼,這是在this paper描述,我認爲這是從斯卡拉天2012

鑑於參考基準的結果,我實現想象這個項目可能會滿足你的需求。