Jump to content

Recommended Posts

Posted (edited)

Hi all, 

I have a problem with product of two big numbers in Autolisp

(rtos	(* 412866307 249513616)	2)

it Returns : "-368000080"

I could not find the reason of the problem, does someone know the reason of it?

Edited by amir0914
Posted

$ (rtos    (* 412866307.0 249513616.0)    2)
"1.0302E+17"
_$ (rtos    (* (float 412866307) (float 249513616))    2)
"1.0302E+17"
_$

  • Like 1
Posted

Integers in AutoLISP are stored as 32-bit signed integers, which have an upper limit of (2^31)-1 = 2,147,483,647. Exceeding this limit will cause the sign bit to be flipped, causing the number to wrap around to -2^31 = -2,147,483,648.

  • Like 1
Posted (edited)
50 minutes ago, rlx said:

$ (rtos    (* 412866307.0 249513616.0)    2)
"1.0302E+17"
_$ (rtos    (* (float 412866307) (float 249513616))    2)
"1.0302E+17"
_$

Many thanks, I wanted to print it on a msgbox, but it nor appears in full 

(setq num (rtos (* 412866307.0 249513616.0) 2))
(alert num)

Is it possible to display full text on alert window :  "103015765184136112"

 

 

Screenshot (1926).png

Edited by amir0914
Posted

you can increase the precision with units command (or LUPREC) and /or  use RTOS like (rtos i 2 8) but AutoCad will only display numbers to a certain max/min value and after that is switches automatically to scientific notation.

 

from help RTOS:

The rtos function returns a string that is the representation of number according to the settings of mode, precision, and the AutoCAD UNITMODE, DIMZIN, LUNITS, and LUPREC system variables.

The mode and precision arguments correspond to the AutoCAD LUNITS and LUPREC system variables. If you omit the arguments,rtos uses the current settings of LUNITS and LUPREC.

so (setq num (rtos (* 412866307.0 249513616.0) 2 16))  would give a few more decimals but unfortunately its still not enough for what you want. Not sure if its possible to first devide both numbers by lets say ten thousand and calculate before and after decimal point separately and join them afterwards. I don't have a degree in math like master Lee.

  • Like 1
Posted (edited)
1 hour ago, rlx said:

... Not sure if its possible to first devide both numbers by lets say ten thousand and calculate before and after decimal point separately and join them afterwards. I don't have a degree in math like master Lee.

I was about to bring this challenge up :)

So, this is a way to multiply large positive numbers:

(defun multip (a b / q m n r c l)
  (setq q (max (length a) (length b)))
  
  (repeat (- q (length a))
    (setq a (cons 0 a))
  )
  
  (repeat (- q (length b))
    (setq b (cons 0 b))
  )
  
  (setq c 0)
  
  (repeat q
    (setq q (1- q)
          m (cons (nth q a) m)
          n (cons (nth q b) n)
          r (+ c (apply '+ (mapcar '* m (reverse n))))
          c (/ r 10)
          l (cons (rem r 10) l)
    )
  )
  (setq n (reverse n)
        m (reverse m)
  )
  (while (setq m (cdr m))
    (setq n (cdr n)
          r (+ c (apply '+ (mapcar '* m (reverse n))))
          c (/ r 10)
          l (cons (rem r 10) l)
    )
  )
  
  (while (> c 0)
    (setq l (cons (rem c 10) l)
          c (/ c 10)
    )
  )
  
  (while (zerop (car l)) (setq l (cdr l)))
  
  l
)
_$ (MULTIP '(4 1 2 8 6 6 3 0 7) '(2 4 9 5 1 3 6 1 6))
(1 0 3 0 1 5 7 6 5 1 8 4 1 3 6 1 1 2)
_$ (MULTIP '(4 1 2 8 6 6 3 0 7 4 1 2 8 6 6 3 0 7 4 1 2 8 6 6 3 0 7) '(2 4 9 5 1 3 6 1 6 2 4 9 5 1 3 6 1 6 2 4 9 5 1 3 6 1 6))
(1 0 3 0 1 5 7 6 5 3 9 0 1 6 7 6 4 2 6 7 7 3 1 9 5 1 9 7 5 8 4 3 9 8 6 6 4 7 1 2 8 7 9 8 9 1 8 4 1 3 6 1 1 2)
_$ 

