The previous post mentioned that Avogadro’s constant is approximately 24!. Are there other physical constants that are nearly factorials?

I searched SciPy’s collection of physical constants looking for values that are either nearly factorials or nearly reciprocals of factorials.

The best example is the “classical electron radius” *r*_{e} which is 2.818 × 10^{-15} m and 1/17! = 2.811 × 10^{-15}.

Also, the “Hartree-Hertz relationship” E_{h}/*h* equals 6.58 × 10^{15} and 18! = 6.4 × 10^{15}. (E_{h} is the Hartree energy and *h* is Plank’s constant.)

Here’s the Python code I used to discover these relationships.

from scipy.special import gammaln from math import log, factorial from scipy.optimize import brenth from scipy.constants import codata def inverse_factorial(x): # Find r such that gammaln(r) = log(x) # So gamma(r) = x and (r-1)! = x r = brenth(lambda t: gammaln(t) - log(x), 1.0, 100.0) return r-1 d = codata.physical_constants for c in d: (value, unit, uncertainty) = d[c] x = value if x < 0: x = abs(x) if x < 1.0: x = 1.0/x r = inverse_factorial(x) n = round(r) # Use n > 6 to weed out uninteresting values. if abs(r - n) < 0.01 and n > 6: fact = factorial(n) if value < 1.0: fact = 1.0/fact print c, n, value, fact

Not really a fundamental physical constant, but 6 weeks is exactly 10! seconds.

Neat post and interesting tidbit, Paul. I’ve always found it interesting that 10! = 6! * 7!

A favourite code kata is to find non-trivial a,b,c such that a! = b! * c!

Is that useful in any way? (No criticism implied, but I’m not a mathematician, and there might be an implication I’m missing.)

Using numbers I found (the dots indicate the number of matching digits, including dp):

..032e+4 4.12529612494192710313e+4 square degrees about a point

..032e+4 4.356e+4 square feet per acre

..032e+4 4.41e+4 ISO 11172-3 MPEG-1 Audio sample rate

..6288e+5 3.3459e+5 Latent heat of melting of water at 0 C, in J/Kg

..6288e+5 3.32837e+5 Sun mass relative to Earth

..2270208e+9 6.7005361e+9 joule-atomic mass unit relationship

..402373705728e+15 6.579683920721e+15 hartree-hertz relationship

..124e+21 1.05e+21 50000_Quaoar mass in kg

..124e+21 1.21e+21 2005_QU182 mass in kg

..124e+21 1.096e+21 Dione mass in kg

..124e+21 1.2e+21 Umbriel mass in kg

..20448e+23 6.0221415e+23 Avogadro’s number NA,L

..20448e+23 6.4185e+23 Mars mass, Kg

..480158e-5 2.5689e-5 proton magnetic shielding correction

..605904e-10 1.4924179e-10 atomic mass constant energy equivalent, joules

..605904e-10 1.50534957e-10 neutron mass energy equivalent

..605904e-10 1.50327743e-10 proton mass energy equivalent

….1457e-15 2.8179402894e-15 classical electron radius, re = e2 / 4??0mec2

…6192e-16 1.519829846006e-16 hertz-hartree relationship

..279889e-30 3.339e-30 Debye in Coloumb per meter

Oops,

First number is the factorial, second what it matched against.

I used the options: -match 1 -fuzz 0.1

and you will have to keep the number of digits in the factorial value small (say less than 10) otherwise various heuristics intended to stop spurious matches kick in.

Calculating factorials is a great exercise in critical thinking and problem solving, particularly when large factorials are involved.

When I was young (and dinosaurs roamed the earth) it seemed I could hardly throw a stone without hitting a factorial calculation routine that used recursion. It was everyone’s favorite illustration of recursion, but I think it was the worst imaginable way to actually calculate them. Shockingly, I saw that approach in many ‘real’ applications written by statisticians. Typically anytime a factorial was needed, that recursive routine was called. I think it was a watershed moment for me when I learned that tabulating 171 values would cover all the representable factorials for your typical C/C++ ‘double’ type.

My favorite exercise is writing a routine to calculate the number of trailing zeroes in absurdly large factorials such as 9999!, since just doing the obvious won’t work.

@John Venier: The number of zeros of a factorial is a classic problem.

It’s amusing to derive a formula for a ballpark estimate of the number

of zeros of n!. A rough answer is n/4… A somewhat improved estimate is

0.25*(n-1) – 0.5*log_5(n). The error is of order log_5(n).

@Michael Easter,

That’s trivial, however

10! = 6! * 7 * 8 * 9 * 10

7 * 8 * 9 * 10 just happens to have the same prime factors as 7! (with the same degree)

@Glenn: Yep, it even has its own Wikipedia page: http://en.wikipedia.org/wiki/Trailing_zero

Except, you must mean the number of trailing zeroes, right? I think determining the total number of zeroes would be tricky except for doing it brute force.

@John Venier: Apologies, yes – I meant the number of trailing zeros.

I hadn’t realized so much existed discussing this problem, I last remember it from a math competition more than 20 years ago!

Can you suggest something to caclulate probability of hash collision? For example, I have k = 10*1000*1000*1000 elements, and their md5 hashes. Cardinality of of hash space equals N=2^128

If I tries to estimate probability of no collision = log( П (1 – i/N) ) = Log(N!) – Log(k!) – N*Log(N), then difference of gammaln(N!)-gammaln(k!) is out of floating-point precision.

I use now estimation log(1 – i/N) ≈ -i/N, but exponentiation of estimation can lead to very inaccurate result.

_winnie: Did you mean to calculate gammaln(N!). If you need to calculate log(N!) then that’s just gammaln(N+1).

gammaln(N+1.0) is roughly 3 e40 and gammaln(k + 1.0) is roughly 2e11, so there’s no difficulty subtracting them.

gammaln(N+1) and N*log(N) are close, but you’d only lose one significant figure in the subtraction.

Sorry, half of formula was misspelled

P(no_collision) = (1 - 0/N) * (1 - 1/N) * (1 - 2/N) * (1 - 3/N) * ... * (1 - (N-k+1)/N)

`Log(P(no_collision)) = Log(N!) - Log((N-k)!) - k*Log(N)`

for N = 2^128 and relatively small values of k (like k = 1, or 10) i got absurd results. So I am in doubt, that for k = 1e10 this formula gives any meaning result. When i subtract gammaln(N+1)-gammaln((N-k)+1) I got always zero, which cannot be true.

from scipy.special import gammaln

import math

N = 2.0 ** 128

k = 10

gammaln(N+1) - gammaln((N-k)+1) - k*math.log(N)

-887.22839111672999 #hmmm, probability of md5(10 elements) is almost 1.0 ?..

`gammaln(N+1) - gammaln((N-k)+1)`

0.0 #absurd! gammaln(N+1) equals to gammaln((N-k)+1)