実行時にマネージコードがコールバックする(アンマネージド)アセンブリコードを生成するSOがあります。それは非常に興味深いですが、私は、この目的のために単純にC++/CLIを使用することを提案します。これは、interopシナリオを単純化するために設計されたものです。新しいVisual C++ CLRのクラスライブラリを作成し、それを単一rdrandwrapper.cpp
を与える:
#include <immintrin.h>
using namespace System;
namespace RdRandWrapper {
#pragma managed(push, off)
bool getRdRand(unsigned int* pv) {
const int max_rdrand_tries = 10;
for (int i = 0; i < max_rdrand_tries; ++i) {
if (_rdrand32_step(pv)) return true;
}
return false;
}
#pragma managed(pop)
public ref class RandomGeneratorError : Exception
{
public:
RandomGeneratorError() : Exception() {}
RandomGeneratorError(String^ message) : Exception(message) {}
};
public ref class RdRandom
{
public:
int Next() {
unsigned int v;
if (!getRdRand(&v)) {
throw gcnew RandomGeneratorError("Failed to get hardware RNG number.");
}
return v & 0x7fffffff;
}
};
}
これは単に1つの非負整数の乱数を得ることにRandom.Next
を模倣しようとすると非常に最低限の実装です。質問では、RDRAND
がCPU上で実際に利用可能であることを検証しようとはしませんが、命令が存在しても動作しない場合を処理します。 (これが壊れていない限り、現在のハードウェアでは発生しません。詳細はhere)
結果のアセンブリは、管理対象のC#コードで使用できる混合アセンブリです。アセンブリされていないコードには特定のビットが1つしかないため、正しく動作しません。デフォルトでは、プロジェクトは「Any CPU」としてコンパイルされるように設定されています。
using System;
using RdRandWrapper;
class Program {
static void Main(string[] args) {
var r = new RdRandom();
for (int i = 0; i != 10; ++i) {
Console.WriteLine(r.Next());
}
}
}
私はパフォーマンスについての主張はしていませんが、おそらくそれほど大きくはありません。このように多くのランダムな値を取得したい場合は、interopのオーバーヘッドを減らすために、1回の呼び出しで多数のランダムな値を取得するために、オーバーロードをNext(int[] values)
にすることをお勧めします。
['RNGCryptoServiceProvider'](https://msdn.microsoft.com/library/system.security.cryptography.rngcryptoserviceprovider)を使用するだけで十分です。これは、擬似乱数よりも優れている必要があるほとんどの目的に適しています。 –
@JeroenMostertご意見ありがとうございます。しかし、科学的に正確なソフトウェア実験の目的に合うように、本当にランダムになることが本当に必要です。私はTrueRNGV3を注文しましたが、到着するには時間がかかりすぎ、その間に代替案を探していましたが、RDRANDは有望です。 –
C#でプロセッサ固有のアセンブリを実行することはできません。 C++コードを記述し、C++/CLIまたはP/Invokeを使用してラップすることができます(ここではhttps://stackoverflow.com/questions/13436130/)。 –