C# Mersenne Twister 随机整数生成器实现 (SFMT) 蒙特卡罗模拟
Posted
技术标签:
【中文标题】C# Mersenne Twister 随机整数生成器实现 (SFMT) 蒙特卡罗模拟【英文标题】:C# Mersenne Twister random integer generator implementation (SFMT) monte carlo simulation 【发布时间】:2010-11-13 01:51:29 【问题描述】:到目前为止,我一直在使用此处找到的 C# Mersenne Twister 来生成随机数:
http://www.centerspace.net/resources.php
我刚刚发现 SFMT 应该是这里的两倍:
http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/
谁能指出我的 SFMT 的 C# 实现?
我的要求是生成一个介于(包括)0 和 2^20 (1048576) 之间的整数。
为了在 24 小时制上运行的模拟,我需要每天进行数万亿次,因此我准备花几天时间将其调整到完美。
目前,我通过添加一种新方法来调整 Center Space Mersenne Twister 以满足我的要求:
public uint Next20()
return (uint)(genrand_int32() >> 12);
使用方法genrand_int32()
我想生成我自己的版本genrand_int20()
,它生成一个介于(包括)0 和 2^20 之间的整数,以节省 上面的转换和移位 但我不懂数学。我该怎么做呢?
还使用 uint 会比 int 更快,还是只是可寻址数字的问题?因为我最多只需要1048576,所以我只关心速度。
这也将在带有 .NET 2 的 Windows Server 2003 R2 SP2(32 位)机器上运行。处理器为 AMD Opteron 275(4 核)。
【问题讨论】:
一个 20 位的数字代表 0 到 2^20-1 的范围,2^20 需要 21 位来表示(1 后跟 20 个零) Nifle:不要将生成器的周期(即序列的长度)与您希望随机的间隔混淆数字。 @Patrick 谢谢你是正确的 2^20-1 是我需要的,我需要随机索引到长度为 2^20 的数组中。 @Nifle 是的,我知道,我问是否有人可以指出我的 SFMT 的 C# 实现。 【参考方案1】:您可以下载您在 Code Project 中发现的 source from the link。解压缩,在 Visual Studio 中加载解决方案并进行编译。这将为您提供源代码、非托管 c dll 和 .lib 文件。
你可以 P/Invoke 这个 dll 中的函数,(只导出了 5 个简单的函数,你只需要其中两个)或者你可以使用这个 dll、lib 和 SFMT 头文件来创建一个托管包装 dll您可以在没有 P/Invoke 的情况下在 C# 中使用。我刚试过这个方法,做起来很简单。没有涉及明确的编组。
方法如下。一旦您下载并编译了 source(除了 dll,您还需要头文件和创建的 lib 文件)创建一个新的 C++ CLR 类库项目。称之为 WrapSFMT 什么的。转到项目属性。在 C++/Precompiled Headers 下,更改为“Not using precompiled headers”。在 Linker/General/Additional Library Directories 下,输入 SFMT.lib 的路径。在链接器/输入/附加依赖项下,添加 SFMT.lib。关闭属性页。将 SFMT.h 复制到您的项目文件夹并将其包含在项目中。
编辑 WrapSFMT.h 如下:
#pragma once
#include "SFMT.H"
using namespace System;
namespace WrapSFMT
public ref class SRandom
public:SRandom(UInt32);
public:UInt32 Rand32(void);
;
这些声明将在您的类中的方法。现在编辑 WrapSFMT.cpp 以阅读:
#include "WrapSFMT.h"
namespace WrapSFMT
SRandom::SRandom(UInt32 seed)
init_gen_rand(seed);
UInt32 SRandom::Rand32()
return gen_rand32();
这些实现了你在头文件中声明的方法。您所做的只是从 SFMT.dll 调用函数,而 C++/CLI 会自动处理从非托管到托管的转换。现在您应该能够构建 WrapSFMT.dll 并在您的 C# 项目中引用它。确保 SFMT.dll 在路径中,您应该没有问题。
【讨论】:
我下载了他的 DLL 并尝试将它们添加为我的 C# 项目的引用,我得到:------------ --- Microsoft Visual Studio --------------- 无法添加对“SFMTc.dll”的引用。请确保该文件是可访问的,并且它是一个有效的程序集或 COM 组件。 - - - - - - - - - - - - - - 好的 - - - - - - - - - - - - - - 有任何想法吗?关于如何使用它并以最有效的方式从 Visual Studio 调用它 好的,我已经将 DLL 放在我的 bin 文件夹中,并且有代码: [DllImport("SFMTc.dll")] static extern UInt32 gen_rand32();这个调用没有错误,但我得到的只是 0,没有任何其他数字。 如果你想使用P/Invoke,你需要调用两个函数,init_gen_rand(UInt32),用种子初始化生成器,然后你可以随意调用gen_rand32() . (但你可能不应该超过梅森捻线器的时期) 对于您的第一条评论,如果您想在 C# 项目中引用 dll 并避免 P/Invoke,则需要使用 C++/CLI 创建一个包装 dll 并引用它。这并不难。我将编辑答案,向您展示如何操作。 真棒@R Ubben 正是我正在寻找的,我正在尝试 DllImport 路线,这可能会更快?另外,我最好的播种方法是什么?以及如何为多线程代码播种?或者我可以在启动线程之前在程序的整个生命周期内只初始化一次,然后每个独立线程都可以调用 gen_rand32() ,前提是调用 gen_rand32() 是线程安全的?否则我看不出如何将其分开并有效地为每个线程提供它自己的随机数生成器,以便它们是独立的?【参考方案2】:您可以在以下位置找到 SFMT(以及其他 RNG 算法)的 C# 实现... http://rei.to/random.html 页面和源代码cmet都是日文的,但是你应该能看出来。
您还可以在以下位置找到该页面的 Google 翻译版本(英文)... http://translate.google.com/translate?hl=en&sl=ja&u=http://rei.to/random.html
【讨论】:
【参考方案3】:我并没有真正看到您的速度问题。在我的机器(Core 2 Duo T7200 @ 2 GHz)上,使用 MT19937 或 MT19937-64 生成随机整数大约需要 20 ns(平均而言,绘制 50000 个数字时)。所以这将是每天大约 4,32 × 1012 (大约 4 万亿 个数字)。这是一个核心。用Java。因此,我认为您可以期望性能足以满足您的需求。
要实际回答您的问题:我不知道 SFMT 的 C# 实现,但是将 C 代码转换为 C# 应该相当简单。但是,您并没有获得太多收益,因为 SFMT 针对 SIMD 进行了优化,而 C# 目前不直接支持这一点。
【讨论】:
我计算了此模拟的每日随机数需求,以支持 1,645,668,000,000 的业务。模拟做了很多其他的事情,主要是矩阵乘法,所以我不能把所有的 CPU 时间都花在随机数生成上,显然我想尽可能地减少每个随机数生成,因此 *** 问题。 嗯,你仍然有多个内核,蒙特卡罗模拟往往是相当可并行化的。我想说你应该先解决你的问题,如果它们被证明是性能问题,则重新审视解决方案的各个部分。 对于 SFMT,我没有意识到,也许我最好的方法是尝试在这里编译 c 版本:math.sci.hiroshima-u.ac.jp/~m-mat/bin/dl/…,然后以某种方式从我的 C# 蒙特卡罗模拟中使用它。我不熟悉 c/c++ 如何编译他们的 src 以及如何在 C# 中使用它。 感谢@Johannes,我的实现可以使用 3 个内核(盒子上的 4 个)所以是的,即使到那时它也将是一个并行实现(以 3 倍的胜利)我已经接近达到应用程序中每天 24 小时的执行时间限制。我已经申请了更新的服务器、更多的 cpu 等,但是这家银行的工作速度非常缓慢,现在我被要求进行优化。 听起来你可以使用 Quake 优化规则的一个很好的例子。【参考方案4】:您是否有不能将 C 实现编译成 DLL 并从您的 C# 代码中调用它的原因?
编辑:
对不起,我对 C(实际上是 C#)的了解非常有限,但是“如何创建 C dll”可以在这里回答:http://www.kapilik.com/2007/09/17/how-to-create-a-simple-win32-dll-using-visual-c-2005/ 以及可以检查多快分析代码。
【讨论】:
嗨帕特里克,我从未使用过 c,不知道该怎么做?并从 C# 中使用,我是否可能会因为我假设 .net 将我的调用从 C# 到底层 c DLL 的一些包装而失去很多性能优势? 我猜 P/Invoke 重复进入非托管代码确实会产生相当大的性能开销。 我刚刚发现了这个:codeproject.com/KB/DLL/SFMT_dll.aspx?msg=3130186 我想知道它是否对我的情况有用 我还注意到这里底部有一个 F# 实现 en.wikipedia.org/wiki/Mersenne_twister 不知道如何使用 F#,但可能值得学习和基准测试。 好吧,F# 和 C# 都以 CLR 为目标,我希望 F# 代码实际上比 C# 慢。但是,您始终可以使用 Reflector 查看生成的代码。【参考方案5】:也许this 是您要找的? 有几个实现的列表。
具体来说,this one(由 Cory Nelson 撰写)可能有用。
【讨论】:
以上是关于C# Mersenne Twister 随机整数生成器实现 (SFMT) 蒙特卡罗模拟的主要内容,如果未能解决你的问题,请参考以下文章
伪随机数生成算法-梅森旋转(Mersenne Twister/MT)
CUDA 的 Mersenne Twister 用于任意数量的线程
Mersenne Twister 与 Mersenne Twister 64 位