第五章 疯狂Caché 运算符和表达式(二)
算术运算符

算术运算符将其操作数解释为数值并生成数值结果。在对字符串进行操作时,算术运算符会根据“字符串到数字转换”一节中描述的规则,将该字符串视为其数值。

一元正运算符(+)

一元正运算符(+)对其单个操作数进行数值解释。如果其操作数有字符串值,则将其转换为数字值。它通过将字符串的字符顺序解析为数字来实现这一点,直到它遇到无效字符。然后,它返回字符串的任何前导部分是格式良好的数字。例如:

 WRITE + "32 dollars and 64 cents"        // 32
32
```java
如果字符串没有前导数字字符,则一元正运算符会将操作数赋给零值。例如:
```java
 WRITE + "Thirty-two dollars and 64 cents" // 0
0

一元正运算符对数值没有影响。它不会改变正数或负数的符号。例如:

 SET x = -23
 WRITE " x: ", x,! // -23
 WRITE "+x: ",+x,! // -23
 x: -23
+x: -23

一元负运算符(-)

一元负运算符(-)反转数值解释的操作数的符号。例如:

 SET x = -60
 WRITE " x: ", x,! // -60
 WRITE "-x: ",-x,! // 60

 x: -60
-x: 60

如果其操作数具有字符串值,则一元负运算符在反转其符号之前将其解释为数字值。此数值解释与上述一元正运算符执行的数字解释完全相同。例如:

 SET x = -23
 WRITE -"32 dollars and 64 cents" // -32
-32

CachéObjectScript使一元负运算符优先于二元算术运算符。CachéObjectScript首先扫描数字表达式并执行任何一元负操作。然后,CachéObjectScript对表达式求值并生成结果。

在下面的示例中,CachéObjectScript扫描字符串并遇到数值2,然后停止。然后,它将一元负运算符应用于该值,并使用连接运算符(_)将值“RATS”从第二个字符串连接到数字值。

WRITE -"2Cats"_"Rats" // -2Rats
-2Rats

要返回数值表达式的绝对值,请使用$ZABS函数。

DHC-APP 3d1>w $zabs(-3)
3
DHC-APP 3d1>w $zabs(+3)
3

加法运算符(+)

加法运算符产生两个数值解释的操作数之和。它使用任何前导有效数字字符作为操作数的数字值,并生成操作数的数字值之和的值。

下面的示例对两个数字文字执行加法:

 WRITE 2936.22 + 301.45 
3237.67

下面的示例对两个本地定义的变量执行加法:

 SET x = 4
 SET y = 5
 WRITE "x + y = ",x + y 
x + y = 9

下面的示例对具有前导数字的两个操作数执行字符串算术,并将结果数字相加:

 WRITE "4 Motorcycles" + "5 bicycles"
9

下面的示例说明数值计算的操作数上的前导零不会影响运算符生成的结果:

 WRITE "007" + 10 
17

减法运算符(-)

减法运算符产生两个数值解释的操作数之间的差值。它将任何前导的有效数字字符解释为操作数的数字值,并生成减法后的余数的值。

下面的示例对两个数字文字执行减法:

WRITE 2936.22 - 301.45 
 2634.77

下面的示例对两个本地定义的变量执行减法:

 SET x = 4
 SET y = 5
 WRITE "x - y = ",x - y 
-1

下面的示例对具有前导数字的两个操作数执行字符串算术,减去结果数字:

WRITE "8 apples" - "4 oranges" 
4

如果操作数没有前导数字字符,则CachéObjectScript假定其值为零。例如:

 WRITE "8 apples" - "four oranges" // 8
8

乘法运算符(*)

二进制乘法产生两个数值解释的操作数的乘积。它使用任何前导数字字符作为操作数的数字值,并生成乘积结果。

下面的示例对两个数字文字执行乘法:

WRITE 9 * 5.5 
49.5

下面的示例对两个本地定义的变量执行乘法:

 SET x = 4
 SET y = 5
 WRITE x * y 
20

下面的示例对具有前导数字的两个操作数执行字符串算术,并将结果数字相乘:

 WRITE "8 apples" * "4 oranges"  
32

如果操作数没有前导数字字符,则二进制乘法会为其赋值为零。

 WRITE "8 apples"*"four oranges"
0

除法运算符(/)

二进制除法产生将两个数值解释的操作数相除的结果。它使用任何前导数字字符作为操作数和乘积的数字值,结果就是商。

下面的示例对两个数字文字执行除法:

 WRITE 9 / 5.5 
1.636363636363636364

下面的示例对两个本地定义的变量执行除法:

SET x = 4
 SET y = 5
 WRITE x / y
.8

下面的示例对具有前导数字的两个操作数执行字符串算术,并将结果数字相除:

