QCElemental handles the precision by reading the NIST string into a Python Decimal object, which preserves the input decimal places. The resulting C and Fortran headers are thus consistent with NIST (psi4/physconst.h at master · psi4/psi4 · GitHub). Uncertainty is not used, except in the comment. I’m not finding specific notation, but ... indicates exact values. qcel does register constants with the Python units module pint, but that’s an effort to have self-consistent unit conversions w/i the CODATA set, rather than handling exact/derived.
I’ve supposed that the reason CODATA contains so many variations on derived constants is to guide users toward the number of sigfigs that NIST’s analysis of experimental precision and constants coupling (CODATA Values of the Fundamental Constants) indicates.
Somehow, you are right (I’m doing something similar, in my physical constant module).
However, the exact fundamental constants change time to time. In 2018, the Avogadro number, NA, is exact, while in 2014 it was not exact …
the number of particles that are contained in one mole
But now:
However, in its 26th Conference, the BIPM adopted a different approach: effective 20 May 2019, it defined the Avogadro number as the exact value N = 6.02214076×10^23, and redefined the mole as the amount of a substance under consideration that contains N constituent particles of the substance.
So, it was derived from the mole, and now the mole is derived from Avogadro’s number.
@gardhor , do you agree with the following correction?
It seems you forgot to update b with the b-aint(b) result (it was just calculated in the test).
pure integer function number_of_digits(a)
real (kind=wp), intent(in) :: a
real (kind=wp) :: b, c
integer :: i
b = a
i = 0
do
c = b-aint(b)
if (c < 0.01_wp) exit
i = i + 1
b = c * 10._wp
end do
number_of_digits = i
end function number_of_digits
I have incorporated your code in my local branch. And my Python script is now generating automatically a test.f90 file which tries to print the two first columns of the NIST file using the constants from the Fortran module. We must now validate the other part of your code.
With “ANINT”, instead of “AINT”, the function works better. However, it still has problems for number close to one (such, conventional_value_of_farad_90 and conventional_value_of_henry_90).
conventional value of farad-90 0.999 999 982 20... (exact) F
conventional value of henry-90 1.000 000 017 79...
For the farad-90, the problem is that the nearest number in the IEEE-754 representation is: 0.99999998219999997...
In that case the nearest() function is helpful: nearest(0.99999998219999997d0, 1d0) yields 0.99999998220000008... (next IEEE 754 real) and the number_of_digits() function will stop because there is many trailing zeros.
Concerning henry-90 the problem is that the same function will also be stopped by the 7 zeros after the decimal point: 1.000 000 017 79
You’re right. The print statement prints only 17 digits of those exact numbers. I’ve updated my original message with “…”
With those rounding effects, I think the Python script should give to the Fortran program two infos on each constants: for example numbers of digits to print at the left and at the right of the decimal point, or number of decimals and value of the exponent.
I have pushed a v0.2 of my project. The Python script now writes a test.f90 which tries to print all constants using the CODATA format (two first columns). The Python script analyzes the format of each constant and test.f90 know of many decimals to print, and what exponent to use. The output is now very close to the CODATA style:
alpha particle-electron mass ratio 7294.29954142
alpha particle mass 6.6446573357E-27
alpha particle mass energy equivalent 5.9719201914E-10
alpha particle mass energy equivalent in MeV 3727.3794066
alpha particle mass in u 4.001506179127
alpha particle molar mass 4.0015061777E-03
...
Most of the constants are written correctly. Very few problems remain, for example:
conventional value of Josephson constant 4.8E+09
should be 483597.9e9. Let me know if you find others.
We need now a subroutine receiving a 25 characters string with the number and inserting spaces between groups of 3 digits, except when a digit would then be alone. The idea is to start from the decimal point and to scan firstly toward the left. Then scan toward the right. And before inserting a space, we must verify that there will be at least two digits after. A subroutine insert_space(string, position) which insert one space at the given position has already been pushed.
Updated 2021-03-20:
I am now very near my goal (not yet pushed on GitHub):
alpha particle-electron mass ratio 7294.299 541 42
alpha particle mass 6.644 657 3357 e-27
alpha particle mass energy equivalent 5.971 920 1914 e-10
alpha particle mass energy equivalent in MeV 3727.379 4066
alpha particle mass in u 4.001 506 179 127
alpha particle molar mass 4.001 506 1777 e-03
The Fortran program must now delete the zeros beginning the exponent: e-3 instead of e-03.
And a diff shows that all values are identical to the NIST file except for 6 constants (over 354). Need further analyze for those 6…
The fortran_generated_????.txt file generated with fpm test is now nearly identical (concerning the first two columns) to the NIST file. A few constants are written differently because the NIST file don’t use the classical scientific format: for example, the molar mass of carbon-12 is written 1.199 999 999 58 e-2 in our file but 11.99 999 999 58 e-3 in the NIST file. But it is quick to verify that those values are correct. Some of the values in the NIST file can be calculated from other constants and are terminated by “…” in the NIST file: note that their values in the Fortran module are not calculated, but have the same number of digits as in the NIST file.
Fantastic! Here’s also Bob Apthorpe’s repo, with similar approach and result. One way or another, we’ll have a good candidate for physical constants in stdlib.