Try this:
Function RandTot(iTot As Long, iMin As Long, iMax As Long, _
Optional bVol As Boolean = False) As Variant
' shg 2010
Dim nNum As Long
Dim i As Long
Dim ad() As Double
Dim dd As Double
Dim iTry As Long
If bVol Then Application.Volatile
With Application.Caller
If .Rows.Count > 1 And .Columns.Count > 1 Then
RandTot = "Enter as row or column vector only!"
Exit Function
End If
nNum = .Count
End With
If iMax < iMin Or iTot < nNum * iMin Or iMax > iTot Then
RandTot = CVErr(xlErrValue)
Exit Function
End If
ReDim ad(1 To nNum - 1)
Randomize
For i = 1 To nNum - 1
ad(i) = RandBetw(iMin, iMax)
Next i
With WorksheetFunction
Do
iTry = iTry + 1
If iTry > 200 Then
RandTot = "Time-out"
Exit Function
End If
Select Case iTot - .Sum(ad)
Case Is < iMin
i = .Match(.Max(ad), ad, 0)
Case Is > iMax
i = .Match(.Min(ad), ad, 0)
Case Else
ReDim Preserve ad(1 To nNum)
ad(nNum) = iTot - .Sum(ad)
RandTot = ad
' Debug.Print iTry
Exit Function
End Select
ad(i) = RandBetw(iMin, iMax)
Loop
End With
End Function
Function RandBetw(iMin, iMax) As Long
RandBetw = (Rnd * (iMax - iMin) + Rnd * (iMax - iMin) + Rnd * (iMax - iMin)) / 4 + iMin
End Function
Then for example, select A1:A10, and enter this formula:
=TRANSPOSE(RandTot(10000, 500, 1500))
The formula MUST be confirmed with Ctrl+Shift+Enter.
The Min and Max values have to reasonably center around the average value (here, 1000).
Bookmarks