1

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

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
4

2 回答 2

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)  
于 2016-09-22T05:53:55.587 回答
1

/所描述的结果是被编码为除法运算符的副作用。该/运算符不是CL 中的整数除法运算符;某些语言可能会提供//作为该效果的附加除法运算符,或者可能作为标量函数,例如 a 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  )

与我在 24Sep 对 OP 的评论中提到的不同,没有能力编写以下表达式以仅在一个 CHGVAR 语句中实现所需的结果;第一个表达式未能通过 msg CPD0058“内置函数 %INT 允许 1 个参数”进行语法检查。第二个失败并显示 msg CPD0181 "Argument for built-in function %INT not valid."。而且我希望通过编码 %DEC 内置 [具有零刻度规范;即为小数位参数指定的零]:

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

( &dividend - %int((&dividend / &divisor)) * &divisor )
于 2016-09-29T16:56:15.073 回答