Author Topic: Greater Than is_NOT_equal_to  (Read 6637 times)

0 Members and 1 Guest are viewing this topic.

hendie

  • Guest
Greater Than is_NOT_equal_to
« on: July 29, 2004, 08:08:36 AM »
Quote
_$ Dist
100.0
_$ L1
100.0
_$ (> Dist L1)
T

why?
Dist is a variable returned by (getreal...)
L1 is a variable returned by querying an objects length (the object was created using exactly 100 as the length)
(type obj) returns REAL in both cases
to all extents and purposes, both are "exactly" equal, yet > returns True.


I know it's to do with ("one of the quirks" quotes Autodesk) of the rounding of floating point values. So, rather, I suppose my question should be
What is the preferred method of getting around this ?
as a workaround I can use
Code: [Select]
(> (rtos Dist)(rtos L1))
but is that likely to turn around and bite my ar$e later ?

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
Greater Than is_NOT_equal_to
« Reply #1 on: July 29, 2004, 08:22:13 AM »
That bites.

What do you get from
(* 1000000000 Dist)
(* 1000000000 L1)
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

hendie

  • Guest
Greater Than is_NOT_equal_to
« Reply #2 on: July 29, 2004, 08:31:41 AM »
Quote
(* 1000000000 Dist)
(* 1000000000 L1)
1.0e+011
1.0e+011


however I found a more appropriate solution

Code: [Select]
(> Dist (vlax-curve-getEndParam Pobj))

where Pobj is the object in question (obviously)
thanks to Stig again !

Mark

  • Custom Title
  • Seagull
  • Posts: 28762
Greater Than is_NOT_equal_to
« Reply #3 on: July 29, 2004, 08:49:49 AM »
I get nil using the code below and selecting a line that is 100 units long.

Code: [Select]

(if (setq ent (car (entsel "\nPick an enttity: ")))
  (setq L1 (vla-get-length (vlax-ename->vla-object ent)))
  )

(setq dist (getreal "\nEnter a length: ")) ; entered 100

(setq ans (> dist L1)) ; returns nil
TheSwamp.org  (serving the CAD community since 2003)

hendie

  • Guest
Greater Than is_NOT_equal_to
« Reply #4 on: July 29, 2004, 09:14:01 AM »
seems to be working now  ~ must have been operator (me) trouble :crazy:

sinc

  • Guest
Greater Than is_NOT_equal_to
« Reply #5 on: July 29, 2004, 08:46:18 PM »
This just came up recently somewhere else, I forget where.  The problem is you can never compare reals for exact equality because computers need to approximate reals using binary numbers.  So, if you want to find out if two reals are equal, you need to apply a "fuzz factor", or allowable tollerance, as in:

(equal L1 100.0 0.000001)

The way it just came up in the other discussion was that the following returns nil instead of T:

(= 6.0 (- 8.2 2.2))

hendie

  • Guest
Greater Than is_NOT_equal_to
« Reply #6 on: July 30, 2004, 04:11:08 AM »
thanks sinc, I think I saw that same post but did a search and couldn't locate it again.
as it turned out, the fuzz factor couldn't really help me in this case but using Stig's curve functions solved the problem

SMadsen

  • Guest
Greater Than is_NOT_equal_to
« Reply #7 on: July 30, 2004, 05:55:43 AM »
Quote from: hendie
.. using Stig's curve functions solved the problem

Ummm, thanks Hendie but I think those are Aut0desk's, not mine   :lol:

Sorry, can't add a clever solution for the equality problem.

daron

  • Guest
Greater Than is_NOT_equal_to
« Reply #8 on: July 30, 2004, 08:14:51 AM »
Of course, Hendie means the knowledge you imparted to us about curve parameters helped him solve the problem.

sinc

  • Guest
Greater Than is_NOT_equal_to
« Reply #9 on: July 30, 2004, 08:28:27 AM »
Quote from: hendie
thanks sinc, I think I saw that same post but did a search and couldn't locate it again.
as it turned out, the fuzz factor couldn't really help me in this case but using Stig's curve functions solved the problem

How did the curve functions solve the problem?

