as400 CL脚本算术给出0

时间:2016-09-21 22:07:08

标签: math ibm-midrange division cl

我试图用算法计算除法的余数:

remainder = dividend - (dividend / divisor) * divisor

全部以整数计算。

实施例: 得到剩下的15/6。

1. (15 / 6) = 2
2. (2) * 6 = 12
3. 15 - 12 = 3

15/6的剩余部分确实是3。

我的问题是在我的CL脚本中使用此算法只是一直返回0。那是为什么?

pgm
dcl var(&dividend) type(*int) value(15)
dcl var(&divisor) type(*int) value(6)
dcl var(&remainder) type(*int)

dcl var(&msg) type(*char)

/* Calculate remainder. [ed: 29Sep2016] "* &remainder" is now: "* &divisor" */ 
chgvar var(&remainder) value(&dividend - (&dividend / &divisor) * &divisor)

/* Prior to 29-Sep-2016 redaction, the above was coded as the incorrect expression: +
chgvar var(&remainder) value(&dividend - (&dividend / &divisor) * &remainder)       +
   and remains, commented-out, to preserve relevance of user-comments about the OP */

/* Cast remainder and display. */
chgvar var(&msg) value(&remainder)
sndpgmmsg msg(&msg)

endpgm

编译:

crtclpgm pgm(test) srcfile(test) srcmbr(test)

执行命令

call test

输出:

0

2 个答案:

答案 0 :(得分:1)

这是非常有趣的系统行为。看起来引擎在乘以它之前不会对括号中的值应用整数中继。换句话说,发生了以下情况:

&dividend - (&dividend / &divisor) * &divisor
= 15 - (15 / 6) * 6
= 15 - 2.5 * 6
= 15 - 15
= 0

为了解决这个问题,我做了以下几点:

chgvar     var(&remainder) value(&dividend / &divisor)
chgvar     var(&remainder) value(&dividend - &remainder * &divisor)  

答案 1 :(得分:1)

所描述的结果是被编码为除法运算符的/的副作用。 /运算符不是CL中的整数除法运算符;某些语言可能会提供//作为该效果的附加除法运算符,或者可能作为标量函数,例如DIV;虽然当一种语言提供这样的附加算术特征时,它们也可能提供相关的标量,例如MODREM来直接获得余数。

IRP清单显示CL的操作就像明确编码为具有非零标度的中间值;有效TYPE(*DEC) LEN(24 9),但CL只允许15位精度,所以我在这个程序示例中使用TYPE(*DEC) LEN(15 5),在执行表达式的其余部分之前模仿分区的中间结果的创建:

pgm
 dcl var(&dividend) type(*int) value(15)
 dcl var(&divisor) type(*int) value(6)
 dcl var(&remainder) type(*int)
 dcl var(&intermedP) type(*dec) len(15 5)
/* Calculate remainder. *two-step process -- mimics IRP listing; yields 0  */
chgvar var(&intermedP) value(&dividend / &divisor) /* P15,5 intermed result */
chgvar var(&remainder) value(&dividend - &intermedP             * &divisor  )


因为正确的结果要求(&dividend / &divisor) [作为表达式&dividend - (&dividend / &divisor) * &divisor]的一部分必须产生整数结果,这意味着必须强制执行该除法运算的中间结果* INT类型或具有零刻度的其他数字类型。
正如已经接受的答案所示,以下修订版使用整数作为中间结果解决了这个问题:

pgm
 dcl var(&dividend) type(*int) value(15)
 dcl var(&divisor) type(*int) value(6)
 dcl var(&remainder) type(*int)
 dcl var(&intermedI) type(*int)
 /* Calculate remainder. *two-step process; per change, correctly yields 3  */
chgvar var(&intermedI) value(&dividend / &divisor) /* *INT  intermed result */
chgvar var(&remainder) value(&dividend - &intermedI             * &divisor  )

与我在对OP的24Sep评论中提到的不同,没有能力编写以下表达式以在一个CHGVAR语句中实现所需的结果;第一个表达式无法使用msg进行语法检查CPD0058“内置函数%INT允许1个参数。”第二个失败,msg CPD0181“内置函数%INT的参数无效。”。我希望编译%DEC内置[具有零刻度规范的相同效果[但我没有验证];即为 decimal-places 参数指定的零值:

( &dividend - %int(&dividend / &divisor) * &divisor )

( &dividend - %int((&dividend / &divisor)) * &divisor )