WRITE "8 apples" / "4 oranges"  
2

如果操作数没有前导数字字符,则二进制除法假定其值为零。例如:

 WRITE "eight apples" / "4 oranges" 
 
0
 WRITE "8 apples"/"four oranges" 
DHC-APP 3d1> WRITE "8 apples"/"four oranges"
 
 WRITE "8 apples"/"four oranges"
 ^
<DIVIDE>^PHA.TEST.ObjectScript.1

请注意,这些操作中的第二个是无效的。不允许将数字除以零。CachéObjectScript返回<Divide>错误消息。

求幂运算符(**)

求幂运算符产生左操作数的指数化值,该值是右操作数的幂。

  • 0 ** 0:0的零幂等于0。但是,如果任一操作数是IEEE双精度数(例如,0 ** $DOUBLE(0)$DOUBLE(0) ** 0),则零的零幂为1。

  • 0**n:0的任意正数n的幂是0。这包括0**$DOUBLE(“INF”)。尝试将0取负数的幂会导致错误:Caché负数会生成<非法值>错误;$DOUBLE负数会生成<Divide>错误。

  • Num**0:任何非零数(正数或负数)的零幂都是1。这包括$DOUBLE(“INF”)**0

  • 1**n:1的任意数字的幂(正、负或零)是1。

  • -1**n:-1的0次方等于1。-1的1次方或者-1次方等于-1。

  • Num**n:正数(整数或小数)乘以任意幂(整数或分数、正或负)返回正数。

  • -num**n:负数(整数或小数)乘以偶数(正或负)的幂将返回正数。负数(整数或小数)乘以奇数(正或负)的幂将返回负数。

  • -num**.N:尝试将负数提高到小数的幂会导致<非法值>错误。

  • $DOUBLE(\“INF\”)**n:无穷大数字(正数或负数)的0次方是1。无限数(正数或负数)与任何正数(整数、小数或INF)的幂都是INF。无限数(正数或负数)与任何负数(整数、小数或INF)的幂均为0。

  • $DOUBLE(“NaN”):求幂运算符两侧的NaN始终返NaN,而不考虑另一个操作数的值。

非常大的指数可能会导致上溢值和下溢值:

  • Num**nnn:大于1且具有较大正指数值的正数或负数(如9**153-9.2**152)会生成<MAXNUMBER>错误。

  • Num**-nnn:大于1且具有较大负指数值的正数或负数(如9**-135-9.2**-134)返回0。

  • .num**nnn:小于1且具有较大正指数值(例如.22**196-.2**184)的正数或负数返回0。

  • .Num**-nnn:小于1且具有较大负指数值的正数或负数(如.22**-196或-.2**-184)会生成<MAXNUMBER>错误。

超过Caché number支持的最大值的指数要么会发出<MAXNUMBER>错误,要么会自动转换为IEEE双精度浮点数。

此自动转换是通过使用%SYSTEM.Process类的TruncateOverflow()方法(基于每个进程)或Config.Miscellous类的TruncateOverflow属性(基于系统范围)指定的。

以下示例对两个数值文字执行幂运算:

 WRITE "9 ** 2 = ",9 ** 2,! 
 WRITE "9 ** -2 = ",9 ** -2,! 
 WRITE "9 ** 2.5 = ",9 ** 2.5,!
9 ** 2 = 81
9 ** -2 = .01234567901234567901
9 ** 2.5 = 242.9999999994422343

下面的示例对两个本地定义的变量执行幂运算:

 SET x = 4, y = 3
 WRITE "x ** y = ",x ** y,! 
64

下面的示例执行字符串算术。求幂使用任何前导数字字符作为操作数的值,并生成结果。

 WRITE "4 apples" ** "3 oranges"
64

如果操作数没有前导数字字符,则求幂假定其值为零。

下面的示例演示如何使用求幂来查找数字的平方根。

WRITE 256 ** .5 // 16
16

还可以使用$zpower函数执行幂运算。

DHC-APP>w $ZPOWER(2,2)
4
DHC-APP>w 16**0.5**0.5
2
DHC-APP>w 16**0.25
1.999999999999999883

整数除法运算符(\ )

整数除运算符产生左操作数除以右操作数的整数结果。它不返回余数,也不四舍五入结果。
下面的示例对两个整数操作数执行整数除法。CachéObjectScript不返回数字的小数部分:

 WRITE "355 \ 113 = ", 355 \ 113 
355 \ 113 = 3

下面的示例执行字符串算术。INTEGER DIVIDE使用任何前导数字字符作为操作数的值,并生成整数结果。

WRITE "8 Apples" \ "3.1 oranges" 
2

如果操作数没有前导数字字符,则CachéObjectScript假定其值为零。如果尝试使用零值除数进行整数除法,则CachéObjectScript将返回<divide>错误。

