I like these topics -- Food for the brain :-)
Since the OP has been properly helped already, I think he will not mind
if I go slightly off topic. This could interest him anyway.
--------------------------------------------------
Funky did good in warning against the flaws of the 32nd bit.
However, it is not completely unsafe to work with it.
But sure it is due care.
If you make certain that your integer is only treated as a
"repository" of bits, and you only Set and Query the bits _as bits_
(ie: like Lightfoot8 described in his "towns" example), then you
can rely on the 32nd bit safely.
In all other cases, it is wise to heed Funky warning and double-check
that all your bits are behaving. Better test 2 minutes now than debug
2 hours later -- Agree?
In regard to bits and operations with bits, I am aware of 3 specific
bugs. And more subtle ones may exist -- if anyone can list them
I will hear him gladly.
Bug 1) the float datatypeSparing you the gory details of the floating point encoding / decoding
(you can read all about it if you google for IEEE 754 Single Precision Floating Point)
I tell you that in NWscript the Least Significant Bit in the float Mantissa is
"lost" in the act of encoding. And upon decoding it is always assumed to be 0,
which causes a small loss of precision in the final decoded value.
The Least Significant Bit (LSB) is bit 0, or the 1st bit, or the >> leftmost >> bit.
That is, the 1 in this pattern: 00000000 | 00000000 | 00000000 | 00000001
Said bit happens to be always 0 when you read from a float. And there is no
way to prevent the bug, other than not feeding to a float a value that makes use
of the LSB -- Which is not a practical solution.
Your best bet to dodge the problems caused by this is to not make use of
decimal values that want many digits of precision. The more digits you attempt
to retain, the heavier the precision loss sparked from that last 0 bit.
-
ODDLY enough, though, the NWscript float is correctly capable of storing and
retrieving any integer in the range -16777215 to +16777215 -- thus demonstrating
that the float bug strikes only when the Mantissa is employed to encode values
with a _decimal_ part whether it fits or not the 23 bits Mantissa storage.
-
Depending on the importance of your float values, it may be desirable to
pre-emptively convert them to an integer (multiplying by a proper power of 10)
so long it fits in the 23 bits range, and then assign them to the float variable.
I know it sounds extravagant -- well, extravagant solutions for extravagant bugs.
This will ensure that you retain (and can later retrieve) all your digits,
whatever the original value.
Bug 2) The >>> operator (part 1)Consider the following code snippet:
int nInteger = -100;
int nZero = nInteger >>> 32;
nInteger set to -100 creates the following bit pattern:
11111111 | 11111111 | 11111111 | 10011100
Then the RightShift operator (>>>) is expected to clear all
the 32 bits by pushing them to the right, leaving in their
place only a streak of 0s, like this:
00000000 | 00000000 | 00000000 | 00000000
Here is the bug: the call to >>> 32 will produce no change.
nZero will be assigned the unmodified input pattern:
11111111 | 11111111 | 11111111 | 10011100
Which is wrong.
If you need to RightShift by 32 positions, you have to do so
in 2 moves, for an example: a >>> 31 followed by a >>> 1.
Any combo that sums up to 32 will work.
But avoid a >>> 16 followed by another >>> 16, because a
different bug can occur in that scenario (read below).
Bug 3) The >>> operator (part 2)Consider the following code snippet:
int nInteger = 0xAAAA1111;
int nHiWord = nInteger >>> 16;
When RightShift-ing by 16 positions with the >>> operator,
and the 32nd bit is set... the >>> operator will behave just
like the >> operator.
That is, it will _drag_ the MSB and propagate it to its right.
Which is wrong.
In the above snippet, nHiWord should be assigned the value: 0x0000AAAA.
Instead it will be assigned the value: 0xFFFFAAAA, with the
phantom 0xFFFF0000 introduced by the MSB propagation.
To enforce the >>> behavior, in this specific case, there
is need of a [extra] masking operation to ensure that you
only retain the lower 16 bits.
Like this:
int nInteger = 0xAAAA1111;
int nHiWord = (nInteger >>> 16) & 0xFFFF;
Disclaimer:(because the Strange does happen)Should the code snippets I posted fail to reproduce the bugs,
I can provide the original (but way longer) source code that
will spark them sure-shot. Ask, no problem.
-fox
Modifié par the.gray.fox, 12 novembre 2011 - 03:35 .