TheSwamp
Code Red => AutoLISP (Vanilla / Visual) => Topic started by: jtoverka on October 10, 2019, 01:58:50 PM
-
I am using Lee Mac's rounding function for an application. I have a function that rotates a point around another point with an angle. It's quite simple. There is a problem where the angle is correct, but the distance is not.
(defun rotatePoint (origin point ang1 / x y r)
(setq r (distance origin point))
(setq ang2 (angle origin point))
(setq x (LM:roundto (* r (cos (+ ang1 ang2))) 8))
(setq y (LM:roundto (* r (sin (+ ang1 ang2))) 8))
(mapcar '+ origin (list x y 0))
)
(defun LM:roundto ( n p )
(LM:roundm n (expt 10.0 (- p)))
)
(defun LM:roundm ( n m )
(* m (atoi (rtos (/ n (float m)) 2 0)))
)
After debugging, I found it to be the rounding function. I notice the LM:roundto function has incorrect results after certain values. For example:
(lm:roundto 21 8) ; = 21.0
(lm:roundto 22 8) ; = 21.4748
anything above 21.4748 just yeilds 21.4748.
This error is a function of the decimal places used. for example:
(lm:roundto 22 7) ; = 22.0 correct
(lm:roundto 220 7) ; = 214.748 incorrect
(lm:roundto 220 6) ; = 220.0 correct
(lm:roundto 2200 6) ; = 2147.48 incorrect
(lm:roundto 2200 5) ; = 2200.0 correct
-
Looking into it, it appears to be an overflow error since the range of a 32 bit integer is 2147483647 to -2147483648. This error takes place at the point of atoi in the LM:roundm routine.
(atoi "2200000000") = 2147483647
I reduced the decimal bits from 8 to 6 in my application as it will be "okay."
-
Very old code by Doug Broad:
;;; Written by Doug Broad
;;; If value given 'to' argument is a real, a real is returned.
;;; Rounds to nearest multiple of 'to' real or integer.
(defun round (value to)
(setq to (abs to))
(* to (fix (/ ((if (minusp value) - +) value (* to 0.5)) to)))
)
(defun roundup (value to / try)
(setq to (abs to)
try (+(* to (fix (/ ((if (minusp value) - +) value (* to 0.5)) to)))to)
)
(if(eq (+ 0.1 try) (+ 0.1 value to))(- try to) try)
)
; examples:
; (round 12232e-015 1)
; 0
; (round 12232e-015 1.0)
; 0.0
; (round 123.6 1.0)
; 124.0
; (round -123.6 1.0)
; -124.0
; (round 6.00000000008 4)
; 8
; 6.00000000008 rounded to the nearest multiple of 4 is 8
; Command: (roundup 30.01 5)
; 35
; Command: (roundup 30 5)
; 30
Try: (round 22 0.00000001)
to get 22.0 as (round 22 8)
rounds to the nearest multiple of 8 which is 24.
-
This is much better, however it still suffers some drawbacks.
(ROUND 170.123456 0.00001) = 170.123
(ROUND 170.123456 0.001) = 170.123
I would like a function that can round to a specified decimal place. This function must work at all boundary conditions. Now the work I do does not require that level of precision. However, a function should be capable of handling all possible scenarios.
I'll take a crack at it soon. Hopefully, it'll be as pretty as the other functions.
-
i ended up with
(atof (rtos r 2 p))
-
i ended up with
(atof (rtos r 2 p))
This is the KISS principle in action. Thank you very much!