If you're trying to compare reals for equality, you still have the problem, no matter how you get your reals.  If changing the method you use to get your reals seems to make things work, it's just luck of the draw.  Change your object to a different length and it might not work.

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
Greater Than is_NOT_equal_to
« Reply #10 on: July 30, 2004, 10:27:33 AM »
How about this?
Code: [Select]
(defun c:test()
  (prompt "\nEqual ")
  (princ (*equal* 6.0 (- 8.2 2.2)))
 
  (prompt "\n< ")
  (princ (*<* 6.0 (- 8.2 2.2)))
 
  (prompt "\n> ")
  (princ (*>* 6.0 (- 8.2 2.2)))
 
  (prompt "\n<= ")
  (princ (*<=* 6.0 (- 8.2 2.2)))
 
  (prompt "\n=> ")
  (princ (*>=* 6.0 (- 8.2 2.2)))
  (princ)
)

(defun *Real_Test* (sym a b)
  (apply sym (list(fix (+(* a 100000)0.1))(fix(+(* b 100000)0.1))))
)
(defun *=* (a b)
  (*Real_Test* '= a b)
)
(defun *<* (a b)
  (*Real_Test* '< a b)
)
(defun *>* (a b)
  (*Real_Test* '> a b)
)
(defun *<=* (a b)
  (*Real_Test* '<= a b)
)
(defun *>=* (a b)
  (*Real_Test* '>= a b)
)


Add a little Mapcar majic & a list of more than 2 vars could be processed.
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

hendie

  • Guest
Greater Than is_NOT_equal_to
« Reply #11 on: July 30, 2004, 04:15:28 PM »
I ended up using
Code: [Select]
(while   (> Dist (vlax-curve-getdistatparam Pobj (vlax-curve-getendparam Pobj)))
         (initget 5)
         (setq Dist (getreal "\nPlease enter distance))
       )

which seemed to solve my problem. I think it was perhaps a combination of things (of my own doing) and I should have investigated a bit further before posting  :oops:

sinc

  • Guest
Greater Than is_NOT_equal_to
« Reply #12 on: July 30, 2004, 10:55:12 PM »
Quote from: hendie
I ended up using
Code: [Select]
(while   (> Dist (vlax-curve-getdistatparam Pobj (vlax-curve-getendparam Pobj)))
         (initget 5)
         (setq Dist (getreal "\nPlease enter distance))
       )

which seemed to solve my problem.

Ah hah, I think I finally understand what you're asking!  That bit of code did it.  :D

Sounds like you want the user to be able to enter a  number that should indicate a distance along an object, right?  Therefore, you're checking to see if the number indicated is a valid point on the object.  Is this right?

If so, you still might run into the problem from time to time the way you're doing it, just much less frequently.  The culprit is still the rounding error, it's just been obscured.

You might try:

Code: [Select]
(if (vlax-curve-paramAtDist Pobj Dist)
  (princ "Got a point on the item!")
)


This is more straightforward than the way you're doing things, and (depending on how Autocad did the implementation) may even take a built-in fuzz-factor into account for you (at least enough to account for the 16/32 bit rounding problem that exists between Autocad and Windows).  Probably not, but it should work at least as well as your getEndParam version (both versions do pretty much the same exact thing), except in a more direct and readable form.

If you still have problems, then the correct way of going about your task so that you're SURE you'll never have a problem is something along these lines:

Code: [Select]
(setq
     *FUZZ*  .00001
     objLen   (vla-get-length obj)
) ;_ setq
(while
  (progn
    (setq dist (getreal "\nPlease enter distance: "))
    (and (> dist objLen)
(not (equal dist objLen *FUZZ*))
    ) ;_ and
  ) ;_ progn
) ;_ while

Keep in mind that you have to use (equal) and a fuzz factor EVERY time you check lengths...  It's a pain, I know, but it's the only way to GUARANTEE that you'll never have a problem.

Note that, whenever possible, it's better to use vla-get-length because its intent is clearer to others than something like (distAtParam obj (endParam obj)).

hendie

  • Guest
Greater Than is_NOT_equal_to
« Reply #13 on: July 31, 2004, 04:36:47 AM »
Quote from: sinc
Sounds like you want the user to be able to enter a number that should indicate a distance along an object, right?

spot on.
thanks for the info.I'll look into that. I'm also thinking of adding a default "endpoint" just to help eliminate that problem

SMadsen

  • Guest
Greater Than is_NOT_equal_to
« Reply #14 on: July 31, 2004, 06:47:12 AM »
Quote from: sinc
... (at least enough to account for the 16/32 bit rounding problem that exists between Autocad and Windows).

Richard, can you elaborate on this? I thought that whenever a 64 bit IEEE floating point number is passed around that it remains intact and doesn't loose precision.