取余数(#

模运算符在两个数值解释的操作数上产生算术模运算符的值。当两个操作数为正时,模运算是左操作数整数除以右操作数的余数。

以下示例对数值文字执行模运算,并返回余数:

 WRITE "37 # 10 = ",37 # 10,! 
 WRITE "12.5 # 3.2 = ",12.5 # 3.2,! 

37 # 10 = 7
12.5 # 3.2 = 2.9

下面的示例执行字符串算术。当对字符串进行操作时,它们在应用模运算符之前被转换为数字值(根据变量键入和转换一节中描述的值)。因此,以下两个表达式等效:

 WRITE "8 apples" # "3 oranges",!  // 2
 WRITE 8 # 3 // 2
2
2

因为Caché将没有前导数字字符的字符串求值为零,所以这种右操作数会产生<Divide>错误。

逻辑比较运算符

逻辑比较运算符会比较它们的操作数的值,并返回布尔值:TRUE(1)FALSE(0)

一元运算符Not

一元NOT反转布尔操作数的真值。如果操作数为TRUE(1),则UNARY NOT为其赋值FALSE(0)。如果操作数为FALSE(0),则UNARY NOT为其赋值TRUE(1)

例如,以下语句生成的结果为FALSE(0)

  SET x=0
  WRITE x
0

而以下语句产生的结果为true(1)

  SET x=0
  WRITE 'x
1

带有比较运算符的一元NOT将颠倒其执行的操作的意义。它有效地反转了操作的结果。例如,以下语句显示FALSE(0)的结果:

  WRITE 3>5
0

但是,以下语句显示TRUE(1)的结果:

 WRITE 3'>5
1

优先运算符和逻辑运算符

由于CachéObjectScript对运算符执行从左到右的严格求值,因此涉及其他运算符的逻辑比较必须使用括号对运算进行分组,才能获得所需的优先级。例如,可能需要逻辑二进制或()。在以下程序中测试以返回TRUE(1)

  SET x=1,y=0
  IF x=1 ! y=0 {WRITE "TRUE"}
  ELSE {WRITE "FALSE" } 
FALSE

但是,要正确执行此逻辑比较,必须使用括号来嵌套其他操作。以下示例给出了预期结果:

  SET x=1,y=0
  IF (x=1) ! (y=0) {WRITE "TRUE"}
  ELSE {WRITE "FALSE" } 
TRUE

And与

并测试其两个操作数是否都具有TRUE(1)真值。如果两个操作数都为true(即在数值计算时具有非零值),则CachéObjectScript会生成值true(1)。否则,CachéObjectScript将生成值False(0)

二进制AND有两种形式:&&&

  • &运算符计算两个操作数,如果其中一个操作数的计算结果为零,则返回值FALSE(0)。否则,它返回值true(1)

  • &&运算符计算左操作数,如果计算结果为零,则返回值FALSE(0)。只有当左操作数非零时,&&运算符才会计算右操作数。如果右操作数的计算结果为零,则返回值FALSE(0)。否则,它返回值true(1)

下面的示例将两个非零值操作数求值为TRUE,并生成值TRUE(1)

 SET A=-4,B=1
 WRITE A&B // TRUE (1)
1
 SET A=-4,B=1
 WRITE A&&B // TRUE (1)
1

下面的示例计算一个TRUE和一个FALSE操作数,并生成FALSE(0)值。

 SET A=1,B=0
 WRITE "A = ",A,!
 WRITE "B = ",B,!
 WRITE "A&B = ",A&B,! // FALSE (0)
 SET A=1,B=0
 WRITE "A&&B = ",A&&B,! // FALSE (0)
A = 1
B = 0
A&B = 0
A&&B = 0

下面的示例显示了“&”运算符和“&&”运算符之间的区别。在这些示例中,左操作数的计算结果为FALSE(0),并且未定义右操作数。“&”和“&&”运算符对此情况的响应不同:

  • &”运算符尝试计算这两个操作数,但失败,并显示<unfined>错误。
  TRY {
       KILL B
       SET A=0
       WRITE "variable A defined?: ",$DATA(A),!
       WRITE "variable B defined?: ",$DATA(B),!
       WRITE A&B
       WRITE !,"Success"
       RETURN
      }
  CATCH exp
  {
      IF 1=exp.%IsA("%Exception.SystemException") {
         WRITE !,"System exception",!
         WRITE "Name: ",$ZCVT(exp.Name,"O","HTML"),!
         WRITE "Data: ",exp.Data,!!
      }
      ELSE { WRITE "not a system exception"}
  }

variable A defined?: 1
variable B defined?: 0

System exception
Name: <UNDEFINED>
Data: B

&&”运算符仅计算左操作数,并生成值FALSE(0)

  TRY {
       KILL B
       SET A=0
       WRITE "variable A defined?: ",$DATA(A),!
       WRITE "variable B defined?: ",$DATA(B),!
       WRITE A&&B
       WRITE !,"Success"
       RETURN
      }
  CATCH exp
  {
      IF 1=exp.%IsA("%Exception.SystemException") {
         WRITE !,"System exception",!
         WRITE "Name: ",$ZCVT(exp.Name,"O","HTML"),!
         WRITE "Data: ",exp.Data,!!
      }
      ELSE { WRITE "not a system exception"}
  }

variable A defined?: 1
variable B defined?: 0
0
Success

非与(NAND)

通过将一元NOT运算符与二元AND(&)运算符配合使用,可以指定布尔NOT AND(NAND)运算,格式如下:

operand '& operand  '(operand & operand)

NOT AND运算反转&BINARY的真值,并将其应用于两个操作数。当一个或两个操作数都为假时,它会生成值true(1)。当两个操作数都为TRUE时,它会生成值FALSE。

&&二元AND运算符不能以一元NOT运算符为前缀:不支持“‘&&”格式。但是,支持以下格式:

'(operand && operand)

下面的示例执行两个等效的NOT AND操作。每个操作数计算一个FALSE(0)和一个TRUE(1)操作数,并产生TRUE(1)值。

 SET A=0,B=1
 WRITE !,A'&B   // Returns 1
 WRITE !,'(A&B) // Returns 1
1
1

下面的示例通过执行&&二元AND运算,然后使用一元NOT来反转结果,从而执行NOT AND运算。&&操作测试第一个操作数,因为布尔值为false(0),所以&&不测试第二个操作数。一元值不反转生成的布尔值,因此表达式返回TRUE(1)

 SET A=0
 WRITE !,'(A&&B)  
1

如果任一操作数的值为TRUE或两个操作数的值都为TRUE(1),则二进制或生成TRUE(1)的结果。BINARY OR仅在两个操作数都为FALSE(0)时才生成FALSE(0)结果。

二进制或有两种形式:!(感叹号)和||(两个竖线)。

运算符对两个操作数求值,如果两个操作数的求值均为零,则返回值False(0)。否则,它返回值true(1)

||运算符计算左操作数。如果左操作数的计算结果为非零值,则||运算符返回TRUE(1)值,而不计算右操作数。只有当左操作数的计算结果为零时,||运算符才会计算右操作数。如果右操作数的计算结果也为零,则返回FALSE(0)值。否则,它返回值true(1)

下面的示例计算两个TRUE(非零)操作数,对它们应用二进制或,并生成TRUE结果:

 SET A=5,B=7
 WRITE "A!B = ",A!B,! 
 SET A=5,B=7
 WRITE "A||B = ",A||B,!
A!B = 1
A||B = 1

下面的示例计算一个FALSE和一个TRUE操作数,对它们应用二进制或,并生成TRUE结果:

 SET A=0,B=7
 WRITE "A!B = ",A!B,!
 SET A=0,B=7
 WRITE "A||B = ",A||B,!
A!B = 1
A||B = 1

下面的示例计算两个假操作数并生成值为false的结果。

 SET A=0,B=0
 WRITE "A!B = ",A!B,!
 SET A=0,B=0
 WRITE "A||B = ",A||B,!
A!B = 0
A||B = 0

非或(或非)(NOR)

可以通过将Unary NOT与!一起使用来产生NOT或(NOR)运算。二进制或以下任一等效格式:

operand '! operand '(operand ! operand)

如果两个操作数的值都为FALSE,则NOT OR运算将产生TRUE(1)结果。如果其中一个操作数的值为TRUE,或者两个操作数都为TRUE,则NOT OR运算将生成FALSE(0)结果。

'(operand || operand)

下面的NOT或示例计算两个假操作数并生成TRUE结果。

 SET A=0,B=0
 WRITE "A'!B = ",A'!B  
A'!B = 1
 SET A=0,B=0
 WRITE "'(A!B) = ",'(A!B)   
'(A!B) = 1

下面的NOT或示例计算一个TRUE和一个FALSE操作数并产生FALSE结果。

SET A=0,B=1
 WRITE "A'!B = ",A'!B   
A'!B = 0

 SET A=0,B=1
 WRITE "'(A!B) = ",'(A!B)  
'(A!B) = 0

下面的NOT OR(||)示例计算左操作数,并且因为它为TRUE(1),所以不计算右操作数。一元值不反转生成的布尔值,因此表达式返回FALSE(0)

 SET A=1
 WRITE "'(A||B) = ",'(A||B)   // Returns 0
'(A||B) = 0