2013-07-29 2 views
2

Récemment, j'ai (enfin) commencé à utiliser le trait numérique de Scala, qui fait des merveilles. Par exemple:Mathématiques plus avancées avec les nombres numériques et fractionnaires de Scala

def square[A](x: A)(implicit num: Numeric[A]): A = num.times(x, x) 

Maintenant, je peux carré un nombre que ce soit Double, Integer, BigDecimal, ou que non. Et si je voulais faire des maths plus avancés? Par exemple, mes logistic function pour Double nombres ressemble à ceci:

def logisticFunction(x: Double): Double = 1.0/(1.0 + math.exp(-x)) 

que je pouvais faire l'ajout et la division facilement (je devrais juste utiliser trait Fractional au lieu de Numeric), mais qu'en est-exposant? Je ne veux certainement pas écrire ma propre fonction exp (ou toute fonction arbitraire qui prend Double arguments). Donc, ma question est la suivante: comment puis-je convertir mon A en Double, faire mes calculs à ce sujet, puis revenir à A. Est-ce même possible?

EDIT:

Voilà comment la signature de ma fonction devrait ressembler à:

def logisticFunction[A](x: A)(implicit num: Fractional[A]): A = 
    /* Magic happens here */ 

J'ai compris la partie sur la conversion de doubler, ce qui est aussi facile que num.toDouble(x). Cependant, le problème de la conversion à A reste.

+2

Le logisticFunction ne va jamais revenir un membre valide de A pour, par exemple, entier, donc non, je ne vois pas comment c'est possible à moins que vous ne vouliez commencer à l'utiliser comme une fonction partiellement appliquée et la modifier pour la comparer à des types numériques valides pour la fonction. – Shadowlands

+1

'importer Numeric.Implicits._' et écrire' x * x' au lieu de 'num.times (x, x)'. –

+0

Désolé de demander l'évidence, mais je suppose qu'il y a des applications plus compliquées au travail ici? Pourquoi écririez-vous ces fonctions en utilisant numérique étant donné leur simplicité? Je dis cela parce que honnêtement, vous voulez éviter la plupart des fonctionnalités de Scala pour un usage quotidien, croyez-moi sur cette beaucoup de fonctionnalités comme implicits n'ont pas leur place dans les systèmes financiers robustes. –

Répondre

6

Je doute encore cette approche est vraiment utile. Mais avec votre description, vous voulez quelque chose comme ceci:

type FromDouble[A] = Double => A 
type ToDouble [A] = A => Double 

def logisticFunction[A: FromDouble: ToDouble](x: A): A = 1.0/(1.0 + math.exp(-x)) 

logisticFunction(0.5) 
implicit def bigDecimalToDouble(b: BigDecimal) = b.toDouble  
logisticFunction(BigDecimal(0.5)) 

Ou avec classe de type dédié:

object FromDouble { 
    implicit object _Double extends FromDouble[Double] { 
    def apply(d: Double) = d 
    } 
    implicit object _BigDecimal extends FromDouble[BigDecimal] { 
    def apply(d: Double) = BigDecimal(d) 
    } 
} 
trait FromDouble[A] extends (Double => A) 

object ToDouble { 
    implicit object _Double extends ToDouble[Double] { 
    def apply(d: Double) = d 
    } 
    implicit object _BigDecimal extends ToDouble[BigDecimal] { 
    def apply(b: BigDecimal) = b.toDouble 
    } 
} 
trait ToDouble[A] extends (A => Double) 

def logisticFunction[A: FromDouble: ToDouble](x: A): A = 1.0/(1.0 + math.exp(-x)) 

logisticFunction(0.5) 
logisticFunction(BigDecimal(0.5)) 
3

Vous aurez besoin d'une classe de type fournissant des fonctions trigonométriques telles que exp. La bibliothèque standard de Scala ne va pas au-delà de Fractional. Vous pouvez essayer d'utiliser Spire.

Exemple:

$ sbt core/console 

import spire.math._ 
import spire.algebra._ 
import spire.implicits._ 

def logisticFunction[A](x: A)(implicit m: Field[A], t: Trig[A]): A = 
    m.one/(m.one + exp(-x)) 

logisticFunction(0.5) 
logisticFunction(BigDecimal(0.5)) 
+0

Mon problème ne concerne pas vraiment les nombres, je veux créer une méthode générique qui accepte n'importe quel nombre fractionnaire (Double, Float, BigDecimal), fait des maths et retourne le résultat du même type. opérations (+, *, etc), mais pas avec des fonctions arbitraires qui acceptent les doubles –

+0

Ensuite, vous avez besoin de classes de type pour les conversions vers/à partir de Double, bien qu'il semble étrange que si vous faites ce calcul avec 'Double' vous voulez convertir et de retour en premier lieu –

Questions connexes