More efficient would be to divide the original number in fractions of thousand. The lisp above will work if 10 is replaced by 1000.

But I'm more interested of some clever codes. Mine is (almost) just a translation of the way the kids are doing multiplication in class.

 

... and the test function

(defun test (a b / l1 l2)
  (if
    (and
      (eq (type a) 'int)
      (eq (type b) 'int)
    )
    (progn
      (while (> a 0)
        (setq l1 (cons (rem a 10) l1)
              a (/ a 10)
        )
      )
      (while (> b 0)
        (setq l2 (cons (rem b 10) l2)
              b (/ b 10)
        )
      )
;;;      (alert
        (apply 'strcat (mapcar 'itoa (multip l1 l2)))
;;;      )
    )
  )
)
_$ (test 412866307 249513616)
"103015765184136112"
_$ 

 

Edited by Stefan BMR
  • Like 2
Posted

@Stefan BMR , nice job , I'm sure you-know-who probably can come up with a more generic formula but it's the end result that counts.

  • Like 1
Posted

Thank you both, @Stefan BMR  function was great.

But another question, Should I use @Stefan BMR method if I want to use SUBSTR function.??

  (setq num (rtos (* 412866307.0 249513616.0) 2))

  (substr num 1 7)

Returns : "1.03015"

Whilst must return : "1030157"

Posted

stefans method obviously , but if you want to ditch the dot in a string you could use something like (vl-string-subst "" "." "1.234")

  • Like 1
Posted (edited)

Here is my conversion...

 

;;;------------------------------------------------------------------;;;
;;; multp - sub function - multiplication of 2 numbers of any length ;;;
;;;                                                                  ;;;
;;; Arguments :                                                      ;;;
;;; a - first number - type = string                                 ;;;
;;; b - second number - type = string                                ;;;
;;;                                                                  ;;;
;;; Return :                                                         ;;;
;;; r - resulting number - type = string                             ;;;
;;;                                                                  ;;;
;;; Written by Marko Ribar, d.i.a. (architect)                       ;;;
;;;------------------------------------------------------------------;;;

(defun multp ( a b / s ad bd dp an bn k c n l ll r rr )
  (if (and (= (type a) 'STR) (/= a "") (= "" (vl-string-trim "-0123456789." a)) (= (type b) 'STR) (/= b "") (= "" (vl-string-trim "-0123456789." b)))
    (progn
      (if (or (and (minusp (atof a)) (not (minusp (atof b)))) (and (not (minusp (atof a))) (minusp (atof b))))
        (setq s t)
      )
      (if (or (zerop (atof a)) (zerop (atof b)))
        (setq r "0")
        (progn
          (setq a (vl-string->list a))
          (setq b (vl-string->list b))
          (setq ad a)
          (if (vl-position 46 ad)
            (while (/= (car ad) 46)
              (setq ad (cdr ad))
            )
            (setq ad nil)
          )
          (setq bd b)
          (if (vl-position 46 bd)
            (while (/= (car bd) 46)
              (setq bd (cdr bd))
            )
            (setq bd nil)
          )
          (if (or (vl-position 46 ad) (vl-position 46 bd))
            (setq dp (+ (if ad (1- (length ad)) 0) (if bd (1- (length bd)) 0)))
            (setq dp 0)
          )
          (setq an (vl-remove 45 (vl-remove 46 a)))
          (setq bn (vl-remove 45 (vl-remove 46 b)))
          (setq an (reverse an))
          (setq bn (reverse bn))
          (setq k 0)
          (foreach aa an
            (setq k (1+ k))
            (setq c 0)
            (foreach bb bn
              (setq n (rem (+ c (* (atoi (chr aa)) (atoi (chr bb)))) 10))
              (setq c (fix (/ (+ c (* (atoi (chr aa)) (atoi (chr bb)))) 10.0)))
              (if (zerop (fix (/ n 10.0)))
                (setq l (cons n l))
                (progn
                  (setq l (cons (rem n 10) l))
                  (setq c (fix (/ n 10.0)))
                )
              )
            )
            (if (not (zerop c))
              (setq l (cons c l))
            )
            (setq ll (cons (reverse l) ll))
            (setq l nil)
            (repeat k
              (setq l (cons 0 l))
            )
          )
          (setq n (apply 'max (mapcar 'length ll)))
          (setq ll (mapcar '(lambda ( x ) (if (= (length x) n) x (progn (repeat (- n (length x)) (setq x (append x (list 0)))) x))) ll))
          (setq r (apply 'mapcar (cons '+ ll)))
          (setq c 0)
          (foreach x r
            (if (zerop (fix (/ (+ x c) 10.0)))
              (progn
                (setq rr (cons (+ x c) rr))
                (setq c 0)
              )
              (progn
                (setq rr (cons (rem (+ x c) 10) rr))
                (setq c (fix (/ (+ x c) 10.0)))
              )
            )
          )
          (if (not (zerop c))
            (setq rr (cons c rr))
          )
          (setq k nil)
          (setq r (apply 'append (mapcar '(lambda ( x ) (if (null k) (setq k 1) (setq k (1+ k))) (if (/= k dp) (list (ascii (itoa x))) (list (ascii (itoa x)) 46))) (reverse rr))))
          (setq r (reverse r))
          (while (and (= (car r) 48) (/= (cadr r) 46))
            (setq r (cdr r))
          )
          (if s
            (setq r (strcat "-" (vl-list->string r)))
            (setq r (vl-list->string r))
          )
        )
      )
      r
    )
  )
)

