我试图用算法计算除法的余数:
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(÷nd) 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(÷nd - (÷nd / &divisor) * &divisor)
/* Prior to 29-Sep-2016 redaction, the above was coded as the incorrect expression: +
chgvar var(&remainder) value(÷nd - (÷nd / &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
答案 0 :(得分:1)
这是非常有趣的系统行为。看起来引擎在乘以它之前不会对括号中的值应用整数中继。换句话说,发生了以下情况:
÷nd - (÷nd / &divisor) * &divisor
= 15 - (15 / 6) * 6
= 15 - 2.5 * 6
= 15 - 15
= 0
为了解决这个问题,我做了以下几点:
chgvar var(&remainder) value(÷nd / &divisor)
chgvar var(&remainder) value(÷nd - &remainder * &divisor)
答案 1 :(得分:1)
所描述的结果是被编码为除法运算符的/
的副作用。 /
运算符不是CL中的整数除法运算符;某些语言可能会提供//
作为该效果的附加除法运算符,或者可能作为标量函数,例如DIV
;虽然当一种语言提供这样的附加算术特征时,它们也可能提供相关的标量,例如MOD
或REM
来直接获得余数。
IRP清单显示CL的操作就像明确编码为具有非零标度的中间值;有效TYPE(*DEC) LEN(24 9)
,但CL只允许15位精度,所以我在这个程序示例中使用TYPE(*DEC) LEN(15 5)
,在执行表达式的其余部分之前模仿分区的中间结果的创建:
pgm
dcl var(÷nd) 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(÷nd / &divisor) /* P15,5 intermed result */
chgvar var(&remainder) value(÷nd - &intermedP * &divisor )
因为正确的结果要求(÷nd / &divisor)
[作为表达式÷nd - (÷nd / &divisor) * &divisor
]的一部分必须产生整数结果,这意味着必须强制执行该除法运算的中间结果* INT类型或具有零刻度的其他数字类型。
正如已经接受的答案所示,以下修订版使用整数作为中间结果解决了这个问题:
pgm
dcl var(÷nd) 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(÷nd / &divisor) /* *INT intermed result */
chgvar var(&remainder) value(÷nd - &intermedI * &divisor )
与我在对OP的24Sep评论中提到的不同,没有能力编写以下表达式以在一个CHGVAR语句中实现所需的结果;第一个表达式无法使用msg进行语法检查CPD0058“内置函数%INT允许1个参数。”第二个失败,msg CPD0181“内置函数%INT的参数无效。”。我希望编译%DEC内置[具有零刻度规范的相同效果[但我没有验证];即为 decimal-places 参数指定的零值:
( ÷nd - %int(÷nd / &divisor) * &divisor )
( ÷nd - %int((÷nd / &divisor)) * &divisor )