为什么会导致溢出错误? (SML)

时间:2018-05-01 21:10:59

标签: sml smlnj

此代码产生溢出错误,我不完全确定原因。这是SML,我现在对此有些不熟悉,所以我不完全确定如何解决它。

fun detPrime(num:int, divn:int) =
    if divn = num
    then true
    else if num mod divn = 0
         then false
         else detPrime(num, divn+1);

fun prime(num: int) = 
    detPrime(num, 2);

fun goldbachHelp(num1: int, num2: int) = 
    if num2 > num1
    then []
    else if prime(num2) = true andalso prime(num1) = true
         then num2::num1::[]
         else goldbachHelp(num1-1, num2+1);

fun goldbach(num: int) = 
    if num mod 2 = 1
    then []
    else goldbachHelp(num, 0);

goldbach(100);

1 个答案:

答案 0 :(得分:1)

  

为什么会导致溢出错误?

更重要的是,你怎么知道的?

溢出意味着整数超出Int.minIntInt.maxInt的范围。你所做的就是在不同的地方增加和减少一个。所以不知何故应该最终终止这些增量和减量的条件。我稍微修改了您的代码并在其中插入了一些打印语句:

fun detPrime (num, divn) =
    num = divn orelse
    num mod divn <> 0 andalso
    detPrime (num, divn+1)

fun isPrime num =
    ( print ("isPrime(" ^ Int.toString num ^ ")\n")
    ; detPrime (num, 2)
    )

fun goldbachHelp (num1, num2) =
    ( print ("goldbachHelp(" ^ Int.toString num1 ^ ", " ^ Int.toString num2 ^")\n")
    ; if num1 > num2
      then []
      else if isPrime num1 andalso isPrime num2
           then [num2, num1]
           else goldbachHelp(num1+1, num2-1)
    )

fun goldbach num =
    goldbachHelp (0, num)

调用此代码会打印:

- goldbach 100;
goldbachHelp(0, 100)
isPrime(0)
goldbachHelp(1, 99)
isPrime(1)

uncaught exception Overflow [overflow]
  raised at: <file stdIn>

手动评估isPrime 1

isPrime 1 ~> detPrime (1, 2)
          ~> 1 = 2 orelse 1 mod 2 <> 0 andalso detPrime (1, 2+1)
          ~> 1 mod 2 <> 0 andalso detPrime (1, 2+1)
          ~> 1 <> 0 andalso detPrime (1, 2+1)
          ~> detPrime (1, 3)
          ~> 1 = 3 orelse 1 mod 3 <> 0 andalso detPrime (1, 3+1)
          ~> 1 mod 3 <> 0 andalso detPrime (1, 3+1)
          ~> 1 <> 0 andalso detPrime (1, 3+1)
          ~> detPrime (1, 4)
          ~> 1 = 4 orelse 1 mod 4 <> 0 andalso detPrime (1, 4+1)
          ~> 1 mod 4 <> 0 andalso detPrime (1, 4+1)
          ~> 1 <> 0 andalso detPrime (1, 4+1)
          ~> detPrime (1, 5)
          ~> ... you can see where this is going ...

那么即使您可能使用合理的输入(isPrime≥2来测试num,因为根据定义,这是最小的素数),goldbachHelp设法用不合理的方式调用它输入:

goldbach 100 ~> goldbachHelp (0, 100)
             ~> if 0 > 100
                then []
                else if isPrime 0 andalso isPrime 100
                     then [100, 0]
                     else goldbachHelp(0+1, 100-1)
             ~> if isPrime 0 andalso isPrime 100
                then [100, 0]
                else goldbachHelp(0+1, 100-1)
             ~> if detPrime (0, 2) andalso isPrime 100
                then [100, 0]
                else goldbachHelp(0+1, 100-1)
             ~> if 0 = 2 orelse
                   0 mod 2 <> 0 andalso
                   detPrime (0, 3) andalso isPrime 100
                then [100, 0]
                else goldbachHelp(0+1, 100-1)
             ~> if false orelse
                   false andalso
                   detPrime (0, 3) andalso isPrime 100
                then [100, 0]
                else goldbachHelp(0+1, 100-1)
             ~> if false andalso isPrime 100
                then [100, 0]
                else goldbachHelp(0+1, 100-1)
             ~> goldbachHelp(1, 99)
             ~> if 1 > 99
                then []
                else if isPrime 1 andalso isPrime 99
                     then [99, 1]
                     else goldbachHelp(1+1, 99-1)
             ~> if isPrime 1 andalso isPrime 99
                then [99, 1]
                else goldbachHelp(1+1, 99-1)
             ~> ... you can see where this is going ...

顺便提一下,isPrime 0有效,但后续迭代中的isPrime 1并不适用。

当问题难以找到时你可以做的事情:

  • 插入print语句以找到计算偏离的点。

  • 彻底测试您的子组件; isPrime接受 int ;你不希望在任何 int 上调用它,但如果你做了什么呢?而不是测试每个可能的 int divide the domain into equivalence classes and check the boundaries:如果它可以得到的那么小,该怎么办?如果它能够获得的大小怎么办?如果它为零怎么办?如果它刚刚超过零怎么办?如果它低于零怎么办?已知的素数,非素数和各种大小的伪素数。 (顺便说一下,isPrime (~1)也会导致溢出。)

  • 制作isPrime robust

    fun isPrime num =
        num > 1 andalso detPrime (num, 2)