摘抄“GPU Programming And Cg Language Primer 1rd Edition” 中文名“GPU编程与CG语言之阳春白雪下里巴人”

在上一章中,我们已经介绍了 Cg 语言的基础数据类型( 7 种)、内置数据类型,以及数组、结构、接口等类型,本章将在此基础上讨论 Cg 中的表达式,表达式由操作符( operator )关联一个或多个操作数( operand )构成,我们首先阐述各种类型的操作符,并结合数据类型讲解操作符的具体使用方法。

Cg 中的操作符与 C 语言中的类似(操作符的功能和写法与 C 相同,但用法不尽相同),按照操作符的功能可以划分为:关系操作符、逻辑操作符、条件操作符。 Cg 中有一类较为独特的操作符,称为 Swizzle 操作符, 这个操作符用于取出向量类型变量中的分量。此外,与 C 语言不同的是, Cg 允许在向量类型变量上使用操作符,例如 > 操作符可以用来比较两个向量各个分量的大小关系。 Cg 中的表达式还有很多与 C 语言不同的细节之处,将在本章中一一分说。

6.1关系操作符( Comparison Operators )

关系操作符,用于比较同类型数据(不同类型的基础数据需要进行类型转换,不同长度的向量,不能进行比较)之间的大小关系或者等价关系。 Cg 中有 6 种关系操作符,如 表 1 所示 , 关系操作符运算后的返回类型均为 bool 类型。

关系操作符

功能

用法

<

小于

expr < expr

<=

小于或等于

expr <= expr

!=

不等于

expr != expr

==

等于

expr == expr

>=

大于或等于

expr >= expr

>

大于

expr > expr

1 关系操作符

在 Cg 中,由于关系操作符以及下节会讲到的逻辑操作符,都返回 bool 类型结果,所以这两种操作符有时也被统一称为 boolean operator 。

Cg 语言表达式允许对向量使用所有的 boolean operator ,如果是二元操作符,则被操作的两个向量的长度必须一致。表达式中向量的每个分量都进行一对一的运算,最后返回的结果是一个 bool 类型的向量,长度和操作数向量一致。例如:

float3 a = float4(0.5, 0.0, 1.0);

float3 b = float4(0.6, -0.1, 0.9);

bool3 c = a<b;

运算后向量 c 的结果为 float3(true, false, true);

6.2逻辑操作符( Logical Operators )

Cg 语言中有 3 种逻辑操作符 ( 也被称为 boolean Operators) ,如 表 2 所示,逻辑操作符运算后的返回类型均为 bool 类型。

逻辑操作符

功能

用法

&&

逻辑与

expr && expr

||

逻辑或

expr || expr

!

逻辑非

!expr

2 逻辑操作符

正如上节所说,逻辑操作符也可以对向量使用,返回的变量类型是同样长度的内置 bool 向量。

有一点需要注意: Cg 中的逻辑与( && )和逻辑或( || )不存在 C 中的短路现象( short-circuiting ,即只用计算一个操作数的 bool 值即可),而是参与运算的操作数据都进行 bool 分析。

6.3数学操作符( Math Operators )

Cg 语言对向量的数学操作提供了内置的支持, Cg 中的数学操作符有: * 乘法; / 除法; - 取反; + 加法;—减法; % 求余; ++ ;——; *= ; /= ; += ; -= ;后面四种运算符有时被归纳入赋值操作符,不过它们实际上进行数学计算,然后进行赋值,所以这里也放入数学操作符中进行说明。

在文献【 2 】第 3.3 节 Math Expressions 中,其行文意思容易让人觉得“好像只有加减乘除等运算可以对向量进行”,实际上经过我的测试, ++ 、——等数学运算符同样可以使用在向量上。所以“ Cg 语言对向量的数学操作提供内置支持”这句话是非常准确的。

需要注意的是:求余操作符 % 。只能在 int 类型数据间进行,否则编译器会提示错误信息: error C1021: operands to “ % ” must be integral.

