PDA

View Full Version : =, eq, equal



David.Hoole
2004-07-27, 03:02 PM
Hi folks

I remember a discussion, many moons ago on Ye Olde AUGI Guild, of why these functions often return nil when it seems that they should return T. I know it's due to very small rounding errors caused by AutoCAD not working to the same numeric accuracy as the operating system, and that it can be overcome by using the fuzz factor in the EQUAL function. But the discussion posted had a very good illustration of exactly why this happens. Does anyone still have a copy of this discussion secreted somewhere that they could share.

Thanks in advance.

Mike.Perry
2004-07-27, 03:33 PM
Hi

I think the below is what you're referring to -

-----Oprindelig meddelelse-----
Fra: Perry, Michael P
Til: whdjr@bellsouth.net; Guild Lisp
Sendt: 17-10-2003 18:37
Emne: Re: [LISP] nil or not to nil

Hi

I think (hope) the below is something like what your after -


(while
(and (not (setq Entity (entsel)))
(/= 52 (getvar "ErrNo"))
)
(if (= Entity nil)
(princ "\nNo object selected, please try again: ")
)
)

If it is, credit must go to Robert Bell.

If it's not, please feel free to publicly mock me ;-)

Have a good one, Mike

******

-----Oprindelig meddelelse-----
Fra: stig.madsen@natmus.d
Til: guild-lisp@augi.com
Sendt: 18-10-2003 00:09
Emne: Re: [LISP] nil or not to nil

Now that you asked for it, Mike:

