7

What is the best way to check this famous equation:

0x2b || ~0x2b == 0xff

Mathematica doesn't seem to have a handy bitwise negation operator.

The best thing I did come up was:

FromDigits[IntegerDigits[16^^2B, 2, 8]
~BitOr~(IntegerDigits[16^^2B, 2, 8] /. {1 -> 0, 0 -> 1}), 2] == 16^^FF

which is rather terse. Or:

2^^00101011~BitOr~2^^11010100 == 16^^FF

which is ok. But it's not the same.

My naive hope was that something like this would work but it doesn't:

16^^2B~BitOr~BitNot@16^^2B == 16^^FF

Which yields False and reveals that I do not understand what bitwise negation in Mathematica parlance means...

I had hoped that BitNot[16^^2B] would yield 16^^D4, but I was utterly wrong. How can you force Mathematica to use bytes? Because IntegerDigits[16^^2B,2,8] yields {0, 0, 1, 0, 1, 0, 1, 1} which is ok, but IntegerDigits[BitNot[16^^2B], 2, 8] yields {0, 0, 1, 0, 1, 1, 0, 0}.

Apparently not really a bitwise negation.

Help, tips, etc. appreciated.

EDIT:

So due to Daniel Lichtblau's answer the best result so far might be:

NOT[bits_Integer, len_Integer: 8] /; bits >= 0 && len >= 0 := BitXor[bits, 2^len - 1]
OR = BitOr

16^^2B~OR~NOT@16^^2B == 16^^FF

:) Hilarious!

EDIT 2

I'd say the BitNot should have an optional argument, if 2's-complement is wanted, defaulting to True. As such:

protected = Unprotect[BitNot];
$BitNotActive = True;
    Options[BitNot] = {Compl -> True, Len -> 8};
    BitNot[n_Integer, OptionsPattern[]] /; $BitNotActive :=
    Block[{$BitNotActive = False},
        If[OptionValue[Compl], BitNot[n], 
            BitXor[n, 2^OptionValue[Len] - 1]]
    ]
Protect[Evaluate[protected]];

So the big question (which is actually no question at all, since it's always true...) in Mathematica would become:

16^^2B~BitOr~BitNot[16^^2B, Compl -> False] == 16^^FF

I demand overloaded operators and number representation without the "base^^" syntax!

Stefan
  • 5,347
  • 25
  • 32
  • 1
    that is the question... – cormullion Jan 24 '13 at 15:26
  • 1
    Actually it is a very real (as in correctly implemented) 2's complement bitwise negation. – Daniel Lichtblau Jan 24 '13 at 15:30
  • Shakespeare was obviously ahead of his time – user1066 Jan 24 '13 at 15:40
  • @TomD "There are more things in heaven and earth, Horatio, Than are dreamt of in your philosophy." – Dr. belisarius Jan 24 '13 at 15:53
  • @belisarius "The fault, dear brutus is not in our stars, but in our selves" – Stefan Jan 24 '13 at 15:56
  • The only way your identity holds is explicitly knowing you are using 8 bits to represent your integers. You wished that was assumed by the fact you used 2 hexas to write them in? – Rojo Jan 24 '13 at 17:47
  • @Rojo. Nope but would you agree that 0x2B fits perfectly into 8 bits? – Stefan Jan 24 '13 at 17:57
  • It also fits perfectly in 6, so why 8 and not 13? Lowest 8*2^n that's higher than the bit length? – Rojo Jan 24 '13 at 17:59
  • @Rojo Good Lord. What started as a joke becomes now a philosophical discussion. I was only wondering how to force binary representation of numbers that BitNot's definition "BitNot[n] turns ones into zeros and vice versa in the binary bit representation of n." holds. – Stefan Jan 24 '13 at 18:07
  • If we take a 6 bit representation, I believe 0x2B~OR~NOT@0x2Bshould give b111111 which is different from 0xff. You think a question whose answer would change the expected output is philosophical? – Rojo Jan 24 '13 at 18:12
  • @Rojo. Just imagine you were Hamlet and you want to use Mathematica to answer the question: X | ~X? And Mathematica yields magically "True"! – Stefan Jan 24 '13 at 18:15
  • @Rojo. I do not have a 6-bit machine; never had. Do you? Jesus. Yes indeed. cs = 0x000000000000002b <- something every debugging hacker discovers very often. So. the '0x' indicates base 16 and my computer likes base 2 and we're talking about bytes and I do know that a different base leads to different answers. Btw. It's a funny response ;) – Stefan Jan 24 '13 at 18:24
  • 3
    Once upon a time there was a (well hidden) unsigned bit complement function. In[3]:= Internal`UnsignedBitNot[43,8]

    Out[3]= 212

    In[4]:= $Version

    Out[4]= 5.2 for Linux (September 17, 2006) I no longer recall why it was discarded. Maybe because it was too well hidden to get any use. I think this is the first time I've seen it requested.

    – Daniel Lichtblau Jan 24 '13 at 20:54

2 Answers2

13

You want to complement bits based on a given length. Easy enough.

complementBits[bits_Integer, len_Integer] /; bits >= 0 && len >= 0 := 
 BitXor[bits, 2^len - 1]

(If you really want to compliment them, tell them the size is much too big for them..)

Quick test.

complementBits[43, 8]

(* Out[237]= 212 *)

Getting back to the question at hand, we have

BitOr[16^^2B, complementBits[16^^2B, 8]] == 16^^FF

(* Out[238]= True *)
Daniel Lichtblau
  • 58,970
  • 2
  • 101
  • 199
  • Hello @Daniel. The comment I wrote before does not show up; so again. Thank you for your answer. I knew about the xor'ing scheme, but was stuck due to the strange results with BitNot. I don't know what BitNot is good for. I knew before. But now? Grmpf... – Stefan Jan 24 '13 at 15:52
  • 2
    Once upon a time, before the bitwise operator functionality was ever released in Mathematica, I implemented the version you have in mind. It was overruled (somewhat noisily, I might add) in favor of 2's complement. There are arguments to be made for either one, and 2's complement does help to preserve various bitwise identities one might wish to have. – Daniel Lichtblau Jan 24 '13 at 15:59
4

As far as I can see Mathematica's result is the correct one.

[I will use a byte representation of your bits in the following, but a longer representation will work as well.]

$2B equals 00101011, which is turned into 11010100 ($D4) with a bitwise Not.

The interpretation of this bitpattern as an integer follows the usual 2's complement rules. The first bit signals that we are dealing with a negative number. IntegerDigits ignores the sign of the number (see Properties and Relations section of its doc page) so we need its absolute value. To get this, we subtract 1 (yielding 11010011) and bit negate the result to get 00101100, which is precisely what you get.

So, conclusion: the BitNot result of the number you input is precisely what you would expect. It is the translation in a visible bit sequence that is causing your problems.

Sjoerd C. de Vries
  • 65,815
  • 14
  • 188
  • 323
  • I know about the 2's complement form. Believe me. What I did not expect that IntegerDigits[16^^FF, 2, 8] yields {1, 1, 1, 1, 1, 1, 1, 1}. The documentation says: "BitNot[n] turns ones into zeros and vice versa in the binary bit representation of n." And for integers that they are represented in 2's complement form. So. How to force binary bit representation? I can not help but this is weird. I'm from the C/C++ area so I did indeed expect that ~0b10101010 == 0x01010101. I don't think that Mathematica is fully correct on that matter. – Stefan Jan 24 '13 at 17:13