Jump to content

Recommended Posts

Posted

The other day I spent a good amount of time tracking down an unexpected behavior in one of my routines, to finally realized that I had been another victim of the famous fuzz factor using the fix function.

 

Command: (setq test (- 8.2 2.2))

6.0

Command: (fix test)

5

 

Fix, fool me once, shame on you... fool me twice, shame on me!

(defun fuzzfix (input / *error*)
  ;Jef! 2015-12-15. Automatic addition of a fuzz factor to avoid fix
  ;returning a bad value due to a fuzz difference.
  (defun *error* ( msg )
       (if (not (member msg '("Function cancelled" "quit / exit abort")))
           (princ (strcat "\nError: " msg))
       )
       (princ)
  )
  (if (> 0 input)
      (fix (- input 0.000000000000001))
      (fix (+ input 0.000000000000001))
  )
)

Command: (fuzzfix test)

6

 

Heres my questions:

-Would you forsee any counterindications whatsoever of automatically adding a fuzz every time fix is used?

-Would you have done it differently?

-Do you know any other function (beside fix) that could be affected by a fuzz and return unexpected results?

 

And a more general question... when do you use/don't use *error*? Here i guess i could have just made a numberp verification, and in both cases using fuzzfix in a function would trigger an error in that function wether fuzzfix returns (by *error*) "Error: bad argument type: numberp: nil" or a custom message like "fuzzfix requires a number" returned by my own numberp "else". Any advice on that is welcome.

 

Thanks & Cheers!

Posted

I would use a rounding function

(round test 1e-15)

 

As to *error*, as a general rule, I always use it if the data base is going to be modified DBMOD > 0

 

 

(equal) will be affected if no fuzz factor is specified

Posted

Hi David.

I was actually surprised to see that there was no native rounding function. I should have think about looking for a lisper made, which gives more flexibility by not only dealing with a fuzz factor, therefore having more uses than the function i just made.

 

Indeed equal is affected, but enable a fuzz to be specified. I was asking more for functions that would require a totally different approach (like fix which requires an home made rounding function). From what I have experienced so far, fix seems to be... unique.

 

As for your general rule on *error* handling, it makes so much sense that i'm almost ashamed I asked. I would have been better to use a numberp verification instead. I also get the feeling it is always a better practice to avoid errors instead of handling them when they occur, whenever it is possible...

Many thanks for your input David.

Posted

I strongly disagree with the use of a local error function within supporting functions such as this; in my opinion, the validity of the arguments (for example, the argument data type) should be the responsibility of the calling function (in line with the behaviour of standard AutoLISP functions).

 

More importantly, note that localised error functions are not evaluated up the stack when an error occurs - that is, if an error function is defined locally to function A, and another error function is defined locally to function B, if function B is then evaluated from within function A and an error occurs, only the error function defined locally to function B will be evaluated. This could easily result in cleanup operations pertinent to function A not being performed in the event of an error.

 

Consider the following example:

(defun funA ( / *error* )
   (defun *error* ( m )
       (princ "\nfunA error handler.")
       (princ)
   )
   (funB nil)
)
(defun funB ( x / *error* )
   (defun *error* ( m )
       (princ "\nfunB error handler.")
       (princ)
   )
   (rtos x)
)

_$ (funA)

funB error handler.

Now, as another example, consider a case in which funA has a file descriptor open when funB is evaluated - one would need to include expressions to close this file descriptor within the error function local to funB and the error function local to funA, meaning that funB could no longer be a library function.

Posted

I think I totally get your point Lee. Like if in your example Within funA you would be changing variables, in that kind of setup they would never get resetted back.

The responsability of the calling function....

(defun funA (passedvalue / *error* )
   (defun *error* ( m )
       (princ "\nfunA error handler.")
       (princ)
   )
   (if (numberp passedvalue)
      (funB passedvalue)
      (princ "I think i understood, thanks!")
   )
  (princ)
)
(defun funB ( x / *error* )
   (rtos x)
)

 

_$ (FunA "Lee,")
I think i understood, thanks!

 

From the understanding that i'm making of this, a library function should always return the same thing / format. Sounds very logical.

David, Lee, thanks for your input! Much appreciated!

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...