CUDA ドキュメントで引用されている rint() の説明は正しくありません。浮動小数点結果による整数への丸めは、IEEE-754 (2008) で指定された丸めモードを次のようにマップします。
trunc() // round towards zero
floor() // round down (towards negative infinity)
ceil() // round up (towards positive infinity)
rint() // round to nearest or even (i.e. ties are rounded to even)
round() // round to nearest, ties away from zero
通常、これらの関数は C99 標準で説明されているとおりに機能します。rint() の場合、標準では、現在の丸めモードに従って関数が丸められることが指定されています (デフォルトでは、最も近いまたは偶数に丸められます)。CUDA は動的な丸めモードをサポートしていないため、現在の丸めモードを使用するように定義されているすべての関数は、「最も近いまたは偶数に丸める」丸めモードを使用します。round() と rint() の違いを示す例を次に示します。
argument rint() round()
1.5 2.0 2.0
2.5 2.0 3.0
3.5 4.0 4.0
4.5 4.0 5.0
round() は、投稿したコードの行に沿ってかなり簡単にエミュレートできますが、rint() の単純なエミュレーションについては知りません。「int」は、「double」で正確に表現できる整数よりも狭い数値範囲をサポートするため、整数への中間キャストを使用したくないことに注意してください。代わりに、trunc()、ceil()、floor() を適宜使用してください。
rint() は現在の C および C++ 標準の一部であるため、MSVC にこの関数が含まれていないことに少し驚いています。MSDN をチェックして、代替品が提供されているかどうかを確認することをお勧めします。プラットフォームが SSE4 に対応している場合は、丸めモードを に設定して、 で_mm_round_sd(), _mm_round_pd()
定義されている SSE 組み込み関数を使用して、CUDA の rint() の機能を実装できます。smmintrin.h
_MM_FROUND_TO_NEAREST_INT
(私の経験では) SSE 組み込み関数は Windows、Linux、および Mac OS X 間で移植可能ですが、ハードウェア固有のコードは避けた方がよいかもしれません。この場合、次のコードを試すことができます (軽くテストされています)。
double my_rint(double a)
{
const double two_to_52 = 4.5035996273704960e+15;
double fa = fabs(a);
double r = two_to_52 + fa;
if (fa >= two_to_52) {
r = a;
} else {
r = r - two_to_52;
r = _copysign(r, a);
}
return r;
}
MSVC 2010 には標準の copysign() 関数もないように見えるので、_copysign() に置き換える必要があることに注意してください。上記のコードは、現在の丸めモードが最も近い偶数への丸め (デフォルト) であることを前提としています。2**52 を追加することで、整数単位のビットで丸めが確実に行われます。これも、純粋な倍精度計算が実行されることを前提としていることに注意してください。中間結果に高い精度を使用するプラットフォームでは、「fa」と「r」を揮発性として宣言する必要がある場合があります。