2

这是我的基本问题:

LOW←6     ⍝ lower bound
UPP←225   ⍝ upper bound
INC←0.01  ⍝ increment
VAL←50    ⍝ value

我想确定 VAL 是否是增量的倍数。我最初的解决方案是检查 (VAL-LOW)÷INC 是否为整数。这是我遇到 ⎕CT 问题的地方(以下不是我的实际代码,但它说明了我的情况)。

V←(VAL-LOW)÷INC
W←⌊0.5+|V
V
    4400
W
    4400
V=W
    0
|V-W
    1.somethingE¯13

哦亲爱的!(注意:当然,当我“赤脚”运行代码时,这不会发生 - 只有当它在实际环境中的调用堆栈深处时才会发生。)

第二个想法不是很优雅,但在纸面上似乎是合理的:

V←0 12⍕(VAL-LOW)÷INC
0=⍎(1+V⍳'.')↓V

将 V 格式化为 12 位,去掉小数点和它左边的所有内容。执行其余的并检查它是否等于零。那行得通,直到它没有,我只剩下十二个九了。

哦!

然后我突然想到,也许我并不总是需要 12 位小数。事实上,我只需要 INC 中的数量:

DEC←(⌽⍕INC)⍳'.'
V←0 DEC⍕(VAL-LOW)÷INC
0=⍎(1+V⍳'.')↓V

我不知道......它变得越来越混乱。当 UPP 很大而 INC 为 1000 时会发生什么?有没有更聪明的方法来做到这一点?

幼稚的解决方案是基于 LOW、INC 和 UPP 生成有效 VAL 的列表,但这样的解决方案总是有耗尽工作内存的风险。

4

2 回答 2

2

将 []PP 设置为 16 或 17,无论系统最大值是多少,这样您所见即所得。系统可以方便地对显示的值进行四舍五入,以使它们看起来是整数值,而实际上它们不是。请注意,这只影响您看到的内容,⍕ 的结果,而不影响任何计算本身。准确度与精确度。

然后尝试将 []CT 设置为相对“大”的值,可能是 1e-10 或 1e-8。这将使关系函数看起来不那么挑剔。看看有什么作用。

您也可以尝试将比较更改为

0.000001 > | V - W

即自己做[]CT的事情。请务必将 []CT 设置为零。

如果您的数字在普通整数或可以用 64 位浮点数表示的整数范围内(大约 2e50),那么一切都应该很好。

于 2014-10-14T11:23:18.577 回答
0

这是所有编程语言中的一个问题,只有当你不理解它时才会成为一个问题。

大多数(全部?)APL 实现中的十进制值由计算机存储为二进制浮点值。二进制意味着整数和小数部分都是通过分别对两个的正负幂求和得出的:

3 = 2 + 1 = 2 1 + 2 0 = 11 二进制

3.5 = 2 + 1 + 1/2 = 2 1 + 2 0 + 2 -1 = 11.1 二进制

3.125 = 2 + 1 + 1/8 = 2 1 + 2 0 + 2 -3 = 11.001 二进制

0.75 = 1/2 + 1/4 = 2 -1 + 2 -2 = 0.11 二进制

浮点意味着只存储前 N 个最重要的二进制数字,以及一个将它们“移动”到左侧或右侧的指数值。

当您尝试使用这种内部格式(二进制浮点)来存储精确的十进制值时,这只会成为一个问题,因为在大多数情况下它不能。

这是因为许多(有理)数在基数 10 中具有有限的十进制扩展,而不是在基数 2 中:

0.1 = 2 -4 + 2 -5 + 2 -8 + 2 -9 + 2 -12 + 2 -13 + ... = 0.0 0011 0011 0011...(周期性)

如果您的 APL 实现支持“十进制”变量类型,您可以使用它。否则,通常的解决方法(以及“十进制”变量通常在提供它们的语言或库中实现的方式)是使用以 10 为底的几个整数、一个值和一个指数。

例如: 0.00123 = 123 × 10 -5,所以你可以将它表示为整数向量:123, -5

现在有趣的部分是在这些向量上实现你需要的所有算术运算,以你的 APL 风格,确保在任何时候都只使用引擎盖下的整数算术。这留给读者作为练习:-)

当然,如果您从不期望需要超过 X 个十进制数字,您可以使用常规整数和常规整数算术,按照惯例,您的变量代表美分、千分之一、百万分之一或其他分数。顺便说一句,这就是(应该)在计算机程序中处理货币值的方式,以避免任何舍入错误:以美分表示的整数值。

于 2014-10-25T06:49:36.620 回答