一个聪明的自制模数实现

Ben*_*cai 9 algorithm math plc modulus

我正在使用一些传统软件编程PLC(RSLogix 500,请不要问),它本身不支持模数运算,但我需要一个.我没有访问:模数,整数除法,局部变量,截断操作(虽然我可以通过舍入来破解它).此外,我可用的所有变量都在按数据类型排序的表中列出.最后,它应该适用于浮点小数12345.678 MOD 10000 = 2345.678.

如果我们做出等式:

dividend / divisor = integer quotient, remainder
Run Code Online (Sandbox Code Playgroud)

有两个明显的实现.

实现1:执行浮点除法:dividend / divisor = decimal quotient.然后破解一起截断操作,你找到了integer quotient.将它乘以divisor并找出它与之间的差异dividend,从而产生remainder.

我不喜欢这个,因为它涉及一堆不同类型的变量.我无法将变量"传递"到子程序,因此我只需要分配位于多个不同变量表中的一些全局变量,并且很难遵循.不幸的是,"难以遵循"非常重要,因为它需要足够简单,以便维护人员能够搞砸.

实现2:创建一个循环,同时dividend > divisor divisor = dividend - divisor.这是非常干净的,但它违反了PLC编程的一个重要规则,即永远不会使用循环,因为如果有人无意中修改了索引计数器,你可能会陷入无限循环,机器会变得疯狂或无法恢复故障.Plus循环很难进行维护以进行故障排除.另外,我甚至没有循环指令,我必须使用标签和跳转.好恶.

所以我想知道是否有人有任何聪明的数学黑客或更聪明的模数实现.我可以访问+ - */,exponents,sqrt,trig函数,log,abs值和AND/OR/NOT/XOR.

Kei*_*all 6

你要处理多少比特?你可以这样做:

if dividend > 32 * divisor  dividend -= 32 * divisor
if dividend > 16 * divisor  dividend -= 16 * divisor
if dividend > 8 * divisor  dividend -= 8 * divisor
if dividend > 4 * divisor  dividend -= 4 * divisor
if dividend > 2 * divisor  dividend -= 2 * divisor
if dividend > 1 * divisor  dividend -= 1 * divisor
quotient = dividend
Run Code Online (Sandbox Code Playgroud)

只需滚动多少次就可以了dividend.确保小心那些溢出的倍数.这就像你的#2,除了它需要log(n)而不是n次迭代,所以完全展开是可行的.


Jon*_*oni 5

如果你不介意过度复杂化并浪费计算机时间,你可以使用周期性的trig函数计算模数:

atan(tan(( 12345.678 -5000)*pi/10000))*10000/pi+5000   =   2345.678
Run Code Online (Sandbox Code Playgroud)

说真的,减去10000一次或两次(你的"实施2")更好.一般浮点模数的常用算法需要许多位级操作,这些操作对您来说可能是不可行的.例如,参见http://www.netlib.org/fdlibm/e_fmod.c(算法很简单,但由于特殊情况,代码很复杂,因为它是为IEEE 754双精度数而编写的,假设没有64位整数类型)