Visual LISP, AutoLISP and General Customization
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Laymen's Explanations of (logand), (logior) and (boole)

32 REPLIES 32
Reply
Message 1 of 33
Anonymous
2601 Views, 32 Replies

Laymen's Explanations of (logand), (logior) and (boole)

I had a really hard time coming to understand what the AutoLisp bit-related (logand), (logior) and
(boole) functions actually DO, despite a lot of trying. I wanted something in English to get around
my lack of experience with programming outside AutoCAD. Help didn't do it for me (nor for a lot of
other people who've wondered about these on Newsgroup threads), or I wouldn't be posting this. I
searched the Newsgroup, and found some links to what ought to have been helpful website articles,
but they all seem to be obsolete. I looked at AfraLisp, Googled, and I was still at a loss, until I
messed with them enough to figure them out (sort of -- see below). But having figured at least most
of it out, I'm putting these Laymen's Explanations on record for the sake of others who, I hope,
will be able to find this a useful route into being able to USE these functions. They can be very
useful in the right situations, but I never used them until recently, because I didn't "get" how
they worked.

Preface:

All integers can be expressed as a unique sum of powers of 2, expressed here in the form
2-to-the-X-power = 2^X. For example,
7 = 1 + 2 + 4 [or 2^0 + 2^1 + 2^2]
42 = 2 + 8 + 32 [or 2^1 + 2^3 + 2^5]
64 = 64 [only, because it *is* a power of 2, namely 2^6]
etc.

This system is used to store things like AutoCAD System Variables that can be made of various
combinations of values, such as OSMODE, *because* of the fact that every value represents a unique
combination -- each Osnap mode is assigned a value that is a power of 2, and any possible
combination of Osnap modes is represented by its own unique sum.

Consider integers in terms of the collection of power-of-2 components, otherwise known as bits, that
make them up. [I will use the power-of-2 values themselves, because one finds them referred to with
different "bit numbers" in some sources, e.g. 8 seems to be called "bit 3" in some places, because
it's 2^3, and "bit 4" in other places, because it's represented by a 1 in the 4th position from the
right in a binary number.]

The "log" in (logand) and (logior) stands for "logical bitwise," meaning basically "when considered
in terms of the component bit values that make up the integers in question." "Boole" is the name of
a mathematician who's memorialized in a system of logical operations.

Laymen's explanation of (logand):

