Visual LISP, AutoLISP and General Customization
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Generate a list of n random numbers who sum is 1 or 100

8 REPLIES 8
SOLVED
Reply
Message 1 of 9
Anonymous
2614 Views, 8 Replies

Generate a list of n random numbers who sum is 1 or 100

Hello,

 

I oud this code to generate random numbers from 0 to 1:

 

(defun rnd (/ modulus multiplier increment random)
  (if (not seed)
    (setq seed (getvar "DATE"))
  )
  (setq modulus    65536
        multiplier 25173
        increment  13849
        seed  (rem (+ (* multiplier seed) increment) modulus)
        random     (/ seed modulus)
  )
)

I need to generate a n list of random numbers who sum is 1.

Any ideas?

Thanks,

 

júlio

8 REPLIES 8
Message 2 of 9
pbejse
in reply to: Anonymous

would you settle for 99 instead?

it could be as siimple as this

 

(defun rnd99 nil (atoi (Substr (rtos (getvar "cdate") 2 17) 16 2)))

 

Message 3 of 9
Anonymous
in reply to: pbejse

Hello,

 

Not exactly what I'm looking for, but thanks for your sugestion.

I need a simple way to generate a n list of number (can be float) that de sum of its values equals 100.

Something like this:

 

(a list with 20 members)

(2.11 2.61 1.22 7.52 8.59 4.5 3.29 6.07 9.36 3.6 9.16 8.21 8.03 4.13 0.61 5.01
3.0 6.04 3.04 3.9)

 

Thanks again,

 

julio

Message 4 of 9
Kent1Cooper
in reply to: Anonymous


@Anonymous wrote:

....

I need a simple way to generate a n list of number (can be float) that de sum of its values equals 100.

....


I'm not sure how to generate numbers like that.  The ones near the end would have to become less and less "random" to ensure the total didn't go over the target, and the last one wouldn't be random at all.

 

But here's a possible approach.  Download the routine from Message 20 at the end of this thread:

http://forums.autodesk.com/t5/Visual-LISP-AutoLISP-and-General/draw-a-fuzzy-line/td-p/2340241/page/2

 

Draw a horizontal Line 100 drawing units long [or 1 unit long for your first request].  Use WPL on it, with the EXisting-object-selection option, and tell it you want 20 [or however many] segments.  Then it shouldn't be hard to extract the differences in X coordinate values between adjacent vertices, for a series of numbers that will, because it doesn't randomize the endpoint locations, necessarily add up to the total length of the original Line.

 

It could certainly be revised for your specific purpose to randomize only in the X direction, and to compile that list of the X-value differences along the length for you.  It could prompt the user for a total and a quantity of numbers, and draw its own line and randomize locations along it.

 

Experiment with the "Maximum displacement as percentage of average segment length" option.  If you give it something over 50%, you could sometimes get negative numbers in your list.

 

It does impose a limitation that you may not want.  Since it randomizes positions from starting locations that are evenly spaced, if you don't want negative numbers and therefore use 50% or less for the maximum displacement, then it can never return any value greater than twice the evenly-divided segment length -- that is, for 20 numbers totaling 100, none will ever be larger than 10.  But none are in your example, so maybe that's an acceptable limitation.

Kent Cooper, AIA
Message 5 of 9
martti.halminen
in reply to: Anonymous

This is a little overconstrained problem: using a given range of random numbers, you can choose n or the sum but not both. If the range of numbers is not important, this is easy: generate n random numbers, calculate the sum and scale the values so that the result is correct. For example:

(defun randomish-numbers (n sum / scale result)
  ;; creates a list of N numbers, scaled so that their sum is SUM.
  (repeat n (setq result (cons (rnd) result)))
  (setq scale (/ sum  (apply (function +) result)))
  (mapcar (function
           (lambda (x)
            (* x scale)))
          result))

 

--

Message 6 of 9
pbejse
in reply to: Anonymous

This one even the length of the list is random

 

(defun rndm  (num sum / i total a)
      (setq total 0
            i 0)
      (while (< (apply '+ a) sum)
            (setq Total (+ Total i)
                  i     (* (atoi (Substr (rtos (getvar "cdate") 2 17)
                                         16
                                         1))
                           (+ num (rnd))))
            (if (not (zerop i))
                  (setq a (cons i a)))
            )
      (cons (- sum (apply '+ (cdr a))) (cdr a))
      )

 

(rndm 1100)

(14.6405 10.9837 11.424 11.0789 15.442 12.0417 10.847 13.5422)

 

(rndm 5 200)
(3.46939 22.3278 23.1368 21.1276 20.702 22.9052 22.9081 20.6072 20.5946 22.2213) 

 

(rndm 2 200)
(3.71804 13.138 10.9898 11.7753 12.2026 11.0488 10.9933 14.1946 13.7756 10.3837 12.4695 11.5527 10.1859 10.5708 14.8174 14.9449 13.2389)

 

(rndm  num sum)

num as mulitplier integer added to result

sum as target total

Message 7 of 9
stevor
in reply to: martti.halminen

Maybe an exact solution, or set of,

if 'constrained'  to a number range,

as in  the example that julio   provided, ie, n.nn or n.n; 

and, using backtracking until a fit if found.

Similar to Bayesian adjustments.

S
Message 8 of 9
john.uhden
in reply to: Anonymous

I have tried to use (getvar "date") to develop random numbers and found that AutoCAD does not update the variable often enough, so that 5 or 10 calls in a row might yield the same result.  I really don't know how to get consistently random numbers in AutoCAD.  One would think that you need some value that is varying constantly, but I don't know what that might be.  The only thing that seemed to work was to introduce a delay that would cause a change in the value of (getvar "date").  But that just slowed the process unacceptably.  I agree that scaling is a good approach to reaching the desired sum.  Then again, if you are looking for integers only, it would probably require a number of iterations.

 

Of course the answer to creating a list of positive integers that total 1 is easy...

'(0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 etc.)

 

The answer to creating a list of positive integers that total 0 is even easier...

'(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 etc.)

 

Wait a second.  How about using the sine of a changing angle?  Not the significant number, but a couple of adjacent decimals, like...

 

(atoi (substr (rtos (sin ang) 2 10) 7 2))

John F. Uhden

Message 9 of 9
stevor
in reply to: john.uhden

1. Perhaps only calling the date once,

and using the math convoluted random algorithm

would provide an adequate randomness for this use.

 

2. martti's scaling methods seems very effective,

especially since all numbers are actually pseudo random.

S

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Technology Administrators


Autodesk Design & Make Report