İçeriğe atla

toprak.run/apple/metal/03-operatorler

METAL SHADING LANGUAGE · BÖLÜM 3

Operatörler

ASIL METİN Apple — Metal Shading Language Specification, Sürüm 4

Dolaylı komut arabellekleri için atama operatörü (=), bir komutun içeriğini kopyalamaz. Dolaylı komut arabelleklerinde komutların kopyalanması hakkında daha fazla bilgi için 6.16.3 bölümüne bakın.

Bu bölüm hem ikili hem de tekli operatörleri listeler ve bunların skaler ve vektör operandları üzerindeki etkilerini açıklar.

Alışılmış aritmetik dönüşümleri takiben, tüm aritmetik operatörler operandların türüyle aynı yerleşik türde (tamsayı veya kayan noktalı) bir sonuç döndürür. Dönüşümden sonra aşağıdaki durumlar geçerlidir:

  • Aritmetik ikili operatörün iki operandı da skaler ise, işlemin sonucu bir skalerdir.
  • Bir operand skaler ve diğer operand bir vektör ise:
    • Skaler, vektör operandının kullandığı eleman türüne dönüştürülür.
    • Daha sonra skaler türü, vektör operandıyla aynı sayıda bileşene sahip bir vektöre genişletilir.
    • Metal işlemi bileşen bazında gerçekleştirir ve sonuç aynı boyutta bir vektör olur.
  • İki operand aynı boyutta vektör ise, Metal işlemi bileşen bazında gerçekleştirir ve sonuç aynı boyutta bir vektör olur.

Tamsayı türlerinde, sonuç değeri ilgili tamsayı türünün temsil edebildiği maksimum ve minimum değerlerle sınırlanan aralığın dışında kalıyorsa — örneğin işaretli tamsayı türleri için TYPE.MIN / -1 veya sıfıra bölme gibi durumlarda — bir istisna oluşmaz ancak sonuç belirtilmemiş bir değerdir.

Kayan noktalı türlerde sıfıra bölme işlemi, IEEE-754 standardında tanımlandığı gibi ±∞ veya NaN sonucu üretir.

bfloat ve half birbirine örtük olarak dönüştürülemediğinden, operatörler bfloat ve half türlerinin birlikte kullanılmasını desteklemez.

Tüm işletim sistemlerinde: Metal 1 ve sonrası sürümler skaler, vektör ve matris operatörlerini destekler.

3.1 Skaler ve Vektör Operatörleri

1. Aritmetik İkili Operatörler

Aritmetik ikili operatörler +, , * ve /, skaler ve vektör; tamsayı ve kayan noktalı veri türü operandları üzerinde çalışır.

2. Modül Operatörü

Modül operatörü %, skaler ve vektör tamsayı veri türü operandları üzerinde çalışır ve alışılmış aritmetik dönüşümlerden sonra operandlarla aynı yerleşik türde bir sonuç döndürür.

Geçerli durumlar:

  • İki operand da skaler ise sonuç bir skalerdir.
  • Bir operand skaler ve diğeri vektör ise:
    • Skaler, vektör operandının kullandığı eleman türüne dönüştürülür.
    • Skaler, aynı sayıda bileşene sahip bir vektöre genişletilir.
    • Metal işlemi bileşen bazında gerçekleştirir ve sonuç aynı boyutta bir vektör olur.
  • İki operand aynı boyutta vektör ise işlem bileşen bazında gerçekleştirilir.

İkinci operandı sıfır olan herhangi bir bileşen için hesaplanan modül sonucu tanımsızdır. Operandlardan biri veya her ikisi negatif ise sonuçlar tanımsızdır. Sıfır olmayan operandlara sahip diğer bileşenler için sonuçlar tanımlı kalır.

Her iki operand da negatif değilse, kalan değeri de negatif değildir.

3. Aritmetik Tekli Operatörler

Aritmetik tekli operatörler + ve , skaler ve vektör tamsayı ve kayan noktalı operandlar üzerinde çalışır.

4. Artırma ve Azaltma Operatörleri

Aritmetik artırım ve azaltım operatörlerinin ön ve son biçimleri (++ ve --) skaler ve vektör tamsayı türü operandlara sahiptir.

Tüm tekli operatörler operandları üzerinde bileşen bazında çalışır. Sonuç operand ile aynı türdedir.

Sonradan ve önceden artırma ve azaltma işlemleri için, ifade bir lvalue olarak atanabilir olmalıdır.

  • Ön-artırım / Ön-azaltım: ifadenin içeriğine 1 ekler veya çıkarır ve oluşan değeri döndürür.
  • Son-artırım / Son-azaltım: 1 ekler veya çıkarır, ancak ifade değişiklikten önceki değere karşılık gelir.

5. İlişkisel Operatörler

İlişkisel operatörler >, <, >= ve <=, skaler ve vektör tamsayı ve kayan noktalı operandlar üzerinde çalışır. Sonuç bir Boolean (bool) skaler veya vektördür.