The "and" stands for the logical or Boolean "and" function, which [in AutoLisp-type terms] returns
True only if *every* thing being looked at has the characteristic being tested for -- this *and*
that *and* the other thing are *all* True, so the "and" combination is, too. If any of them are
*not* True, then neither is the combination.
The (logand) function, when applied to a set of integers is asking the question: "What power-of-2
component bits are a part of the makeup of *all* of these integers?" It returns an integer that is
the *sum* of all of those bits shared by *all* of the numbers being looked at.
So, to use Help's examples:
(logand 7 15 3) returns 3, because *all* of those numbers [1+2+4, 1+2+4+8, 1+2] are made up of
combinations that include a 1 and a 2 [which together constitute the 3 that is returned], and those
are the only bits that are contained in all of those numbers.
(logand 2 3 15) returns 2, because those numbers all have the 2 bit in them, and no others in
common.
(logand 8 3 4) return 0, because those numbers [8, 1+2, 4] share no common bits.
This can be used, for example, to determine whether a particular Object Snap mode is set. For
example, Intersection is represented by 32, so if the value of OSMODE is the sum of a combination of
bits that includes 32, then Intersection mode is set. The question is: "Do the number 32 and the
value of OSMODE share any bits?" [Since 32 is itself a power of 2, it's the only one they can
possibly share.] Or, in AutoLisp terms:
(logand 32 (getvar 'osmode))
That will return 32 if they do, that is, if Intersection mode is set, because 32 is the sum of all
the bits the two number share.
You can also look at combinations. For example, Endpoint is 1 and Midpoint is 2; you can ask
whether the sum of those [3] and OSMODE share any bits, the same way:
(logand 3 (getvar 'osmode))
If that returns 1, then Endpoint is set, but not Midpoint; if it returns 2, it's the other way
around; and if it returns 3, both are set.

Laymen's explanation of (logior):

The "ior" part stands for the Boolean "inclusive or" [sometimes just called "or"] function, which
returns True if *any* thing being looked at has the characteristic being tested for -- this *or*
that *or* the other thing is True, so the "or" combination is, too. It's only if *none* of them are
True that the combination therefore is not, either. It's "inclusive" because it includes the
possibility that *more than one* thing may be True, as opposed to the "exclusive or" function which
is True only if *just one* of the things being looked at is True, but *not* more than one of them.
The (logior) function, when applied to a set of integers is asking the question: "What power-of-2
component bits are a part of the makeup of *any* of these integers?" It returns an integer that is
the sum of all of those bits included in *any* the numbers being looked at.
So, to use Help's examples:
(logior 1 2 4) returns 7, because 1, 2, and 4 [which add up to 7] are all contained in at least one
of those numbers [and happen, in this case, to *be* the numbers themselves, which share no common
bits].
(logior 9 3) returns 11, because 9 = 1+8 and 3=1+2, so together they involve 1 [which happens to be
part of both of them, but doesn't get counted twice], 2, and 8, and those three bits add up to 11.

Laymen's explanation of (boole) [for two-integer comparisons]:

The operator bits in Help's "truth table," which are added together to make the 'operator' argument
in the function, are asking:
1 -- "For each bit value, is that bit a part of both of the integers being looked at?" The returned
integer includes that bit value if it's included in both.
2 -- "For each bit value, is that bit a part of the first number but not of the second?" The
returned integer includes that bit value if that's the case.
4 -- "For each bit value, is that bit a part of the second number but not of the first?" The
returned integer includes that bit value if that's the case.
8 -- "For each bit value, is that bit a part of *neither* number?" The returned integer includes
that bit value if it's not in either.
So, to use Help's examples:
(Boole 1 12 5) returns 4. The 1 operator is asking for bit values that are part of both 12 and 5.
They both include a 4, but have no other common bits, so 4 is returned.
(Boole 6 6 5) returns 3. The 6 operator = 2+4. The 2 component of that is looking for bits that
are part of the 6 but not part of the 5, and bit value 2 fits that description. The 4 component is
looking for bits that are part of the 5 but not of the 6, and bit value 1 fits that description.
[The 4 that is part of both numbers satisfies neither test.] The returned 3 is the sum of the 2 and
the 1 that those two components of the operator found.
(Boole 4 3 14) returns 12. The 4 operator is looking for bits that are part of the 14 but not of
the 3, and finds bit values 4 and 8. The 14 includes a 2, but since that's also part of 3, it isn't
included in the returned sum of 12.
The specific operator 6, as in (boole 6 x y), can be used to toggle bit values on and off in things
like System Variables, because if it finds a shared bit value, it doesn't include that in its
returned integer, but if it finds a value that's only in one number, it does include that. For
example, if you want to toggle Intersection mode [represented by 32] on or off within OSMODE, you
can do this [an approach found in many Newsgroup threads]:
(setvar 'osmode (boole 6 32 (getvar 'osmode)))
What it's doing is looking [with the 2 component of the 6 operator] for bit values that are in 32
but are not in OSMODE, and [with the 4 component] for bit values that are in OSMODE but are not in
32. [Combined, that's the "exclusive or" function -- looking for things that are in either one, but
not both.] If Intersection is set, the first check will *not* be satisfied, because 32 will be part
of *both* numbers. So the return will *not* include a 32, and Intersection will be removed from the
OSMODE combination. But the second check will find all the bit values that are in OSMODE but not in
32, which will include all other modes that are set, so the return will still include all of those.
If, on the other hand, Intersection is *not* set, the first check *will* be satisfed, because 32 is
part of only the first number checked. So the return will include a 32 [along with, again, all the
other values found by the second check], and Intersection will be *added* into the OSMODE
combination.

Questions arise about (boole) for more than two integers:

Help for (boole) implies at the beginning that you can look at *more than two* integers, but none of
its examples do, its truth table doesn't seem to allow for it, and no examples I found anywhere else
do. I have my suspicions about how that works, but welcome any better information:

(boole 1 a b c d) seems to find bits that are common to all the integers listed, but it's not really
"needed" because it's the equivalent of (logand a b c d):
(boole 1 1 3 5 7 9) returns 1, because that's the one bit value shared by all the numbers; some
other bits are shared by some, but not all, numbers;
(boole 1 3 5 12) returns 0, because while all the numbers share a bit with one of the others, no bit
is common to all.

(boole 2 a b c d) seems to find, as expected, bit values that are in the first integer, but in
*none* of the rest:
(boole 2 6 10 18) returns 4, which is in 6 and not in the others, but the 2 part of the 6 is in both
the others;
(boole 2 6 10 37) returns 0, because the 2 that's part of the 6 is also part of the 10, and the 4 in
it is part of the 37, so both bit values that make up the first number are disqualified. And since
the 37 is the third number, I infer that it is indeed looking at all numbers, not just the first two
as the truth table seems to imply.

(boole 4 a b c d) however, seems *not* to do what I expected, namely look for bits that are in the
last number but none of the others:
(boole 4 9 24 33 6) returns 6 as I expected, because none of the other numbers has the 2 or 4 bit
that make up that 6. That suggests that it is indeed the *last* number it's comparing the others to
[rather than the second, as in two-number comparisons], simply because none of the others can
contribute to that result. But:
(boole 4 15 24 33 6) also returns 6, despite the fact that the 15 contains both the 4 and 2 bit
values. However,
(boole 4 24 33 15 6) returns 0, suggesting that it compares the last number *only to the
next-to-last number,* and ignores the rest. Why this isn't analagous to the way the 2 operator
works, in reverse, I can't guess.

I was hoping that (boole 6 a b c) would function as a more-than-two-number "exclusive or" function,
finding bit values that are part of only one of the integers compared, however many there are. And
sometimes that seems to work, for example:
(boole 6 2 5 12) returns 11 -- 1 is part of only the 5, 2 is part of only the 2, [4 doesn't count
because it's part of both the 5 and the 12,] and 8 is part of only the 12; the result is 1+2+8 = 11.
Also, using (a b c) values involving one 1 and two 0's, in any combination, returns 1 [if any one of
the three includes 1, but not more than one of them, then 1 is part of the returned value], and one
0 and two 1's in any combination returns 0 [not 1, because 1 is part of more than one of the
integers]. But:
(boole 6 2 5 12 37 40) returns 6, which should mean that 2 and 4 are in only one number each. 1 is
in two of them, 2 is part of only the 2 [that's good], 8 is in two of them, 16 isn't in any of them,
and 32 is in two of them. But 4 is a part of the 5 and the 12 and the 37, so it "shouldn't" be part
of the returned value. If anyone knows anything about the "thought process" here, I'd appreciate
hearing about it.

An interesting thing happens with (boole 8), which Help does not use in any examples. If it's
looking for bit values that are not part of either integer (or any of them, if more than two are
compared), in theory it *could* accept all bit values higher than the highest integer, off to
infinity! But it doesn't do that. In two-number comparisons, it seems to find bits that are not
part of either number, and add them up [so far so good], then *subtract* the next bit-value beyond
the highest integer, and not look any further:
(boole 8 5 9) returns -14; 1, 4 and 8 are disqualified because they're part of at least one of the
integers, but 2 isn't, so it qualifies; 16 is the next bit value above 9; 2-16 = -14.
I haven't been able to find any pattern to suggest how it reaches a result from comparing more than
two numbers this way. But all the ones I've tried are positive, rather than negative as in
two-integer comparisons. Any ideas?

--
Kent Cooper
32 REPLIES 32
Message 21 of 33
Tom Smith
in reply to: Anonymous

Kent, my comments were directed at the Help-bashing, not accusing you of failing to look things up elsewhere.

I appreciate your effort, however I agree with Tony that a simple breakdown to binary numbers makes it far easier to understand.

My advice to others would be, if Kent's explanation leaves you just as confused as before, Google "Boolean binary" and skip the Wikipedia entry, which goes into all manner of other things.

For example http://users.senet.com.au/~dwsmith/boolean.htm uses nothing but 1's and 0's, so the truth tables are simple to understand.
Message 22 of 33
Anonymous
in reply to: Anonymous

[If nothing else, this thread has gotten some links into the Newsgroup that are current, whereas
many of those I found in searching it before were not.]
--
Kent Cooper


wrote...
.... Google "Boolean binary" and skip the Wikipedia entry, which goes into all manner of other
things.

For example http://users.senet.com.au/~dwsmith/boolean.htm uses nothing but 1's and 0's, so the
truth tables are simple to understand.
Message 23 of 33
Inciner
in reply to: Anonymous

Oh my God, thank you mr Cooper, thank you!

After all this years I've got all this logical stuff just only after your's excellent explantion!

You've definitely made my day!

 

OSMODE and other bit-coded variables are just 2x bases 😃

After that I've got how to get all summed bases from integer. It is so simple for now 😃

 

(defun 1D_BS ( x / q l ) 
(setq q 1)
(while (<= q x) (setq l (cons (logand q x) l) q (* q 2) ) )
(reverse (vl-remove 0 l))
)

(1d_bs 267) -> (1 2 8 256)

(1d_bs 267560) -> (8 32 256 1024 4096 262144)

 

 

Also I've realised, that there are no positive integers, that cannot be represented via summ of bases, or single base:

(progn
(setq i 1)
(repeat 400
(princ "\n")
(setq f (1d_bs i))
(princ i) (princ " = ") (princ (apply '+ f)) (princ " ") (princ f)
(setq i (1+ i))
)
)

 

From Russia with love, Paul

😃

Message 24 of 33
mid-awe
in reply to: Inciner

It's still clear as mud to me 😉
Message 25 of 33
Inciner
in reply to: mid-awe

😄

Well, it is so simple for now 😃

These functions are interesting from  how we can use them, not from their math.

Basically,  all that you need to know to use bit-coded sytem is a couple of things:

 

0) Why do we need it? To control values, and ANY combination of values via single integer!

 

1) Use only base of 2 for summing. Autocad variables uses them only.

0, 2^0, 2^1, 2^2, 2^3, 2^4... 2^n

0, 1, 2, 4 ,8, 32, 64, 128, 256... etc.

They are bit codes (used as different options of some function/variable, like OSMODE, 1,2,3,4,5, where 1st~1, 4th~8, 7th~128)

 

2) Why do we use the 2x base only? Because logand, logior and boole perfectly fits to them!

 

3) How do I know, if some value were already summed in total integer 3067?

(logand 16 3067) = 16 - yes, unique value 16 should be summed to get 3067 integer value

(logand 4 3067)  = 0 - no, unique value 4 weren't summed to get 3067 integer value

 

4) What bit codes we need to summ to get 3067? What bases values were summed to get this integer value?

