为什么 PRINT 一个 true 布尔表达式会输出 -1?

13
在Commodore 64 BASIC V2中,打印一个真的布尔表达式会输出-1:
READY.
A=(5=5)

READY.
PRINT A
-1

为什么是 -1 而不是 1?

enter image description here


2
true 非零,所以这并不重要。从技术上讲,带有单个位的有符号二进制补码数字可以是 0 或 -1,也许是因为这个原因。 - falstro
当计算5=5时,它返回True,因为比较是相等的。 - eoredson
3个回答

9

Commodore Basic没有布尔数据类型。布尔表达式的值是一个数字,其中0表示False,-1表示True。

由于没有布尔数据类型,因此也没有布尔类型表达式。您可以在IF语句中使用任何数值表达式,它将把任何非零值解释为True。

一些语言中,布尔值是数字或可以转换为数字值,使用-1来表示真值。对于整数值0,所有位都被清除,而对于-1,所有位都被设置,因此它们可以看作是自然互补的。

尽管Commodore Basic不使用整数,而是使用浮点数,但据说选择了值-1,因为其他一些语言使用它。


1
你能举一些例子来澄清“大多数语言”这部分吗?我所知道的大多数语言使用1,而不是-1(有一些使用0,但它们很奇怪) :) - falstro
@roe:你说得对,使用1而不是-1的语言比我记得的多。我已经相应调整了答案。 - Guffa
Commodore Basic使用16位整数来存储变量值,除非需要浮点数,因为要存储的值超出了16位整数的限制或者有小数。 - Paolo
@Paolo 只有标记为 % 的整数变量被存储为 16 位值。而且,无论类型如何,计算都是以浮点精度进行的。标量变量即使是数字类型相同,也占用相同的内存空间,“浪费”了每个整数标量变量三个字节。 - BlackJack
@BlackJack 你说得对。我更新了答案。谢谢。 - Paolo

6

简短回答

为什么是-1而不是1?

这只是一种惯例。


一些推测...

选择这种惯例背后的原因可能与大多数平台上整数数字的内部表示有关:

假设一个布尔值存储在一个16位宽的整数中,false0(每个位都未设置)。

0 => 00000000 00000000

达成另一种惯例是true等于所有位设置:

11111111 11111111

(这是一个非常合理的选择,因为所有的1是所有的0的按位NOT

其位全部设置的有符号整数的十进制表示为-1

-1 => 11111111 11111111

而1的二进制表示形式为

1 => 00000001 00000000(在小端平台上)。

所以为什么是-1而不是1:这只是一种惯例;但如果你看一下该值的二进制表示形式,你可能会同意这种惯例是有道理的。

然而,尽管所有上述考虑,这种惯例远未被普遍采用。在许多语言中,将true转换为数字值将得到1


关于您发布的代码的重要说明:

你写道

A=(5=5)

A是一个实数变量,其值由5个字节(1个指数和4个尾数)表示。

真实值0的C64内部表示为所有位0,但-1的表示远非所有位都是1

(所有位都是1将导致值为-1.70141183e+38

因此,C64 Basic只遵循惯例。


最后让我们解释一下您代码中IF语句的行为。

IF语句中,任何与0不同的值都将被视为true进行评估(大多数语言都是如此,或许全部都是)。


底部说明:

如果您想查看C64变量(仅限整数或实数,不包括字符串)的内部表示,则可以使用以下代码:

READY.

10 REM THE VARIABLE TO INSPECT
20 A=(5=5)
30 REM THE ADDR. OF THE FIRST VARIABLE
40 B=PEEK(45)+256*PEEK(46)
50 REM DISPLAY THE VAR'S 7 BYTES
60 FOR C=B TO B+6
70 PRINT C;": ";PEEK(C)
80 NEXT C

RUN
 2227 :  65
 2228 :  0
 2229 :  129
 2230 :  128
 2231 :  0
 2232 :  0
 2233 :  0

请注意前两个地址(2227,2228)存储了变量的名称(A为65,0)。

您可以尝试将变量声明为整数,并查看结果:

20 A%=(5=5)

在Commodore BASIC中,默认情况下,变量和数字字面值是5字节浮点数,而不是2字节整数。但即使是真正的整数在算术运算期间也会被提升为浮点数。因此,您的解释对问题中提出的示例没有太大影响。 - Psychonaut
1
@Psychonaut,我进行了一些研究,你说得对。我更新了答案。谢谢。 - Paolo

2

有一种方法可以使用,即通过自定义for循环。例如,如果您希望在按下某个键之前发生某些事情,可以这样做:

0 for i=-1 to 0
1 rem logic here ...
10 get a$: i=(a$=""): next i

这与 do...while 循环的逻辑相同。

编辑 - 如果您特别希望将 0 视为 false,将 1 视为 true,则可以定义一个如下的函数(我忘记了 ABS 关键字,因为我大概有 20 年没用过它了 :-|):

0 def fn b(x) = abs(x)
1 i = 7
2 a$ = "hello"
3 if fn b (i=6) then print "i is 6"
4 if fn b (i<10) then print "i is less than 10"
5 if fn b (a$="hi") then print "hey there!"
6 if fn b (a$="hello") then print a$

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