OpenCL C 中的 pown() 和 pow() 有什么区别?
pown(x, n) 用于计算整数次幂,指数参数是 int;pow(x, y) 的指数参数是浮点类型,可以是整数值,也可以是非整数值。
数学上,pown() 计算的是整数指数的幂。但在程序中,不能直接将它替换为 pow(x, (float)n):类型转换可能改变指数,而且两个函数不保证返回逐位相同的浮点结果。
参数类型有什么区别?
以单精度标量版本为例:
float pow(float x, float y);
float pown(float x, int n);
| 调用 | 计算含义 |
|---|---|
pow(4.0f, 0.5f) | (4^{0.5}) |
pow(4.0f, 3.0f) | (4^3) |
pown(4.0f, 3) | (4^3) |
pown(4.0f, -2) | (4^{-2}) |
pown() 支持负整数指数,返回值仍是浮点数。向量版本按分量计算,例如 pown(float4, int4)。OpenCL 数学函数参考
pow() 也能处理负底数
对于有限负底数,只要 pow() 的浮点指数是整数值,就可以计算相应的实数幂;指数为非整数时,规范通常要求返回 NaN。
以下示例可放在 OpenCL C kernel 或函数体内,注释给出了数学结果:
float a = pow(-2.0f, 3.0f); // (-2)^3 = -8
float b = pown(-2.0f, 3); // (-2)^3 = -8
float c = pown(-2.0f, -3); // (-2)^(-3) = -0.125
float d = pow(-2.0f, 0.5f); // NaN:没有对应的实数结果
因此,pow() 遇到负底数时是否返回 NaN,要看指数的数值是否为整数。即使指数的类型是 float,它的值也可以是整数。OpenCL C 规范:边界行为
为什么不能直接把整数转成 float?
单精度 float 能精确表示区间 ([-2^{24}, 2^{24}]) 内的所有整数。超出这个范围后,一些整数会在转换时丢失精度,甚至改变奇偶性。
例如:
int n = 16777217; // 2^24 + 1,奇数
float y = convert_float_rte(n); // 舍入为 16777216,偶数
float a = pown(-1.0f, n); // 数学结果为 -1
float b = pow(-1.0f, y); // 数学结果为 +1
这里用 convert_float_rte() 显式指定向最近偶数舍入。调用 pow() 之前,指数就已经从奇数变成了偶数。pown() 直接接收 int,保留了原整数的值和奇偶性。
如果整数指数能被对应的浮点类型精确表示,两者计算的数学值相同,但仍可能因实现和舍入而得到不同的浮点近似结果。
实际使用时怎么选?
指数本来就是 int,且需要计算整数次幂时,直接使用 pown();指数允许小数时,使用 pow()。不要为了调用 pown() 随意将浮点指数强制转换为 int,因为这会截去小数部分,改变运算含义。
性能、精度和实现方式还需要分别考虑:
- 规范指出,某些实现上的
pown()可能比pow()快,具体性能需要在目标设备上测量。 pown()不保证更准确。例如,普通单精度版本中,两者的规范误差上限均为≤ 16 ulp。- 规范没有要求
pown()必须使用连续乘法或平方求幂,也没有要求pow()必须通过exp()和log()实现。
使用时,应根据实际的浮点类型和编译选项核对精度要求及边界行为。启用 -cl-fast-relaxed-math 等放宽数学要求的选项后,不能直接套用普通模式下的全部保证。OpenCL C 规范
备注:内容仅供参考。