当使用这些数学操作符对一个标量和一个向量进行运算时,标量首先被复制到一个长度相同的向量中,然后进行运算,例如下面的代码形式是正确的:

void function()

{

float2 a = float2(1.0, 1.0);

float b = 2.0;

f *= d;

f *= 2.0;

}

6.4移位操作符

Cg 语言中的移位操作符,功能和 C 语言中的一样,也可以作用在向量上,但是向量类型必须是 int 类型。例如:

int2 a = int2(0.0,0.0);

int2 b = a>>1;

如果使用如下代码,会出现错误提示信息: error C1021:operands to “ shr ” must be integral.

float2 a = int2(0.0,0.0);

float2 b = a>>1;

6.5Swizzle 操作符

可以使用 Cg 语言中的 swizzle 操作符( . )将一个向量的成员取出组成一个新的向量。 swizzle 操作符被 GPU 硬件高效支持。 swizzle 操作符后接 x 、 y 、 z 、 w ,分别表示原始向量的第一个、第二个、第三个、第四个元素; swizzle 操作符后接 r 、 g 、 b 和 a 的含义与前者等同。不过为了程序的易读性,建议对于表示颜色值的向量,使用 swizzle 操作符后接 r 、 g 、 b 和 a 的方式。

举例如下:

float4(a, b, c, d).xyz    等价于   float3(a, b, c)

float4(a, b, c, d).xyy    等价于   float3(a, b, b)

float4(a, b, c, d).wzyx   等价于   float4(d, c, b, a)

float4(a, b, c, d).w      等价于   float d

值得注意的是, Cg 语言中 float a 和 float1 a 是基本等价的,两者可以进行类型转换; float 、 bool 、 half 等基本类型声明的变量也可以使用 swizzle 操作符。例如:

float a = 1.0;

float4 b = a.xxxx;

注意: swizzle 操作符只能对结构体和向量使用,不能对数组使用,如果对数组使用 swizzle 操作符则会出现错误信息: error C1010: expression left of . ” x ” is not a struct or array (其实个人觉得,提示的错误信息中 array 换成 vector 更加合适)。

要从数组中取值必须使用 [] 符号。例如:

float a[3] = {1.0,1.0,0.0};

float b = a[0]; // 正确

float c = a.x; // 编译会提示错误信息

6.6条件操作符( Conditional Operators )

条件操作符的语法格式为:

expr1 ? expr2 : expr3;

expr1 的计算结果为 true 或者 flase ,如果是 true, 则 expr2 执行运算,否则 expr3 被计算。

条件操作符为简单的 if-else 语句提供了一种便利的替代方式,例如我们可以不必写:

if(a < 0){b = a}

else{c = a}

而改写为:

( a < 0 ) ?(b = a) :( c = a);

Cg 中的条件操作符一个独特的性能是:支持向量运算。即, expr1 的计算结果可以是 bool 型向量, expr2 和 expr3 必须是与 expr1 长度相同的向量。举例如下:

float3 h = float3(-1.0,1.0,1.0);

float3 i = float3(1.0,0.0,0.0);

float3 g = float3(1.0,1.0,0.0);

float3 k;

k = (h < float3(0.0,0.0,0.0))?(i):(g);

三元向量 h 与 float3(0.0, 0.0, 0.0) 做比较运算后结果为( true, false, false ) , 所以 i 的第一个数据赋值给 K 的第一个数据, g 的第二个和第三个数据赋值给 k 的第二个和第三个数据, K 的值为 (1.0, 1.0, 0.0) 。

6.7操作符优先顺序

Cg 语言中操作符的优先顺序如 表 3 所示,从上到下表示从高级到低级的优先级;同一行的操作符具有同等优先级。该表参考了 Cg 教程 _ 可编程实时图形权威指南第 3.3.1 节。

操作符

结合律

功能

() [] -> .

从左到右

函数调用、数组引用、结构引用、成员选择

! ~ ++ - + - * & (type) sizeof

从右到左