Dönüşümden sonra:

  • Her iki operand da skaler ise sonuç bir Boolean'dır.
  • Bir operand skaler ve diğeri vektör ise:
    • Skaler, vektör operandının eleman türüne dönüştürülür.
    • Skaler, aynı sayıda bileşene sahip bir vektöre genişletilir.
    • İşlem bileşen bazında gerçekleştirilir ve bir Boolean vektör elde edilir.
  • Her iki operand da aynı boyutta vektör ise işlem bileşen bazında gerçekleştirilir ve aynı boyutta bir Boolean vektör elde edilir.

Argümanlardan herhangi biri NaN ise, ilişkisel operatör false döndürür.

Bir vektörün elemanları üzerinde ilişkisel işlemleri test etmek için if(...) ifadesi bağlamında any ve all yerleşik fonksiyonlarını kullanın (bkz. bölüm 6.4).

6. Eşitlik Operatörleri

Eşitlik operatörleri == ve !=, skaler ve vektör tamsayı ve kayan noktalı operandlar üzerinde çalışır ve bir Boolean skaler veya vektör döndürür.

Geçerli durumlar:

  • Her iki operand skaler ise sonuç bir Boolean'dır.
  • Bir operand skaler ve diğeri vektör ise:
    • Skaler, vektör operandının eleman türüne dönüştürülür.
    • Skaler, aynı sayıda bileşene sahip bir vektöre genişletilir.
    • İşlem bileşen bazında gerçekleştirilir ve bir Boolean vektör elde edilir.
  • Her iki operand aynı boyutta vektör ise işlem bileşen bazında gerçekleştirilir ve aynı boyutta bir Boolean vektör elde edilir.

Argümanlardan biri veya her ikisi NaN ise:

  • ==false döndürür
  • !=true döndürür

7. Bit Düzeyi Operatörleri

Bit düzeyi operatörler &, |, ^ ve ~, skaler ve vektör kayan noktalı türler dışında tüm skaler ve vektör yerleşik türler üzerinde çalışabilir.

  • Vektör türleri için Metal operatörleri bileşen bazında uygular.
  • Bir operand skaler ve diğeri vektör ise:
    • Skaler, vektör eleman türüne dönüştürülür.
    • Skaler, aynı sayıda bileşene sahip bir vektöre genişletilir.
    • İşlem bileşen bazında gerçekleştirilir ve sonuç aynı boyutta bir vektör olur.

8. Mantıksal Operatörler

Mantıksal operatörler && ve ||, Boolean ifadeler olan iki operand üzerinde çalışır. Sonuç skaler veya vektör Boolean'dır.

9. Mantıksal Tekli Operatör

Mantıksal tekli operatör !, bir Boolean ifade üzerinde çalışır ve skaler veya vektör Boolean döndürür.

Koşullu Operatör

Koşullu operatör şu biçimdedir:

exp1 ? exp2 : exp3
  • exp1 bir skaler Boolean değere değerlendirilmelidir.
  • exp1 true ise exp2 değerlendirilir.
  • exp1 false ise exp3 değerlendirilir.

exp2 veya exp3 ifadelerinden yalnızca biri değerlendirilir.

İkinci ve üçüncü ifadeler aşağıdaki durumlarda herhangi bir türde olabilir:

  • Türleri eşleşiyorsa, veya
  • Biri diğerine dönüştürülebiliyorsa (bkz. bölüm 2.12), veya
  • Biri vektör ve diğeri vektör türüne genişletilebilen bir skaler ise.

Ortaya çıkan eşleşmiş tür, tüm ifadenin türü olur.

Kaydırma Operatörleri

Sağa kaydırma (>>) ve sola kaydırma (<<) operatörleri skaler ve vektör tamsayı operandlar üzerinde çalışır. Vektör türleri için Metal işlemi bileşen bazında uygular.

10. Üçlü Seçim Operatörü

Üçlü seçim operatörü (?:), ifade olan üç operand üzerinde çalışır. En sağdaki operandın skaler olması gerekir. İlk operand vektör ise, en sağdaki operand vektör veya skaler olabilir.

E1 << E2 sonucunda, E1, E2 içindeki en az anlamlı log2(N) bit kadar sola kaydırılır; E2 işaretsiz bir tamsayı değeri olarak değerlendirilir:

  • E1 skaler ise, N, E1 veri türünü temsil etmek için kullanılan bit sayısıdır.
  • E1 vektör ise, N, E1 elemanlarının türünü temsil etmek için kullanılan bit sayısıdır.

E1 >> E2 sonucunda, E1, E2 içindeki en az anlamlı log2(N) bit kadar sağa kaydırılır; E2 işaretsiz bir tamsayı değeri olarak değerlendirilir:

  • E1 skaler ise, N, E1 veri türünü temsil etmek için kullanılan bit sayısıdır.
  • E1 vektör ise, N, E1 elemanlarının veri türünü temsil etmek için kullanılan bit sayısıdır.

