Scala整型溢出

Scala整型溢出,scala,Scala,任何人都可以帮助我理解为什么Int型溢出结果与更高的数字不一致。有时是正的,有时是负的,最后收敛到零 import scala.annotation.tailrec object FactorialExample { def main(args: Array[String]): Unit = { (1 to 100).foreach(i => println(s"Factorial of ${i} is " + factorial(i))) } def facto

任何人都可以帮助我理解为什么Int型溢出结果与更高的数字不一致。有时是正的,有时是负的,最后收敛到零

import scala.annotation.tailrec

object FactorialExample {

  def main(args: Array[String]): Unit = {
    (1 to 100).foreach(i => println(s"Factorial of ${i} is " + factorial(i)))
  }

  def factorial(i: Int): Int = {
    @tailrec
    def fact(i: Int, acc: Int): Int = {
      if (i <= 0) acc
      else fact(i - 1, acc * i)
    }
    fact(i, 1)
  }
}
import scala.annotation.tailrec
对象分解示例{
def main(参数:数组[字符串]):单位={
foreach(i=>println(s“Factorial of${i}是”+Factorial(i)))
}
def阶乘(i:Int):Int={
@泰勒克
定义事实(i:Int,acc:Int):Int={
如果(i)
为什么Int型溢出结果与较大的数字不一致。有时为正,有时为负,最后收敛到零

import scala.annotation.tailrec

object FactorialExample {

  def main(args: Array[String]): Unit = {
    (1 to 100).foreach(i => println(s"Factorial of ${i} is " + factorial(i)))
  }

  def factorial(i: Int): Int = {
    @tailrec
    def fact(i: Int, acc: Int): Int = {
      if (i <= 0) acc
      else fact(i - 1, acc * i)
    }
    fact(i, 1)
  }
}
这就是溢出int类型的行为。您可以在(例如)或上阅读更多内容。您有具体问题吗


我确实理解它的溢出情况,但我的问题是,一旦溢出情况出现,编译器应该抛出一个数字,用户应该知道它是垃圾,并且需要使用其他数据类型


正如其他人指出的那样,Scala和Java默认情况下不会对整数值执行溢出检查。(我同意,悄悄溢出值可能会导致意外和不必要的行为,以及许多非常微妙的错误。)但是,所有这些都不会丢失。
Java.lang.Math
有静态方法(
addExact
incrementExact
multiplyExact
subtractExact
,等等),如果计算溢出基础类型,将引发
算术异常。例如:

scala>def阶乘(n:Int):Int={
|if(n阶乘(12)
res0:Int=479001600
scala>阶乘(13)
java.lang.arithmetricException:整数溢出
在java.lang.Math.multiplyExact(Math.java:867)
阶乘(:13)
…28删去
此版本不是尾部递归的,抛出异常违反了函数式编程原则(更好的方法是返回一个封装可能错误的类型,例如
Try[Int]
或[Throwable,Int]
),但它将检测并报告
Int
类型的溢出。有关详细信息,请参阅

例如,这里有一个不会耗尽堆栈的功能版本:

scala>导入scala.annotation.tailrec
导入scala.annotation.tailrec
scala>导入scala.util.Try
导入scala.util.Try
scala>def阶乘(n:Int):尝试[Int]={
|@tailrec
|定义事实(i:Int,acc:Int):Int={
|if(i)阶乘(12)
res0:scala.util.Try[Int]=Success(479001600)
scala>阶乘(13)
res1:scala.util.Try[Int]=失败(java.lang.arithmetricException:整数溢出)
关于溢出值:您可以认为这些结果实际上是随机的。这是只保留溢出结果最右边的32位(
Int
类型的容量)的结果。如果设置了最高有效位,则该值将被视为负值。(正如其他人所指出的,有关如何解释
Int
位模式的更详细说明,请参阅。)虽然这取决于您正在执行的计算,但在一般情况下,结果不会收敛于零

例如,
factorial(13)
是导致
Int
溢出的最低参数值。如果不使用
Math.multiplyExact
,原始函数将返回值
1932053504
,这显然不是错误的。不幸的是,如果我们使用
Long
而不是
Int
,我们可以精确地按照
622计算此结果7020800
。但让我们看看这些数字的二进制表示形式:

scala>1932053504.toBinaryString
res0:String=111001100101000110000000000
scala>6227020800L.toBinaryString
res1:String=1011100101000110000000000

最右边的32位具有相同的值!(请注意,前导零被省略。)但是,
Long
表示有一个加法位,它不能存储在
Int
表示中,这就产生了所有的差异。不幸的是,递归算法(
n!=n*(n-1)!
)这意味着一旦我们得到溢出,这些错误就会变得复杂,这意味着,对于大于13的参数值,我们开始乘以溢出值,导致总垃圾,并进一步破坏溢出值中的任何模式。特别是,一旦阶乘计算为零,所有后续值显然也将为零。

Int
是这样的,我确实理解它的溢出情况,但我的问题是,一旦溢出情况出现在图片中,编译器应该抛出一个数字,用户应该知道它是垃圾,并且需要使用其他数据类型。实际上,整数溢出不是垃圾,它是一个在安全性中经常使用的特性。“我确实理解它的溢出情况是“完美的”。我的问题是一旦溢出情况出现在图片中,编译器应该抛出一个数字”这不是一个问题,这是你的观点,这没有多大意义(抛出一个数字是什么意思?)如果你想问为什么整数溢出不会导致异常,那就这么问吧。回答得好。你显然比我写我的:-)@Rich时更有耐心。谢谢!但有时更简洁的回答会起作用…;-)