(defun c:multp ( / a b )
  (setq a (getstring "\nSpecify number a : "))
  (while (or (= a "") (/= "" (vl-string-trim "-0123456789." a)))
    (prompt "\nInvalid a number specification...")
    (setq a (getstring "\nSpecify number a : "))
  )
  (setq b (getstring "\nSpecify number b : "))
  (while (or (= b "") (/= "" (vl-string-trim "-0123456789." b)))
    (prompt "\nInvalid b number specification...")
    (setq b (getstring "\nSpecify number b : "))
  )
  (princ (strcat "\n" (multp a b)))
  (princ)
)

 

Edited by marko_ribar
  • Like 1
Posted
10 minutes ago, marko_ribar said:

Here is my conversion... Negative numbers are not implemented, but decimals are...

Nice one Marko, but sometimes a "1" in front is missing. It might be the "c" variable that still holds something greater than 0.

Command: MULTP
Specify number a : 1235462574.32561

Specify number b : 845655123645487545852.65514
044775256050696071694271543803.8134001354

 

  • Like 1
Posted
1 hour ago, Stefan BMR said:

Nice one Marko, but sometimes a "1" in front is missing. It might be the "c" variable that still holds something greater than 0.


Command: MULTP
Specify number a : 1235462574.32561

Specify number b : 845655123645487545852.65514
044775256050696071694271543803.8134001354

 

 

Thanks Stefan for your input, I revised my code...

M.R.

  • Like 1
Posted (edited)

And here is very simple example of how to process list of number strings...

 

;;;--------------------------------------------------------------------------------------------------------------;;;
;;; multplst - sub function - successive multiplication numbers of any length stored in a list of number strings ;;;
;;;                                                                                                              ;;;
;;; Requirements : Loaded (multp a b) sub-function                                                               ;;;
;;;                                                                                                              ;;;
;;; Arguments :                                                                                                  ;;;
;;; lst - list of number strings - type = list ; for ex. (setq lst '("2" "4" "6"))                               ;;;
;;;                                                                                                              ;;;
;;; Return :                                                                                                     ;;;
;;; r - resulting number - type = string                                                                         ;;;
;;;                                                                                                              ;;;
;;; AutoLisp synonym :                                                                                           ;;;
;;; (apply (function *) lst) => number (real or integer) ; lst - list of numbers (reals or integers)             ;;;
;;;                                                                                                              ;;;
;;; Example :                                                                                                    ;;;
;;; (setq lst '("2" "4" "6"))                                                                                    ;;;
;;; (setq r (multplst lst)) => r = "48"                                                                          ;;;
;;; (princ (strcat "\n" r)) => 48                                                                                ;;;
;;; (princ)                                                                                                      ;;;
;;;                                                                                                              ;;;
;;; Written by Marko Ribar, d.i.a. (architect)                                                                   ;;;
;;;--------------------------------------------------------------------------------------------------------------;;;

(defun multplst ( lst / r )
  (setq r "1")
  (while (car lst)
    (setq r (multp r (car lst)))
    (setq lst (cdr lst))
  )
  r
)

P.S. You have to have loaded (multp a b) sub-function I posted in my previous code...

HTH.

Regards, M.R.

Edited by marko_ribar
  • Like 1

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...