If you know about Markov chains you can basically solve the P(E) for any C value. You need to think about a bunch of states {1,2,3...}, which correspond to how many "stacks" of C you've accumulated.
So you have a matrix P where the nth row and kth column holds the probability that you go from n stacks to k stacks. However, the only valid transitions are:
- From n stacks to 1 stack when you proc and it resets.
- From n stacks to n+1 stacks when you don't proc.
The matrix is of finite size because once you reach n = ⌈1/C⌉
(rounded up) stacks, the probability of going back to 1 stack is 100%.
Now with your A matrix constructed, you can compute what is known as a stationary distribution, where aX = a, where a is a vector and X is a matrix. If you have Matlab you can solve for a by taking the eigenvector of the eigenvalue 1. This eigenvector represents the proportion of time spent in each state, so by dividing it by the sum of all the values, you obtain a long term proportion of time spent in each state.
Once you know the probability of being in each state you can multiply it by the probability of a proc in that state and sum it across states to get the average proc rate. Then you just try different C values until you achieve desired P(E).
Below is some Matlab code I put together, the values are not exactly the same as the wiki page by they are sufficiently similar that I have not put more thought into it.
function [C, prob] = pseudorand(target) % Takes in a target p and outputs the C value
C = 0.30210; % Initial points for iterating
prob = 0.5;
while abs(target-prob)>10^-8 % Iterate and adjust C until desire p is
achieved.
if C<0.1
C = C + (target-prob)/8; % Be more careful around small C values
else
C = C + (target-prob)/2;
end
P = zeros(ceil(1/C)); % Determine the size of the matrix.
for n = 1:size(P,1) % Set values of first column to n*C, rounding
if n*C < 1 down to 1 on the final row.
P(n,1) = n*C;
else
P(n,1) = 1;
end
end
for n = 1:size(P,1)-1
P(n,n+1) = 1-P(n,1); % Populating entries of nth row and (n+1)th
end column with value 1-n*C (once again with
rounding on the last row).
[v, d] = eig(P'); % Obtain eigenvectors and eigenvalues.
stationary = v(:,1)/sum(v(:,1));% Take first eigenvector and normalise.
prob = stationary'*P(:,1); % Find P(E) for corresponding C value.
end
EDIT (response to comment below): I'm sorry but I don't quite understand what you mean by "testing values". This process rests on the assumption that the pseudo-random probability satisfies p = n × C. The assumption is that the Warcraft 3 developers wrongly calculated the C values which lead to a inconsistency between expected (in the tooltip) and observed. So the true values can either be found by taking the observed (through parsing) probability to calculate the corresponding C value using my algorithm or you could somehow acquire the table used for C values in the source code, which is from where I assume the wiki got them from.
The other solution would to be parse in a way that discriminates between the number of misses experienced, for example you can calculate the frequency of procs after 2,3,4 non-procs then fit a straight line across the points to determine the linear growth of the C value. This method is probably the most cumbersome but provides some good granularity and also gives some indictation as to whether or not the probability is indeed p = n × C (ignoring the point where n × C goes above 1, the values should pretty much sit in a straight line).
C
values using data from the game. I parsed a lot of data for the 25% chance critical but do not understand how to obtain that value.