(1D_BS 3067) = (1 2 8 16 32 64 128 256 512 2048) - that bases should be summed. Yep, we can see 16, and can't see 4.

 

5) How we can get summ of 1 2 8 16 32 64 128 256 512 and 2048 bits?

(logior 1 2 8 16 32 64 128 256 512 2048) = 3067

 

6) ?????

 

7) PROFIT!

Message 26 of 33
mid-awe
in reply to: Inciner

Thank you, that was a very clear answer. I can't say I fully get it, but I definitely got a sense of understanding. I'll need to use it a little first.
Message 27 of 33
Rtogores
in reply to: mid-awe

For those of you that can read Spanish, I can offer the learning materials I used in a course delivered in 1999 at the Universidad Nacional del Nordeste (in Corrientes, Argentina). Though even if not understanding Spanish, the AutoLISP code included could be useful, I think.

http://www.togores.net/vl/curso/lisp/bases/control/binario

 

In my recent book AutoCAD expert's Visual LISP I also treat this subject (this time in English Smiley Happy).

This book is also available in Kindle E-book format:

The Language and its Development Environment (AutoCAD expert's Visual LISP, Volume 1)

Controlling AutoCAD from Visual LISP (AutoCAD expert's Visual LISP, Volume 2)

Message 28 of 33
bhull1985
in reply to: Anonymous

This is excellent stuff, very useful.

Iterations of an explination to a point of complete understanding are what most of us seek when scouring the internet anyways, and this is one extreme of it, quite opposite that of the binary conversion method.

Much appreciated, and it makes even more sense why the programmer would think the helpdocs not required nor overly useful whereas the nincompoo beginner would look to them, considering they were created by the programmers, probably an annoyance, not a learning/teaching tool.

You rock Kent

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Please use code tags and credit where credit is due. Accept as solution, if solved. Let's keep it trim people!
Message 29 of 33
mracad
in reply to: bhull1985

This is not so muddy now.....besides I like mud (baths).
Message 30 of 33
john.uhden
in reply to: Anonymous

Except for lengthy code, I think that is the longest response I have ever seen, but I guess Kent gets most of the credit for that.

It's good to hear from you!

John F. Uhden

Message 31 of 33
john.uhden
in reply to: Anonymous

Yay! Another old-timer has returned from the past.

Of course it will take me another 11 years to figure out how that all works. But if I need you, you can call me.

John F. Uhden

Message 32 of 33
john.uhden
in reply to: Anonymous

Maybe being "a mere architect" is the problem. <G>

Being "useless" just reminds me of a Johnny Bad Mouth joke.

John F. Uhden

Message 33 of 33
john.uhden
in reply to: Tom Smith

If it's any help, here is something from my archives...

 

;;------------------------------------------------------------------------
;; Functions added (09-01-02) to "push" and "pop" the OSMODE on/off state.
;; It stores the value of the 16384 bit in the global variable $osmode.
;;
(defun push_osmode ()
   (setq $osmode (logand (getvar "osmode") 16384))
)
(defun pop_osmode ()
   (if (= (type $osmode) 'INT)
     (setvar "osmode" (boole 2 (getvar "osmode")(boole 2 16384 $osmode)))
   )
)
(defun off_osmode ()
   (push_osmode)
   (setvar "osmode" (logior (getvar "osmode") 16384))
)

All I know is that it seems to work.  With what I am distressed is Autodesk's having 
removed the "Quick" toggle some years ago. If you don't know, it can be set by: (setvar "osmode" (logior 1024 (getvar "osmode"))) OR: (vlax-invoke *doc* 'Setvariable "osmode" (logior 1024 (vlax-invoke *doc* 'Getvariable "osmode") ) ) where (setq *doc* (vlax-get-activedocument (vlax-get-acad-object)))

John F. Uhden

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Design & Make Report

”Boost