游戏人生在F#与加速器
-
21-09-2019 - |
题
我想在F#写寿命使用加速器V2,但对于一些奇怪的原因,我的输出不是正方形,尽管我所有的阵列是正方形的 - 看起来一切,但一个矩形区域左上角的矩阵是被设置为false。我有不知道如何这可能发生因为我所有的操作都应该平等地对待整个数组。任何想法?
open Microsoft.ParallelArrays
open System.Windows.Forms
open System.Drawing
type IPA = IntParallelArray
type BPA = BoolParallelArray
type PAops = ParallelArrays
let RNG = new System.Random()
let size = 1024
let arrinit i = Array2D.init size size (fun x y -> i)
let target = new DX9Target()
let threearr = new IPA(arrinit 3)
let twoarr = new IPA(arrinit 2)
let onearr = new IPA(arrinit 1)
let zeroarr = new IPA(arrinit 0)
let shifts = [|-1;-1|]::[|-1;0|]::[|-1;1|]::[|0;-1|]::[|0;1|]::[|1;-1|]::[|1;0|]::[|1;1|]::[]
let progress (arr:BPA) = let sums = shifts //adds up whether a neighbor is on or not
|> List.fold (fun (state:IPA) t ->PAops.Add(PAops.Cond(PAops.Rotate(arr,t),onearr,zeroarr),state)) zeroarr
PAops.Or(PAops.CompareEqual(sums,threearr),PAops.And(PAops.CompareEqual(sums,twoarr),arr)) //rule for life
let initrandom () = Array2D.init size size (fun x y -> if RNG.NextDouble() > 0.5 then true else false)
type meform () as self=
inherit Form()
let mutable array = new BoolParallelArray(initrandom())
let timer = new System.Timers.Timer(1.0) //redrawing timer
do base.DoubleBuffered <- true
do base.Size <- Size(size,size)
do timer.Elapsed.Add(fun _ -> self.Invalidate())
do timer.Start()
let draw (t:Graphics) =
array <- array |> progress
let bmap = new System.Drawing.Bitmap(size,size)
target.ToArray2D array
|> Array2D.iteri (fun x y t ->
if not t then bmap.SetPixel(x,y,Color.Black))
t.DrawImageUnscaled(bmap,0,0)
do self.Paint.Add(fun t -> draw t.Graphics)
do Application.Run(new meform())
解决方案
正如罗伯特提到的,我写了一篇文章,介绍如何实现生命的博弈F#使用加速器V2,所以你可以看一看,对于一个工作版本。我记得有类似的问题,但我不完全在什么情况下知道的。
无论如何,如果你正在使用DX9Target
那么问题可能是,这个目标是不应该支持业务与整数(因为模拟GPU的整数算术恰恰是不使用DX9可能)。我认为,这也是一个原因,我结束了我在执行使用FloatParallelArray
。你有没有机会尝试X64MulticoreTarget
来看看是否能够正常工作?
修改:我做了一些进一步的调查和(除非我失去了一些重要的东西),这似乎是与CompareEqual
方法的错误。这里是一个非常简单的例子,显示了问题:
open Microsoft.ParallelArrays
let target = new DX9Target()
let zeros = new IntParallelArray(Array2D.create 4 4 0)
let trues = target.ToArray2D(ParallelArrays.CompareEqual(zeros, zeros))
trues |> Array2D.iter (printfn "%A")
预期的结果将是true
(几次),但是如果运行它,它打印true
只有4次,然后打印12次false
。我会从加速器团队问问别人并张贴在这里的答案。在此期间,你可以做同样的事情,我在我的例子做了 - 也就是说,模拟使用FPA
并避免使用BPA
和CompareEqual
布尔运算
修改2 强>:下面是从加速器团队成员的答复:
这是关系到缺乏DX9 GPU的精确整数计算。因为数值抖动的,与自身的整数的布尔比较并不总是计算为完全相等。 (...)
所以,总的来说,你不能真正依靠BPA
。唯一的选择就是做我的建议 - 用FPA
模拟布尔值(也可能比较一些小三角附近的数以避免因GPU的抖动)。这shoudl但是与X86MulticoreTarget
工作 - 如果你能找到一些最起码的摄制是示出在情形库崩溃,那将是非常有用的。
其他提示
关于精度问题:DX9级的GPU没有专用整数硬件,所以整流被解释为浮点流(与缺乏精确度,你见过)
DX10级的GPU不现在支持与所有的C位运算精确的32位整数。但是,这并不一定意味着他们拥有真正的32位整数ALU的。例如在当前DX10 NVIDIA根整数运算与24位整数单元完成的,从而32位整数OPS被模仿。下一代DX11 NVIDIA会带来真正的32位整数单元。