这是我的基本问题:
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个位置,删除小数点以及其左侧的所有内容。执行其余的并检查它是否等于零。这样做没问题,直到它没有,我留下了十二个九。
D'哦!
然后让我感到震惊的是,我可能并不总是需要12位小数。事实上,我只需要INC中的数量:
DEC←(⌽⍕INC)⍳'.'
V←0 DEC⍕(VAL-LOW)÷INC
0=⍎(1+V⍳'.')↓V
我不知道......它变得更加混乱和混乱。 当UPP很大且INC为1000时会发生什么? 有没有更聪明的方法呢?
天真的解决方案是基于LOW,INC和UPP生成有效VAL的列表,但是这样的解决方案总是存在工作内存耗尽的风险。
答案 0 :(得分:2)
将[] PP设置为16或17,无论系统最大值是多少,所以你看到的就是你得到的。系统可以方便地对显示的值进行舍入,以使它们看起来是整数值,而实际上它们不是。请注意,这仅影响您看到的内容,affects的结果,而不影响任何计算本身。精度与精度。
然后尝试将[] CT设置为相对"大",可能是1e-10或1e-8。这将使关系函数看起来行为不那么挑剔。看看它做了什么。
您也可以尝试将比较更改为
0.000001 > | V - W
即。自己做[] CT事。务必将[] CT设置为零。
如果您的数字在普通整数或整数范围内,可以在64位浮点范围内,大约2e50左右,那么一切都应该很好。
答案 1 :(得分: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个十进制数字,您可以使用常规整数和常规整数运算,其惯例是您的变量代表分数,千分之一,或百万分之一,或其他一些分数。顺便说一下,这就是计算机程序中应该(应该)处理货币值的方式,以避免任何舍入错误:以整数值表示,以美分表示。