【问题标题】:Random number generate issue in swift language - EXC_BAD_INSTRUCTION快速语言中的随机数生成问题 - EXC_BAD_INSTRUCTION
【发布时间】:2014-08-21 11:41:58
【问题描述】:

我尝试使用随机顺序的字符串生成一个数组,但在函数 randomPile 的末尾总是出现错误“Thread1:EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)”。以下是我的代码:

import UIKit

class RandomView: UIViewController {

override func viewDidLoad() {
    super.viewDidLoad()

    var cardOrder = ["HeartSix","HeartNine", "ClubQueen", "SpadeKing" ]

    // cannot randomlize due to the lanuage drawbacks.
    cardOrder = randomPile(cardOrder)

}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
}

// random the order of the original card pile
func randomPile(arrayPile: String[]) -> String[] {
    var arry = arrayPile
    for( var i = arry.count-1; i > 0; --i){
        var r = Int(arc4random())%(i+1)
        var a = arry[r]
        arry[r] = arry[i]
        arry[i] = a

    }
    return arry
}    
}

【问题讨论】:

  • 你应该使用arc4random_uniform(i+1)来避免模偏差。
  • 试过,但 arc4random_uniform(i+1) 也有错误:“找不到接受提供的参数的 '+' 的重载”。
  • 抱歉,忘了说您需要将参数转换为UInt32
  • 你的问题是 arc4random() 返回 UInt32。在 32 位目标 上——比如 iPhone 4S 模拟器——你将试图将结果填充到一个 有符号 32 位整数中,从而导致崩溃,有时。它可以在游乐场(几乎可以肯定是 64 位)或 64 位模拟器或设备上工作。见stackoverflow.com/questions/24087518/…
  • @MattGibson 所以使用带有 31 位或更少参数的 arc4random_uniform() 应该安全地转换为 Int?除了模偏差问题之外,还有另一个使用它的原因。

标签: xcode swift exc-bad-instruction


【解决方案1】:

也不是答案,因为我也可以在操场上跑步,所以我不知道你的问题出在哪里。但是,不需要创建对数组的新引用并返回它。我还实现了一个 Fisher-Yates shuffle 变体,它适用于排除其上限的整数 PRNG,就像 arc4random_uniform 所做的那样:

func randomPile(myArray: String[]) -> Void {
    for i in 0..(myArray.count - 1) {
        let j = Int(arc4random_uniform(UInt32(myArray.count - i))) + i
        let tmp = myArray[i]
        myArray[i] = myArray[j]
        myArray[j] = tmp
    }
}

let cardOrder: String[] = ["HeartSix","HeartNine", "ClubQueen", "SpadeKing" ]
println(cardOrder)
randomPile(cardOrder)
println(cardOrder)

在你的数组上调用它之后,它会被洗牌,不需要重新分配给cardOrder

附录 - 我刚刚检查过,由于 cardOrder 不再出现在赋值左侧,因此可以使用 let 声明。

您还可以将随机播放功能设为通用,为什么不呢?

func shuffle<T>(myArray: T[]) -> Void {
    for i in 0..(myArray.count - 1) {
        let j = Int(arc4random_uniform(UInt32(myArray.count - i))) + i
        let tmp:T = myArray[i]
        myArray[i] = myArray[j]
        myArray[j] = tmp
    }
}

let cardOrder: String[] = ["HeartSix","HeartNine", "ClubQueen", "SpadeKing"]
println(cardOrder)  // [HeartSix, HeartNine, ClubQueen, SpadeKing]
shuffle(cardOrder)
println(cardOrder)  // sample result: [SpadeKing, HeartNine, HeartSix, ClubQueen]
let intValues = [1,2,3,4,5,6,7,8,9,10]
println(intValues)  // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
shuffle(intValues)
println(intValues)  // sample result: [3, 10, 8, 4, 9, 7, 1, 2, 5, 6]

【讨论】:

  • 关于您的回答还有一个问题:为什么不需要创建新的参考? swift 知道这个函数是用于设置还是获取输入?在我的原始代码中,引用 carOrder 在 func viewDidLoad(); 中声明。它是本地的。
  • 您将数组引用作为参数传递,而不是数组的副本。基于该引用的索引的操作操作原始数组的内容,就像在 C 或 Objective-C 中一样。
  • 哇,我们正在恢复为通过引用返回。多年来,我们一直在努力摆脱这个概念的代码。
  • @Zaph 看起来更像 Java 的对象引用,而不是 C/C++/Objective-C 指针。它们可以是左值,您可以使用[] 进行偏移访问,但它是经过边界检查的。我还没有找到用它们做其他算术的方法。相当良性,并且可以节省复制大量数据的时间。
【解决方案2】:

不是答案,此处显示用于代码形成:

这在操场和应用程序中都适用于我:

var cardOrder: String[] = ["HeartSix","HeartNine", "ClubQueen", "SpadeKing" ]
println(cardOrder)

cardOrder = randomPile(cardOrder)
println(cardOrder)

也许错误在别处。

注意:var r = Int(arc4random_uniform(UInt32(i+1))) 既简单又避免偏见。

【讨论】:

  • 该功能在操场上也适用于我,并且是第一次在这个 UIViewController 中。但是当我再次重新运行它时,会出现错误并且每次它出现在循环的不同循环中。对于实验,我只构建了这个 UIViewController,连接到情节提要中的空白控制器。另外,您的注释也会为我生成一个错误,显示“找不到接受提供的参数的 '+' 的重载”,即使我为它添加了空间。
  • 你一定要爱 Swift 的所有痛苦——好吧,我不喜欢。 (确保使用当前的 arc4random_uniform 示例,我修复了错误,非常糟糕的错误消息,嗯?)
猜你喜欢
  • 1970-01-01
  • 2010-11-05
  • 2012-03-13
  • 1970-01-01
  • 2020-05-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-21
相关资源
最近更新 更多