一元操作符:取反、增加、减少、正号、负号、间接、地址、转换

* / %

从左到右

乘法、除法、余数

+ -

从左到右

加法、减法

<<  >>

从左到右

移位操作符

< >= > >=

从左到右

关系操作符

==  !=

从左到右

等于,不等

&

从左到右

位操作符与

^

从左到右

位操作符异或

|

从左到右

位操作符或

&&

从左到右

逻辑与

||

从左到右

逻辑或

?:

从右到左

条件表达式

= += -= *= /= %= &= ^= != <<= >>=

从右到左

赋值、赋值表达式

,

从左到右

逗号操作符

3 操作符优先级

6.8控制流语句( Control Flow Statement )

程序最小的独立单元是语句( statement ),语句一般由分号结尾,缺省情况下,语句是顺序执行的,但是当涉及逻辑判断控制时,就要求有控制流程序语句。控制流程序语句分为条件语句和循环语句,在 C 语言中,条件语句有 if 、 if-else 、 switch 等,而循环过程则由 while 、 do-while 和 for 语句支持。 Cg 中的控制流语句和循环语句与 C 语言类似:条件语句有: if 、 if-else ;循环语句有: while 、 for 。 break 语句可以和在 for 语句中使用。

Cg 语言中的控制流语句要求其中的条件表达式返回值都是 bool 类型,这一点是与 C 语言不同之处( C 语言中,条件表达式返回值可以是 0 、 1 )

vs_2_x, vp30 和 vp40 这些 profile 支持分支指令(又称转移指令, branch instruction ), for 和 while 循环指令在这些 profile 中被完全支持。在文献【 3 】中提到:

“ In other profiles, for and while loops may only be used if the compiler can fully unroll them (that is, if the compiler can determine the iteration count at compile time) ”。

这句话的意思是“在其他的 profiles 中, for 和 while 循环只有当确切的知道循环次数时才能被使用”。但经过试验,如果使用“在 fp40 和 ps_3_0 之前的” 片段 profiles 编译含义 for, while 语句时会出现错误提示信息: error c6003 : instruction limit of exceeded …… 。因此,如果没有确切的把握,不要在低级的 profiles 中使用循环控制语句。

同样, return 只能作为最后一条语句出现。函数的递归调用( recursion )在 Cg 语言中是被禁止的。 Switch 、 case 和 default 在 Cg 中作为保留关键字存在,但是它们目前不被任何 profile 所支持。

