Rnz

From NetHackWiki
Revision as of 20:02, 5 May 2007 by Ray Chason (talk | contribs) (Initial revision)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

The correct title of this article is rnz. The name is capitalized due to technical limitations.

Probability graph of a call of rnz(100).

rnz is a function that generates a random number with a distribution that is meant to peak at a given value and trail off at larger values. A call of rnz(350), for example, gives the base prayer timeout and will often return a number close to 350, sometimes a number somewhat less or somewhat more than 350, and rarely a number much greater or much less than 350.

The most probable outcome turns out not to be the given parameter, but half of that number, as can be seen in the graph to the right.

rnz is used for the following purposes:

  • rnz(100) is the time that one must wait after invoking an artifact before invoking it again.
  • rnz(10) (or rnz(25) when first building a level) plays a part in determining when a corpse disintegrates (or revives if it's a troll or Rider).
  • A number of rnz calls are used in determining the prayer timeout. In particular, the timeout after successful prayer is rnz(350), with a penalty of rnz(1000) added if you are crowned or have killed the Wizard of Yendor. If you have killed the Wizard and are also crowned, the penalty is doubled.

Mathematical analysis

rnz produces such a bizarre distribution that it is hard to tell what the original programmer had in mind. It's quite possible that it was meant to be some distribution with Z in the name, but its construction doesn't seem to suggest one.

The code is quoted below, with some cleanup for readability:


int
rnz(i)
int i;
{
        register long x = i;
        register long tmp = 1000;
 
        tmp += rn2(1000);
        tmp *= rne(4);
        if (rn2(2)) { x *= tmp; x /= 1000; }
        else { x *= 1000; x /= tmp; }
        return((int)x);
}

The rn2(2) call chooses, with equal probability, between two different distributions; one is

 i * ( rne(4) * \frac{1000 + rn2(1000)}{1000})

and the other is

 i / ( rne(4) * \frac{1000 + rn2(1000)}{1000}) .

The function is easier to analyze if the expression

\frac{1000 + rn2(1000)}{1000}

is replaced by a continuous uniformly distributed variable with range from 1 to 2. Let this variable be called z. For the case where the variable i is divided by the random formula, it helps to know the distribution of the reciprocal of z; it is z-2 for 0.5 <= z <= 1, and 0 otherwise.

The rne(4) call returns an integer from 1 to 5, with the following probabilities:

Return Probability
1 3/4
2 3/16
3 3/64
4 3/256
5 1/256

If the hero's experience level is 18 or greater, then rne can return numbers greater than 5; but this event has low probability, and to keep this explanation simple it will not be considered.

We can now consider all possible outcomes of the rn2(2) and rne(4) calls:

rn2(2) returns rne(4) returns Probability Outcome Range Distribution
1 5 \frac{1}{512} \frac{1}{5z} \frac{1}{10} to \frac{1}{5} \frac{x^{-2}}{2560}
1 4 \frac{3}{512} \frac{1}{4z} \frac{1}{8} to \frac{1}{4} \frac{3x^{-2}}{2048}
1 3 \frac{3}{128} \frac{1}{3z} \frac{1}{6} to \frac{1}{3} \frac{x^{-2}}{128}
1 2 \frac{3}{32} \frac{1}{2z} \frac{1}{4} to \frac{1}{2} \frac{3x^{-2}}{64}
1 1 \frac{3}{8} \frac{1}{z} \frac{1}{2} to 1 \frac{3x^{-2}}{8}
0 1 \frac{3}{8} z 1 to 2 \frac{3}{8}
0 2 \frac{3}{32} 2z 2 to 4 \frac{3}{64}
0 3 \frac{3}{128} 3z 3 to 6 \frac{1}{128}
0 4 \frac{3}{512} 4z 4 to 8 \frac{3}{2048}
0 5 \frac{1}{512} 5z 5 to 10 \frac{1}{2560}

Where the ranges overlap, the distributions add:

Range Distribution
\frac{1}{10} to \frac{1}{8} \frac{x^{-2}}{2560}
\frac{1}{8} to \frac{1}{6} \frac{19x^{-2}}{10240}
\frac{1}{6} to \frac{1}{5} \frac{99x^{-2}}{10240}
\frac{1}{5} to \frac{1}{4} \frac{19x^{-2}}{2048}
\frac{1}{4} to \frac{1}{3} \frac{7x^{-2}}{128}
\frac{1}{3} to \frac{1}{2} \frac{3x^{-2}}{64}
\frac{1}{2} to 1 \frac{3x^{-2}}{8}
1 to 2 \frac{3}{8}
2 to 3 \frac{3}{64}
3 to 4 \frac{7}{128}
4 to 5 \frac{19}{2048}
5 to 6 \frac{99}{10240}
6 to 8 \frac{19}{10240}
8 to 10 \frac{1}{2560}

This random variable, multiplied by the parameter i, is the return value of rnz.