TheSwamp
Code Red => AutoLISP (Vanilla / Visual) => Topic started by: Coder on May 18, 2017, 12:11:30 PM
-
Hello everyone.
I have a strange result of the rem function other than I expected.
For example:
Doesn't return 0.0 but it returns 1.11022e-016
Thank you.
-
it's a well know autocad's behavior
problem is not only with rem function
see
(= (- 1.1 1.0) 0.1) -> nil
-
Refer to Floating-point Arithmetic Accuracy Problems (https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems).
Suggestion:
-
Thank you guys for your kind replies.
I thought my thread would look stupid to ask but I think it wasn't.
-
(rem 13.3 0.1) → 0.1
autocad 2014 test
-
(rem 13.3 0.1) → 0.1
autocad 2014 test
Confiremed the same, AutoCAD 2018...
:oops:
Command: (rem 0.1 0.1)
0.0
Command: (rem 0.2 0.1)
0.0
Command: (rem 0.3 0.1)
0.1
Command: (rem 0.4 0.1)
0.0
Command: (rem 0.5 0.1)
0.1
Command: (rem 0.6 0.1)
0.1
Command: (rem 0.7 0.1)
0.1
Command: (rem 0.8 0.1)
0.0
Command: (rem 0.9 0.1)
0.1
Command: (rem 1.0 0.1)
0.1
Command: (rem 1.1 0.1)
2.77556e-17
Command: (rem 1.2 0.1)
0.1
Command: (rem 1.3 0.1)
0.1
Command: (rem 1.4 0.1)
0.1
Command: (rem 1.5 0.1)
0.1
-
BricsCAD v20.1.06
: (rem 13.3 0.1)
0.1
: (rem 13.2 0.1)
0.0999999999999986
: (rem 0.1 0.1)
0.0
: (rem 0.2 0.1)
0.0
: (rem 0.3 0.1)
0.1
: (rem 0.4 0.1)
0.0
: (rem 0.5 0.1)
0.1
: (rem 0.6 0.1)
0.1
: (rem 0.7 0.1)
0.0999999999999999
: (rem 0.8 0.1)
0.0
: (rem 0.9 0.1)
0.1
: (rem 1.0 0.1)
0.1
: (rem 1.1 0.1)
0.0
: (rem 1.2 0.1)
0.0999999999999999
: (rem 1.3 0.1)
0.1
: (rem 1.4 0.1)
0.0999999999999998
: (rem 1.5 0.1)
0.0999999999999999
-
Solution is to perhaps use custom (rem n1 n2) function :
Command: (fix (/ 13.3 0.1))
133
Command: (rtos (/ 13.3 0.1) 2 50)
"133.0000000000000"
Command: (rem 13.3 0.1)
0.1
Command: (defun rem ( n1 n2 )
(_> (- (/ (float n1) (float n2)) (fix (/ (float n1) (float n2))))
(_> )
REM
Command: (rem 13.3 0.1)
0.0
-
Since I don't know how to change built-in function, I'll put this in my acaddoc.lsp :
(defun rem ( n1 n2 )
(- (/ (float n1) (float n2)) (fix (/ (float n1) (float n2))))
)
HTH., M.R.
-
(defun rem ( n1 n2 )
(- (/ (float n1) (float n2)) (fix (/ (float n1) (float n2))))
)
(rem 4.1 0.1)
-
I saw it VovKa... I've just fixed it :
(defun rem ( n1 n2 )
(if (< (abs n1) (abs n2))
(if (or (= (type n1) 'real) (= (type n2) 'real))
0.0
0
)
(if (or (= (type n1) 'real) (= (type n2) 'real))
(if (minusp n1)
(- (* (- (/ (float (abs n1)) (float (abs n2))) (fix (/ (float (abs n1)) (float (- (abs n2) 1e-16))))) (abs n2)))
(* (- (/ (float n1) (float (abs n2))) (fix (/ (float n1) (float (- (abs n2) 1e-16))))) (abs n2))
)
(if (minusp n1)
(fix (- (* (- (/ (float (abs n1)) (float (abs n2))) (fix (/ (float (abs n1)) (float (- (abs n2) 1e-16))))) (abs n2))))
(fix (* (- (/ (float n1) (float (abs n2))) (fix (/ (float n1) (float (- (abs n2) 1e-16))))) (abs n2)))
)
)
)
)
-
Here are the results after implementation of my subfunction :
Command: (rem 0.1 0.1)
0.0
Command: (rem 0.2 0.1)
0.0
Command: (rem 0.3 0.1)
-4.44089e-17
Command: (rem 0.4 0.1)
0.0
Command: (rem 0.5 0.1)
0.0
Command: (rem 0.6 0.1)
-8.88178e-17
Command: (rem 0.7 0.1)
-8.88178e-17
Command: (rem 0.8 0.1)
0.0
Command: (rem 0.9 0.1)
0.0
Command: (rem 1.0 0.1)
0.0
Command: (rem 1.1 0.1)
0.0
Command: (rem 1.2 0.1)
-1.77636e-16
Command: (rem 1.3 0.1)
0.0
Command: (rem 1.4 0.1)
-1.77636e-16
Command: (rem 1.5 0.1)
0.0
Command: (rem 2.05 0.1)
0.05
Command: (rem -2.05 0.1)
-0.05
Command: (rem -2 0.1)
0.0
Command: (rem -2 1)
0
Command: (rem 1 2)
0
Command: (rem 1.0 2)
0.0
Command: (rem 1.0 2.0)
0.0
Command: (rem 1.0 3.0)
0.0
Command: (rem pi pi)
0.0
Command: (rem (* 2 pi) pi)
0.0
Command: (rem (* 3 pi) (* 0.5 pi))
0.0
Command: (rem (* 3.05 pi) (* 0.5 pi))
0.15708
Command: (rtos (rem (* 3.05 pi) (* 0.5 pi)) 2 50)
"0.1570796326794891"
Command: (rtos (* 0.05 pi) 2 50)
"0.1570796326794896"
HTH., M.R.
-
Since rem is typically used to test the even divisibility of a number by a given divisor, you can easily account for the rounding errors introduced by the limited precision of the double-precision floating-point format by simply testing the result with some tolerance, e.g.:
-
??
-
(if (or (= (type n1) 'real) (= (type n2) 'real))
0.0
0
)
this should be changed to n1
-
(if (or (= (type n1) 'real) (= (type n2) 'real))
0.0
0
)
this should be changed to n1
This is not so important - original (rem) function returns real here - although it's wrong :
Command: (rem 1 2.0)
1.0
Command: (rem 1 0.5)
0.0
-
Actually I was wrong... This was correct :
Command: (rem 1 2)
1
Command: (rem 1 2.0)
1.0
Command: (rem 1 0.5)
0.0
I just overprogrammed it... So it's simply :
Sorry, we all make mistakes sometimes, but built-in function was also wrong... At least I think I fixed it now for sure...
Regards, M.R.
-
since problem is known, fixed it:
(rem (* 10 0.1)(* 10 0.1))
(rem (* 10 0.2)(* 10 0.1))
(rem (* 10 0.3)(* 10 0.1))
(rem (* 10 0.4)(* 10 0.1))
(rem (* 10 0.5)(* 10 0.1))
(rem (* 10 0.6)(* 10 0.1))
(rem (* 10 0.7)(* 10 0.1))
(rem (* 10 0.8)(* 10 0.1))
(rem (* 10 0.9)(* 10 0.1))
(rem (* 10 1.0)(* 10 0.1))
(rem (* 10 1.1)(* 10 0.1))
(rem (* 10 1.2)(* 10 0.1))
(rem (* 10 1.3)(* 10 0.1))
(rem (* 10 1.4)(* 10 0.1))
(rem (* 10 1.5)(* 10 0.1))
-
Command:
Command: (rem (* 10 0.1)(* 10 0.1))
0.0
Command: (rem (* 10 0.2)(* 10 0.1))
0.0
Command: (rem (* 10 0.3)(* 10 0.1))
0.0
Command: (rem (* 10 0.4)(* 10 0.1))
0.0
Command: (rem (* 10 0.5)(* 10 0.1))
0.0
Command: (rem (* 10 0.6)(* 10 0.1))
0.0
Command: (rem (* 10 0.7)(* 10 0.1))
0.0
Command: (rem (* 10 0.8)(* 10 0.1))
0.0
Command: (rem (* 10 0.9)(* 10 0.1))
0.0
Command: (rem (* 10 1.0)(* 10 0.1))
0.0
Command: (rem (* 10 1.1)(* 10 0.1))
0.0
Command: (rem (* 10 1.2)(* 10 0.1))
0.0
Command: (rem (* 10 1.3)(* 10 0.1))
0.0
Command: (rem (* 10 1.4)(* 10 0.1))
0.0
Command: (rem (* 10 1.5)(* 10 0.1))
0.0
-
Thanks all! :smitten:
-
Since rem is typically used to test the even divisibility of a number by a given divisor, you can easily account for the rounding errors introduced by the limited precision of the double-precision floating-point format by simply testing the result with some tolerance, e.g.:
(divp 12.4 0.1)→(rem x d)
Sometimes 1.0e-006, sometimes 1.0e-008
-
I think 1e-8 is more than sufficient -
-
I think 1e-8 is more than sufficient -
Lee are you saying (rem) built-in function is working well... I think this was bug... (rem 12.4 0.1) should be 0.0 and not 0.1... (/ 12.4 0.1) = 124 without reminder - reminder is 0.0
-
I think 1e-8 is more than sufficient -
Lee are you saying (rem) built-in function is working well... I think this was bug... (rem 12.4 0.1) should be 0.0 and not 0.1... (/ 12.4 0.1) = 124 without reminder - reminder is 0.0
I'm saying that issues such as this are inevitable when working with doubles due to the inability to represent certain Real numbers with finite memory, and one has to remember that the error introduced at the nth decimal place can be both positive & negative; in this case, since we are working with modular arithmetic, the error will be either 0+1e-16 or m-1e-16 where m is the modulus.
-
But with my function, there is no such issue... I've reprogrammed (rem) function to be correct... And I placed it at first place in my acaddoc.lsp before all other things and I've tested it with my acaddoc.lsp, this returned 0.0 which is correct :
(defun c:remtest nil
(princ (rem 13.3 0.1))
(princ)
)
My function, if you didn't noticed is here :
http://www.theswamp.org/index.php?topic=53061.msg597469#msg597469
M.R.
-
I'm probably missing something but why would it need to be more ambitious than:
(defun _rem ( n d / r )
(cond
((equal 0 (setq r (rem n d)) 1e-6) 0)
((apply 'equal (mapcar 'abs (list d r 1e-6))) 0)
(r)
)
)
?
-
Yes, you are missing something :
My (rem n1 n2) is designed to overwrite buit-in (rem) function, and your if you change name (_rem) to (rem) it will act recursively calling function you just defined and not built-in (rem)... I am afraid it has to be my way if you want to overwrite original (rem) definition...
-
I didn’t intend to overwrite the built in function thus my naming was deliberate. In over 30 years of LISP programming I don’t recall ever having such need and remain of the opinion it should be avoided [unless replicating Joshua Overkamp’s efforts of late - highly unlikely for me]. Mileages vary of course.
-
...remain of the opinion it should be avoided [unless replicating Joshua Overkamp’s efforts of late - highly unlikely for me]...
Why would you keep original (rem) if you know it's buggy? I would say if you can mention where is this errornous odd behaviour of original (rem) used in correct and succesful manner, then I'll appreciate your opinion, otherwise I and perhaps everyone else would suggest (strongly) that you should overwrite buggy (rem)... As for efficency behaviour it's I suppose just slightly slower than original as its not built-in optimized Alisp Function like others are...
-
buggy
(rem_ribarm 1 0.0000000000001)
-
Why would you keep original (rem) if you know it's buggy?
It's a matter of standard policy. Any programming, be it mine, my colleagues, my clients or third party software I may use should be able to rely on the standard functions as original platform supplied, regardless whether they meet my requirements or assessment of accuracy. Where deemed necessary alts can be penned and used, incorporating a naming convention that ensures original functions are preserved, e.g. a leading underscore as suggested in my example. Notwithstanding all said - what if the overriding programming proves flawed? Altogether just bad practice and a recipe for numerous, cascading problems difficult to trace to source.
... I and perhaps everyone else would suggest (strongly) that you should overwrite buggy (rem)...
Profoundly disagree and would recommend avoiding the works of any programmers that employ that strategy.
-
Really sad to hear that... This sounds to me like politician answer and not scientific... (rem) function is simple math and you should know that... Just to warn you : One mistake may lead to another one, and that to yet another, ... , and so on... If you don't want to update it's your business anyway, but don't accuse than someone else when and if something fails despite your program looks good and you want to implement it without any failure... Mistake was made by programming badly by you or someone else and if you want to avoid lacks in job, mistakes have to be treated as soon as possible by the time they were spot and reported... I for sure can't guarantee that my job is perfectly done and that I don't make mistakes, but I am behaving to be less stubborn person and I am trying to be flexible as much as possible in situations they occur to me... For sure my advantage is the fact that I am persistent in efforts to make things as much good and well as possible and that means that I treat mistakes they should be treated and I correct them in a workflow... I want that everyone is satisfied with consequences his/her duty brings and that job done by me or someone else should be satisfactory beneficial and as much as possible done without mistakes... This all tells me that I should trust rather something that is based on proofs and facts and not just arguments that defend and censor errors and bad practice made in past... To me things should always be better than they were no matter where and in what field of profession you look at... But that's just me, and yes I'll make changes to my life and profession especially when I see that something is wrong no matter there are arguments that it's not practical or profession ethical like you stated... Like no one can stop you not to react on the facts that something should be corrected, no one can stop me to correct thing I think that are wrong and this is the one case of such situation...
Stay well and be present in challenges they are to come yet and avoid to convince people in things you are unsure they are correct if you don't have arguments based on proofs that are already considered as natural universal facts and that are unnecessary to be tested for their validness...
-
This sounds to me like politician answer and not scientific ...
Thank you for your opinion.
Just to warn you : One mistake may lead to another one, and that to yet another, ... , and so on ...
Your arguments support my policy and recommendation.
I am persistent in efforts to make things as much good and well as possible and that means that I treat mistakes they should be treated and I correct them in a workflow...
You don't enjoy a monopoly on this work ethic. My record will have to speak for itself.
... froth ...
Pass.
I've used rem in my programming hundreds, perhaps thousands of times in my decades of programming - with integers - not once with reals. If I ever require rem to process reals I'll opt to use a reliable _rem alternate, which is the correct way to deal with issues like this - in my opinion.
My recommendations stand.
Cheers.
-
Why would you keep original (rem) if you know it's buggy?
Any programming, be it mine, my colleagues, my clients or third party software I may use should be able to rely on the standard functions as original platform supplied, regardless whether they meet my requirements or assessment of accuracy.
I couldn't agree more with this sentiment. Locally redefining standard functions introduces yet another potential source of inconsistency when trying to debug behavioural differences in a program between two environments; when I use a standard function in a program, I would like to be confident in the knowledge that the definition of such function is consistent for all environments in which it is evaluated, bugs and all.
-
I couldn't agree more with this sentiment.
Thank you Lee.
Locally redefining standard functions introduces yet another potential source of inconsistency when trying to debug behavioral differences in a program between two environments; when I use a standard function in a program, I would like to be confident in the knowledge that the definition of such function is consistent for all environments in which it is evaluated, bugs and all.
Exactly.
Cheers.
-
Sorry I found the party late (someone gave me the wrong address; I suspect no foul play and still feel I am popular and funny).
Devil's-advocate-hat: what about: "(defun *error* (..."
Personal Opinion: I agree with some people---i.e. not prefer to redefine a built-in--because I feel it causes more concerns/work then just rolling my own version. -e.g. Debugging, sharing, mistakes etc.
If you override a built-in, there are essentially a few areas of major concern:
1. You should reset to the default behavior when you are done; other programs may rely on the default.
2. (common sense) Share/ship your override with every share (more critical then the use of a custom).
a. if a custom function doesn't ship, the code will fail and the missing function will be obvious.
-
Devil's-advocate-hat: what about: "(defun *error* (..."
-
I'm no where near the coding expert as you MP .. but I totally agree that redefining built in functions with your own version is a bad idea. I know I could break all kinds of $h!+ :)
-
Yay! Yet another time I opened the box and out jumped a whole bunch of snide.
Not that I've noticed a lot of this but what happens when a user-defined *error* is not localized or reset (and contains "custom/weird/turn-things-pink" code) and someone else uses that error. ...I was just trying to add to the conversation.
(*error* "")) )
(alert "Program 2 *error*")) (*error* "")) )
-
I'm no where near the coding expert as you MP .. but I totally agree that redefining built in functions with your own version is a bad idea. I know I could break all kinds of $h!+ :)
Thank you for posting the kind compliment and your take on the issue Ron.
Yay! Yet another time I opened the box and out jumped a whole bunch of snide.
John I'm not a mind reader. I anted up what I thought was an appropriate response. Breathe.
Cheers.
-
...
John I'm not a mind reader. I anted up what I thought was an appropriate response. Breathe.
...
1. You should reset to the default behavior when you are done; other programs may rely on the default.
Nor a post reader. You invested about 2 seconds before belittlement. Yes, I was restating the obvious/previous statements about an overridden function but I thought I'd give a place for people to address how they deal with--if at all (hence: "devils advocate")--the most overridden AutoLisp function in the tool box (*error*).
-i.e.
1. Do you trust that it's there--or functioning along the lines of "normal"--and use as normal?
2. Do you always include your own version?
3. Do you set to nil?
4. ...
Cannon fodder out
-
John, you're mistaking brevity for snide.
I didn't think it warranted more than what I posted. But I'll indulge you.
It's a user defined function. Similar to a system variable, as a programmer I have to assume it will not exhibit the definition or state I require for my programming, so I will define it, or set it, according to my needs. Conscientious programmers restore the original environment on exit. That said, it does not enjoy the same repercussions as overriding a standard function but I'm not going to reiterate what's already been covered.
Have a great day, cheers.