A definitive proposal can be found in:
Elo, Arpad E. (August, 1967). The Proposed USCF Rating System, Its Development, Theory, and Applications. Chess Life XXII (8): 242-247.
How exactly are
- THE PERCENTAGE EXPECTANCY CURVE (Fig. 1),
- TABLE I - RATING DIFFERENCES, and
- TABLE II- WINNING EXPECTANCIES
(page 243-244) calculated, including rounding details. I tried the normal distribution function with mean = 0
and sigma = 2000 / 7
. But I could not get the rounding correct. For example the percentage expectancy of rating difference DP = 344
is 89% instead of 88% as in table II. Other irregularities: 54, 343, 358, 392, 620.
At page 247 we find a short reference list, including:
- A. E. Elo; Analytical Reports, 1961, 1963 & 1965; (Privately Printed).
Are these reports lost forever, or are copies preserved and available in the public domain?
Update
My question is not about the validity of the model, but about the calculation within the model. How exactly can I reproduce Table II? Why is the rating expectancy of DP = 344
equal to P = .88
instead of .89 as I would expect.
In The Rating of Chess players, Elo states in chapter 8.94 Development of the Percentage Expectancy Table:
For example, suppose D = 160. Then z = 160/284.84. The table gives .7143 and .2857. as the areas of the two portions under the curve. These probabilities are rounded to two figures in table 2.11.
Apparently Elo refers to a z-table, but which z-table was in use at that time (±1960)?
- @whuber I tried.
σ=2000/7
D H |z-score | Tabel (t) | t/2 + 50% | N(z) | P
54 58%| 0,189 |0.14990 71832 09998 |0,574953591604999|0,574953591604999| 57%
| 1,200 |0.76986 06595 56583 |0,884930329778292|0,884930329778292|
343 88%| 1,2005 | | interpolatie |0,885027364557095| 89%
| 1,201 |0.77024 87986 71795 |0,885124399335897|0,885124399335898|
344 88%| 1,204 |0.77141 04214 54696 |0,885705210727348|0,885705210727348| 89%
358 90%| 1,253 |0.78979 42933 03286 |0,894897146651643|0,894897146651643| 89%
392 92%| 1,372 |0.82993 65621 86873 |0,914968281093437|0,914968281093436| 91%
620 99%| 2,170 |0.96999 31540 52536 |0,984996577026268|0,984996577026268| 98%
Source:
- @cdalitz, 2000/7 is folklore, used by the Dutch Chess federation. I have no reference from literature.
Constructing TABLE-1 from TABLE-2
Table I and II are effectively mirror-images. See also the FIDE Handbook B. Permanent Commissions / 02. FIDE Rating Regulations.
R-code
D <-
c( 3, 10, 17, 25, 32, 39, 46, 53, 61, 68, 76, 83, 91, 98, 106, 113, 121,
129, 137, 145, 153, 162, 170, 179, 188, 197, 206, 215, 225, 235, 245, 256, 267, 278,
290, 302, 315, 328, 344, 357, 374, 391, 411, 432, 456, 484, 517, 559, 619, 735, 736
)
## TABLE I - RATING DIFFERENCES, between 51% and 99%.
## Column DP of TABLE-1 constitutes the midpoints of TABLE II, indexed by P.
## This is a reasonable approximation with the exception of P=99%.
table_1 <-
head(cbind(P =seq(from=0.51, to=1.0, by=0.01),
DP=trunc((head(D, -1) + tail(D, -1) + 1)/2) ),
-1)
table_1
Constructing TABLE II - WINNING EXPECTANCIES with sigma = 200 * (10/7)
Note (10/7) is a rough approximation of sqrt(2). Conversion of rating difference to z-score gives at most 4 significant digits, which is useful when using a table indexed by z-score.
## Create rating differences, winning expectancy between 1 and 736, from 50% upto 100%.
n <- 736
Pfull <- rep(-1, n)
pct <- 0.50
k <- 1
for(i in seq_along(D) ){
while(k <= D[i]){
Pfull[k] <- pct
k <- k + 1
}
pct <- pct + 0.01
}
## calculate / add normal probabilities (pnorm).
# P2, P15 probabilities rounded by 2, 15 digits.
df <- data.frame(D=seq(n), P=Pfull)
Deviations in Elo's expectations table
sd <- 200 * (10/7) # standard deviation, using (10/7) instead of sqrt(2).
within(df,
{ P15 = round(pnorm(D / sd , 0, 1,1), 15)
P2 = round(P15, 2)
attP2 = round(P - P2, 10)
}
) -> df2
subset(df2, attP2 != 0)
D P attP2 P2 P15
54 54 0.58 0.01 0.57 0.5749536
343 343 0.88 -0.01 0.89 0.8850274
344 344 0.88 -0.01 0.89 0.8857052
358 358 0.90 0.01 0.89 0.8948971
392 392 0.92 0.01 0.91 0.9149683
620 620 0.99 0.01 0.98 0.9849966
Constructing TABLE II by interpolation, third try
Consider rating values in steps of 20. The corresponding Z-score step is 20 * 7 / 2000 = 0.07. Finding the percentage scores corresponding to the rating values D = 0, 20, 40, etc. does not require any calculations. They can be extracted directly from the Z-table.
To calculate the intermediate values, linear interpolation is the most obvious. For example calculate the P value of 54 as follows:
sd = 2000 / 7, the standard deviation chosen to ensure discrete steps in the Z table.
D = 40 + 14, where 14 is the index in rating range 40-60
Z_b = 40 * 7 / 2000 = 0.14, P_b = 0.5557 (From the Z table)
Z_e = Z_b + 0.07 = 0.21 P_e = 0.5832 (From the Z table)
The step size of P becomes: (0.5832 - 0.5557) / 20 = 0.001375
This gives:
P4 = 0.5557 + 14 * 0.001375 = 0.57495
= 0.57495 + 5E-5 + 1E-6, rounded up to two decimals gives
P42 = 58%.
R-code.
dD <- 20 # step in D = 0, 20, 40, etc.
sd <- 2000 / 7 # standard deviation.
dZ <- dD / sd # Short table, Z in two decimals.
within(df,
{ Z_sc <- D / sd # 4 decimals.
P15 <- round(pnorm(Z_sc), 15) # value from extended table (1953).
Z_b <- trunc(D / dD) * dD * 7 / 2000 # index in short table, begin.
Z_e <- Z_b + dZ # index in short table, end.
P_b <- round(pnorm(Z_b ), 4) # P before.
P_e <- round(pnorm(Z_b + dZ), 4) # P after.
## Corrections to fit Elo tables.
## P_b[340:359] <- .8830 - .0010 # Feller = .8836
## P_b[380:399] <- .9082 + .0001 # Feller = .9083
ix <- D %% dD # index 0 - 20.
Pstep <- (P_e - P_b) / dD # interpolation step.
## Pstep[340:359] <- Pstep[320:339] # Previous step size
## Pstep[380:399] <- Pstep[380:399] + .00001 # .00545 --> .00555
P4e <- P_b + ix * Pstep # intermediate percentage.
P42e <- round(P4e + 5E-5 + 1E-6, 2) # rounded up to next percentage.
attP42e <- round(P42e - P, 15) # deviation .
}
) -> inter_lin
#subset(inter_lin, D >= 340 & D <= 360)
subset(inter_lin, attP42e != 0)
Between D = 340 and D = 400 we find 4 deviations:
D P attP42e P42e P4e Pstep ix P_e P_b Z_e Z_b P15 Z_sc
343 0.88 0.01 0.89 0.88498 0.00066 3 0.8962 0.8830 1.26 1.19 0.8850274 1.2005
344 0.88 0.01 0.89 0.88564 0.00066 4 0.8962 0.8830 1.26 1.19 0.8857052 1.2040
358 0.90 -0.01 0.89 0.89488 0.00066 18 0.8962 0.8830 1.26 1.19 0.8948971 1.2530
392 0.92 -0.01 0.91 0.91480 0.00055 12 0.9192 0.9082 1.40 1.33 0.9149683 1.3720
How did it happen? - It is easy to see that the table is not entirely consistent. Look at the number of rating differences assigned to a percentage:
P L - H Range
.86 303 - 315 13
.87 316 - 328 13
.88 329 - 344 16 <<<
.89 345 - 357 13
.90 358 - 374 20
Since the expectation function is monotonically increasing, the difference between H and L should not decrease. The 16 is clearly an outlier.
The error in D = 392 can be explained by using .00555 instead of .00545 as the step size for the linear interpolation. Errors in D=343, 344, 358 can be explained by taking a wrong starting percentage (related to Z = 1.19), and the step size of the previous group.
The above is obvious an educated guess. I am afraid I have to visit the Royal Library in the Hague to find out more.
Rounding - It is plausible that Elo confused the z boundary 1.2005 with 1.2050 (P=.885). That leaves D=54, D=358 to explain.
Now consider the folowing critical D values:
sigma = 200 * (10 / 7), z(D) = D / sigma.
D z(D) P(D) P-bndry z-bndry phi plo zlo Truncated
54 0.189 0.585 * 0.575 0.189231 0.5753 0.5714 0.18 Yes
76 0.266 0.605 0.605 0.266316 0.6064 0.6026 0.26 No
106 0.371 0.645 0.645 0.371892 0.6480 0.6443 0.37 No
162 0.567 0.715 0.715 0.567941 0.7157 0.7123 0.56 No
188 0.658 0.745 0.745 0.658750 0.7454 0.7422 0.65 No
256 0.896 0.815 0.815 0.896538 0.8159 0.8133 0.89 No
358 1.253 0.905 * 0.895 1.253333 0.8962 0.8944 1.25 Yes
zpt = 0.189xxx is truncated to .189, so P-bndry( 54) is moved to the next bin.
zpt = 1.253xxx is truncated to .253, so P-bndry(358) is moved to the next bin.
However this logic is not applied to the other values.