Sağa kaydırma operatörü için, eğer E1 işaretsiz bir türe sahipse veya E1 işaretli bir türe sahip olup negatif değilse, boşalan bitler sıfırlarla doldurulur. Eğer E1 işaretli bir türe sahip ve değeri negatifse, boşalan bitler birlerle doldurulur.

lvalue = expression atama işlemi: eğer expression skaler bir tür ve lvalue vektör türündeyse, skaler vektör operandının kullandığı eleman türüne dönüştürülür. Daha sonra skaler türü, vektör operandıyla aynı sayıda bileşene sahip bir vektöre genişletilir. Metal işlemi bileşen bazında gerçekleştirir ve sonuç aynı boyutta bir vektör olur.

Yukarıda ayrıntılı olarak açıklanmayan diğer C++17 operatörleri — örneğin sizeof(T), tekli (&) operatörü ve virgül (,) operatörü — C++17 Spesifikasyonu'nda tanımlandığı şekilde davranır.

İşaretsiz tamsayılar 2^n modülü aritmetiğinin kurallarına uyar; burada n, ilgili tamsayı boyutunun değer gösteriminde kullanılan bit sayısıdır. İşaretli tamsayı taşmasının sonucu tanımsızdır.

Tamsayı operandlar için bölme (/) operatörü, kesirli kısmı atılmış cebirsel bölümü verir (genellikle sıfıra doğru kesme olarak adlandırılır). Eğer bölüm a/b sonuç türünde temsil edilebiliyorsa, (a/b)*b + a%b ifadesi a değerine eşittir.

Aritmetik toplama (+) ve çıkarma () operatörleri matrisler üzerinde çalışır. Her iki matrisin de aynı sayıda satır ve sütuna sahip olması gerekir. Metal işlemi bileşen bazında uygular ve sonuç aynı boyutta bir matris olur. Aritmetik çarpma (*) operatörü aşağıdaki durumlarda çalışır:

3.2 Matris Operatörleri

  • bir skaler ve bir matris
  • bir matris ve bir skaler
  • bir vektör ve bir matris
  • bir matris ve bir vektör
  • bir matris ve bir matris

Operandlardan biri skaler ise, skaler değer matrisin her bileşeniyle çarpılır ve sonuç aynı boyutta bir matris olur. Sağdaki vektör operand sütun vektörü olarak, soldaki vektör operand ise satır vektörü olarak değerlendirilir.

Vektör‑matris, matris‑vektör ve matris‑matris çarpımı için, sol operandın sütun sayısı sağ operandın satır sayısına eşit olmalıdır. Çarpma işlemi lineer cebirsel bir çarpma gerçekleştirir ve sonuç olarak sol operandla aynı satır sayısına ve sağ operandla aynı sütun sayısına sahip bir vektör veya matris elde edilir.

Aşağıdaki örnekler bu vektör, matris ve skaler değişkenlerin başlatılmış olduğunu varsayar. Aşağıda açıklanan vektör‑matris, matris‑vektör ve matris‑matris çarpım işlemlerinde kısmi toplamların hesaplanma sırası tanımlı değildir.

Matris‑Skaler Çarpımı

float3x3 m1 = m * a;
m1[0][0] = m[0][0] * a;
m1[0][1] = m[0][1] * a;
m1[0][2] = m[0][2] * a;
m1[1][0] = m[1][0] * a;
m1[1][1] = m[1][1] * a;
m1[1][2] = m[1][2] * a;
m1[2][0] = m[2][0] * a;
m1[2][1] = m[2][1] * a;
m1[2][2] = m[2][2] * a;

Vektör‑Matris Çarpımı

u.x = dot(v, m[0]);
u.y = dot(v, m[1]);

u.x = m[0].x * v.x + m[1].x * v.y + m[2].x * v.z;
u.y = m[0].y * v.x + m[1].y * v.y + m[2].y * v.z;
u.z = m[0].z * v.x + m[1].z * v.y + m[2].z * v.z;

r[0].x = m[0].x * n[0].x + m[1].x * n[0].y + m[2].x * n[0].z;
r[0].y = m[0].y * n[0].x + m[1].y * n[0].y + m[2].y * n[0].z;
r[0].z = m[0].z * n[0].x + m[1].z * n[0].y + m[2].z * n[0].z;

r[1].x = m[0].x * n[1].x + m[1].x * n[1].y + m[2].x * n[1].z;
r[1].y = m[0].y * n[1].x + m[1].y * n[1].y + m[2].y * n[1].z;
r[1].z = m[0].z * n[1].x + m[1].z * n[1].y + m[2].z * n[1].z;

r[2].x = m[0].x * n[2].x + m[1].x * n[2].y + m[2].x * n[2].z;
r[2].y = m[0].y * n[2].x + m[1].y * n[2].y + m[2].y * n[2].z;
r[2].z = m[0].z * n[2].x + m[1].z * n[2].y + m[2].z * n[2].z;