2011-12-20 13 views
24

Por favor escriba en esta.en Scala, largo, int, etc.

scala> 86400000 * 150 
res0: Int = 75098112 


scala> val i : Long = 86400000 * 150 
i: Long = 75098112 


val i = 86400000 * 150.asInstanceOf[Long] 
i: Long = 12960000000 

val i = 86400000 * 150L 
i: Long = 12960000000 

Lo que en el mundo está pasando aquí? He estado haciendo paracaidismo y debo decir que esto es lo más peligroso que he visto en mi vida. ¿No hay un compilador que compruebe esto? Obviamente si estuviera sustituyendo 150 por una variable que es diferente.

* * EDITAR

Este era el código real que me tiene preocupado.

val oneDay = 86400000 
val days150 = oneDay * 150 

days150 = 75098112 

Esto no fue culpa de Scala o de cualquier persona, excepto la mía. Me tienes preocupado.

+13

No vota esta pregunta hacia abajo. Es una pregunta legítima y el desbordamiento de enteros es muy peligroso y causa problemas reales con programas reales. El hecho de que sea común en muchos idiomas y no solo en Scala no lo hace ir abajo, merece la pena votar. –

+1

Cuando realmente necesitas números realmente grandes, siempre hay [BigInteger] (http://docs.oracle.com/javase/1.5.0/docs/api/java/math/BigInteger.html). Es un poco torpe, pero funciona. –

+1

Votado para cerrar; esto es más una farsa que una pregunta. Los diversos ejemplos ilustran que el interlocutor ya sabe exactamente lo que está sucediendo: desbordamiento de enteros. –

Respuesta

15

No hay nada específico de Scala sobre esto. Es solo una cuestión de que el tipo de destino de la asignación sea irrelevante para el tipo en el que se realiza una operación (multiplicación en este caso).

Por ejemplo, en C#:

using System; 

class Program 
{ 
    static void Main(string[] args) 
    { 
     int a = unchecked(86400000 * 150); 
     long b = unchecked(86400000 * 150); 
     long c = 86400000 * (long) 150; 
     long d = 86400000 * 150L; 
     Console.WriteLine(a); // 75098112 
     Console.WriteLine(b); // 75098112 
     Console.WriteLine(c); // 12960000000 
     Console.WriteLine(d); // 12960000000 
    } 
} 

La parte unchecked aquí es porque el compilador de C# es lo suficientemente inteligente como para darse cuenta de que los desbordamientos de operación, pero sólo porque ambos operandos son constantes. Si cualquiera de los operandos hubiera sido una variable, hubiera estado bien sin unchecked.

mismo modo en Java:

public class Program 
{ 
    public static void main(String[] args) 
    { 
     int a = 86400000 * 150; 
     long b = 86400000 * 150; 
     long c = 86400000 * (long) 150; 
     long d = 86400000 * 150L; 
     System.out.println(a); // 75098112 
     System.out.println(b); // 75098112 
     System.out.println(c); // 12960000000 
     System.out.println(d); // 12960000000 
    } 
} 
+0

Gracias por esto. Nunca me he dado cuenta de este problema con Java por alguna razón. –

+3

Culpa C. Tanto Scala como C# copiaron sus reglas enteras de tamaño fijo de Java y Java, básicamente, copiaron sus reglas de C++, que a su vez las clonó de C. –

+4

, que a su vez las obtuvo de FORTRAN, que las obtuvo de ASM. Triste.Estamos en una profesión que no existía cuando nació mi padre y somos como académicos talmúdicos analizando textos antiguos. – Malvolio

0

Es obvio que no hay conversión implícita pasando. 86400000 * 150 es visto como int * int por Imagino el jvm. Se calcula luego se asigna a cualquier tipo de variable u deseo que no hace diferencia. Entonces, lo correcto es asegurarse de que al menos uno de los números o variables se genere como un tipo largo, 86400000 * 150.toLong. El jvm aparece de forma predeterminada en el tipo más grande.

Por cierto, creo que una verificación de desbordamiento en el extremo de Scala solo paralizaría el rendimiento. Por lo tanto, la omisión de la conversión de tipo automática introduce riesgos pero permite un mejor rendimiento. Solo tienes que tener cuidado ..., que debería ser algo natural si vienes de una copia de seguridad c/C++.

Cuestiones relacionadas