# How to speedup comparison in the following example?

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?

You forgot to inline the zmin.

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 /.
(* See here *)OwnValues@zmin // ReleaseHold;

coefval1 = 10;
TestIf[coefval1, EnergyList]; // AbsoluteTiming
(* {0.0730369, Null} *)


If one avoids repetition and explicit iteration, then one get fast code without compiling:

TestIfNew[coef_,EnergyList_] := With[{X=coef*EnergyList},
With[{Y=uzmin[X]},
{X,Y,uzmax[X],N[1]+UnitStep[Y-0.9999999]*N[zmin-1]}
]]//Transpose;


Timing:

coefval1=10;
TestIfNew[coefval1,EnergyList]; // RepeatedTiming
(* 0.04 seconds *)