詳しくは「表:比較関数」(表B.117「表:比較関数」)を参照ください。
比較関数では単純な等号、大小を比べる操作が行なえます。
int any (igentype x)
引数xのどれかの要素の最上位ビットが設定されているときは1、それ以外のときは0を返します。
int all (igentype x)
引数xの全ての要素の最上位ビットが設定されているときは1、それ以外のときは0を返します。
サンプル.
int8 intvec1 = vload8(0, number); int8 intvec2 = vload8(0, number); int8 intvec3 = -1; int any2 = any(intvec1); //(1) printf("any2 %d\n", any2); int any3 = any(intvec3); //(2) int all3 = all(intvec3); //(3) printf("any3 and all3 %d : %d\n", any3, all3); int4 intvec4 = (int4)(1,-1,1,-1); int4 intvec5 = (int4)(1,0,1,-1); int4 intvec6 = 0; int any4 = any(intvec4); //(4) int all4 = all(intvec4); //(5) printf("any4 and all4 %d : %d\n", any4, all4); intvec6 = intvec4 == intvec5; printf("intvec6 = %v4d\n",intvec6); int any5 = any(intvec6); //(6) int all5 = all(intvec6); //(7) printf("any5 and all5 %d : %d\n", any5, all5);
符号つきの整数の最上位ビットは負の整数だが、全て正のため0を返します。 | |
-1の要素が一つでもあるため、1を返します。 | |
全ての要素が-1のため、1を返します。 | |
-1の要素が一つでもあるため、1を返します。 | |
全ての要素が-1でないため、0を返します。 | |
-1の要素が一つでもあるため、1を返します。 | |
全ての要素が-1でないため、0を返します。 |
出力.
intvec1 = 0,1,2,3,4,5,6,7 intvec2 = 0,1,2,3,4,5,6,7 any2 0 any3 and all3 1 : 1 any4 and all4 1 : 0 intvec6 = -1,0,-1,-1 any5 and all5 1 : 0
allとanyが最も活躍できる分野は自然言語処理です。以下のように、文字列の比較を一括で行なう場合に使用できます。
char4 word1 = (char4) ('a','b','c','\0'); char4 word2 = (char4) ('b','c','d','\0'); char2 word3 = word1.s01 == word2.s12; int all6 = all(word3); printf("word match all6: %d\n", all6);
無論、次のような等号の比較をする関数も用意されています。
int isequal (float x, float y)
各要素にたいして、x == yの比較をし、その結果を返します。
int isinf (float)
無限大(正または負)かテストをします。
int isnormal (float)
正規値(0, 非正規化数, 無限大, NaN のいずれでもない)かテストします。
float nan = NAN; float huge_val = HUGE_VALF; float infinity = INFINITY; int is_nan = isnan(nan); int is_infinity1 = isinf(huge_val); //(1) int is_infinity2 = isinf(infinity); int is_normal1 = isnormal(nan); //(2) int is_normal2 = isnormal(-2.4f); int is_normal3 = isnormal(0.5f); int is_normal4 = isnormal(MAXFLOAT+1.0f); printf("edge test: %d - %d - %d\n", is_nan, is_infinity1, is_infinity2); printf("normal test1: %d\n", is_normal1); printf("normal test2: %d\n", is_normal2); printf("normal test3: %d\n", is_normal3); printf("normal test4: %d\n", is_normal4);
出力.
edge test: 1 - 1 - 1 normal test1: 0 normal test2: 1 normal test3: 1 normal test4: 1
int isordered (float x, float y)
isequal(x, x) && isequal(y, y)の計算をします。
int isunordered (float x, float y)
 xまたはyがNaNのときはゼロ以外、それ以外は0を返します。
int signbit (float)
符号ビットをテストします。符号ビットが設定されているときはゼロ以外、それ以外のときは0を返します。
float4 floatvec1 = (float4)(3.0f, -4.0f, 5.0f, -6.0f); int4 sign = signbit(floatvec1); //(1) printf("signbit test: %#v4d\n", sign); int ordered1 = isordered(floatvec1.x, floatvec1.z); //(2) printf("isordered test: %d\n", ordered1); int ordered2 = isunordered(floatvec1.x, floatvec1.z); //(3) printf("isunordered test: %d\n", ordered2);
signbit test: 0,-1,0,-1 isordered test: 1 isunordered test: 0
詳しくは「表:比較関数」(表B.117「表:比較関数」)を参照ください。
GPU等の専用デバイスでは、if構文などの分岐は一番苦手とするところで、(筆者は例外を知らないが)大半のベンダーがif文を使わないように推奨しています。
OpenCLの組込みbitselect、select関数では分岐を避けることができます。まずbitselect関数を見てみましょう。
gentype bitselect ( gentype a, gentype b, gentype c)
この関数は戻り値のビットを条件により選別、設定します。変数cの対応するビットが0のときは、aのビットそれ以外のときは、bのビットを返します。
uchar4 bit_result; uchar4 bit_mask = (uchar4)(0x00,0x99,0x00,0x99); uchar4 bit_input1 = (uchar4)(0x55,0x55,0x55,0x55); uchar4 bit_input2 = (uchar4)(0xFF,0xFF,0xFF,0xFF); bit_result = bitselect(bit_input1,bit_input2,bit_mask); printf("Result vector is %#v4u\n", bit_result);
Result vector is 85,221,85,221
この場合、0x55が85なので、221を見ればビットセレクトが処理した内容が理解できます。
mask | 1 | 0 | 0 | 1 | 1 | 0 | 0 | 1 |
a | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
b | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 |
戻り値(十進数) | 128 | 64 | 0 | 16 | 8 | 4 | 0 | 1 |
戻ったビットの和は221となります。
次により単純な分岐処理ができるselect関数を見てみます。
gentype select ( gentype a, gentype b, igentype c) gentype select ( gentype a, gentype b, ugentype c)
ベクトル型のとき c[i] の最上位ビット(MSB)から ? b[i] : a[i] を計算します。
スカラ型のときは、c ? b : aを計算します。
それでは実装例を見てみましょう。
float4 in1 = (float4)(1.5f, 15.0f,5.0f,7.5f); float4 in2 = (float4)(-20.0f, -5.0f, 1.0f, 100.0f); int4 mask = (int4)(-1,0,0,-1); printf("in1 vector is %#v4f\n", in1); printf("in2 vector is %#v4f\n", in2); printf("mask vector is %#v4d\n", mask); float4 result = select(in1, in2, mask); printf("Result vector is %#v4f\n", result);
出力.
in1 vector is 1.500000,15.000000,5.000000,7.500000 in2 vector is -20.000000,-5.000000,1.000000,100.000000 mask vector is -1,0,0,-1 Result vector is -20.000000,15.000000,5.000000,100.000000
int mask_sc = 1; float in1_sc = 20.0f; float in2_sc = 10.0f; printf("in1 scalar is %#f\n", in1_sc); printf("in2 scalar is %#f\n", in2_sc); printf("mask scalar is %#d\n", mask_sc); float scalar_result = select(in1_sc,in2_sc,mask_sc); printf("Result scalar is %f\n", scalar_result);
出力.
in1 scalar is 20.000000 in2 scalar is 10.000000 mask scalar is 1 Result scalar is 10.000000
最上ビットを使うベクトル型に対して、スカラ型はif分岐のように使えます。これは分岐の苦手なGPUでは分岐の代用となります。
Copyright 2018-2019, by Masaki Komatsu