在Visual Studio 2010 math.h中不存在rint并且等效于CUDA rint

Jac*_*ern 3 c++ cuda visual-studio-2010

我正在将CUDA代码移植到C++并使用Visual Studio 2010.CUDA代码使用的rint函数似乎不存在于Visual Studio 2010 math.h中,因此我似乎需要自己实现它.

根据这个链接,CUDA rint功能

将x舍入到浮点格式的最接近的整数值,中间的情况舍入为零.

我想我可以使用int丢弃小数部分的转换,有效地向零舍入,所以我最终得到了以下函数

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

它有两种不同的铸件,一对一int和一对double.

我有三个问题:

  1. rint对于"小"数字,上述功能是否完全等同于CUDA ?对于无法表示为"大"的数字,它会失败int吗?
  2. 是否有更多计算有效的方法(而不是使用两个铸件)定义rint

非常感谢你提前.

nju*_*ffa 10

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
Run Code Online (Sandbox Code Playgroud)

通常,这些功能的工作方式与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
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

请注意,MSVC 2010似乎也缺少标准的copysign()函数,因此我不得不替换_copysign().上面的代码假定当前的舍入模式是舍入到最近的偶数(默认情况下是这样).通过添加2**52,可确保在整数单位处进行舍入.注意,这也假设执行纯双精度计算.在对中间结果使用更高精度的平台上,可能需要将'fa'和'r'声明为volatile.