mathematical anomaly

Discussion in 'AutoCAD' started by liftedaxis, Sep 29, 2004.

  1. liftedaxis

    liftedaxis Guest

    can someone tell me why this is, and/or another way to do it.
    given a real with one decimal place, say 1.2, I would like the decimal portion as an integer (just the 2).
    so like this:
    (setq a1 1.2)
    1.2
    (setq a1 (- a1 (fix a1))
    0.2
    (setq a1 (* a1 10))
    2.0
    (setq a1 (fix a1))
    1

    WTF? any thoughts?
    or a better way to solve for this?

    --J
     
    liftedaxis, Sep 29, 2004
    #1
  2. Like this?

    (fix (rem (* 1.2 10) 10))
     
    Rick Francken, Sep 29, 2004
    #2
  3. liftedaxis

    David Bethel Guest

    It just the way real numbers are stored in a 'puter.

    (setq a1 (atoi (rtos a1 2 14)))

    Allows you to control the accuracy. -David
     
    David Bethel, Sep 29, 2004
    #3
  4. Yes,that is another way to do it, but why doesn't this work?

    (setq a1 (fix (* (- a1 (fix a1)) 10)))

    if the value of a1 is 1.2, mathematically, this equasion looks like:
    (1.2 - 1.0)*10

    this equates to 2, so why doesn't autocad come up with the same number?

    In autocad, using a value of 1.3, the above lisp tidbit returns '3' but if
    you enter 1.4, it returns '3'.... This makes little sense.
     
    Casey Roberts, Sep 29, 2004
    #4
  5. liftedaxis

    Joe Burke Guest

    This seems to work.

    ;; return the decimal value of a real number as an integer
    (defun DV (num / str)
    (if (= (type num) 'REAL)
    (progn
    (setq str (rtos num 2))
    (atoi
    (vl-string-right-trim "0"
    (substr str
    (+ 2 (vl-string-search "." str)))))
    )
    )
    )

    Command: (dv -3.10250)
    1025

    Joe Burke
     
    Joe Burke, Sep 29, 2004
    #5
  6. liftedaxis

    Joe Burke Guest

    Casey,

    I think fix should be avoided with something like this. Though the number appears to
    be 1.4, it may be stored internally as 1.39999999... Fix simply discards the decimal
    value. So your function might return 3.

    See my string based solution below.

    Joe Burke
     
    Joe Burke, Sep 29, 2004
    #6
  7. (defun ALE_NumberLeftPtTrim (NumVal / CurDZn OutVal PtnPos)
    (if (= 8 (setq CurDZn (getvar "DIMZIN")))
    (setq CurDZn nil)
    (setvar "DIMZIN" 8)
    )
    (setq OutVal (rtos NumVal 2))
    (and CurDZn (setvar "DIMZIN" CurDZn))
    (if (setq PtnPos (vl-string-position (ascii ".") OutVal))
    (atoi (substr OutVal (+ 2 PtnPos)))
    0
    )
    )

    Comando: (ALE_NumberLeftPtTrim 1)
    0

    Comando: (ALE_NumberLeftPtTrim 1.2)
    2

    Comando: (ALE_NumberLeftPtTrim 1.23)
    23

    Comando: (ALE_NumberLeftPtTrim 1.234)
    234

    Comando: (ALE_NumberLeftPtTrim 1.23400)
    234

    Comando: (ALE_NumberLeftPtTrim 0)
    0

    Comando: (ALE_NumberLeftPtTrim 0.0)
    0

    Comando: (ALE_NumberLeftPtTrim 0.0000)
    0

    Comando: (ALE_NumberLeftPtTrim 0.1)
    1

    Comando: (ALE_NumberLeftPtTrim 0.1234000)
    1234


    --

    Marc'Antonio Alessi
    http://xoomer.virgilio.it/alessi
    (strcat "NOT a " (substr (ver) 8 4) " guru.")

    --
     
    Marc'Antonio Alessi, Sep 30, 2004
    #7
  8. liftedaxis

    Joe Burke Guest

    Hi, Marco.

    I guess we both forgot the rtos precision argument.

    Command: (ale_numberleftpttrim 1.23456789)
    2346

    A question for you and others. I was fairly certain the function should return nil
    when passed an integer. Obviously you thought otherwise, and you might be right. My
    thinking was returning zero seems to indicate there was a decimal value, when there
    was none.

    ;; revised 9/29/2004
    ;; return the decimal value of a number as an integer
    (defun DV (num / str)
    (if (= (type num) 'REAL)
    (progn
    (setq str (rtos num 2 14)) ;added precision
    (atoi
    (vl-string-right-trim "0"
    (substr str
    (+ 2 (vl-string-search "." str)))))
    )
    )
    )

    Regards
    Joe Burke
     
    Joe Burke, Sep 30, 2004
    #8
  9. liftedaxis

    David Bethel Guest

    Casey,

    Acad has the computer store integers as they are inputed. 0 to 32,767 X
    2 ( + and - ) 4 bytes per integer ( 16 x 16 x 16 x 16 ) 65,536

    Real numbers ( ie 1.2 ) are stored in scientific notation with 15
    significant places. 8 bytes per real. It is not always totally
    accurate and therefore can lead to some erroneous results

    Most of this comes from the days when PC storage space and memory were
    at a premium. Today there are long integers. I don't know if reals
    have been updated.

    So things like (fix), division of integers (/ 3 2), can still be a problem.

    HTH -David
     
    David Bethel, Sep 30, 2004
    #9
  10. liftedaxis

    liftedaxis Guest

    I know of no other operating system or programming language that returns this erroneous result.
    It sounds to me like an Acad floating point bug.

    --Jeremiah
     
    liftedaxis, Sep 30, 2004
    #10
  11. Thanks, may be this is better:

    (defun ALE_NumberLeftPtTrim (NumVal / CurDZn OutVal PtnPos)
    (if (= 8 (setq CurDZn (getvar "DIMZIN")))
    (setq CurDZn nil)
    (setvar "DIMZIN" 8)
    )
    (setq OutVal (rtos NumVal 2 14))
    (and CurDZn (setvar "DIMZIN" CurDZn))
    (if (setq PtnPos (vl-string-position (ascii ".") OutVal))
    (atoi (substr OutVal (+ 2 PtnPos)))
    )
    )


    Yours has better performance:
    DV > 10000 iterations: 0.36 secs.
    ALE_NUMBERLEFTPTTRIM > 10000 iterations: 0.38 secs.

    setting DIMZIN outside the function:
    ALE_NUMBERLEFTPTTRIM > 10000 iterations: 0.32 secs


    Cheers.

    --

    Marc'Antonio Alessi
    http://xoomer.virgilio.it/alessi
    (strcat "NOT a " (substr (ver) 8 4) " guru.")

    --
     
    Marc'Antonio Alessi, Sep 30, 2004
    #11
Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.