如何在ZX Spectrum基础语言中模拟逻辑异或运算?

15

有时候,在ZX Spectrum Basic中编写代码时,我需要评估由两个操作数和逻辑异或运算符组成的逻辑表达式,就像这样:

IF (left operand) xor (right operand) THEN

由于ZX Basic仅了解NOT、OR和AND,因此我不得不采用某种包括多次使用左/右操作数的花式计算。这很麻烦,因为它会消耗时间和内存,如果你在一台8位机器上工作,这两个资源都很稀缺。我想知道是否有巧妙的技巧来模拟异或运算符。

为了测试结果,我提供了一个小代码示例:

 5 DEF FN x(a,b)=(a ??? b) : REM the xor formula, change here
10 FOR a=-1 TO 1 : REM left operand
20 FOR b=-1 TO 1 : REM right operand
30 LET r=FN x(a,b) : REM compute xor
40 PRINT "a:";a;" b:";b;" => ";r
50 NEXT b
60 NEXT a

你能帮我找到一个高效的解决方案吗?到目前为止,我尝试了DEF FN x(a,b)=(a AND NOT b) OR (b AND NOT a),但它有点笨拙。

编辑:

如果你想测试你的想法,我建议使用BasinC v1.69 ZX模拟器(仅限Windows)。

正如@Jeff指出的那样,大多数BASIC,例如ZX BASIC,将零值视为,非零值视为

我已经适应了样例以测试各种非零值。


1
逻辑上,NOT(A AND B) AND (A OR B) 是否成立? - Worse_Username
@Worse_Username 那个方法可以用,但它并没有加速我目前的代码。^^ - yacc
我仍在寻找简洁的解决方案,欢迎回答。任何想法都受欢迎。 - yacc
似乎我的一个(尤其是它的更新)表现最佳? :-) - Ed.
不要忘记 https://retrocomputing.stackexchange.com 的存在,那里有很多类似的精彩问题。 - peterh
显示剩余2条评论
4个回答

11

逻辑异或在语义上等价于不相等。

IF (left operand) <> (right operand) THEN

应该可以工作。

编辑:对于整数操作数,您可以使用

IF ((left operand) <> 0) <> ((right operand) <> 0) THEN

3
大多数BASIC语言似乎认为0为假,非零为真。鉴于此,我不确定为什么你认为“-1 XOR 1”是一个“边缘情况”。 - Jeff Zeitlin
@macmoonshine 尽管我很喜欢那个答案,但它并不足以涵盖所有情况。这就是为什么我发布了一个悬赏的原因。 - yacc
哪种情况没有被覆盖? - clemens
在这里,基本上0表示False,但是其他任何值都表示True,例如-1或3.14,因此您的比较将无法起作用。 - yacc
1
我已经根据这个需求进行了适应。 - clemens
显示剩余3条评论

5
DEF FN x(a,b)=((NOT a) <> (NOT b))

使用NOT将值强制转换为布尔值。

编辑 先前每个侧面都有NOT NOT,这对于区分两者是不必要的,因为其中一个仍然会强制转换!

编辑2 添加了括号以解决优先级问题。


我刚意识到每边只需要一个NOT。已相应地进行了编辑。 - Ed.
由于“NOT”的优先级较低,使用您的更新后,当a=-1b=0时,我现在得到了一个0。您有测试过您的任何建议吗? - yacc
抱歉,我恐怕无法安装环境。我添加了括号,应该可以排序了。 - Ed.
1
现在看起来还有一些可以压缩的括号,但是已经看起来可以接受了。 - yacc
2
抱歉我离开了一段时间。到目前为止,我从你的回答中得出的最短版本是:DEF FN x(a,b)=(NOT a) <> NOT b - yacc

5
考虑到这个问题和这里的答案非常有趣,我想分享一些性能测试的结果(在模拟器上执行):enter image description here 经过的时间以秒为单位,时间越短越好。 x1测试仅用于确定表达式是否符合要求并包括输出结果,x256重复256次相同的测试而不打印任何输出;without FN测试与其相同,但不会将表达式因式分解为FN语句。
我还分享了在Github上的代码和测试套件: https://github.com/rondinif/XOR-in-ZX-Spectrum-basic,以造福所有复古计算爱好者(像我一样)并分享我们的观点。

我已尽力,但目前只进行了一些检查,可能会无意中犯下错误。如果您发现有可能改进的地方,可以在 GitHub 上开问题或 fork-it/pull-request。 - Franco Rondini
Franco,如果你已经设置好基础设施,可以尝试我的答案来测试性能吗? - Ed.
1
@Ed. (NOT a <> NOT b) 的性能相当不错,我已更新答案和 git 存储库。 - Franco Rondini
我理解的是,如果我们排除你的数字5(因为它只适用于BASIC中的1和0,而不是所有有效的布尔值),那么我的两个数字(3和7)是最快的? - Ed.
我的回答进一步更新 - 前两个也应该从比较中删除,因为显然它们也是不正确的! - Ed.
1
我从Ed的回答中得出的最短版本是:DEF FN x(a,b)=(NOT a)<>NOT b。如果能在表格中加入就太好了。@FrancoRondini - yacc

2

请注意,这里的值是整数: 我认为数学运算可能很有趣:(A-B)*(A-B)应该可以工作。 基于简单的操作,它应该更节省时间。 或者使用ABS:ABS(A-B)


2
这样做不行,因为A和B不仅仅是0或1。在Basic中,如果操作数<> 0,则操作数为True。例如,如果A为2且B为-1,则仍需要A xor B评估为0(False)。 - yacc
2
它可以与提供的示例一起使用 :) 它取决于您管理布尔值的方式。通过使用 A AND A 或 A OR A,基本上很容易将其转换为布尔形式。 - Christophe Durieux
是的,这个问题就是关于这个的。找到一种高效的方法来获取布尔形式的0/1并执行异或操作。也许可以用SGN,我不知道? - yacc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接