2011-12-20 4 views
24

Пожалуйста, введите это.типы в Scala, Long, Int и т.д.

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 

Что в мире происходит? Я прыгал с парашютом, и я должен сказать, что это самая опасная вещь, которую я когда-либо видел. Нет компилятора для этого? Очевидно, если бы я заменил 150 для переменной, которая отличается.

* EDIT *

Это фактический код, который получил меня беспокоит.

val oneDay = 86400000 
val days150 = oneDay * 150 

days150 = 75098112 

Это не было ошибкой Scala или любой виной, кроме моей собственной. Меня только что волновало.

+13

Пожалуйста, не голосуйте этот вопрос. Это законный вопрос, и целочисленное переполнение очень опасно и вызывает реальные проблемы с реальными программами. Тот факт, что он распространен на многих языках, а не только на Scala, не делает его нисходящим голосованием. –

+1

Когда вам действительно нужны действительно большие цифры, всегда есть [BigInteger] (http://docs.oracle.com/javase/1.5.0/docs/api/java/math/BigInteger.html). Это немного неуклюже, но это работает. –

+1

Проголосовало за закрытие; это скорее напыщенная речь, чем вопрос. Различные примеры иллюстрируют, что вопросник уже точно знает, что происходит: целочисленное переполнение. –

ответ

15

В этом нет ничего особенного в Scala. Дело в том, что целевой тип присваивания не имеет отношения к типу, в котором выполняется операция (умножение в этом случае).

Например, в 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 
    } 
} 

unchecked часть здесь потому, что C# компилятор достаточно умен, чтобы понять, что операция перетоков, но только потому, что оба операнда являются константами. Если бы какой-либо операнд был переменной, это было бы прекрасно без unchecked.

Аналогична в 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

Благодарим за это. Я почему-то не замечал эту проблему с Java. –

+3

Вина C. Оба Scala и C# скопировали свои фиксированные правила целочисленного размера из Java и Java в основном скопировали свои правила из C++, которые в свою очередь клонировали их из C. –

+4

которые, в свою очередь, получили их от FORTRAN, которые получили их от ASM. Грустный.У нас есть профессия, которой не было, когда родился мой отец, и мы похожи на талмудистов, изучающих древние тексты. – Malvolio

0

Очевидно, что нет неявного приведения происходит. 86400000 * 150 рассматривается как int * int Я представляю себе jvm. Затем он вычисляется в соответствии с любым желанием переменной типа u, которое не имеет никакого значения. Поэтому правильная вещь - убедиться, что хотя бы один из чисел или переменных получает отличную форму, 86400000 * 150.toLong. По умолчанию jvm по умолчанию имеет больший тип.

Btw, я считаю, что проверка переполнения на конце Scala будет только калечить производительность. Таким образом, пропуск автоматического преобразования типов вводит риск, но позволяет повысить производительность. Вам просто нужно быть осторожным ..., который должен быть второй натурой, если вы придете из резервной копии c/C++.

Смежные вопросы