4

CUDAコードをC++に移植し、Visual Studio 2010を使用しています。CUDAコードはrint、Visual Studio 2010 math.hには存在しないように見える関数を使用しているため、自分で実装する必要があるようです。

このリンクによると、CUDArint機能

xを浮動小数点形式の最も近い整数値に丸め、途中の場合はゼロに丸めます。

int小数部を捨てる鋳造を使って、実質的にゼロに丸めることができると思うので、次の関数になりました。

inline double rint(double x)
{
    int temp; temp = (x >= 0. ? (int)(x + 0.5) : (int)(x - 0.5));
    return (double)temp;
}

これには2つの異なるキャストがあります。1つはtointで、もう1つはtodoubleです。

私は3つの質問があります:

  1. rint上記の関数は、 「小さい」数のCUDAと完全に同等ですか?として表現できない「大きな」数では失敗しintますか?
  2. (2つのキャストを使用するのではなく)計算上効率的な定義方法はありrintますか?

事前にどうもありがとうございました。

4

1 に答える 1

11

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」を揮発性として宣言する必要がある場合があります。

于 2013-02-17T23:48:47.267 に答える