Written and maintained by CASRAI Editorial Board
Last updated
pnorm() is the R function that returns the cumulative distribution function (CDF) of the normal distribution: given a quantile q, it returns the probability that a normal random variable is at most q. The call is pnorm(q, mean = 0, sd = 1, lower.tail = TRUE, log.p = FALSE). This guide covers the arguments that decide whether you get the right tail or the left, how to use pnorm on whole columns of z-scores, and how to turn a z-statistic into a two-tailed p-value with 2*pnorm(-abs(z)).
What pnorm is used for in research
In R’s documentation pnorm sits in the “Normal” family with dnorm (density), qnorm (quantile function) and rnorm (random generation). The R manual An Introduction to R describes the naming rule: prefix the distribution name with d for the density, p for the CDF, q for the quantile function (and r for random simulation). pnorm is therefore the “p” member for the normal distribution.
Typical research uses:
- Finding the proportion of a normally distributed measurement below, above or between cut-offs.
- Converting a z-statistic into a p-value (see how to find a p-value from a z-score).
- Overlaying a fitted normal CDF on an empirical distribution; the manual’s own example draws
pnorm(x, mean = mean(long), sd = sqrt(var(long)))as a line on a plot.
For the concept behind the function, see the cumulative distribution function and the probability distribution function of the normal distribution. For the reverse direction, from a probability back to a quantile, use qnorm in R.
Install or access (official source only)
pnorm belongs to the stats package, which is part of the base distribution of R and is attached by default, so nothing beyond R itself needs to be installed and no library() call is needed. Download R from the Comprehensive R Archive Network, cran.r-project.org, which lists downloads for each operating system. As of 2026-10-29 the CRAN Windows page offers R 4.6.1 (last change 2026-06-26). Once R is running, ?pnorm opens the help page.
Step-by-step: compute a normal probability with pnorm
The examples use a variable that is normally distributed with mean 100 and standard deviation 15.
- Standard normal, left tail. With
meanandsdomitted, R uses 0 and 1.pnorm(0)returns 0.5, because half of the standard normal distribution lies at or below zero.pnorm(1.96)returns 0.9750021. - Your own mean and standard deviation.
pnorm(115, mean = 100, sd = 15)returns 0.8413447: the probability that the variable is at most 115, which is one standard deviation above the mean. - Right tail.
pnorm(130, mean = 100, sd = 15, lower.tail = FALSE)returns 0.02275013, the probability that the variable exceeds 130. - Between two values. Subtract two CDF values:
pnorm(130, 100, 15) - pnorm(70, 100, 15)returns 0.9544997, the probability of falling between 70 and 130 (within two standard deviations of the mean). - Two-tailed p-value from a z-statistic. For a test statistic
zthat is standard normal under the null hypothesis,2 * pnorm(-abs(z))doubles the probability in the tail beyond |z|. Forz = 2.5this gives2 * pnorm(-2.5)= 0.01241933. The doubling idiom is the same one the R manual shows for a t-distribution,2*pt(-2.43, df = 13).
Output and how to read it
lower.tail: left tail or right tail
The documentation defines lower.tail as a logical: if TRUE (the default), probabilities are P[X ≤ x]; otherwise they are P[X > x]. The two calls therefore always add to one: pnorm(q) + pnorm(q, lower.tail = FALSE) equals 1. Writing pnorm(q, lower.tail = FALSE) is the direct way to get an upper-tail probability, and it is the form to prefer over 1 - pnorm(q) when the upper tail is very small.
log.p: probabilities on the log scale
With log.p = TRUE the function returns the logarithm of the probability. The documentation’s own examples use it. For a far-out quantile such as pnorm(-10), the probability is about 7.6e-24, and pnorm(-10, log.p = TRUE) returns its natural logarithm, about -53.23. Use this when you need to add or compare very small probabilities, for example in likelihood work.
Vectorised input
The Value section of the manual states that the result has the length of the longest numeric argument and that numerical arguments are recycled. Only the first element of each logical argument (lower.tail, log.p) is used. Two consequences for data work:
pnorm(c(-1.96, 0, 1.96))returns three probabilities (0.0249979, 0.5, 0.9750021) in one call, so you can apply it directly to a column of z-scores, for exampledf$p_lower <- pnorm(df$z).meanandsdmay also be vectors, so one call can evaluate each row against its own normal distribution.
pnorm and qnorm are inverses
qnorm(pnorm(1.96)) returns 1.96 again. Use pnorm when you start from a quantile and want a probability; use qnorm when you start from a probability. Both are documented on the same help page.
Troubleshooting
- NaN returned. The manual states that a negative
sdis an error and givesNaN. Check that you did not pass a variance where a standard deviation is expected:sdis the standard deviation, so usesqrt(variance). - sd = 0. The documentation says this gives the limit as
sddecreases to 0, a point mass atmu: the CDF jumps from 0 to 1 at the mean. - Result looks like 1 – the answer you expected. You have the wrong tail. Left-tail probabilities are the default; add
lower.tail = FALSEfor P[X > x]. - Upper-tail probability prints as 0 or 1. At extreme quantiles a value near 1 cannot hold the small tail probability. Use
lower.tail = FALSEorlog.p = TRUErather than subtracting from 1. - Wrong p-value from a z-statistic.
pnorm(z)is the left-tail probability only. A two-tailed p-value needs2 * pnorm(-abs(z)).
Free alternatives
The same normal CDF is available outside R. Both tools below are free and open source.
| Tool | Equivalent call | Notes |
|---|---|---|
R (base stats) |
pnorm(q, mean, sd) |
Reference implementation described here; lower.tail and log.p built in. |
| Python, SciPy | scipy.stats.norm.cdf(x, loc, scale) |
The normal distribution object in scipy.stats; loc is the mean and scale the standard deviation. |
| Python standard library | statistics.NormalDist(mu, sigma).cdf(x) |
No extra package; left-tail probability only. |
For MATLAB see the normal distribution in MATLAB.
FAQ
What does pnorm do in R?
It returns the cumulative probability of the normal distribution: P[X ≤ q] by default, or P[X > q] with lower.tail = FALSE.
What is the difference between pnorm, dnorm and qnorm?
dnorm gives the density at a point, pnorm gives the cumulative probability up to a quantile, and qnorm inverts pnorm to return the quantile for a given probability. rnorm generates random values. See qnorm in R for the inverse.
How do I use pnorm in R to get a p-value?
For a standard normal test statistic z, a one-tailed upper p-value is pnorm(z, lower.tail = FALSE) and a two-tailed p-value is 2 * pnorm(-abs(z)). See how to find a p-value from a z-score, and the inverse normal for critical values.
How do I calculate the probability between two values?
Subtract the two CDF values: pnorm(b, mean, sd) - pnorm(a, mean, sd) for a < b.
What is the default mean and standard deviation in pnorm?
If mean or sd is omitted, R uses 0 and 1, the standard normal distribution.
Sources (official documentation)
- R Core Team, “The Normal Distribution” help page for
stats::Normal(stat.ethz.ch R manual), checked 2026-10-29. The page cites Cody (1993) as the basis ofpnorm. - R Core Team, An Introduction to R, section “Probability distributions” (cran.r-project.org), checked 2026-10-29.
- CRAN, R for Windows download page (cran.r-project.org/bin/windows/base), checked 2026-10-29.
- SciPy documentation,
scipy.stats.norm(docs.scipy.org), checked 2026-10-29.







