There is an interesting value you can get in BASIC, which exposes a bug and offers an insight into how numbers are stored within Petit Computer.
Z=FLOOR(-524287.5)
or Z=&H80000
or Z=&B10000000000000000000
(that's 19 zeroes) will set the variable Z to this value. ?Z
will show -0
. Interestingly, ?-Z
will also show -0
. ?Z*1
gives the result Overflow (?)
, as does ?1*Z
, ?Z+0
, ?0+Z
, ?Z-0
, and ?Z/1
.
Petit Computer stores all numbers as a 2s-complement signed 32-bit fixed-point (as opposed to floating-point) value with a particular format, probably to prevent unexpected results from occurring when using bitwise operators like AND
and XOR
. 12 bits of precision are assigned to fractional values, thus, a value v
is really represented as (v * 4096)
.
(Interestingly, since Petit Computer only allots 12 bits for the fractional value, it can only store the noninteger part of a number in units of 1/4096. A simple two-line program can demonstrate this:
M=1/4096:IF (M*4096)==1 THEN PRINT "1/4096 is calculated precisely" N=1/4097:IF N==0 THEN PRINT "1/4097 is rounded to zero"
This program will print both lines, showing that 'epsilon', the smallest nonzero value that SmileBasic can handle, is 1/4096.)
Here's an example of how a typical number might be stored, in this case -250.125 (multiplied by 4096, this gives 1024512, or in binary, 1111 1010 0010 0000 0000):
1111 1111 1111 0000 0101 1110 0000 0000 \----------------------/ \------------/ | | integer part (rounded down) fractional part
The advantage of 2s complement representation is that signed numbers can be added with the same binary rules as unsigned numbers, the only difference being detection of overflows. The disadvantage is an asymmetry in the numbers represented: one more negative number can be represented than positive numbers (e.g. in 8-bit signed arithmetic, you can represent numbers from -128 to 127 inclusive). A side-effect of this is that if you do the 2s complement operation for negating a number (flip all the bits, then add 1), this will work for all numbers except -128... if you try it on -128 you get... -128. This is obviously somewhat unsatisfying, but most software engineers have come to terms with this quirk. Part of the reason for this acceptance is because if you try to work around it, it's all too easy to leave a loophole... exactly as the designers of Petit Computer did.
The FLOOR
operation simply clears the last 12 bits of the representation of the number. This will always have the effect of transforming the number to the next lowest integer, if it is not an integer already.
The bit breakdown for the value 524287.5
is as follows:
0111 1111 1111 1111 1111 1000 0000 0000 \----------------------/ \------------/ | | integer part fractional part
-524287.5
, then, is:
1000 0000 0000 0000 0000 1000 0000 0000 \----------------------/ \------------/ | | integer part fractional part
The floor of this value is:
1000 0000 0000 0000 0000 0000 0000 0000 \----------------------/ \------------/ | | integer part fractional part
By the rules of 2s complement arithmetic, this is really the value -524288. This is the one value on which negation will not work, you cannot represent the positive value 524288 with this format. Negating this binary representation gives the same binary representation (which is why both ?Z
and ?-Z
both produce the same result).
The value -524288 cannot be generated by the arithmetic operators: subtraction, e.g. -524287-1, or multiplication, e.g. -262144*2, will cause an Overflow
error.
Other results from the interpreter's math operations (after assigning -0 to Z) are as follows:
Z==0
gives0
(false)Z<0
gives1
(true)NOT Z
gives524287
Z/2
gives-262144
Z%3
=-2
Z OR 1
=-524287
HEX$(Z)
="80000"
ABS(Z)
=-0
(the only time ABS will give a negative result)SGN(Z)
=-1
EXP(Z)
=0
(but then, -36909/4096 and all lower values give0
)DEG(Z)
=369214.3505859
ATAN(Z)
=-1.5708078
, which is-PI()/2
.ATAN(0,Z)
=3.14160156
ATAN(Z,0)
=-1.57080078
ATAN(Z,Z)
=-2.35620117
, which is-PI()*3/4
POW(Z,1)
gives-0
SIN(Z)
,COS(Z)
,TAN(Z)
, and the two-parameterATAN
withZ
as either parameter (except as shown above) will crash the application with no warning.
IAmAPersson made the CrashPTC application which utilizes this glitch.
Note that this glitched -0
value is distinct from the values -1/4096
and -2/4096.
Both of these values also PRINT
as -0
, but do not have the glitched properties of the above value. Z==-1/4096
and Z==-2/4096
both give 0 (FALSE
).
For another bug with some similar properties, see 524287.999755859375 (Numerical Value), and for another interesting numerical bug, see 0.999995 (Numerical Value).