I have the following problem: I would like to generate random values of some variable $z$ obeying some distribution, but simultaneously within the interval zmin
<z<zmax
. Below, there is the inverse CDF for this distribution, myInvCDF
(it depends on parameter ldecay
), the interval, and the CDF range uzmin
,uzmax
corresponding to the interval:
myInvCDF[u_, ldecay_] =
z /. Solve[1 - Exp[-(z/ldecay)] == u, z][[1]] /. {C[1] -> 0};
zmin = 14;
zmax = 34;
uzmin[ldecay_] = u /. Solve[myInvCDF[u, ldecay] == zmin, u, Reals][[1]];
uzmax[ldecay_] = u /. Solve[myInvCDF[u, ldecay] == zmax, u, Reals][[1]];
This is the distribution in ldecay
up to some coefficient coef
(ldecay[[i]]=coef*EnergyList[[i]]
):
EnergyList = Abs[RandomVariate[NormalDistribution[1, 5], 10^6]];
I start with the following test table returning the value of ldecay[[i]]
, uzmin
, uzmax
for this ldecay
, and evaluation of the condition If[uzmin[coef*EnergyList[[i]]] > 0.9999999,zmin,1]
:
TestIf = Hold@
Compile[{coef, {EnergyList, _Real, 1}},
Table[{coef*EnergyList[[i]], uzmin[coef*EnergyList[[i]]],
uzmax[coef*EnergyList[[i]]],
If[uzmin[coef*EnergyList[[i]]] > 0.9999999, zmin, 1]}, {i, 1,
Length[EnergyList], 1}], CompilationTarget -> "C",
RuntimeOptions -> "Speed"] /. DownValues@uzmin /.
DownValues@uzmax // ReleaseHold
The latter is needed since my inverse CDF myInvCDF
becomes infinite if uzmin
becomes very close to 1 (numeric inaccuracy: Mathematica replaces say 1-Exp[-15]
by 1). So, I regularize the infinity: if uzmin[coef*EnergyList[[i]]] > 0.9999999
,
then instead of calling this inverse CDF, I return zmin
(if false, here for simplicity I return 1).
It turns out that this condition works very slow if ldecay
becomes mostly comparable with zmin
, or smaller:
coefval1 = 10000;
TestIf[coefval1, EnergyList]; // AbsoluteTiming
coefval1 = 10;
TestIf[coefval1, EnergyList]; // AbsoluteTiming
{0.114952, Null}
{28.6273, Null}
If I remove If
, the table may be computed very fast.
Could you please tell me how to speed up this comparison, or regularize the Mathematica's inaccuracy when substituting values of u
being very close to 1 in myInvCDF
in a more efficient way?