Cg(C for Graphic)语言表达式与控制语句(转)的更多相关文章

  1. EL语言表达式 (二)【EL对数据的访问】

    一.访问方式: EL中访问数据和Java中访问数组的方式相同,即可以通过“[]”和“.”运算符进行访问.而且两种形式是等价的.如: 访问JavaBean对象userInfo中的id属性,可以写成下面两 ...

  2. EL语言表达式 (一)【语法和特点】

    一.基本语法规则: EL表达式语言以“${”开头,以"}"结尾的程序段,具体格式如下: ${expression} 其中expression:表示要指定输出的内容和字符串以及EL运 ...

  3. 代数式到c语言表达式和常用的c语言数学库函数_pow_sqrt_exp_fabs_abs

    数学知识来源于生活,因此我们需要把相关的数学的知识在自己生活找到实例. #include "common.h" #include <stdio.h> #include ...

  4. Go语言_流程控制语句:for、if、else、switch 和 defer

    流程控制语句:for.if.else.switch 和 defer 学习如何使用条件.循环.分支和推迟语句来控制代码的流程. Go 作者组编写,Go-zh 小组翻译. https://go-zh.or ...

  5. Shell脚本[运算表达式,条件控制语句]

    #!/bin/bash #你值得收藏的四则表达式运算. val1=1 val2=1 val3=1 val4=1 val5=1 val6=1 val7=1 let val1++ ((val2++)) v ...

  6. C语言表达式和语句

    一.表达式 在C语言中,常量.变量.函数调用以及按C语言语法规则用运算符把运算数连接起来的式子都是合法的表达式 . 最后一类可以理解为运算符和运算对象的组合.例如: 算术表达式 = 算术运算符 + 运 ...

  7. C#语言-03.逻辑控制语句

    a. 逻辑控制语句: i. 条件语句:先对条件判断,然后根据判断结果执行不同的分支 . If 和 if-else:判断“布尔表达式的值”来决定执行那个代码块 a. 语法:if(布尔表达式){ b. 布 ...

  8. C语言-表达式和运算符

    表达式:表达式是c语言的主体,在c语言中,表达式由操作符和操作数组成.简单的表达式可以只有一个操作数.根据操作符的个数,可以将表达式分为简单表达式和复杂表达式,简单的表达式只含有一个操作符(如:5+5 ...

  9. 第六课,T语言表达式(版本5.0)

    TC综合开发工具里的表达式大体分为:计算表达式.条件表达式 计算表达式: 它一般是用在赋值过程中,或者是和条件表达式混合使用这样的表达式里只有数字运算符(如:+.-.+=.*=等等运算符),没有关系运 ...

随机推荐

  1. C#读取指定路径下的Config配置文件

    ExeConfigurationFileMap map = new ExeConfigurationFileMap(); map.ExeConfigFilename = @"F:\App1. ...

  2. 为什么说JAVA中要慎重使用继承 C# 语言历史版本特性(C# 1.0到C# 8.0汇总) SQL Server事务 事务日志 SQL Server 锁详解 软件架构之 23种设计模式 Oracle与Sqlserver:Order by NULL值介绍 asp.net MVC漏油配置总结

    为什么说JAVA中要慎重使用继承   这篇文章的主题并非鼓励不使用继承,而是仅从使用继承带来的问题出发,讨论继承机制不太好的地方,从而在使用时慎重选择,避开可能遇到的坑. JAVA中使用到继承就会有两 ...

  3. poj1703 Find them,Catch them 【并查集】

    做过一些的带权并查集,再来做所谓的"种类并查集",发现好像就顿悟了. 种类并查集与带权并查集实质上的区别并不大. 关键的区别就是种类并查集仅仅是带权并查集再弄个%取余操作而已.然后 ...

  4. ok6410[000] 搭建裸机开发环境

    1.安装交叉工具链arm-linux-gcc-4.3.2 先把这个工具复制到rhat系统中[rhel-server-6.3-i386-dvd.iso] 解压arm-linux-gcc-4.3.2到一个 ...

  5. XML Schema笔记

    XML Schema是为了弥补DTD的不足而开发的一种新的用于约束和规范XML文档的标准 XML Schema作用: 定义可出现在文档中的元素定义可出现在文档中的属性定义哪些元素是子元素定义子元素的次 ...

  6. Cocos Console命令总结

    1. 工程创建 使用Cocos Console创建工程非常简单,安装完cocos命令之后,只需要在需要创建工程的目标目录下打开终端或命令行工具,输入下面的命令即可: cocos new -l js P ...

  7. Deep Learning 32: 自己写的keras的一个callbacks函数,解决keras中不能在每个epoch实时显示学习速率learning rate的问题

    一.问题: keras中不能在每个epoch实时显示学习速率learning rate,从而方便调试,实际上也是为了调试解决这个问题:Deep Learning 31: 不同版本的keras,对同样的 ...

  8. POJ 1861 Network (Kruskal算法+输出的最小生成树里最长的边==最后加入生成树的边权 *【模板】)

    Network Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 14021   Accepted: 5484   Specia ...

  9. HDU4280 Island Transport —— 最大流 ISAP算法

    题目链接:https://vjudge.net/problem/HDU-4280 Island Transport Time Limit: 20000/10000 MS (Java/Others)   ...

  10. URAL1519 Formula 1 —— 插头DP

    题目链接:https://vjudge.net/problem/URAL-1519 1519. Formula 1 Time limit: 1.0 secondMemory limit: 64 MB ...