2009-08-29 9 views
15

J'ai une lecture d'entrée dynamiquement changeante à partir d'un fichier. Les numéros sont Int ou Double. Pourquoi Scala imprime .0 après tous les numéros Double? Existe-t-il un moyen pour Scala de l'imprimer de la même manière qu'il le lit?Formatage des nombres dans Scala?

Exemple:

var x:Double = 1 
println (x)    // This prints '1.0', I want it to print '1' 
x = 1.0     // This prints '1.0', which is good 

Je ne peux pas utiliser Int parce que certains de l'entrée que je reçois sont Double s. Je ne peux pas utiliser String ou AnyVal car j'effectue certaines opérations mathématiques.

Merci,

Répondre

7

Utilisation printf:

printf("The value is %.0f", x) 

Pour une description de la chaîne de format, voir this page de la documentation de l'API Java SE 6. Notez que vous pouvez également utiliser la bibliothèque Java de Scala, donc d'autres façons de formater des nombres à partir de Java peuvent également être utilisées à partir de Scala. Vous pouvez par exemple utiliser la classe java.text.DecimalFormat:

val df = new java.text.DecimalFormat("#####") 
println(df.format(x)) 
+0

Merci pour vous répondre Mais le problème est que le nombre est inconnu, que ce soit il est « 1 » ou « 1.0 ». Si c'est '1' je veux imprimer '1', si c'est '1.0' alors je veux imprimer '1.0'. Mais comme il s'agit de Double, Scala imprime toujours en '1.0' –

+3

Si vous le souhaitez, vous devrez le stocker sous forme de chaîne. Un «double» ne se souvient pas si vous l'avez assigné avec «1» ou «1,0». – cdmckay

+2

Kodo, les nombres n'ont pas intrinsèquement un nombre de chiffres. Il n'y a pas de différence entre un nombre qui a la valeur 1 et un nombre qui a la valeur 1.0. – Jesper

9
var x:Double = 1 
var y:Double = 1.0 

print(x) // => 1.0 
print(y) // => 1.0 

Si je vous comprends question que vous voulez imprimer scala x et y différemment? Le problème est que x et y sont à la fois une variable du type Double et se ressemblent. Pourquoi est-ce que vous définissez explicitement le type de vars, pourquoi?

var x = 1 
var y= 1.0 

print(x) // => 1 
print(y) // => 1.0 
+0

Il a dit "changer dynamiquement la lecture des entrées à partir d'un fichier". Il introduit des nombres, et les nombres peuvent être entiers ou non (mais toujours stockés comme un double). – akauppi

1

Utilisez l'inférence de type plutôt que la saisie explicite.

scala> val xi = 1 
xi: Int = 1 

scala> val xd = 1.0 
xd: Double = 1.0 

scala> println(xi) 
1 

scala> println(xd) 
1.0 
+0

Ooops désolé c'est une réponse en double. – Synesso

29
scala> "%1.0f" format 1.0 
res3: String = 1 

Si votre entrée est soit Int ou Double, vous pouvez le faire comme ceci:

def fmt(v: Any): String = v match { 
    case d : Double => "%1.0f" format d 
    case i : Int => i.toString 
    case _ => throw new IllegalArgumentException 
} 

Utilisation:

scala> fmt(1.0) 
res6: String = 1 

scala> fmt(1) 
res7: String = 1 

scala> fmt(1.0f) 
java.lang.IllegalArgumentException 
     at .fmt(<console>:7) 
     at .<init>(<console>:6) 
     at .<clinit>(<console>) 
     at RequestResult$.<init>(<console>:4) 
     at RequestResult$.<clinit>(<console>) 
     at RequestResult$result(<console>) 
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
     at sun.reflect.Dele... 

Sinon, vous pouvez utiliser BigDecimals. Ils sont lents, mais ils viennent avec l'échelle, de sorte que « 1 », « 1.0 » et « 1.00 » sont toutes différentes:

scala> var x = BigDecimal("1.0") 
x: BigDecimal = 1.0 

scala> x = 1 
x: BigDecimal = 1 

scala> x = 1.0 
x: BigDecimal = 1.0 

scala> x = 1.000 
x: BigDecimal = 1.0 

scala> x = "1.000" 
x: BigDecimal = 1.000 
+0

C'est horrible. Vous venez de jeter tout type de sécurité par la fenêtre. Le plus simple est de faire: n.toInt.toString – juancn

+4

@juancn Comment ai-je jeté la sécurité de type par la fenêtre? Par ailleurs, "' var n = 1.0; n.toInt.toString' "produit' 1', pas '1.0' comme désiré. –

+2

La chose est que dans 'fmt' vous déclarez que vous acceptez 'Any' qui n'est pas vrai, parce que vous lancez une exception IllegalArgumentException si je passe, disons, une chaîne. Vous pouvez faire quelque chose comme: 'def fmt [T <% math.ScalaNumericConversions] (n: T) = si (n.toInt == n) n.toInt.toString else n.toString' qui est sûr. Les exceptions d'argument non valides ne doivent être lancées que si le système de type ne peut pas exprimer un ensemble de contraintes raisonnable (par exemple, scala ne vous permet pas de spécifier des entiers à distance comme types). – juancn

4

L'utilisation d'un « _.0 » à la fin de la virgule flottante les nombres sont une convention. Juste un moyen de savoir que le nombre est en fait à virgule flottante et non pas un nombre entier.

Si vous avez réellement besoin de "pour l'imprimer de la même façon que vous le souhaitez", vous devrez peut-être repenser la structure de votre code, en préservant éventuellement vos données d'entrée.Si c'est juste une question de mise en forme, le plus simple est de convertir les valeurs en nombres entiers avant l'impression:

val x = 1.0 
println(x.toInt) 

Si certains sont des nombres entiers et certains ne sont pas, vous avez besoin d'un peu plus de code:

def fmt[T <% math.ScalaNumericConversions](n : T) = 
        if(n.toInt == n) n.toInt.toString else n.toString 

val a : Double = 1.0 
val b : Double = 1.5 
val c : Int = 1 

println(fmt(a)) 
println(fmt(b)) 
println(fmt(c)) 

le code ci-dessus doit imprimer:

1 
1.5 
1 

la signature de la méthode fmt accepte tout type que ce soit est un sous-type de ScalaNumericConversions ou peut être converti en un grâce à des conversions implicites (nous pouvons donc utiliser la méthode toInt).

2

A partir de Scala 2.10, vous pouvez utiliser the f interpolator:

scala> val x: Double = 1 
x: Double = 1.0 

scala> println(f"$x%.0f") 
1 

scala> val i = 1 
i: Int = 1 

scala> println(f"$i%.0f") 
1 
Questions connexes