<mocking-in-public-mode=on>
(if (= entity nil) .. <- What's that?
Think it should be (if entity .. ?
</mocking-in-public-mode=off>

:-)

Just note on ERRNO: it doesn't get "reset" to 0 but keeps the last error code (if an error occurred). To be sure that the loop detects a pick in empty space, be sure to setvar it to nil before entering.

Stig Madsen

******

-----Original Message-----
From: guild-lisp-discussion-bounce@lists.hostorlando.com
[mailto:guild-lisp-discussion-bounce@lists.hostorlando.com]On Behalf Of stig.madsen@natmus.dk
Sent: 17 October 2003 23:16
To: guild-lisp@augi.com
Subject: Re: [LISP] nil or not to nil

Uhoh now I asked for it, too:

<mocking-myself-in-public-mode=on>
(if entity .. <- What's that???
Think it should be (if (not entity) .. ?
</mocking-myself-in-public-mode=off>

Stig Madsen

******

-----Oprindelig meddelelse-----
Fra: Perry, Michael P
Til: stig.madsen@natmus.dk; guild-lisp@augi.com
Sendt: 18-10-2003 11:48
Emne: RE: [LISP] nil or not to nil

Hi

*Thanks* for the <mocking-in-public-mode=on> & <mocking-myself-in-public-mode=on> made me laugh :) on a Saturday morning in the office which can only be a good thing.

Is

(if (not entity)

&

(if (= Entity nil)

not basically the same thing? both return T if Entity = nil

Stig please educate/enlighten me to the differences so that I may learn a little (please take it slow and easy as I'm not the brightest or quickest in the box).... still wish I hadn't made my original comment on stuff that I'm not 100% about....

Have a good one, Mike

******

-----Original Message-----
From: guild-lisp-discussion-bounce@lists.hostorlando.com
[mailto:guild-lisp-discussion-bounce@lists.hostorlando.com]On Behalf Of
stig.madsen@natmus.dk
Sent: 19 October 2003 01:18
To: guild-lisp@augi.com
Subject: Re: [LISP] NIL, NULL, =, EQ, EQUAL

Yes, it results in the same thing but it's not often one gets a chance to mock you :))

(= somevalue nil) just hurts the eye because the intention is not clearly laid out. '=' is a relational operator used for comparing values or, as the help reference says, "numerically equal" values.

Nil is not a bound value but a condition of an empty list. Given the definition of nil (the empty list), using '=' to check whether or not a value is bound is not considered good programming.

It might even lead you to use '=' in other comparisons that do not make sense. For example:

(setq a '(A B C))

(A B C)

(setq b (list 'A 'B 'C))

(A B C)

They look suspicially the same, but check out what '=' has to say:

(= a b)

nil

It's not good for comparing other things than numbers and strings, and getting used to rely on '=' for doing comparisons in any which case is the same as relying on luck. Different operators work with different datatypes under different conditions and I think that getting used to match the operator to the circumstances can save alot of errors - even though they work well in some cases!

For example. If you have used '=', EQ and EQUAL at random, at some time you will run out of luck and get a bug that is much harder to find than if you matched the function to begin with. Taking the seemingly equal lists again:

(eq a b)

nil

(equal a b)

T

EQ checks if a and b are bound to the same values. In this case they are not because the lists they are bound to come from different places. EQUAL only compares the values of a and b. Here it finds that a and b holds identical values and returns T.

To illustrate it further, draw a line and assign it's ename to a and b (independently of each other):

(setq a (car (entsel))) -> hit the line

(setq b (car (entsel))) -> hit the exact same line

Now compare:

(= a b)

nil

(eq a b)

T

(equal a b)

T

In this case EQ returns T because a and b are bound to the same pointer in memory - to the exact same entity reference. But '=' even fails in this comparison. Of course, again, EQUAL doesn't care one way or another as long as the values are identical.

Oh, by the way. Here's an extra <mocking-myself-in-public-mode=on>: "be sure to setvar it [ERRNO??] to nil" Geesh! ERRNO should be reset to 0, not nil.

Stig Madsen

******

Have a good one, Mike

David.Hoole
2004-07-27, 03:48 PM
Thanks Mike

Close, but no coconut ;-)

As an example:

(= 6.0 (- 8.1 2.1)) returns...
T

(= 6.0 (- 8.2 2.2)) returns...
nil !?!?

This is apparently due to teeny weeny little rounding errors (technical term).

Someone asked me to explain it to them, and I could only give a sort of vague mumbled answer about rounding errors between AutoCAD & the operating system. The thread I'm referring to went right down into the maths.
I have a feeling that Mr Madsen & Mr Bell may have had a hand in the proceedings (hint) ;-)

sinc
2004-07-27, 04:51 PM
I don't think the problem has as much to do with any difference between AutoCAD and the OS as it does in the method used to calculate whatever value you're talking about.

The reason is actually rather simple. Let's look at an easy example. Try to get to coordinate (1,1) using the polar command. You can't do it exactly, because you need to go at a 45° angle from the x-axis a distance of (square root of 2) units, and being an irrational number, the computer can't figure (square root of 2) exactly. Therefore, no matter what you do, if you use polar coordinates, there's no way to set a point exactly on a point you set at (1,1) using xy coordinates - there's a miniscule amount of error. Most of the time we don't notice it, but sometimes (as in when checking equality) it causes problems. That's why there's the equal command with a fuzz-factor - it deals with this problem. The problem arises when using any irrational number - PI, n/3, n/7, etc.

David.Hoole
2004-07-27, 05:04 PM
Richard

Using the example I gave previously:

(= 6.0 (- 8.2 2.2)) returns...
nil

Where's the irrational number? Both values used to calculate the 2nd argument are provided to the same accuracy as the first argument, and should logically produce the answer 6.0, but they don't.

(rem 6.0 (- 8.2 2.2)) returns...
8.88178e-016

and

(fix (- 8.2 2.2)) returns...
5

As I understand it, this error is produced by the fact that the OS works to 32 or 64 bit, whereas AutoCAD & it's Lisp interpreter talk in 16 bit. What I can't remember is how 0 gets rounded up or down.

sinc
2004-07-27, 05:09 PM
Oh, I see what you're talking about. Yeah, I don't know the details of that one. It's something that's pretty much never important. For most applications, you can just apply a fuzz-factor and the actual direction of the error is irrelevant.

David.Hoole
2004-07-27, 05:16 PM
Yes, the fuzz factor works around the issue, provided that the person writing the code is aware that an issue exists where there logically shouldn't be one.
I was just trying to find the historical thread that gave a really detailed explanation of why this happens at all.
Hopefully someone else will be sad enough to be interested, like me ;-)

sinc
2004-07-27, 06:00 PM
Yeah, sounds like it's a problem created by the fact that AutoCAD never upgraded the internals to 32-bit, even though Windows did that switch a decade ago. Definitely something they should have taken care of by now... Using a fuzz-factor for subtraction is just plain silly.

RobertB
2004-07-27, 09:01 PM
Unhappily, the issue will always remain with us, no matter how wide the registers get. The reason is because some real numbers cannot ever be represented exactly in binary, no matter how precise you get.

hugh.69031
2004-07-28, 01:02 AM
Unhappily, the issue will always remain with us, no matter how wide the registers get. The reason is because some real numbers cannot ever be represented exactly in binary, no matter how precise you get.
This is right. All floating point (FP) numbers have to be approximated within the style of computers we normally use. The format has been standardized by iEEE and others. Google "IEEE floating point",
here's just one:-

http://research.microsoft.com/~holl.../ieeefloat.html (http://research.microsoft.com/~hollasch/cgindex/coding/ieeefloat.html)

The practical consequences are that

- FP comparisons can lead to unintended conclusions if applied without considering roundoff error. If you want to compare two FP's allow for the fuzz e.g. if (abs(x-y)<fuzz) ... rather than if (x ==y) ...

- FP subtraction of very similar numbers can lose precision

- repetitous calculation involving FP can lose all meaning

- 64 bit integers are going to very handy, but wont solve the problem

HTH
Hugh Adamson

sinc
2004-07-28, 01:58 AM
Heh, I actually knew that. I've avoided exact comparisons of floating-point numbers in my code for so long that it's become second-nature, and I do it without thinking any more. I completely forgot why. D'oh! :mrgreen:

David.Hoole
2004-07-28, 07:37 AM
Thanks folks. Question answered. Would still have liked to find that thread though :-(