as400 CL脚本算术给出0

as400 CL script arithmetic gives 0

我正在尝试使用以下算法计算除法的余数:

remainder = dividend - (dividend / divisor) * divisor

全部以整数计算。

示例: 得到 15 / 6 的余数。

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

15/6的余数确实是3

我的问题是在我的 CL 脚本中一直使用这个算法 returns 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

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

&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)  

所描述的结果是编码为除法运算符的 / 的副作用。 / 运算符不是 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  )

与我在 9 月 24 日对 OP 的评论中提到的不同,无法编写以下表达式 以仅在一个 CHGVAR 语句中获得所需的结果;第一个表达式未通过 msg CPD0058 "Built-in function %INT allows 1 arguments." 语法检查,第二个表达式未通过 msg CPD0181 "Argument for built-in function %INT not valid."。而且我希望通过编码内置的 %DEC [具有零刻度规范;但我没有验证]同样的效果;即为 小数位 参数指定的零]:

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

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