rint不存在于Visual Studio 2010 math.h和等效的CUDA rint [英] rint not present in Visual Studio 2010 math.h and equivalent of CUDA rint

查看:415
本文介绍了rint不存在于Visual Studio 2010 math.h和等效的CUDA rint的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我将CUDA代码移植到C ++并使用Visual Studio 2010. CUDA代码使用 rint 函数,它似乎不存在于Visual Studio 2010 math.h,所以看起来我需要自己实现它。



根据链接,CUDA rint / p>

以浮点格式将x四舍五入为最接近的整数值,中间的情况向零舍入。



我想我可以使用转换 int ,它舍弃小数部分,有效地向零舍入,所以我结束了以下函数



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

它有两个不同的铸件,一个到 int 和一个到 double



我有三个问题:


  1. 对于小数字,上述函数是否完全等同于CUDA rint ?对于不能被表示为 int
  2. 的$
  3. 使用两个铸件)定义 rint

解决方案

CUDA文档中引用的rint()说明不正确。使用浮点结果舍入到整数结果映射IEEE-754(2008)指定的舍入模式如下:

  trunc / round to zero 
floor()//向下舍入(向负无穷大)
ceil()//向上舍入(向正无穷大)
rint()//舍入到最接近(即关系被四舍五入)
round()// round to closest,tie away from $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ b

通常,这些函数按照C99标准中的描述工作。对于rint(),标准指定函数根据当前舍入模式舍入(默认为round到最近或偶数)。由于CUDA不支持动态舍入模式,因此定义为使用当前舍入模式的所有函数都使用舍入模式round to nearest or even。下面是一些显示round()和rint()之间区别的例子:

  b 1.5 2.0 2.0 
2.5 2.0 3.0
3.5 4.0 4.0
4.5 4.0 5.0


$ b b

round()可以很容易地沿着你发布的代码行仿真,我不知道一个简单的仿真rint()。请注意,你不想使用一个中间转换为整数,因为'int'支持一个更窄的数字范围比完全可以通过'double'表示的整数。而是适当地使用trunc(),ceil(),floor()。



由于rint()是当前C和C ++标准的一部分,我对MSVC不包含此函数感到有点惊讶;我建议检查MSDN,看看是否提供替代。如果您的平台具有SSE4能力,您可以使用 smmintrin.h _mm_round_sd(),_mm_round_pd() >,其中舍入模式设置为 _MM_FROUND_TO_NEAREST_INT ,以实现CUDA的rint()的功能。



在我的经验中),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()函数。所以我不得不替换_copysign()。上述代码假定当前舍入模式是round-to-nearest-even(默认情况下为round-to-nearest-even)。通过添加2 ** 52它确保舍入发生在整数单位位。注意,这也假定执行纯双精度计算。在对中间结果使用较高精度的平台上,可能需要将fa和r声明为volatile。


I'm porting a CUDA code to C++ and using Visual Studio 2010. The CUDA code uses the rint function, which does not seem to be present in the Visual Studio 2010 math.h, so it seems that I need to implement it by myself.

According to this link, the CUDA rint function

rounds x to the nearest integer value in floating-point format, with halfway cases rounded towards zero.

I think I could use the casting to int which discards the fractional part, effectively rounding towards zero, so I ended-up with the following function

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

which has two different castings, one to int and one to double.

I have three questions:

  1. Is the above function fully equivalent to CUDA rint for "small" numbers? Will it fail for "large" numbers that cannot be represented as an int?
  2. Is there any more computationlly efficient way (rather than using two castings) of defining rint?

Thank you very much in advance.

解决方案

The cited description of rint() in the CUDA documentation is incorrect. Roundings to integer with floating-point result map the IEEE-754 (2008) specified rounding modes as follows:

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

Generally, these functions work as described in the C99 standard. For rint(), the standard specifies that the function rounds according to the current rounding mode (which defaults to round to nearest or even). Since CUDA does not support dynamic rounding modes, all functions that are defined to use the current rounding mode use the rounding mode "round to nearest or even". Here are some examples showing the difference between round() and 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() can be emulated fairly easily along the lines of the code you posted, I am not aware of a simple emulation for rint(). Please note that you would not want to use an intermediate cast to integer, as 'int' supports a narrower numeric range than integers that are exactly representable by a 'double'. Instead use trunc(), ceil(), floor() as appropriate.

Since rint() is part of both the current C and C++ standards, I am a bit surprised that MSVC does not include this function; I would suggest checking MSDN to see whether a substitute is offered. If your platforms are SSE4 capable, you could use the SSE intrinsics _mm_round_sd(), _mm_round_pd() defined in smmintrin.h, with the rounding mode set to _MM_FROUND_TO_NEAREST_INT, to implement the functionality of CUDA's rint().

While (in my experience), the SSE intrinsics are portable across Windows, Linux, and Mac OS X, you may want to avoid hardware specific code. In this case, you could try the following code (lightly tested):

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;
}

Note that MSVC 2010 seems to lack the standard copysign() function as well, so I had to substitute _copysign(). The above code assumes that the current rounding mode is round-to-nearest-even (which it is by default). By adding 2**52 it makes sure that rounding occurs at the integer unit bit. Note that this also assumes that pure double-precision computation is performed. On platforms that use some higher precision for intermediate results one might need to declare 'fa' and 'r' as volatile.

这篇关于rint不存在于Visual Studio 2010 math.h和等效的CUDA rint的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