units-2.24/0000777000175000017500000000000014721206266012073 5ustar adrianadrianunits-2.24/definitions.units0000664000175000017500000133114514721206054015473 0ustar adrianadrian# # This file is the units database for use with GNU units, a units conversion # program by Adrian Mariano adrianm@gnu.org # # Version 3.22 # last updated 22 November 2024 # # Copyright (C) 1996-2002, 2004-2020, 2022, 2024 # Free Software Foundation, Inc # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, # Boston, MA 02110-1301 USA # ############################################################################ # # Improvements and corrections are welcome. # # See the end of this file for a list of items we have chosen to exclude # or have decided are out of scope for GNU units. # # Fundamental constants in this file are the 2018 CODATA recommended values. # # Most units data was drawn from # 1. NIST Special Publication 811, Guide for the # Use of the International System of Units (SI). # Barry N. Taylor. 2008 # https://www.nist.gov/pml/special-publication-811 # 2. CRC Handbook of Chemistry and Physics 70th edition # 3. Oxford English Dictionary # 4. Webster's New Universal Unabridged Dictionary # 5. Units of Measure by Stephen Dresner # 6. A Dictionary of English Weights and Measures by Ronald Zupko # 7. British Weights and Measures by Ronald Zupko # 8. Realm of Measure by Isaac Asimov # 9. United States standards of weights and measures, their # creation and creators by Arthur H. Frazier. # 10. French weights and measures before the Revolution: a # dictionary of provincial and local units by Ronald Zupko # 11. Weights and Measures: their ancient origins and their # development in Great Britain up to AD 1855 by FG Skinner # 12. The World of Measurements by H. Arthur Klein # 13. For Good Measure by William Johnstone # 14. NTC's Encyclopedia of International Weights and Measures # by William Johnstone # 15. Sizes by John Lord # 16. Sizesaurus by Stephen Strauss # 17. CODATA Recommended Values of Physical Constants available at # http://physics.nist.gov/cuu/Constants/index.html # 18. How Many? A Dictionary of Units of Measurement. Available at # http://www.ibiblio.org/units/ # 19. Numericana. http://www.numericana.com # 20. UK history of measurement # https://metrication.uk/more/timeline/ # 21. NIST Handbook 44, Specifications, Tolerances, and # Other Technical Requirements for Weighing and Measuring # Devices. 2011 # 22. NIST Special Publication 447, Weights and Measures Standards # of the United States: a brief history. Lewis V. Judson. # 1963; rev. 1976 # 23. CRC Handbook of Chemistry and Physics, 96th edition # 24. Dictionary of Scientific Units, 6th ed. H.G. Jerrard and D.B. # McNeill. 1992 # 25. NIST Special Publication 330, The International System of # Units (SI). ed. Barry N. Taylor and Ambler Thompson. 2008 # https://www.nist.gov/pml/special-publication-330 # 26. BIPM Brochure, The International System of Units (SI). # 9th ed., 2019 # https://www.bipm.org/en/publications/si-brochure/ # ########################################################################### # # If units you use are missing or defined incorrectly, please contact me. # If your country's local units are missing and you are willing to supply # them, please send me a list. # ########################################################################### ########################################################################### # # Brief Philosophy of this file # # Most unit definitions are made in terms of integers or simple fractions of # other definitions. The typical exceptions are when converting between two # different unit systems, or the values of measured physical constants. In # this file definitions are given in the most natural and revealing way in # terms of integer factors. # # If you make changes be sure to run 'units --check' to check your work. # # The file is USA-centric, but there is some modest effort to support other # countries. This file is now coded in UTF-8. To support environments where # UTF-8 is not available, definitions that require this character set are # wrapped in !utf8 directives. # # When a unit name is used in different countries with the different meanings # the system should be as follows: # # Suppose countries ABC and XYZ both use the "foo". Then globally define # # ABCfoo # XYZfoo # # Then, using the !locale directive, define the "foo" appropriately for each of # the two countries with a definition like # # !locale ABC # foo ABCfoo # !endlocale # ########################################################################### !locale en_US ! set UNITS_ENGLISH US !endlocale !locale en_GB ! set UNITS_ENGLISH GB !endlocale !set UNITS_ENGLISH US # Default setting for English units !set UNITS_SYSTEM default # Set a default value !varnot UNITS_SYSTEM si emu esu gaussian gauss hlu natural natural-gauss hartree planck planck-red default !message Unknown unit system given with -u or UNITS_SYSTEM environment variable !message Valid systems: si, emu, esu, gauss[ian], hlu, natural, natural-gauss !message planck, planck-red, hartree !message Using SI !prompt (SI) !endvar !var UNITS_SYSTEM si !message SI units selected !prompt (SI) !endvar ########################################################################### # # # Primitive units. Any unit defined to contain a '!' character is a # # primitive unit which will not be reduced any further. All units should # # reduce to primitive units. # # # ########################################################################### # # SI units # # On 20 May 2019, the SI was revised to define the units by fixing the # values of physical constants that depend on those units. # # https://www.nist.gov/si-redefinition/ # # The BIPM--the International Bureau of Weights and Measures--provides a # succinct description of the new SI in its Concise Summary: # # https://www.bipm.org/utils/common/pdf/si-brochure/SI-Brochure-9-concise-EN.pdf # # The SI is the system of units in which: # # * the unperturbed ground state hyperfine transition frequency of the # caesium 133 atom is delta nu_Cs = 9 192 631 770 Hz, # * the speed of light in vacuum, c, is 299 792 458 m/s, # * the Planck constant, h, is 6.626 070 15 * 10^-34 J s, # * the elementary charge, e, is 1.602 176 634 * 10^-19 C, # * the Boltzmann constant, k, is 1.380 649 * 10^-23 J/K, # * the Avogadro constant, N_A, is 6.022 140 76 * 10^23 mol^-1, # * the luminous efficacy of monochromatic radiation of frequency # 540 * 10^12 Hz, K_cd, is 683 lm/W, # # where the hertz, joule, coulomb, lumen, and watt, with unit symbols Hz, # J, C, lm, and W, respectively, are related to the units second, metre, # kilogram, ampere, kelvin, mole, and candela, with unit symbols s, m, kg, # A, K, mol, and cd, respectively, according to Hz = s^-1, J = kg m^2 s^-2, # C = A s, lm = cd m^2 m^-2 = cd sr, and W = kg m^2 s^-3. # # These definitions specify the exact numerical value of each constant when # its value is expressed in the corresponding SI unit. By fixing the exact # numerical value the unit becomes defined, since the product of the # numerical value and the unit has to equal the value of the constant, # which is invariant. # # The defining constants have been chosen such that, when taken together, # their units cover all of the units of the SI. In general, there is no # one-to-one correspondence between the defining constants and the SI base # units. Any SI unit is a product of powers of these seven constants and a # dimensionless factor. # # Until 2018, the SI was defined in terms of base units and derived units. # These categories are no longer essential in the SI, but they are maintained # in view of their convenience and widespread use. They are arguably more # intuitive than the new definitions. (They are also essential to the # operation of GNU units.) The definitions of the base units, which follow # from the definition of the SI in terms of the seven defining constants, are # given below. # s ! # The second, symbol s, is the SI unit of time. It is defined second s # by taking the fixed numerical value of the unperturbed # ground-state hyperfine transition frequency of the # cesium-133 atom to be 9 192 631 770 when expressed in the # unit Hz, which is equal to 1/s. # # This definition is a restatement of the previous one, the # duration of 9192631770 periods of the radiation corresponding # to the cesium-133 transition. nu_133Cs 9192631770 Hz # Cesium-133 transition frequency (exact) c_SI 299792458 c 299792458 m/s # speed of light in vacuum (exact) m ! # The metre, symbol m, is the SI unit of length. It is meter m # defined by taking the fixed numerical value of the speed metre m # of light in vacuum, c, to be 299 792 458 when expressed in # units of m/s. # # This definition is a rewording of the previous one and is # equivalent to defining the meter as the distance light # travels in 1|299792458 seconds. The meter was originally # intended to be 1e-7 of the length along a meridian from the # equator to a pole. h_SI 6.62607015e-34 h 6.62607015e-34 J s # Planck constant (exact) kg ! # The kilogram, symbol kg, is the SI unit of mass. It is kilogram kg # defined by taking the fixed numerical value of the Planck # constant, h, to be 6.626 070 15 * 10^-34 when expressed in # the unit J s which is equal to kg m^2 / s. # # One advantage of fixing h to define the kilogram is that this # affects constants used to define the ampere. If the kg were # defined by directly fixing the mass of something, then h # would be subject to error. # # The previous definition of the kilogram was the mass of the # international prototype kilogram. The kilogram was the last # unit whose definition relied on reference to an artifact. # # It is not obvious what this new definition means, or # intuitively how fixing Planck's constant defines the # kilogram. To define the kilogram we need to give the mass # of some reference in kilograms. Previously the prototype in # France served as this reference, and it weighed exactly 1 # kg. But the reference can have any weight as long as you # know the weight of the reference. The new definition uses # the "mass" of a photon, or more accurately, the mass # equivalent of the energy of a photon. The energy of a # photon depends on its frequency. If you pick a frequency, # f, then the energy of the photon is hf, and hence the mass # equivalent is hf/c^2. If we reduce this expression using # the constant defined values for h and c the result is a # value in kilograms for the mass-equivalent of a photon of # frequency f, which can therefore define the size of the # kilogram. # # For more on the relationship between mass an Planck's # constant: # # https://www.nist.gov/si-redefinition/kilogram-mass-and-plancks-constant # This definition may still seem rather abstract: you can't # place a "kilogram of radiation" on one side of a balance. # Metrologists realize the kilogram using a Kibble Balance, a # device which relates mechanical energy to electrical energy # and can measure mass with extreme accuracy if h is known. # # For more on the Kibble Balance see # # https://www.nist.gov/si-redefinition/kilogram-kibble-balance # https://en.wikipedia.org/wiki/Kibble_balance k_SI 1.380649e-23 boltzmann 1.380649e-23 J/K # Boltzmann constant (exact) k boltzmann K ! # The kelvin, symbol K, is the SI unit of thermodynamic kelvin K # temperature. It is defined by taking the fixed numerical # value of the Boltzmann constant, k, to be 1.380 649 * 10^-23 # when expressed in the unit J/K, which is equal to # kg m^2/s^2 K. # # The boltzmann constant establishes the relationship between # energy and temperature. The average thermal energy carried # by each degree of freedom is kT/2. A monatomic ideal gas # has three degrees of freedom corresponding to the three # spatial directions, which means its thermal energy is # (3/2) k T. # # The previous definition of the kelvin was based on the # triple point of water. The change in the definition of the # kelvin will not have much effect on measurement practice. # Practical temperature calibration makes use of two scales, # the International Temperature Scale of 1990 (ITS-90), which # covers the range of 0.65 K to 1357.77K and the Provisional # Low Temperature Scale of 2000 (PLTS-2000), which covers the # range of 0.9 mK to 1 K. # https://www.bipm.org/en/committees/cc/cct/publications-cc.html # # The ITS-90 contains 17 reference points including things # like the triple point of hydrogen (13.8033 K) or the # freezing point of gold (1337.33 K), and of course the triple # point of water. The PLTS-2000 specifies four reference # points, all based on properties of helium-3. # # The redefinition of the kelvin will not affect the values of # these reference points, which have been determined by # primary thermometry, using thermometers that rely only on # relationships that allow temperature to be calculated # directly without using any unknown quantities. Examples # include acoustic thermometers, which measure the speed of # sound in a gas, or electronic thermometers, which measure # tiny voltage fluctuations in resistors. Both variables # depend directly on temperature. e_SI 1.602176634e-19 e 1.602176634e-19 C # electron charge (exact) A ! # The ampere, symbol A, is the SI unit of electric current. ampere A # It is defined by taking the fixed numerical value of the amp ampere # elementary charge, e, to be 1.602 176 634 * 10^-19 when # expressed in the unit C, which is equal to A*s. # # The previous definition was the current which produces a # force of 2e-7 N/m between two infinitely long wires a meter # apart. This definition was difficult to realize accurately. # # The ampere is actually realized by establishing the volt and # the ohm, since A = V / ohm. These measurements can be done # using the Josephson effect and the quantum Hall effect, # which accurately measure voltage and resistance, respectively, # with reference to two fixed constants, the Josephson # constant, K_J=2e/h and the von Klitzing constant, R_K=h/e^2. # Under the previous SI system, these constants had official # fixed values, defined in 1990. This created a situation # where the standard values for the volt and ohm were in some # sense outside of SI because they depended primarily on # constants different from the ones used to define SI. After # the revision, since e and h have exact definitions, the # Josephson and von Klitzing constants will also have exact # definitions that derive from SI instead of the conventional # 1990 values. # # In fact we know that there is a small offset between the # conventional values of the electrical units based on the # conventional 1990 values and the SI values. The new # definition, which brings the practical electrical units back # into SI, will lead to a one time change of +0.1ppm for # voltage values and +0.02ppm for resistance values. # # The previous definition resulted in fixed exact values for # the vacuum permeability (mu0), the impedance of free space # (Z0), the vacuum permittivity (epsilon0), and the Coulomb # constant. With the new definition, these four values are # subject to experimental error. avogadro 6.02214076e23 / mol # Size of a mole (exact) N_A avogadro mol ! # The mole, symbol mol, is the SI unit of amount of mole mol # substance. One mole contains exactly 6.022 140 76 * 10^23 # elementary entities. This number is the fixed numerical # value of the Avogadro constant, N_A, when expressed in the # unit 1/mol and is called the Avogadro number. The amount of # substance, symbol n, of a system is a measure of the number # of specified elementary entities. An elementary entity may # be an atom, a molecule, an ion, an electron, any other # particle or specified group of particles. # # The atomic mass unit (u) is defined as 1/12 the mass of # carbon-12. Previously the mole was defined so that a mole # of carbon-12 weighed exactly 12g, or N_A u = 1 g/mol # exactly. This relationship is now an experimental, # approximate relationship. # # To determine the size of the mole, researchers used spheres # of very pure silicon-28 that weighed a kilogram. They # measured the molar mass of Si-28 using mass spectrometry and # used X-ray diffraction interferometry to determine the # spacing of the silicon atoms in the sphere. Using the # sphere's volume it was then possible to determine the number # of silicon atoms in the sphere, and hence determine the # Avogadro constant. The results of this experiment were used # to define N_A, which is henceforth a fixed, unchanging # quantity. cd ! # The candela, symbol cd, is the SI unit of luminous intensity candela cd # in a given direction. It is defined by taking the fixed # numerical value of the luminous efficacy of monochromatic # radiation of the frequency 540e12 Hz to be 683 when # expressed in the unit lumen/watt, which is equal to # cd sr/W, or cd sr s^3/kg m^2 # # This definition is a rewording of the previous definition. # Luminous intensity differs from radiant intensity (W/sr) in # that it is adjusted for human perceptual dependence on # wavelength. The frequency of 540e12 Hz (yellow; # wavelength approximately 555 nm in vacuum) is where human # perception is most efficient. K_cd 683 lumen/W # Luminous efficiency at 540e12 Hz (exact) # Angular Measure # # The radian and steradian are defined as dimensionless primitive units. # The radian is equal to m/m and the steradian to m^2/m^2 so these units are # dimensionless. Retaining them as named units is useful because it allows # clarity in expressions and makes the meaning of unit definitions more clear. # These units will reduce to 1 in conversions but not for sums of units or for # arguments to functions. # radian !dimensionless # Plane angle subtended at the center of a circle by # an arc equal in length to the radius of the # circle. # Dimension: LENGTH (of arc) / DISTANCE (radius) sr !dimensionless # Solid angle which cuts off an area of the surface steradian sr # of the sphere equal to that of a square with # sides of length equal to the radius of the # sphere. # Dimension: AREA (of surface) / DISTANCE^2 # (radius^2) # # A primitive non-SI unit # bit ! # Basic unit of information (entropy). The entropy in bits # of a random variable over a finite alphabet is defined # to be the sum of -p(i)*log2(p(i)) over the alphabet where # p(i) is the probability that the random variable takes # on the value i. # # Currency: the primitive unit of currency is defined in currency.units. # It is usually the US$ or the euro, but it is user selectable. # # # Absolute value # abs(x) noerror sqrt(x^2) ########################################################################### # # # Prefixes (longer names must come first) # # # ########################################################################### quetta- 1e30 # Allegedly from "q" plus Greek "deka" (ten) ronna- 1e27 # Allegedly from "r" plus Greek "ennea" (nine) yotta- 1e24 # Greek or Latin "octo" (eight) zetta- 1e21 # Latin "septem" (seven) exa- 1e18 # Greek "hex" (six) peta- 1e15 # Greek "pente" (five) tera- 1e12 # Greek "teras" (monster) giga- 1e9 # Greek "gigas" (giant) mega- 1e6 # Greek "megas" (large) myria- 1e4 # Not an official SI prefix kilo- 1e3 # Greek "chilioi" (thousand) hecto- 1e2 # Greek "hekaton" (hundred) deca- 1e1 # Greek "deka" (ten) deka- deca deci- 1e-1 # Latin "decimus" (tenth) centi- 1e-2 # Latin "centum" (hundred) milli- 1e-3 # Latin "mille" (thousand) micro- 1e-6 # Latin "micro" or Greek "mikros" (small) nano- 1e-9 # Latin "nanus" or Greek "nanos" (dwarf) pico- 1e-12 # Spanish "pico" (a bit) femto- 1e-15 # Danish-Norwegian "femten" (fifteen) atto- 1e-18 # Danish-Norwegian "atten" (eighteen) zepto- 1e-21 # Latin "septem" (seven) yocto- 1e-24 # Greek or Latin "octo" (eight) ronto- 1e-27 # Allegedly "r" plus Latin "novum" (nine) quecto- 1e-30 # Allegedly "q" plus Latin "decim" (ten) quarter- 1|4 semi- 0.5 demi- 0.5 hemi- 0.5 half- 0.5 double- 2 triple- 3 treble- 3 kibi- 2^10 # In response to the improper and confusing mebi- 2^20 # use of SI prefixes for powers of two, gibi- 2^30 # the International Electrotechnical tebi- 2^40 # Commission aproved these binary prefixes pebi- 2^50 # in IEC 60027-2 Amendment 2 (1999). exbi- 2^60 zebi- 2^70 # Zebi- and yobi- were added in the 2005 ed., yobi- 2^80 # later superseded by ISO/IEC 80000-13:2008. robi- 2^90 quebi- 2^100 Ki- kibi Mi- mebi Gi- gibi Ti- tebi Pi- pebi Ei- exbi Zi- zebi Yi- yobi Ri- robi Qi- quebi Q- quetta R- ronna Y- yotta Z- zetta E- exa P- peta T- tera G- giga M- mega k- kilo h- hecto da- deka d- deci c- centi m- milli u- micro # it should be a mu but u is easy to type n- nano p- pico f- femto a- atto z- zepto y- yocto r- ronto q- quecto # # Names of some numbers # one 1 two 2 double 2 couple 2 three 3 triple 3 four 4 quadruple 4 five 5 quintuple 5 six 6 seven 7 eight 8 nine 9 ten 10 eleven 11 twelve 12 thirteen 13 fourteen 14 fifteen 15 sixteen 16 seventeen 17 eighteen 18 nineteen 19 twenty 20 thirty 30 forty 40 fifty 50 sixty 60 seventy 70 eighty 80 ninety 90 hundred 100 thousand 1000 million 1e6 twoscore two score threescore three score fourscore four score fivescore five score sixscore six score sevenscore seven score eightscore eight score ninescore nine score tenscore ten score twelvescore twelve score # These number terms were described by N. Chuquet and De la Roche in the 16th # century as being successive powers of a million. These definitions are still # used in most European countries. The current US definitions for these # numbers arose in the 17th century and don't make nearly as much sense. These # numbers are listed in the CRC Concise Encyclopedia of Mathematics by Eric # W. Weisstein. shortbillion 1e9 shorttrillion 1e12 shortquadrillion 1e15 shortquintillion 1e18 shortsextillion 1e21 shortseptillion 1e24 shortoctillion 1e27 shortnonillion 1e30 shortnoventillion shortnonillion shortdecillion 1e33 shortundecillion 1e36 shortduodecillion 1e39 shorttredecillion 1e42 shortquattuordecillion 1e45 shortquindecillion 1e48 shortsexdecillion 1e51 shortseptendecillion 1e54 shortoctodecillion 1e57 shortnovemdecillion 1e60 shortvigintillion 1e63 centillion 1e303 googol 1e100 longbillion million^2 longtrillion million^3 longquadrillion million^4 longquintillion million^5 longsextillion million^6 longseptillion million^7 longoctillion million^8 longnonillion million^9 longnoventillion longnonillion longdecillion million^10 longundecillion million^11 longduodecillion million^12 longtredecillion million^13 longquattuordecillion million^14 longquindecillion million^15 longsexdecillion million^16 longseptdecillion million^17 longoctodecillion million^18 longnovemdecillion million^19 longvigintillion million^20 # These numbers fill the gaps left by the long system above. milliard 1000 million billiard 1000 million^2 trilliard 1000 million^3 quadrilliard 1000 million^4 quintilliard 1000 million^5 sextilliard 1000 million^6 septilliard 1000 million^7 octilliard 1000 million^8 nonilliard 1000 million^9 noventilliard nonilliard decilliard 1000 million^10 # For consistency longmilliard milliard longbilliard billiard longtrilliard trilliard longquadrilliard quadrilliard longquintilliard quintilliard longsextilliard sextilliard longseptilliard septilliard longoctilliard octilliard longnonilliard nonilliard longnoventilliard noventilliard longdecilliard decilliard # The long centillion would be 1e600. The googolplex is another # familiar large number equal to 10^googol. These numbers give overflows. # # The short system prevails in English speaking countries # billion shortbillion trillion shorttrillion quadrillion shortquadrillion quintillion shortquintillion sextillion shortsextillion septillion shortseptillion octillion shortoctillion nonillion shortnonillion noventillion shortnoventillion decillion shortdecillion undecillion shortundecillion duodecillion shortduodecillion tredecillion shorttredecillion quattuordecillion shortquattuordecillion quindecillion shortquindecillion sexdecillion shortsexdecillion septendecillion shortseptendecillion octodecillion shortoctodecillion novemdecillion shortnovemdecillion vigintillion shortvigintillion # # Numbers used in India # lakh 1e5 crore 1e7 arab 1e9 kharab 1e11 neel 1e13 padm 1e15 shankh 1e17 ############################################################################# # # # Derived units which can be reduced to the primitive units # # # ############################################################################# # # Named SI derived units (officially accepted) # newton kg m / s^2 # force N newton pascal N/m^2 # pressure or stress Pa pascal joule N m # energy J joule watt J/s # power W watt coulomb A s # charge C coulomb volt W/A # potential difference V volt ohm V/A # electrical resistance siemens A/V # electrical conductance S siemens farad C/V # capacitance F farad weber V s # magnetic flux Wb weber henry V s / A # inductance, also Wb/A, but needs to be H henry # defined this way for CGS units tesla Wb/m^2 # magnetic flux density T tesla hertz /s # frequency Hz hertz # # Dimensions. These are here to help with dimensional analysis and # because they will appear in the list produced by hitting '?' at the # "You want:" prompt to tell the user the dimension of the unit. # LENGTH meter AREA LENGTH^2 VOLUME LENGTH^3 MASS kilogram AMOUNT mole ANGLE radian SOLID_ANGLE steradian MONEY US$ FORCE newton TORQUE FORCE DISTANCE PRESSURE FORCE / AREA STRESS FORCE / AREA FREQUENCY hertz WAVELENGTH LENGTH WAVENUMBER 1/WAVELENGTH # number of waves per distance VELOCITY DISPLACEMENT / TIME # a vector (includes direction) SPEED DISTANCE / TIME # a scalar ACCELERATION VELOCITY / TIME MOMENTUM MASS VELOCITY # Also ENERGY / VELOCITY or IMPULSE IMPULSE FORCE TIME DISPLACEMENT LENGTH DISTANCE LENGTH ELONGATION LENGTH STRAIN ELONGATION / LENGTH ENERGY joule POWER watt WORK FORCE DISTANCE DENSITY MASS / VOLUME LINEAR_DENSITY MASS / LENGTH SPECIFIC_ENERGY ENERGY / MASS VISCOSITY FORCE TIME / AREA KINEMATIC_VISCOSITY VISCOSITY / DENSITY CURRENT ampere CHARGE coulomb CAPACITANCE farad RESISTANCE ohm CONDUCTANCE siemens # It may be easier to understand the relationship by considering # an object with specified dimensions and resistivity, whose # resistance is given by the resistivity * length / area. RESISTIVITY RESISTANCE AREA / LENGTH CONDUCTIVITY CONDUCTANCE LENGTH / AREA INDUCTANCE henry E_FIELD ELECTRIC_POTENTIAL / LENGTH B_FIELD tesla # The D and H fields are related to the E and B fields by factors of # epsilon (electric permittivity) and mu (magnetic permeability) # respectively. The definitions of permittivity and permeability # below are scaled to make it possible to convert D_FIELD and # E_FIELD between SI and CGS units. ELECTRIC_PERMITTIVITY epsilon0 / epsilon0_SI # SI: F/m MAGNETIC_PERMEABILITY mu0 / mu0_SI # SI: H/m = N/A^2 D_FIELD E_FIELD ELECTRIC_PERMITTIVITY H_FIELD B_FIELD / MAGNETIC_PERMEABILITY ELECTRIC_DIPOLE_MOMENT CHARGE DISTANCE MAGNETIC_DIPOLE_MOMENT TORQUE / B_FIELD POLARIZATION ELECTRIC_DIPOLE_MOMENT / VOLUME MAGNETIZATION MAGNETIC_DIPOLE_MOMENT / VOLUME ELECTRIC_POTENTIAL ENERGY / CHARGE # volt VOLTAGE ELECTRIC_POTENTIAL E_FLUX E_FIELD AREA D_FLUX D_FIELD AREA B_FLUX B_FIELD AREA H_FLUX H_FIELD AREA # # units derived easily from SI units # gram millikg gm gram g gram tonne 1000 kg t tonne metricton tonne sthene tonne m / s^2 funal sthene pieze sthene / m^2 quintal 100 kg bar 1e5 Pa # About 1 atm b bar vac millibar micron micrometer # One millionth of a meter bicron picometer # One brbillionth of a meter cc cm^3 liter 1000 cc # The liter was defined in 1901 as the oldliter 1.000028 dm^3 # space occupied by 1 kg of pure water at L liter # the temperature of its maximum density l liter # under a pressure of 1 atm. This was # supposed to be 1000 cubic cm, but it # was discovered that the original # measurement was off. In 1964, the # liter was redefined to be exactly 1000 # cubic centimeters. Ah amp hour # Unit of charge mho siemens # Inverse of ohm, hence ohm spelled backward galvat ampere # Named after Luigi Galvani angstrom 1e-10 m # Convenient for describing molecular sizes xunit xunit_cu # Used for measuring x-ray wavelengths. siegbahn xunit # Originally defined to be 1|3029.45 of xunit_cu 1.00207697e-13 m # the spacing of calcite planes at 18 xunit_mo 1.00209952e-13 m # degC. It was intended to be exactly # 1e-13 m, but was later found to be # slightly off. Current usage is with # reference to common x-ray lines, either # the K-alpha 1 line of copper or the # same line of molybdenum. angstromstar 1.00001495 angstrom # Defined by JA Bearden in 1965 to replace # the X unit. The wavelength of the # tungsten K alpha1 line was defined as # exactly 0.20901 angstrom star, with the # value chosen to try to make the new # unit close to the angstrom. silicon_d220 1.920155716e-10 m # Silicon lattice spacing siliconlattice sqrt(8) silicon_d220# Silicon lattice parameter, (a), the side # length of the unit cell for the diamond # centered cubic structure of silicon. fermi 1e-15 m # Convenient for describing nuclear sizes # Nuclear radius is from 1 to 10 fermis barn 1e-28 m^2 # Used to measure cross section for # particle physics collision, said to # have originated in the phrase "big as # a barn". shed 1e-24 barn # Defined to be a smaller companion to the # barn, but it's too small to be of # much use. brewster micron^2/N # measures stress-optical coef diopter /m # measures reciprocal of lens focal length fresnel 1e12 Hz # occasionally used in spectroscopy shake 1e-8 sec svedberg 1e-13 s # Used for measuring the sedimentation # coefficient for centrifuging. gamma microgram # Also used for 1e-9 tesla lambda microliter spat 1e12 m # Rarely used for astronomical measurements preece 1e13 ohm m # resistivity planck J s # action of one joule over one second sturgeon /henry # magnetic reluctance daraf 1/farad # elastance (farad spelled backwards) leo 10 m/s^2 poiseuille N s / m^2 # viscosity mayer J/g K # specific heat mired / microK # reciprocal color temperature. The name # abbreviates micro reciprocal degree. crocodile megavolt # used informally in UK physics labs metricounce 25 g mounce metricounce finsenunit 1e5 W/m^2 # Measures intensity of ultraviolet light # with wavelength 296.7 nm. fluxunit 1e-26 W/m^2 Hz # Used in radio astronomy to measure # the energy incident on the receiving # body across a specified frequency # bandwidth. [12] jansky fluxunit # K. G. Jansky identified radio waves coming Jy jansky # from outer space in 1931. flick W / cm^2 sr micrometer # Spectral radiance or irradiance pfu / cm^2 sr s # particle flux unit -- Used to measure # rate at which particles are received by # a spacecraft as particles per solid # angle per detector area per second. [18] pyron cal_IT / cm^2 min # Measures heat flow from solar radiation, # from Greek work "pyr" for fire. katal mol/sec # Measure of the amount of a catalyst. One kat katal # katal of catalyst enables the reaction # to consume or produce one mol/sec. solarluminosity 382.8e24 W # A common yardstick for comparing the # output of different stars. # http://nssdc.gsfc.nasa.gov/planetary/factsheet/sunfact.html # at mean Earth-Sun distance solarirradiance solarluminosity / (4 pi sundist^2) solarconstant solarirradiance TSI solarirradiance # total solar irradiance # # Land Area # # The are was defined by an earlier form of SI. Many countries # redefined old land area units to equal the decare (10 are) # are 100 m^2 a are sotka are # Russian stremma decare # Greece dunam decare # Different spellings of the old dulum decare # Ottoman measure donum decare # !utf8 dönüm decare mål decare # Norway. !endutf8 # # time # sec s minute 60 s min minute hour 60 min hr hour day 24 hr d day da day week 7 day wk week sennight 7 day fortnight 14 day blink 1e-5 day # Actual human blink takes 1|3 second ce 1e-2 day cron 1e6 years watch 4 hours # time a sentry stands watch or a ship's # crew is on duty. bell 1|8 watch # Bell would be sounded every 30 minutes. # French Revolutionary Time or Decimal Time. It was Proposed during # the French Revolution. A few clocks were made, but it never caught # on. In 1998 Swatch defined a time measurement called ".beat" and # sold some watches that displayed time in this unit. decimalhour 1|10 day decimalminute 1|100 decimalhour decimalsecond 1|100 decimalminute beat decimalminute # Swatch Internet Time # # angular measure # circle 2 pi radian degree 1|360 circle deg degree arcdeg degree arcmin 1|60 degree arcminute arcmin ' arcmin arcsec 1|60 arcmin arcsecond arcsec " arcsec '' " !utf8 ° degree ′ ' # prime, U+2032 ″ " # double prime, U+2033 !endutf8 rightangle 90 degrees quadrant 1|4 circle quintant 1|5 circle sextant 1|6 circle sign 1|12 circle # Angular extent of one sign of the zodiac turn circle revolution turn rev turn pulsatance radian / sec gon 1|100 rightangle # measure of grade grade gon centesimalminute 1|100 grade centesimalsecond 1|100 centesimalminute milangle 1|6400 circle # Official NIST definition. # Another choice is 1e-3 radian. pointangle 1|32 circle # Used for reporting compass readings centrad 0.01 radian # Used for angular deviation of light # through a prism. mas milli arcsec # Used by astronomers seclongitude circle (seconds/day) # Astronomers measure longitude # (which they call right ascension) in # time units by dividing the equator into # 24 hours instead of 360 degrees. # # Some geometric formulas # circum(r) units=[m;m] range=[0,) 2 pi r; circum/ 2 pi circum_d(d) units=[m;m] range=[0,) circum(d/2); 2 ~circum(circum_d) circlearea(r) units=[m;m^2] range=[0,) pi r^2 ; sqrt(circlearea/pi) circlearea_d(d) units=[m;m^2] range=[0,) circlearea(d/2); 2 ~circlearea(circlearea_d) spherevolume(r) units=[m;m^3] range=[0,) 4|3 pi r^3 ; \ cuberoot(spherevolume/4|3 pi) spherevolume_d(d) units=[m;m^3] range=[0,) spherevolume(d/2); 2 ~spherevolume(spherevolume_d) spherevol() spherevolume spherevol_d() spherevolume_d circumference() circum circumference_d() circum_d square(x) range=[0,) x^2 ; sqrt(square) cube(x) range=[0,) x^3 ; cube^(1|3) # # Solid angle measure # sphere 4 pi sr squaredegree 1|180^2 pi^2 sr squareminute 1|60^2 squaredegree squaresecond 1|60^2 squareminute squarearcmin squareminute squarearcsec squaresecond sphericalrightangle 1|8 sphere octant 1|8 sphere # # Concentration measures # percent 0.01 % percent mill 0.001 # Originally established by Congress in 1791 # as a unit of money equal to 0.001 dollars, # it has come to refer to 0.001 in general. # Used by some towns to set their property # tax rate, and written with a symbol similar # to the % symbol but with two 0's in the # denominator. [18] proof 1|200 # Alcohol content measured by volume at # 60 degrees Fahrenheit. This is a USA # measure. In Europe proof=percent. ppm 1e-6 partspermillion ppm ppb 1e-9 partsperbillion ppb # USA billion ppt 1e-12 partspertrillion ppt # USA trillion karat 1|24 # measure of gold purity caratgold karat gammil mg/l basispoint 0.01 % # Used in finance fine 1|1000 # Measure of gold purity # The pH scale is used to measure the concentration of hydronium (H3O+) ions in # a solution. A neutral solution has a pH of 7 as a result of dissociated # water molecules. pH(x) units=[1;mol/liter] range=(0,) 10^(-x) mol/liter ; (-log(pH liters/mol)) # # Temperature # # Two types of units are defined: units for converting temperature differences # and functions for converting absolute temperatures. Conversions for # differences start with "deg" and conversions for absolute temperature start # with "temp". # # If the temperature inside is 72 degrees Fahrenheit and you want to # convert this to degrees Celsius then you need absolute temperature: # # You have: tempF(72) # You want: tempC # 22.222222 # # If the temperature rose 72 degrees Fahrenheit during the chemical reaction # then this is a temperature difference: # # You have: 72 degF # You want: degC # * 40 # / 0.025 # TEMPERATURE kelvin TEMPERATURE_DIFFERENCE kelvin # In 1741 Anders Celsius introduced a temperature scale with water boiling at # 0 degrees and freezing at 100 degrees at standard pressure. After his death # the fixed points were reversed and the scale was called the centigrade # scale. Due to the difficulty of accurately measuring the temperature of # melting ice at standard pressure, the centigrade scale was replaced in 1954 # by the Celsius scale which is defined by subtracting 273.15 from the # temperature in Kelvins. This definition differed slightly from the old # centigrade definition, but the Kelvin scale depends on the triple point of # water rather than a melting point, so it can be measured accurately. tempC(x) units=[1;K] domain=[-273.15,) range=[0,) \ x K + stdtemp ; (tempC +(-stdtemp))/K tempcelsius() tempC degcelsius K degC K # Fahrenheit defined his temperature scale by setting 0 to the coldest # temperature he could produce in his lab with a salt water solution and by # setting 96 degrees to body heat. In Fahrenheit's words: # # Placing the thermometer in a mixture of sal ammoniac or sea # salt, ice, and water a point on the scale will be found which # is denoted as zero. A second point is obtained if the same # mixture is used without salt. Denote this position as 30. A # third point, designated as 96, is obtained if the thermometer # is placed in the mouth so as to acquire the heat of a healthy # man." (D. G. Fahrenheit, Phil. Trans. (London) 33, 78, 1724) tempF(x) units=[1;K] domain=[-459.67,) range=[0,) \ (x+(-32)) degF + stdtemp ; (tempF+(-stdtemp))/degF + 32 tempfahrenheit() tempF degfahrenheit 5|9 degC degF 5|9 degC degreesrankine degF # The Rankine scale has the degrankine degreesrankine # Fahrenheit degree, but its zero degreerankine degF # is at absolute zero. degR degrankine tempR degrankine temprankine degrankine tempreaumur(x) units=[1;K] domain=[-218.52,) range=[0,) \ x degreaumur+stdtemp ; (tempreaumur+(-stdtemp))/degreaumur degreaumur 10|8 degC # The Reaumur scale was used in Europe and # particularly in France. It is defined # to be 0 at the freezing point of water # and 80 at the boiling point. Reaumur # apparently selected 80 because it is # divisible by many numbers. degK K # "Degrees Kelvin" is forbidden usage. tempK K # For consistency # Gas mark is implemented below but in a terribly ugly way. There is # a simple formula, but it requires a conditional which is not # presently supported. # # The formula to convert to degrees Fahrenheit is: # # 25 log2(gasmark) + k_f gasmark<=1 # 25 (gasmark-1) + k_f gasmark>=1 # # k_f = 275 # gasmark[degR] \ .0625 634.67 \ .125 659.67 \ .25 684.67 \ .5 709.67 \ 1 734.67 \ 2 759.67 \ 3 784.67 \ 4 809.67 \ 5 834.67 \ 6 859.67 \ 7 884.67 \ 8 909.67 \ 9 934.67 \ 10 959.67 # The Beaufort wind force scale was developed from 1805-1807 by Sir Francis # Beaufort to categorize wind conditions at sea. It is normally defined from # Beaufort 0, also called "Force 0," through Beaufort 12. Beaufort numbers # 13-17 were later defined for tropical cyclones but are rarely used. The # original Beaufort scale was qualitative and did not relate directly to wind # speed. In 1906, George Simpson of the British Met Office fit wind-speed # measurements to visual Beaufort estimates made from five coastal and inland # stations in Britain. Simpson's formula was adopted by the World Meterological # Organization in 1946 to produce a table, known as WMO Code 1100, giving mean # (and min/max) wind speed equivalents at a height of 10 meters for each # Beaufort number. This is the "operational" Beaufort scale that mariners # use. Meterological and climatic researchers typically use a "scientific" # Beaufort scale based on more recent and comprehensive fits. See Wallbrink and # Cook, Historical Wind Speed Equivalents Of The Beaufort Scale, 1850-1950, at # https://icoads.noaa.gov/reclaim/pdf/Hisklim13.pdf # beaufort_WMO1100(B) units=[1;m/s] domain=[0,17] range=[0,) \ 0.836 B^3|2 m/s; (beaufort_WMO1100 s / 0.836 m)^2|3 beaufort(B) units=[1;m/s] domain=[0,17] range=[0,) \ beaufort_WMO1100(B); ~beaufort_WMO1100(beaufort) # Units cannot handle wind chill or heat index because they are two-variable # functions, but they are included here for your edification. Clearly these # equations are the result of a model fitting operation. # # wind chill index (WCI) a measurement of the combined cooling effect of low # air temperature and wind on the human body. The index was first defined # by the American Antarctic explorer Paul Siple in 1939. As currently used # by U.S. meteorologists, the wind chill index is computed from the # temperature T (in deg F) and wind speed V (in mi/hr) using the formula: # WCI = 0.0817(3.71 sqrt(V) + 5.81 - 0.25V)(T - 91.4) + 91.4. # For very low wind speeds, below 4 mi/hr, the WCI is actually higher than # the air temperature, but for higher wind speeds it is lower than the air # temperature. # # heat index (HI or HX) a measure of the combined effect of heat and # humidity on the human body. U.S. meteorologists compute the index # from the temperature T (in deg F) and the relative humidity H (as a # value from 0 to 1). # HI = -42.379 + 2.04901523 T + 1014.333127 H - 22.475541 TH # - .00683783 T^2 - 548.1717 H^2 + 0.122874 T^2 H + 8.5282 T H^2 # - 0.0199 T^2 H^2. # # Physical constants # # Basic constants pi 3.14159265358979323846 # More digits than double tau 2 pi # precision can handle phi (sqrt(5)+1)/2 light c coulombconst alpha hbar c / e^2 # Coulomb constant k_C coulombconst # Gets overridden in CGS modes k_C_SI alpha hbar_SI c_SI / e_SI^2 epsilon0_SI 1 / 4 pi k_C_SI # Vacuum electric permittivity epsilon0 1 / 4 pi k_C # Also overridden in CGS modes mu0_SI 1 / epsilon0_SI c_SI^2 # Vacuum magnetic permeability mu0 1 / epsilon0 c^2 # Also overridden in CGS modes Z0 4 pi k_C / c # Free space impedance energy c^2 # Convert mass to energy hbar h / 2 pi hbar_SI h_SI / 2 pi spin hbar G_SI 6.67430e-11 G 6.67430e-11 N m^2 / kg^2 # Newtonian gravitational constant # Physico-chemical constants atomicmassunit_SI 1.66053906892e-27 atomicmassunit 1.66053906892e-27 kg # Unified atomic mass unit, defined as u atomicmassunit # 1|12 of the mass of carbon 12. amu atomicmassunit # The relationship N_A u = 1 g/mol dalton u # is approximately, but not exactly Da dalton # true (with the 2019 SI). # Previously the mole was defined to # make this relationship exact. amu_chem 1.66026e-27 kg # 1|16 of the weighted average mass of # the 3 naturally occurring neutral # isotopes of oxygen amu_phys 1.65981e-27 kg # 1|16 of the mass of a neutral # oxygen 16 atom molarmassconstant N_A u gasconstant k N_A # Molar gas constant (exact) R gasconstant kboltzmann boltzmann sackurtetrodeconstant 5|2 + ln((u k K / 2 pi hbar^2)^(3|2) k K / atm) # Appears in the Sakur-Tetrode # equation for the entropy of a # monatomic ideal gas. molarvolume R stdtemp / atm # Volume occupied by one mole of an V_m molarvolume # ideal gas at STP. (exact) loschmidt avogadro / molarvolume # Molecules per cubic meter of an n0 loschmidt # ideal gas at STP. Loschmidt did # work similar to Avogadro. molarvolume_si N_A siliconlattice^3 / 8 # Volume of a mole of crystalline # silicon. The unit cell contains 8 # silicon atoms and has a side # length of siliconlattice. stefanboltzmann pi^2 k^4 / 60 hbar^3 c^2 # The power per area radiated by a sigma stefanboltzmann # blackbody at temperature T is # given by sigma T^4. (exact) wiendisplacement (h c/k)/4.9651142317442763 # Wien's Displacement Law gives # the wavelength at which the # Planck spectrum has maximum # intensity. The relation is lambda # T = b where lambda is wavelength, # T is temperature and b is the Wien # displacement. This relation is # used to determine the temperature # of stars. The constant is the # solution to x=5(1-exp(-x)). # This expression has no experimental # error, and x is defined exactly # by the equation above, so it is # an exact definition. wienfrequencydisplacement 2.8214393721220788934 k/h # In a similar vein, # this variant gives the frequency of # maximum intensity. The constant # is the solution to x=3*(1-exp(-x)), # and, as above, this relation is # an exact definition with zero # experimental error. K_J90 483597.9 GHz/V # Direct measurement of the volt is difficult. Until K_J 2e/h # recently, laboratories kept Weston cadmium cells as # a reference, but they could drift. In 1987 the # CGPM officially recommended the use of the # Josephson effect as a laboratory representation of # the volt. The Josephson effect occurs when two # superconductors are separated by a thin insulating # layer. A "supercurrent" flows across the insulator # with a frequency that depends on the potential # applied across the superconductors. This frequency # can be very accurately measured. The Josephson # constant K_J relates the measured frequency to the # potential. Two values given, the conventional # (exact) value from 1990, which was used until the # 2019 SI revision, and the current exact value. R_K90 25812.807 ohm # Measurement of the ohm also presents difficulties. R_K h/e^2 # The old approach involved maintaining resistances # that were subject to drift. The new standard is # based on the Hall effect. When a current carrying # ribbon is placed in a magnetic field, a potential # difference develops across the ribbon. The ratio # of the potential difference to the current is # called the Hall resistance. Klaus von Klitzing # discovered in 1980 that the Hall resistance varies # in discrete jumps when the magnetic field is very # large and the temperature very low. This enables # accurate realization of the resistance h/e^2 in the # lab. The 1990 value was an exact conventional # value used until the SI revision in 2019. This value # did not agree with measurements. The new value # is exact. # The 2019 update to SI gives exact definitions for R_K and K_J. Previously # the electromagnetic units were realized using the 1990 conventional values # for these constants, and as a result, the standard definitions were in some # sense outside of SI. The revision corrects this problem. The definitions # below give the 1990 conventional values for the electromagnetic units in # terms of 2019 SI. ampere90 (K_J90 R_K90 / K_J R_K) A coulomb90 (K_J90 R_K90 / K_J R_K) C farad90 (R_K90/R_K) F henry90 (R_K/R_K90) H ohm90 (R_K/R_K90) ohm volt90 (K_J90/K_J) V watt90 (K_J90^2 R_K90 / K_J^2 R_K) W # Various conventional values gravity 9.80665 m/s^2 # std acceleration of gravity (exact) # Established by the 3rd CGPM in # 1901. This is a nominal midrange # value, originally based on the # acceleration of a body at sea # level at 45 degrees latitude. # The value was actually determined # by measuring at the International # Bureau and correcting the # measurement by a theoretical # cofficient to get the 45 deg # latitude sea level value. # (Wikipedia: Standard gravity) force gravity # use to turn masses into forces atm 101325 Pa # Standard atmospheric pressure atmosphere atm Hg 13.5951 gram force / cm^3 # Standard weight of mercury (exact) water gram force/cm^3 # Standard weight of water (exact) waterdensity gram / cm^3 # Density of water H2O water wc water # water column mach 331.46 m/s # speed of sound in dry air at STP standardtemp 273.15 K # standard temperature stdtemp standardtemp normaltemp tempF(70) # for gas density, from NIST normtemp normaltemp # Handbook 44 # Weight of mercury and water at different temperatures using the standard # force of gravity. Hg10C 13.5708 force gram / cm^3 # These units, when used to form Hg20C 13.5462 force gram / cm^3 # pressure measures, are not accurate Hg23C 13.5386 force gram / cm^3 # because of considerations of the Hg30C 13.5217 force gram / cm^3 # revised practical temperature scale. Hg40C 13.4973 force gram / cm^3 Hg60F 13.5574 force gram / cm^3 H2O0C 0.99987 force gram / cm^3 H2O5C 0.99999 force gram / cm^3 H2O10C 0.99973 force gram / cm^3 H2O15C 0.99913 force gram / cm^3 H2O18C 0.99862 force gram / cm^3 H2O20C 0.99823 force gram / cm^3 H2O25C 0.99707 force gram / cm^3 H2O50C 0.98807 force gram / cm^3 H2O100C 0.95838 force gram / cm^3 # Atomic constants hartree 4.3597447222060e-18 J # Approximate electric potential energy E_h hartree # of the hydrogen atom in its ground # state, and approximately twice its # ionization energy. The hartree # energy is traditionally defined as # coulombconst^2 m_e e^4 / hbar^2, # but it can be measured to greater # precision using the relationship # hartree = 2 h c Rinfinity # because Rinfinity is one of the # most accurately measured physical # constants. Because h and c are # exact we can choose either hartree # or Rinfinity from CODATA to use as # the primary value without # affecting the precision. Rinfinity hartree / 2 h c # The wavelengths of a spectral series R_H Rinfinity m_p / (m_e + m_p) # can be expressed as # 1/lambda = R (1/m^2 - 1/n^2). # where R is a number that various # slightly from element to element. # For hydrogen, R_H is the value, # and for heavy elements, the value # approaches Rinfinity, which can be # computed from # Rinfinity = m_e c alpha^2 / 2 h # with loss of precision. Rinfinity # is one of the most accurately # measured physical constants and is # known to higher precision than m_e # or alpha. alpha 7.2973525643e-3 # The fine structure constant was # introduced to explain fine # structure visible in spectral # lines. bohrradius hbar / alpha m_e c a0 bohrradius prout 185.5 keV # nuclear binding energy equal to 1|12 # binding energy of the deuteron conductancequantum e^2 / pi hbar G0 conductancequantum magneticfluxquantum pi hbar / e Phi0 magneticfluxquantum circulationquantum h / 2 m_e # weak-force related weakmixingangle 0.22305 w_to_z_mass_ratio 0.88145 # Particle radius electronradius alpha^2 bohrradius # Classical thomsoncrosssection 8|3 pi electronradius^2 # Arises in Thomson scattering alphachargeradius 1.6785e-15 m deuteronchargeradius 2.12778e-15 m protonchargeradius 8.4075e-16 m # Masses of elementary particles electronmass_SI electronmass_u atomicmassunit_SI electronmass_u 5.485799090441e-4 electronmass 5.485799090441e-4 u m_e electronmass muonmass 0.1134289257 u m_mu muonmass taumass 1.90754 u m_tau taumass protonmass 1.0072764665789 u m_p protonmass neutronmass 1.00866491606 u m_n neutronmass deuteronmass 2.013553212544 u # Nucleus of deuterium, one m_d deuteronmass # proton and one neutron alphaparticlemass 4.001506179129 u # Nucleus of He, two protons m_alpha alphaparticlemass # and two neutrons tritonmass 3.01550071597 u # Nucleus of H3, one proton m_t tritonmass # and two neutrons helionmass 3.014932246932 u # Nucleus of He3, two protons m_h helionmass # and one neutron # particle wavelengths: the compton wavelength of a particle is # defined as h / m c where m is the mass of the particle. electronwavelength h / m_e c lambda_C electronwavelength protonwavelength h / m_p c lambda_C,p protonwavelength neutronwavelength h / m_n c lambda_C,n neutronwavelength muonwavelength h / m_mu c lambda_C,mu muonwavelength tauwavelength h / m_tau c lambda_C,tau tauwavelength # The g-factor or dimensionless magnetic moment is a quantity that # characterizes the magnetic moment of a particle. The electron g-factor is # one of the most precisely measured values in physics, with a relative # uncertainty of 1.7e-13. g_d 0.8574382335 # Deuteron g-factor g_e -2.00231930436092 # Electron g-factor g_h -4.2552506995 # Helion g-factor g_mu -2.00233184123 # Muon g-factor g_n -3.82608552 # Neutron g-factor g_p 5.5856946893 # Proton g-factor g_t 5.957924930 # Triton g-factor fermicoupling 1.1663787e-5 / GeV^2 # Magnetic moments (derived from the more accurate g-factors) # # The magnetic moment is g * mu_ref * spin where in most cases # the reference is the nuclear magneton, and all of the particles # except the deuteron have spin 1/2. bohrmagneton e hbar / 2 electronmass # Reference magnetic moment for mu_B bohrmagneton # the electron mu_e g_e mu_B / 2 # Electron spin magnet moment mu_mu g_mu mu_B m_e / 2 muonmass # Muon spin magnetic moment nuclearmagneton mu_B m_e / protonmass # Convenient reference magnetic mu_N nuclearmagneton # moment for heavy particles mu_p g_p mu_N / 2 # Proton magnetic moment mu_n g_n mu_N / 2 # Neutron magnetic moment mu_d g_d mu_N # Deuteron magnetic moment, spin 1 mu_t g_t mu_N / 2 # Triton magnetic moment mu_h g_h mu_N / 2 # Helion magnetic moment shielded_mu_h -1.07455311035e-26 J / T shielded_mu_p 1.4105705830e-26 J / T # # Units derived from physical constants # kgf kg force technicalatmosphere kgf / cm^2 at technicalatmosphere hyl kgf s^2 / m # Also gram-force s^2/m according to [15] mmHg mm Hg torr atm / 760 # The torr, named after Evangelista # Torricelli, and is very close to the mm Hg tor Pa # Suggested in 1913 but seldom used [24]. # Eventually renamed the Pascal. Don't # confuse the tor with the torr. inHg inch Hg inH2O inch water mmH2O mm water eV e V # Energy acquired by a particle with charge e electronvolt eV # when it is accelerated through 1 V lightyear c julianyear # The 365.25 day year is specified in ly lightyear # NIST publication 811 lightsecond c s lightminute c min parsec au / tan(arcsec) # Unit of length equal to distance pc parsec # from the Sun to a point having # heliocentric parallax of 1 # arcsec (derived from parallax # second). A distant object with # parallax theta will be about # (arcsec/theta) parsecs from the # Sun (using the approximation # that tan(theta) = theta). rydberg 1|2 hartree # Rydberg energy crith 0.089885 gram # The crith is the mass of one # liter of hydrogen at standard # temperature and pressure. amagat N_A / molarvolume # Used to measure gas as a number amagatvolume mol molarvolume # density lorentz bohrmagneton / h c # Used to measure the extent # that the frequency of light # is shifted by a magnetic field. cminv h c / cm # Unit of energy used in infrared invcm cminv # spectroscopy. wavenumber 1/cm # kcal_mol kcal_th / mol N_A # kcal/mol is used as a unit of # energy by physical chemists. # # CGS system based on centimeter, gram and second # dyne cm gram / s^2 # force dyn dyne erg cm dyne # energy poise gram / cm s # viscosity, honors Jean Poiseuille P poise rhe /poise # reciprocal viscosity stokes cm^2 / s # kinematic viscosity St stokes stoke stokes lentor stokes # old name Gal cm / s^2 # acceleration, used in geophysics galileo Gal # for Earth's gravitational field # (note that "gal" is for gallon # but "Gal" is the standard symbol # for the gal which is evidently a # shortened form of "galileo".) barye dyne/cm^2 # pressure barad barye # old name kayser 1/cm # Proposed as a unit for wavenumber balmer kayser # Even less common name than "kayser" kine cm/s # velocity bole g cm / s # momentum pond gram force glug gram force s^2 / cm # Mass which is accelerated at # 1 cm/s^2 by 1 gram force darcy centipoise cm^2 / s atm # Measures permeability to fluid flow. # One darcy is the permeability of a # medium that allows a flow of cc/s # of a liquid of centipoise viscosity # under a pressure gradient of # atm/cm. Named for H. Darcy. mobileohm cm / dyn s # mobile ohm, measure of mechanical # mobility mechanicalohm dyn s / cm # mechanical resistance acousticalohm dyn s / cm^5 # ratio of the sound pressure of # 1 dyn/cm^2 to a source of strength # 1 cm^3/s ray acousticalohm rayl dyn s / cm^3 # Specific acoustical resistance eotvos 1e-9 Gal/cm # Change in gravitational acceleration # over horizontal distance # # Electromagnetic CGS Units # # For measuring electromagnetic quantities in SI, we introduce the new base # dimension of current, define the ampere to measure current, and derive the # other electromagnetic units from the ampere. With the CGS units one approach # is to use the basic equations of electromagnetism to define units that # eliminate constants from those equations. Coulomb's law has the form # # F = k_C q1 q2 / r^2 # # where k_C is the Coulomb constant equal to 1|4 pi epsilon0 in SI units. # Ampere's force law takes the form # # dF/dl = 2 k_A I1 I2 / r # # where k_A is the ampere constant. In the CGS system we force either k_C or # k_A to 1 which then defines either a unit for charge or a unit for current. # The other unit then becomes a derived unit. When k_C is 1 the ESU system # results. When k_A is 1 the EMU system results. Note that these parameters # are not independent of each other: Maxwell's equations indicate that # # k_C / k_A = c^2 # # where c is the speed of light. # # One more choice is needed to define a complete system. Using Coulomb's law # we define the electric field as the force per unit charge # # E = k_C 1 / r^2. # # But what about the magnetic field? It is derived from Ampere's law but we # have the option of adding a proportionality constant, k_B, that may have # dimensions: # # B = 2 k_A k_B I / r # # We can choose k_B = 1, which is done in the SI, ESU and EMU systems. But if # instead we give k_B units of length/time then the magnetic field has # the same units as the electric field. This choice leads to the Gaussian # and Heaviside-Lorentz systems. # # The relations above are used to determine the dimensions, but the units are # derived from the base units of CGS, not directly from those formulas. We # will use the notation [unit] to refer to the dimension of the unit in # brackets. This same process gives rise to the SI units such as the tesla, # which is defined by # # [tesla] = [2 (1/4 pi c^2 epsilon0) amp / m] = [(mu0 / 2) amp / m] # # which gives kg / A s^2 as expected. # # References: # # Classical Electrodynamics by John David Jackson, 3rd edition. # Cardarelli, Francois. 1999. Scientific Unit Conversion. 2nd ed. Trans. # M.J. Shields. London: Springer-Verlag. ISBN 1-85233-043-0 # # # All of the CGS systems result in electromagnetic units that involve the square # roots of the centimeter and gram. This requires a change in the primitive # units. # !var UNITS_SYSTEM esu emu gaussian gauss hlu sqrt_cm ! sqrt_centimeter sqrt_cm +m 100 sqrt_cm^2 sqrt_g ! sqrt_gram sqrt_g +kg kilo sqrt_g^2 !endvar # Electrostatic CGS (ESU) # # This system uses the statcoulomb as the fundamental unit of charge, with # derived units that parallel the conventional terminology but use the stat- # prefix. The statcoulomb is derived from Coulomb's law based on the dyne # # dyne = statcoulomb^2 / k_C cm^2. # # and in the EUS system, k_C=1. The statcoulomb is also called the # franklin or esu. # # The ESU system was specified by a committee report in 1873 and rarely used. statcoulomb sqrt(dyne cm^2/k_C) # Charge such that two charges esu statcoulomb # of 1 statC separated by 1 cm statcoul statcoulomb # exert a force of 1 dyne statC statcoulomb stC statcoulomb franklin statcoulomb Fr franklin !var UNITS_SYSTEM esu !message CGS-ESU units selected !prompt (ESU) +coulombconst 1 +epsilon0 1 / k_C # SI relation: 1 / 4 pi k_C +A 10 c_SI statamp !endvar statampere statcoulomb / s statamp statampere statA statampere stA statampere statvolt dyne cm / statamp sec statV statvolt stV statvolt statfarad statamp sec / statvolt statF statfarad stF statfarad cmcapacitance statfarad stathenry statvolt sec / statamp statH stathenry stH stathenry statohm statvolt / statamp stohm statohm statmho /statohm stmho statmho statweber statvolt sec statWb statweber stWb statweber stattesla statWb/cm^2 # Defined by analogy with SI; rarely statT stattesla # if ever used stT stattesla debye 1e-10 statC angstrom # unit of electrical dipole moment helmholtz debye/angstrom^2 # Dipole moment per area jar 1000 statfarad # approx capacitance of Leyden jar # Electromagnetic CGS (EMU) # # The abampere is the fundamental unit of this system, with the derived units # using the ab- prefix. The dimensions of the abampere are defined by assuming # that k_A=1, which # # [dyne / cm] = [2 abampere^2 / cm] # # where the brackets indicate taking the dimension of the unit in base units # and discarding any constant factors. This results in the definition from # base CGS units of: # # abampere = sqrt(dyne). # # The abampere is also called the biot. The magnetic field unit (the gauss) # follows from the assumption that k_B=1, which means # # B = 2 I / r, # # and hence the dimensions of the gauss are given by # # [gauss] = [2 abampere / cm] # # or rewriting in terms of the base units # # gauss = abampere / cm. # # The definition given below is different because it is in a form that # gives a valid reduction for SI and ESU and still gives the correct # result in EMU. (It can be derived from Faraday's law.) # # The EMU system was developed by Gauss and Weber and formalized as a system in # a committee report by the British Association for the Advancement of Science # in 1873. abampere 10 A # Current which produces a force of abamp abampere # 2 dyne/cm between two infinitely aA abampere # long wires that are 1 cm apart abA abampere biot abampere Bi biot !var UNITS_SYSTEM emu !message CGS-EMU units selected !prompt (EMU) +coulombconst c^2 +epsilon0 1 / k_C # SI relation: 1 / 4 pi k_C +abampere sqrt(dyne) +A 0.1 abamp !endvar abcoulomb abamp sec abcoul abcoulomb abC abcoulomb abfarad abampere sec / abvolt abF abfarad abhenry abvolt sec / abamp abH abhenry abvolt dyne cm / abamp sec abV abvolt abohm abvolt / abamp abmho /abohm maxwell erg / abamp # Also called the "line" Mx maxwell gauss maxwell / cm^2 # The magnetic field 2 cm from a wire Gs gauss # carrying a current of 1 abampere oersted gauss / mu0 # From the relation H = B / mu Oe oersted gilbert gauss cm / mu0 Gb gilbert Gi gilbert unitpole 4 pi maxwell # unit magnetic pole emu erg/gauss # "electro-magnetic unit", a measure of # magnetic moment, often used as emu/cm^3 # to specify magnetic moment density. # Electromagnetic CGS (Gaussian) # # The Gaussian system uses the statcoulomb and statamp from the ESU system # derived by setting k_C=1, but it defines the magnetic field unit differently # by taking k_B=c instead of k_B=1. As noted above, k_C and k_A are not # independent. With k_C=1 we must have k_A=c^-2. This results in the magnetic # field unit, the gauss, having dimensions give by: # # [gauss] = [2 (c^-2) c statamp / cm] = [statamp / c cm] # # We then define the gauss using base CGS units to obtain # # gauss = statamp / ((cm/s) cm) = statcoulomb / cm^2. # # Note that this definition happens to give the same result as the definition # for the EMU system, so the definitions of the gauss are consistent. # # This definition gives the same dimensions for the E and B fields and was also # known as the "symmetric system". This system was proposed by Hertz in 1888. !var UNITS_SYSTEM gaussian gauss !message CGS-Gaussian units selected !prompt (Gaussian) !endvar !var UNITS_SYSTEM gaussian gauss natural-gauss +coulombconst 1 +A 10 c_SI statamp # Some SI-based definitions need re-scaling # by factors of "c" and/or "4 pi": +epsilon0 1 / k_C # SI relation: 1 / 4 pi k_C +mu0 1 / epsilon0 # SI relation: 1 / epsilon0 c^2 +bohrmagneton (e hbar / 2 electronmass) / c +magneticfluxquantum c (pi hbar / e) +maxwell c (erg / abamp) +weber c (J / A) !endvar # Electromagnetic CGS (Heaviside-Lorentz) # The Heaviside-Lorentz system is similar to the Gaussian system, but it is # "rationalized" so that factors of 4 pi do not appear in Maxwell's equations. # The SI system is similarly rationalized, but the other CGS systems are not. # # The factor of 4 pi appears instead in Coulomb's law, so in this system # k_C = 1 / 4 pi, which means the charge unit is defined by # # dyne = (1 / 4 pi) hlu_charge^2 / cm^2. # # Since we have the leading constant of (1 / 4pi) the numerical value of the # charge number is larger by sqrt(4pi), which in turns means that the HLU # charge unit is smaller by this multiple. But note that the dimensions of the # charge unit are the same as the Gaussian system, so both systems measure # charge with cm^(3/2) g^(1/2) / s, but the amount of charge for this dimension # differs by a factor of sqrt(4pi) between the two systems. # # Ampere's law for the Heaviside-Lorentz system has the form # # B = 1/(2 pi c) * I/r # The Heaviside-Lorentz system does not appear to have any named units, so we # use "hlu" for "Heaviside-Lorentz unit" so we can define values for the basic # units in this system. hlu_charge statcoulomb / sqrt(4 pi) hlu_current hlu_charge / sec hlu_volt erg / hlu_charge hlu_efield hlu_volt / cm hlu_bfield sqrt(4 pi) gauss !var UNITS_SYSTEM hlu !message CGS-Heaviside-Lorentz Units selected !prompt (HLU) !endvar !var UNITS_SYSTEM hlu natural planck planck-red +coulombconst 1 / 4 pi +A 10 c_SI statamp # Some SI-based magnetism definitions # need re-scaling by factors of "c": +mu0 1 / epsilon0 # SI relation: 1 / epsilon0 c^2 +bohrmagneton (e hbar / 2 electronmass) / c +magneticfluxquantum c (pi hbar / e) +weber c (J / A) +maxwell c (erg / abamp) !endvar # "Natural units" (high energy physics and cosmology) # # In particle physics "natural units" (which don't seem to have a more specific # name) are defined by setting hbar = c = boltzmann = 1. In this system the # electron volt is the only base unit. The electromagnetic units can be # derived from the rationalized Heaviside-Lorentz units or from Gaussian units. # The default form is the rationalized HLU derived version. # # The basic mechanical and thermodynamic definitions for the natural # units are identical in both systems. These appear below. The # natural-gauss system has additional electromagnetic redefinitions # that appear above in the "Electromagnetic CGS (Gaussian)" Section. # These are the Heaviside-Lorentz natural units natural_action hbar natural_energy eV #XXX according to CODATA 2022 (at least), natural energy = m_e c^2 natural_charge e / sqrt(4 pi alpha) natural_time natural_action / natural_energy natural_length natural_time c natural_mass natural_energy / c^2 natural_momentum natural_energy / c natural_temp natural_energy / boltzmann natural_force natural_energy / natural_length natural_power natural_energy / natural_time natural_volt natural_energy / natural_charge natural_Efield natural_volt / natural_length natural_Bfield natural_Efield / c natural_current natural_charge / natural_time !var UNITS_SYSTEM natural !message Natural units selected (Heavyside-Lorentz based) !prompt (natural) !endvar !var UNITS_SYSTEM natural-gauss !message Natural units selected (Gaussian based) !prompt (natgauss) !endvar # These definitions are the same in both natural unit systems !var UNITS_SYSTEM natural natural-gauss +eV ! +h 2 pi +c 1 +boltzmann 1 +m e_SI / hbar_SI c_SI eV +kg (c_SI^2 / e_SI) eV +s e_SI / hbar_SI eV +K (k_SI / e_SI) eV !endvar # # Planck units # # Planck units are a set of "natural" units based on physical constants c, G, # hbar, boltzmann's constant, and epsilon0, often used when working with # gravitational theory. In planck units, all quantities are dimensionless. # Some variations are possible for exactly how the units are defined. We # provide two variations, the rationalized planck units and the # rationalized-reduced planck units. # # In both forms the units are defined by c = hbar = boltzmann = 1. # But the choice of rationalized and reduced affects how epsilon0 and G # are treated. # # In the "rationalized" units, factors of 4 pi do not appear in Maxwell's # equation, and Coulomb's law bears a factor of 1/4 pi. See the section on # the Heaviside-Lorentz units for more about this. The choice of rationalized # units means that epsilon0 = 1. (In the unrationalized case, which is not # supported, 1/(4 pi epsilon0) = 1.) # # The "reduced" units similarly are defined to eliminate factors of 8 pi # from the Einstein field equations for gravitation. With reduced units # we set 8 pi G = 1 and with the unreduced units, simply G = 1. # Rationalized, unreduced planck units planckmass sqrt(hbar c / G) m_P planckmass planckenergy planckmass c^2 E_P planckenergy plancktime hbar / planckenergy t_P plancktime plancklength plancktime c l_P plancklength plancktemperature planckenergy / k T_P plancktemperature planckforce planckenergy / plancklength planckcharge sqrt(epsilon0 hbar c) planckcurrent planckcharge / plancktime planckvolt planckenergy / planckcharge planckEfield planckvolt / plancklength planckBfield planckEfield / c # Rationalized, reduced planck units planckmass_red sqrt(hbar c / 8 pi G) planckenergy_red planckmass_red c^2 plancktime_red hbar / planckenergy_red plancklength_red plancktime_red c plancktemperature_red planckenergy_red / k planckforce_red planckenergy_red / plancklength_red planckcharge_red sqrt(epsilon0 hbar c) planckcurrent_red planckcharge_red / plancktime_red planckvolt_red planckenergy_red / planckcharge_red planckEfield_red planckvolt_red / plancklength_red planckBfield_red planckEfield_red /c !var UNITS_SYSTEM planck !message Planck units selected !prompt (planck) +c 1 +h 2 pi +G 1 +boltzmann 1 +kg sqrt(G_SI / hbar_SI c_SI) +s c_SI^2 / hbar_SI kg +m s / c_SI +K k_SI / hbar_SI s !endvar !var UNITS_SYSTEM planck-red !message Reduced planck units selected !prompt (planck reduced) +c 1 +h 2 pi +G 1/8 pi +boltzmann 1 +kg sqrt(8 pi G_SI / hbar_SI c_SI) +s c_SI^2 / hbar_SI kg +m s / c_SI +K k_SI / hbar_SI s !endvar # # Some historical electromagnetic units # intampere 0.999835 A # Defined as the current which in one intamp intampere # second deposits .001118 gram of # silver from an aqueous solution of # silver nitrate. intfarad 0.999505 F intvolt 1.00033 V intohm 1.000495 ohm # Defined as the resistance of a # uniform column of mercury containing # 14.4521 gram in a column 1.063 m # long and maintained at 0 degC. daniell 1.042 V # Meant to be electromotive force of a # Daniell cell, but in error by .04 V faraday N_A e mol # Charge that must flow to deposit or faraday_phys 96521.9 C # liberate one gram equivalent of any faraday_chem 96495.7 C # element. (The chemical and physical faradayconst N_A e # values are off slightly from what is # obtained by multiplying by amu_chem # or amu_phys. These values are from # a 1991 NIST publication.) Note that # there is also a Faraday constant, # which has units of C/mol. kappline 6000 maxwell # Named by and for Gisbert Kapp siemensunit 0.9534 ohm # Resistance of a meter long column of # mercury with a 1 mm cross section. # # Printed circuit board units. # # Iowa State University Center for Nondestructive Evaluation # Electrical Conductivity and Resistivity # https://www.nde-ed.org/Physics/Materials/Physical_Chemical/Electrical.xhtml # # Conductivity is often expressed as a percentage of IACS. A copper wire a # meter long with a 1 mm^2 cross section has a resistance of 1|58 ohm at # 20 deg C. Copper density also has a standard IACS value at that temperature. # copperconductivity 58 siemens m / mm^2 # A wire a meter long with IACS copperconductivity # a 1 mm^2 cross section copperdensity 8.89 g/cm^3 # The "ounce" measures the ouncecopper oz / ft^2 copperdensity # thickness of copper used ozcu ouncecopper # in circuitboard fabrication # # Photometric units # LUMINOUS_INTENSITY candela LUMINOUS_FLUX lumen LUMINOUS_ENERGY talbot ILLUMINANCE lux EXITANCE lux candle 1.02 candela # Standard unit for luminous intensity hefnerunit 0.9 candle # in use before candela hefnercandle hefnerunit # violle 20.17 cd # luminous intensity of 1 cm^2 of # platinum at its temperature of # solidification (2045 K) lumen cd sr # Luminous flux (luminous energy per lm lumen # time unit) talbot lumen s # Luminous energy lumberg talbot # References give these values for lumerg talbot # lumerg and lumberg both. Note that # a paper from 1948 suggests that # lumerg should be 1e-7 talbots so # that lumergs/erg = talbots/joule. # lumerg = luminous erg lux lm/m^2 # Illuminance or exitance (luminous lx lux # flux incident on or coming from phot lumen / cm^2 # a surface) ph phot # footcandle lumen/ft^2 # Illuminance from a 1 candela source # at a distance of one foot metercandle lumen/m^2 # Illuminance from a 1 candela source # at a distance of one meter mcs metercandle s # luminous energy per area, used to # measure photographic exposure nox 1e-3 lux # These two units were proposed for skot 1e-3 apostilb # measurements relating to dark adapted # eyes. # Luminance measures LUMINANCE nit nit cd/m^2 # Luminance: the intensity per projected stilb cd / cm^2 # area of an extended luminous source. sb stilb # (nit is from latin nitere = to shine.) apostilb cd/pi m^2 asb apostilb blondel apostilb # Named after a French scientist. # Equivalent luminance measures. These units are units which measure # the luminance of a surface with a specified exitance which obeys # Lambert's law. (Lambert's law specifies that luminous intensity of # a perfectly diffuse luminous surface is proportional to the cosine # of the angle at which you view the luminous surface.) equivalentlux cd / pi m^2 # luminance of a 1 lux surface equivalentphot cd / pi cm^2 # luminance of a 1 phot surface lambert cd / pi cm^2 footlambert cd / pi ft^2 # The bril is used to express "brilliance" of a source of light on a # logarithmic scale to correspond to subjective perception. An increase of 1 # bril means doubling the luminance. A luminance of 1 lambert is defined to # have a brilliance of 1 bril. bril(x) units=[1;lambert] 2^(x+-100) lamberts ;log2(bril/lambert)+100 # Some luminance data from the IES Lighting Handbook, 8th ed, 1993 sunlum 1.6e9 cd/m^2 # at zenith sunillum 100e3 lux # clear sky sunillum_o 10e3 lux # overcast sky sunlum_h 6e6 cd/m^2 # value at horizon skylum 8000 cd/m^2 # average, clear sky skylum_o 2000 cd/m^2 # average, overcast sky moonlum 2500 cd/m^2 # # Photographic Exposure Value # This section by Jeff Conrad (jeff_conrad@msn.com) # # The Additive system of Photographic EXposure (APEX) proposed in ASA # PH2.5-1960 was an attempt to simplify exposure determination for people who # relied on exposure tables rather than exposure meters. Shortly thereafter, # nearly all cameras incorporated exposure meters, so the APEX system never # caught on, but the concept of exposure value remains in use. Though given as # 'Ev' in ASA PH2.5-1960, it is now more commonly indicated by 'EV'. EV is # related to exposure parameters by # # A^2 LS ES # 2^EV = --- = -- = -- # t K C # # Where # A = Relative aperture (f-number) # t = Exposure time in seconds # L = Scene luminance in cd/m2 # E = Scene illuminance in lux # S = Arithmetic ISO speed # K = Reflected-light meter calibration constant # C = Incident-light meter calibration constant # # Strictly, an exposure value is a combination of aperture and exposure time, # but it's also commonly used to indicate luminance (or illuminance). # Conversion to luminance or illuminance units depends on the ISO speed and the # meter calibration constant. Common practice is to use an ISO speed of 100. # Calibration constants vary among camera and meter manufacturers: Canon, # Nikon, and Sekonic use a value of 12.5 for reflected-light meters, while # Kenko (formerly Minolta) and Pentax use a value of 14. Kenko and Sekonic use # a value of 250 for incident-light meters with flat receptors. # # The values for in-camera meters apply only averaging, weighted-averaging, or # spot metering--the multi-segment metering incorporated in most current # cameras uses proprietary algorithms that evaluate many factors related to the # luminance distribution of what is being metered; they are not amenable to # simple conversions, and are usually not disclosed by the manufacturers. s100 100 / lx s # ISO 100 speed iso100 s100 # Reflected-light meter calibration constant with ISO 100 speed k1250 12.5 (cd/m2) / lx s # For Canon, Nikon, and Sekonic k1400 14 (cd/m2) / lx s # For Kenko (Minolta) and Pentax # Incident-light meter calibration constant with ISO 100 film c250 250 lx / lx s # flat-disc receptor # Exposure value to scene luminance with ISO 100 imaging media # For Kenko (Minolta) or Pentax #ev100(x) units=[;cd/m^2] range=(0,) 2^x k1400 / s100; log2(ev100 s100/k1400) # For Canon, Nikon, or Sekonic ev100(x) units=[1;cd/m^2] range=(0,) 2^x k1250 / s100; log2(ev100 s100/k1250) EV100() ev100 # Exposure value to scene illuminance with ISO 100 imaging media iv100(x) units=[1;lx] range=(0,) 2^x c250 / s100; log2(iv100 s100 / c250) # Other Photographic Exposure Conversions # # As part of APEX, ASA PH2.5-1960 proposed several logarithmic quantities # related by # # Ev = Av + Tv = Bv + Sv # # where # Av = log2(A^2) Aperture value # Tv = log2(1/t) Time value # Sv = log2(N Sx) Speed value # Bv = log2(B S / K) Luminance ("brightness") value # Iv = log2(I S / C) Illuminance value # # and # A = Relative aperture (f-number) # t = Exposure time in seconds # Sx = Arithmetic ISO speed in 1/lux s # B = luminance in cd/m2 # I = luminance in lux # The constant N derives from the arcane relationship between arithmetic # and logarithmic speed given in ASA PH2.5-1960. That relationship # apparently was not obvious--so much so that it was thought necessary # to explain it in PH2.12-1961. The constant has had several values # over the years, usually without explanation for the changes. Although # APEX had little impact on consumer cameras, it has seen a partial # resurrection in the Exif standards published by the Camera & Imaging # Products Association of Japan. #N_apex 2^-1.75 lx s # precise value implied in ASA PH2.12-1961, # derived from ASA PH2.5-1960. #N_apex 0.30 lx s # rounded value in ASA PH2.5-1960, # ASA PH2.12-1961, and ANSI PH2.7-1986 #N_apex 0.3162 lx s # value in ANSI PH2.7-1973 N_exif 1|3.125 lx s # value in Exif 2.3 (2010), making Sv(5) = 100 K_apex1961 11.4 (cd/m2) / lx s # value in ASA PH2.12-1961 K_apex1971 12.5 (cd/m2) / lx s # value in ANSI PH3.49-1971; more common C_apex1961 224 lx / lx s # value in PH2.12-1961 (20.83 for I in # footcandles; flat sensor?) C_apex1971 322 lx / lx s # mean value in PH3.49-1971 (30 +/- 5 for I in # footcandles; hemispherical sensor?) N_speed N_exif K_lum K_apex1971 C_illum C_apex1961 # Units for Photographic Exposure Variables # # Practical photography sometimes pays scant attention to units for exposure # variables. In particular, the "speed" of the imaging medium is treated as if # it were dimensionless when it should have units of reciprocal lux seconds; # this practice works only because "speed" is almost invariably given in # accordance with international standards (or similar ones used by camera # manufacturers)--so the assumed units are invariant. In calculating # logarithmic quantities--especially the time value Tv and the exposure value # EV--the units for exposure time ("shutter speed") are often ignored; this # practice works only because the units of exposure time are assumed to be in # seconds, and the missing units that make the argument to the logarithmic # function dimensionless are silently provided. # # In keeping with common practice, the definitions that follow treat "speeds" # as dimensionless, so ISO 100 speed is given simply as '100'. When # calculating the logarithmic APEX quantities Av and Tv, the definitions # provide the missing units, so the times can be given with any appropriate # units. For example, giving an exposure time of 1 minute as either '1 min' or # '60 s' will result in Tv of -5.9068906. # # Exposure Value from f-number and Exposure Time # # Because nonlinear unit conversions only accept a single quantity, # there is no direct conversion from f-number and exposure time to # exposure value EV. But the EV can be obtained from a combination of # Av and Tv. For example, the "sunny 16" rule states that correct # exposure for a sunlit scene can achieved by using f/16 and an exposure # time equal to the reciprocal of the ISO speed in seconds; this can be # calculated as # # ~Av(16) + ~Tv(1|100 s), # # which gives 14.643856. These conversions may be combined with the # ev100 conversion: # # ev100(~Av(16) + ~Tv(1|100 s)) # # to yield the assumed average scene luminance of 3200 cd/m^2. # convert relative aperture (f-number) to aperture value Av(A) units=[1;1] domain=[-2,) range=[0.5,) 2^(A/2); 2 log2(Av) # convert exposure time to time value Tv(t) units=[1;s] range=(0,) 2^(-t) s; log2(s / Tv) # convert logarithmic speed Sv in ASA PH2.5-1960 to ASA/ISO arithmetic speed; # make arithmetic speed dimensionless # 'Sv' conflicts with the symbol for sievert; you can uncomment this function # definition if you don't need that symbol #Sv(S) units=[1;1] range=(0,) 2^S / (N_speed/lx s); log2((N_speed/lx s) Sv) Sval(S) units=[1;1] range=(0,) 2^S / (N_speed/lx s); log2((N_speed/lx s) Sval) # convert luminance value Bv in ASA PH2.12-1961 to luminance Bv(x) units=[1;cd/m^2] range=(0,) \ 2^x K_lum N_speed ; log2(Bv / (K_lum N_speed)) # convert illuminance value Iv in ASA PH2.12-1961 to illuminance Iv(x) units=[1;lx] range=(0,) \ 2^x C_illum N_speed ; log2(Iv / (C_illum N_speed)) # convert ASA/ISO arithmetic speed Sx to ASA logarithmic speed in # ASA PH2.5-1960; make arithmetic speed dimensionless Sx(S) units=[1;1] domain=(0,) \ log2((N_speed/lx s) S); 2^Sx / (N_speed/lx s) # convert DIN speed/ISO logarithmic speed in ISO 6:1993 to arithmetic speed # for convenience, speed is treated here as if it were dimensionless Sdeg(S) units=[1;1] range=(0,) 10^((S - 1) / 10) ; (1 + 10 log(Sdeg)) Sdin() Sdeg # Numerical Aperture and f-Number of a Lens # # The numerical aperture (NA) is given by # # NA = n sin(theta) # # where n is the index of refraction of the medium and theta is half # of the angle subtended by the aperture stop from a point in the image # or object plane. For a lens in air, n = 1, and # # NA = 0.5 / f-number # # convert NA to f-number numericalaperture(x) units=[1;1] domain=(0,1] range=[0.5,) \ 0.5 / x ; 0.5 / numericalaperture NA() numericalaperture # # convert f-number to itself; restrict values to those possible fnumber(x) units=[1;1] domain=[0.5,) range=[0.5,) x ; fnumber # Referenced Photographic Standards # # ASA PH-2.5-1960. USA Standard, Method for Determining (Monochrome, # Continuous-Tone) Speed of Photographic Negative Materials. # ASA PH2.12-1961. American Standard, General-Purpose Photographic # Exposure Meters (photoelectric type). # ANSI PH3.49-1971. American National Standard for general-purpose # photographic exposure meters (photoelectric type). # ANSI PH2.7-1973. American National Standard Photographic Exposure Guide. # ANSI PH2.7-1986. American National Standard for Photography -- # Photographic Exposure Guide. # CIPA DC-008-2010. Exchangeable image file format for digital still # cameras: Exif Version 2.3 # ISO 6:1993. International Standard, Photography -- Black-and-white # pictorial still camera negative film/process systems -- # Determination of ISO Speed. # # Astronomical time measurements # # Astronomical time measurement is a complicated matter. The length of the # true day at a given place can be 21 seconds less than 24 hours or 30 seconds # over 24 hours. The two main reasons for this are the varying speed of # Earth in its elliptical orbit and the fact that the Sun moves on the ecliptic # instead of along the celestial equator. To devise a workable system for time # measurement, Simon Newcomb (1835-1909) used a fictitious "mean Sun". # Consider a first fictitious Sun traveling along the ecliptic at a constant # speed and coinciding with the true Sun at perigee and apogee. Then # considering a second fictitious Sun traveling along the celestial equator at # a constant speed and coinciding with the first fictitious Sun at the # equinoxes. The second fictitious Sun is the "mean Sun". From this equations # can be written out to determine the length of the mean day, and the tropical # year. The length of the second was determined based on the tropical year # from such a calculation and was officially used from 1960-1967 until atomic # clocks replaced astronomical measurements for a standard of time. All of the # values below give the mean time for the specified interval. # # See "Mathematical Astronomy Morsels" by Jean Meeus for more details # and a description of how to compute the correction to mean time. # TIME second anomalisticyear 365.2596 days # The time between successive # perihelion passages of # Earth. siderealyear 365.256360417 day # The time for Earth to make # one revolution around the Sun # relative to the stars. tropicalyear 365.242198781 day # The time needed for the mean Sun # as defined above to increase # its longitude by 360 degrees. # Most references defined the # tropical year as the interval # between vernal equinoxes, but # this is misleading. The length # of the season changes over time # because of the eccentricity of # Earth's orbit. The time # between vernal equinoxes is # approximately 365.24237 days # around the year 2000. See # "Mathematical Astronomy # Morsels" for more details. eclipseyear 346.62 days # The line of nodes is the # intersection of the plane of # Earth's orbit around the Sun # with the plane of the Moon's # orbit around Earth. Eclipses # can only occur when the Moon # and Sun are close to this # line. The line rotates and # appearances of the Sun on the # line of nodes occur every # eclipse year. saros 223 synodicmonth # The Earth, Moon and Sun appear in # the same arrangement every # saros, so if an eclipse occurs, # then one saros later, a similar # eclipse will occur. (The saros # is close to 19 eclipse years.) # The eclipse will occur about # 120 degrees west of the # preceding one because the # saros is not an even number of # days. After 3 saros, an # eclipse will occur at # approximately the same place. solarday day # Time from noon to noon siderealday 86164.09054 s # The sidereal day is the interval siderealhour 1|24 siderealday # between two successive transits siderealminute 1|60 siderealhour # of a star over the meridian, siderealsecond 1|60 siderealminute # or the time required for # Earth to make one rotation # relative to the stars. Another # way to think about it is to # imagine looking down at the # solar system and noting when # Earth has made a rotation. # The more usual solar day is the # time required to make a # rotation relative to the Sun, # which means the same point on # Earth faces the Sun again. # Because Earth moves in its # orbit, it has to rotate a bit # more to face the Sun again, # hence the solar day is slightly # longer than the sidereal day. # The value given here is the # mean day length taken from # ssd.jpl.nasa.gov/astro_par.html # which in turn cites the # "Explanatory Supplement to the # Astronomical Almanac", 1992. anomalisticmonth 27.55454977 day # Time for the Moon to travel from # perigee to perigee nodicalmonth 27.2122199 day # The nodes are the points where draconicmonth nodicalmonth # an orbit crosses the ecliptic. draconiticmonth nodicalmonth # This is the time required to # travel from the ascending node # to the next ascending node. siderealmonth 27.321661 day # Time required for the Moon to # orbit the Earth lunarmonth 29 days + 12 hours + 44 minutes + 2.8 seconds # Mean time between full moons. synodicmonth lunarmonth # Full moons occur when the Sun lunation synodicmonth # and Moon are on opposite sides lune 1|30 lunation # of the Earth. Since the Earth lunour 1|24 lune # moves around the Sun, the Moon # has to move a bit further in its # orbit to return to the full moon # configuration. year tropicalyear yr year month 1|12 year mo month lustrum 5 years # The Lustrum was a Roman # purification ceremony that took # place every five years. # Classically educated Englishmen # used this term. decade 10 years century 100 years millennium 1000 years millennia millennium solaryear year lunaryear 12 lunarmonth calendaryear 365 day commonyear 365 day leapyear 366 day # The Julian year is The length of an average year over a 4-year cycle in the # Julian calendar. The calendar was proposed by Julius Caesar in 46 BCE and # took effect the following year. It has a normal year of 365 days and a leap # year of 366 days every four years. Though this calendar was used in # Europe for more than 1600 years, it drifts from the topical year by # about 1 day every 128 years, which became noticeable over its period # of use. # This growing discrepancy between the seasons and the calendar was perhaps # confusing but was also of concern to the Catholic Church because it led to a # shift in the date of Easter. To correct this discrepancy, Pope Gregory XIII # introduced the more accurate Gregorian calendar in 1582. The Gregorian year # is the length of an average year over a 400-year cycle in the Gregorian # calendar. Every year that is exactly divisible by four is a # leap year, except for years that are exactly divisible by 100, unless these # centurial years are exactly divisible by 400. This calendar was adopted by # many Catholic countries when it was proclaimed, but was not adopted by many # other countries until much later; Britain and the British Empire, including # what is now the eastern part of the United States, adopted it in 1752. See # https://en.wikipedia.org/wiki/List_of_adoption_dates_of_the_Gregorian_calendar_by_country # for additional details. julianyear 365.25 days gregorianyear 365.2425 days islamicyear 354 day # A year of 12 lunar months. They islamicleapyear 355 day # began counting on July 16, AD 622 # when Muhammad emigrated to Medina # (the year of the Hegira). They need # 11 leap days in 30 years to stay in # sync with the lunar year which is a # bit longer than the 29.5 days of the # average month. The months do not # keep to the same seasons, but # regress through the seasons every # 32.5 years. islamicmonth 1|12 islamicyear # They have 29 day and 30 day months. # The Hebrew year is also based on lunar months, but synchronized to the solar # calendar. The months vary irregularly between 29 and 30 days in length, and # the years likewise vary. The regular year is 353, 354, or 355 days long. To # keep up with the solar calendar, a leap month of 30 days is inserted every # 3rd, 6th, 8th, 11th, 14th, 17th, and 19th years of a 19 year cycle. This # gives leap years that last 383, 384, or 385 days. # # Planetary data from JPL's planet fact sheets. Each planet has its # own sheet at https://nssdc.gsfc.nasa.gov/planetary/factsheet/fact.html # The source for data on the fact sheets is described at # https://nssdc.gsfc.nasa.gov/planetary/factsheet/fact_notes.html # and they also indicate that the values listed are not "official" values: # there is no single set of agreed upon values. # Sidereal days. The sidereal day is the time required for a planet to make a # revolution relative to the stars. This is the default day value. mercuryday mercuryday_sidereal venusday venusday_sidereal earthday earthday_sidereal marsday marsday_sidereal jupiterday jupiterday_sidereal saturnday saturnday_sidereal uranusday uranusday_sidereal neptuneday neptuneday_sidereal plutoday plutoday_sidereal mercuryday_sidereal 1407.6 hr # Mercury is in a 3:2 resonance lock # where it makes 3 rotations per 2 orbits # so 3 sidereal days = 2 years venusday_sidereal 5832.6 hr # Retrograde earthday_sidereal siderealday marsday_sidereal 24.6229 hr jupiterday_sidereal 9.9250 hr saturnday_sidereal 10.656 hr uranusday_sidereal 17.24 hr # Retrograde neptuneday_sidereal 16.11 hr plutoday_sidereal 153.2928 hr # Retrograde # In astronomy, an object's rotation is "prograde" if it rotates in # the same direction as the primary object it orbits. Prograde # rotation is the more common case: in Earth's solar system, Mercury, # Earth, Mars, Jupiter, Saturn, and Neptune have prograde rotation. # When an object rotates opposite the direction of its primary object, # the object's rotation is "retrograde". Venus, Uranus, and Pluto have # retrograde rotation. # # The solar (or synodic) day is the time from noon to noon on a planet. This # is different from the sidereal day because the planet has moved in its orbit, # so (if its rotation is prograde) it needs additional rotation to return to # the same orientation relative to the Sun. In one orbital period (a year), # this amounts to one additional complete rotation, so the number of sidereal # days in a year is one greater than the number of solar days. # # If the planet's rotation is retrograde, less rotation is needed to return to # the same orientation relative to the Sun, and the number of sidereal days in # a year is one fewer than the number of solar days. # # The solar day can be computed from the sidereal day in the typical prograde # case by: # solar_day = sidereal_day year / (year - sidereal_day) # If the planet's rotation is retrograde like Venus then the formula is # solar_day = sidereal_day year / (year + sidereal_day) # If the sidereal day and year are the same length then the same face of the # planet faces the Sun and there is no solar day. mercuryday_solar 4222.6 hr venusday_solar 2802.0 hr earthday_solar 24 hr marsday_solar 24.6597 hr jupiterday_solar 9.9259 hr saturnday_solar 10.656 hr uranusday_solar 17.24 hr neptuneday_solar 16.11 hr plutoday_solar 153.2820 hr # Sidereal years mercuryyear 87.969 day venusyear 224.701 day earthyear siderealyear marsyear 686.980 day jupiteryear 4332.589 day saturnyear 10759.22 day uranusyear 30685.4 day neptuneyear 60189 day plutoyear 90560 day # Equatorial radii for the planets from JPL fact sheets mercuryradius 2440.5 km venusradius 6051.8 km earthradius 6378.137 km marsradius 3396.2 km jupiterradius 71492 km # 1 bar level saturnradius 60268 km # 1 bar level uranusradius 25559 km # 1 bar level neptuneradius 24764 km # 1 bar level plutoradius 1188 km # Volumetric mean radii mercuryradius_mean 2440.5 km venusradius_mean 6051.8 km earthradius_mean 6371 km marsradius_mean 3389.5 km jupiterradius_mean 69911 km saturnradius_mean 58232 km uranusradius_mean 25362 km neptuneradius_mean 24622 km plutoradius_mean 1188 km # Polar radii mercuryradius_polar 2438.3 km venusradius_polar 6051.8 km marsradius_polar 3376.2 km jupiterradius_polar 66854 km saturnradius_polar 54364 km uranusradius_polar 24973 km neptuneradius_polar 24341 km plutoradius_polar 1188 km mercurysundist_min 46.000 Gm mercurysundist_max 69.818 Gm venussundist_min 107.480 Gm venussundist_max 108.941 Gm earthsundist_min sundist_min earthsundist_max sundist_max marssundist_min 206.650 Gm marssundist_max 249.261 Gm jupitersundist_min 740.595 Gm jupitersundist_max 816.363 Gm saturnsundist_min 1357.554 Gm saturnsundist_max 1506.527 Gm uranussundist_min 2732.696 Gm uranussundist_max 3001.390 Gm neptunesundist_min 4471.050 Gm neptunesundist_max 4558.857 Gm plutosundist_min 4434.987 Gm plutosundist_max 7304.326 Gm sundist 1.0000010178 au # mean Earth-Sun distance moondist 384400 km # mean Earth-Moon distance sundist_near 147.095 Gm # Earth-Sun distance at perihelion sundist_min sundist_near sundist_far 152.100 Gm # Earth-Sun distance at aphelion sundist_max sundist_far # The Earth-Moon distances at perigee and apogee are different for every # lunation. The values here are the extremes for 1500-2500 according to # Jean Meeus's Astronomical Algorithms (1991, 332). moondist_min 356371 km # minimum distance at perigee 1500-2500 moondist_max 406720 km # maximum distance at apogee 1500-2500 # Objects on Earth are charted relative to a perfect ellipsoid whose # dimensions are specified by different organizations. The ellipsoid is # specified by an equatorial radius and a flattening value which defines the # polar radius. earthflattening IERS_earthflattening earthradius_equatorial IERS_earthradius_equatorial earthradius_polar (1-earthflattening) earthradius_equatorial # The World Geodetic System maintains a standard, WGS84, which is used by the # the GPS system. This system uses a conventional ellipsoid that was fixed in # 1984 and has remained constant so that data collected at different times is # referenced to the same ellipsoid. https://epsg.io/4326 WGS84_earthflattening 1|298.257223563 WGS84_earthradius_equatorial 6378137 m WGS84_earthradius_polar (1-WGS84_earthflattening) WGS84_earthradius_equatorial # The International Earth Rotation Service (IERS) attempts to # maintain an accurate model of Earth, with updates to maintain the highest # possible accuracy, even though this makes it more difficult to relate geodetic # measurements made at different times. # IERS Conventions, Chapter 1, General definitions and numerical standards (16 November 2017) # https://iers-conventions.obspm.fr/content/chapter1/icc1.pdf IERS_earthflattening 1|298.25642 IERS_earthradius_equatorial 6378136.6 m IERS_earthradius_polar (1-IERS_earthflattening) IERS_earthradius_equatorial landarea 148.847e6 km^2 oceanarea 361.254e6 km^2 moonradius 1738 km # mean value sunradius 6.96e8 m # Many astronomical values can be measured most accurately in a system of units # using the astronomical unit and the mass of the Sun as base units. The # uncertainty in the gravitational constant makes conversion to SI units # significantly less accurate. # The astronomical unit was defined to be the length of the of the semimajor # axis of a massless object with the same year as Earth. With such a # definition in force, and with the mass of the Sun set equal to one, Kepler's # third law can be used to solve for the value of the gravitational constant. # Kepler's third law says that (2 pi / T)^2 a^3 = G M where T is the orbital # period, a is the size of the semimajor axis, G is the gravitational constant # and M is the mass. With M = 1 and T and a chosen for Earth's orbit, we # find sqrt(G) = (2 pi / T) sqrt(AU^3). This constant is called the Gaussian # gravitational constant, apparently because Gauss originally did the # calculations. However, when the original calculation was done, the value # for the length of Earth's year was inaccurate. The value used is called # the Gaussian year. Changing the astronomical unit to bring it into # agreement with more accurate values for the year would have invalidated a # lot of previous work, so instead the astronomical unit has been kept equal # to this original value. This is accomplished by using a standard value for # the Gaussian gravitational constant. This constant is called k. gauss_k 0.01720209895 # This beast has dimensions of # au^(3|2) / day and is exact. gaussianyear (2 pi / gauss_k) days # Year that corresponds to the Gaussian # gravitational constant. This is a # fictional year, and doesn't # correspond to any celestial event. astronomicalunit 149597870700 m # IAU definition from 2012, exact au astronomicalunit # ephemeris for the above described # astronomical unit. (See the NASA # site listed above.) GMsun 132712440041.279419 km^3 / s^2 # heliocentric gravitational constant solarmass GMsun/G # is known more accurately than G. sunmass solarmass # Estimated from DE440 # The following are masses for planetary systems, not just the planet itself, # except for the case of Earth, where the Moon is excluded. Masses are # relative to G because they are known much more accurately than G. # # See https://ssd.jpl.nasa.gov/astro_par.html. Values are from # the DE440 Ephemeris: https://ssd.jpl.nasa.gov/doc/Park.2021.AJ.DE440.pdf mercurymass 22031.868551 km^3 / s^2 G venusmass 324858.592000 km^3 / s^2 G marsmass 42828.375816 km^3 / s^2 G jupitermass 126712764.100000 km^3 / s^2 G saturnmass 37940584.841800 km^3 / s^2 G uranusmass 5794556.400000 km^3 / s^2 G neptunemass 6836527.100580 km^3 / s^2 G plutomass 975.500000 km^3 / s^2 G ceresmass 62.62890 km^3 / s^2 G vestamass 17.288245 km^3 / s^2 G earthmass 398600.435507 km^3 / s^2 G # Earth alone moonmass 4902.800118 km^3 / s^2 G moonearthmassratio moonmass/earthmass earthmoonmass earthmass+moonmass moongravity 1.62 m/s^2 # Earth gravity values at the equator and poles. These values are # obtained from the WGS84 model. gravity_equatorial 9.7803263359 m / s^2 gravity_polar 9.8321849378 m / s^2 # The Hubble constant gives the speed at which distance galaxies are moving # away from Earth according to v = H0*d, where H0 is the hubble constant # and d is the distance to the galaxy. hubble 70 km/s/Mpc # approximate H0 hubble # Parallax is the angular difference between the topocentric (on Earth's # surface) and geocentric (at Earth's center) direction toward a celestial body # when the body is at a given altitude. When the body is on the horizon, the # parallax is the horizontal parallax; when the body is on the horizon and the # observer is on the equator, the parallax is the equatorial horizontal # parallax. When the body is at zenith, the parallax is zero. lunarparallax asin(earthradius_equatorial / moondist) # Moon equatorial moonhp lunarparallax # horizontal parallax # at mean distance # Light from celestial objects is attenuated by passage through Earth's # atmosphere. A body near the horizon passes through much more air than an # object at zenith, and is consequently less bright. Air mass is the ratio of # the length of the optical path at a given altitude (angle above the horizon) # to the length at zenith. Air mass at zenith is by definition unity; at the # horizon, air mass is approximately 38, though the latter value can vary # considerably with atmospheric conditions. The general formula is # E = E0 # exp(-c X), where E0 is the value outside Earth's atmosphere, E is the value # seen by an observer, X is the air mass and c is the extinction coefficient. # A common value for c in reasonably clear air is 0.21, but values can be # considerably greater in urban areas. Apparent altitude is that perceived by # an observer; it includes the effect of atmospheric refraction. There is no # shortage of formulas for air mass # (https://en.wikipedia.org/wiki/Air_mass_(astronomy)); all are subject to # variations in local atmospheric conditions. The formula used here is simple # and is in good agreement with rigorously calculated values under standard # conditions. # # Extraterrestrial illuminance or luminance of an object at a given altitude # determined with vmag() or SB_xxx() below can be multiplied by # atm_transmission() or atm_transmissionz() to estimate the terrestrial value. # # Kasten and Young (1989) air mass formula. alt is apparent altitude # Reference: # Kasten, F., and A.T. Young. 1989. "Revised Optical Air Mass Tables # and Approximation Formula." Applied Optics. Vol. 28, 4735-4738. # Bibcode:1989ApOpt..28.4735K. doi:10.1364/AO.28.004735. airmass(alt) units=[degree;1] domain=[0,90] noerror \ 1 / (sin(alt) + 0.50572 (alt / degree + 6.07995)^-1.6364) # zenith is apparent zenith angle (zenith = 90 deg - alt) airmassz(zenith) units=[degree;1] domain=[0,90] noerror \ 1 / (cos(zenith) + 0.50572 (96.07995 - zenith / degree)^-1.6364) # For reasonably clear air at sea level; values may need adjustment for # elevation and local atmospheric conditions # for scotopic vision (510 nm), appropriate for the dark-adapted eye # extinction_coeff 0.26 # for photopic vision, appropriate for observing brighter objects such # as the full moon extinction_coeff 0.21 atm_transmission(alt) units=[degree;1] domain=[0,90] noerror \ exp(-extinction_coeff airmass(alt)) # in terms of zenith angle (zenith = 90 deg - alt) atm_transmissionz(zenith) units=[degree;1] domain=[0,90] noerror \ exp(-extinction_coeff airmassz(zenith)) # Moon and Sun data at mean distances moonvmag -12.74 # Moon apparent visual magnitude at mean distance sunvmag -26.74 # Sun apparent visual magnitude at mean distance moonsd asin(moonradius / moondist) # Moon angular semidiameter at mean distance sunsd asin(sunradius / sundist) # Sun angular semidiameter at mean distance # Visual magnitude of star or other celestial object. The system of stellar # magnitudes, developed in ancient Greece, assigned magnitudes from 1 # (brightest) to 6 (faintest visible to the naked eye). In 1856, British # astronomer Norman Pogson made the system precise, with a magnitude 1 object # 100 times as bright as a magnitude 6 object, and each magnitude differing # from the next by a constant ratio; the ratio, sometimes known as Pogson's # ratio, is thus 100^0.2, or approximately 2.5119. The logarithm of 100^0.2 is # 0.4, hence the common use of powers of 10 and base-10 logarithms. # # Reference: # Allen, C.W. 1976. Astrophysical Quantities, 3rd ed. 1973, reprinted # with corrections, 1976. London: Athlone. # # The function argument is the (dimensionless) visual magnitude; reference # illuminance of 2.54e-6 lx is from Allen (2000, 21), and is for outside # Earth's atmosphere. Illuminance values can be adjusted to terrestrial values # by multiplying by one of the atm_transmission functions above. # Illuminance from apparent visual magnitude vmag(mag) units=[1;lx] domain=[,] range=(0,] \ 2.54e-6 lx 10^(-0.4 mag); -2.5 log(vmag / (2.54e-6 lx)) # Surface brightness of a celestial object of a given visual magnitude # is a logarithmic measure of the luminance the object would have if its # light were emitted by an object of specified solid angle; it is # expressed in magnitudes per solid angle. Surface brightness can be # obtained from the visual magnitude by # S = m + 2.5 log(pi pi k a b), # where k is the phase (fraction illuminated), a is the equatorial # radius, and b is the polar radius. For 100% illumination (e.g., full # moon), this is often simplified to # S = m + 2.5 log(pi k s^2), # where s is the object's angular semidiameter; the units of s determine # the units of solid angle. The visual magnitude and semidiameter must # be appropriate for the object's distance; for other than 100% # illumination, the visual magnitude must be appropriate for the phase. # Luminance values are for outside Earth's atmosphere; they can be # adjusted to terrestrial values by multiplying by one of the atm_transmission # functions above. # luminance from surface brightness in magnitudes per square degree SB_degree(sb) units=[1;cd/m^2] domain=[,] range=(0,] \ vmag(sb) / squaredegree ; \ ~vmag(SB_degree squaredegree) # luminance from surface brightness in magnitudes per square minute SB_minute(sb) units=[1;cd/m^2] domain=[,] range=(0,] \ vmag(sb) / squareminute ; \ ~vmag(SB_minute squareminute) # luminance from surface brightness in magnitudes per square second SB_second(sb) units=[1;cd/m^2] domain=[,] range=(0,] \ vmag(sb) / squaresecond ; \ ~vmag(SB_second squaresecond) # luminance from surface brightness in magnitudes per steradian SB_sr(sb) units=[1;cd/m^2] domain=[,] range=(0,] \ vmag(sb) / sr ; \ ~vmag(SB_sr sr) SB() SB_second SB_sec() SB_second SB_min() SB_minute SB_deg() SB_degree # The brightness of one tenth-magnitude star per square degree outside # Earth's atmosphere; often used for night sky brightness. S10 SB_degree(10) # Examples for magnitude and surface brightness functions # Sun illuminance from visual magnitude # You have: sunvmag # You want: # Definition: -26.74 = -26.74 # You have: vmag(sunvmag) # You want: lx # * 126134.45 # / 7.9280482e-06 # # Moon surface brightness from visual magnitude and semidiameter at 100% # illumination (full moon): # You have: moonvmag # You want: # Definition: -12.74 = -12.74 # You have: moonsd # You want: arcsec # * 932.59484 # / 0.001072277 # You have: moonvmag + 2.5 log(pi 932.59484^2) # You want: # Definition: 3.3513397 # # Similar example with specific data obtained from another source (JPL # Horizons, https://ssd.jpl.nasa.gov/horizons.cgi); semidiameter is in # arcseconds # # You have: -12.9 + 2.5 log(pi 2023.201|2^2) # You want: # Definition: 3.3679199 # You have: SB_second(-12.9 + 2.5 log(pi 2023.201|2^2)) # You want: # Definition: 4858.6547 cd / m^2 # # If surface brightness is provided by another source (e.g., Horizons), # it can simply be used directly: # You have: SB_second(3.3679199) # You want: cd/m^2 # * 4858.6546 # / 0.0002058183 # The illuminance and luminance values are extraterrestrial (outside # Earth's atmosphere). The values at Earth's surface are less than these # because of atmospheric extinction. For example, in the last example # above, if the Moon were at an altitude of 55 degrees, the terrestrial # luminance could be calculated with # You have: SB_second(3.3679199) # You want: cd/m^2 # * 4858.6546 # / 0.0002058183 # You have: _ atm_transmission(55 deg) # You want: cd/m^2 # * 3760.6356 # / 0.0002659125 # If desired, photographic exposure can be determined with EV100(), # leading to acceptable combinations of aperture and exposure time. # For the example above, but with the Moon at 10 degrees, # You have: SB_second(3.3679199) atm_transmission(10 deg) # You want: EV100 # 13.553962 # # The Hartree system of atomic units, derived from fundamental units # of mass (of the electron), action (Planck's constant), charge, and # the Coulomb constant. This system is used in the fields of physical # chemistry and condensed matter physics. # # Fundamental units atomicmass electronmass atomiccharge e atomicaction hbar atomicenergy hartree # Derived units atomicvelocity sqrt(atomicenergy / atomicmass) atomictime atomicaction / atomicenergy atomiclength atomicvelocity atomictime atomicforce atomicenergy / atomiclength atomicmomentum atomicenergy / atomicvelocity atomiccurrent atomiccharge / atomictime atomicdipolemoment atomiccharge atomiclength atomicpotential atomicenergy / atomiccharge # electrical potential atomicvolt atomicpotential atomicEfield atomicpotential / atomiclength atomicBfield atomicEfield / atomicvelocity atomictemperature atomicenergy / boltzmann # # In Hartree units, m_e = hbar = e = coulombconst = bohrradius = alpha*c = 1 # !var UNITS_SYSTEM hartree !message Hartree units selected !prompt (hartree) +hartree 1 +kg 1/electronmass_SI +K k_SI / hbar_SI s +m alpha c_SI electronmass_SI / hbar_SI +s alpha c_SI m +A 1 / s e_SI !endvar # # These thermal units treat entropy as charge, from [5] # thermalcoulomb J/K # entropy thermalampere W/K # entropy flow thermalfarad J/K^2 thermalohm K^2/W # thermal resistance fourier thermalohm thermalhenry J K^2/W^2 # thermal inductance thermalvolt K # thermal potential difference # # United States units # # linear measure # The US Metric Law of 1866 legalized the metric system in the USA and # defined the meter in terms of the British system with the exact # 1 meter = 39.37 inches. On April 5, 1893 Thomas Corwin Mendenhall, # Superintendent of Weights and Measures, decided, in what has become # known as the "Mendenhall Order" that the meter and kilogram would be the # fundamental standards in the USA. The definition from 1866 was turned # around to give an exact definition of the yard as 3600|3937 meters This # definition was used until July of 1959 when the definition was changed # to bring the US and other English-speaking countries into agreement; the # Canadian value of 1 yard = 0.9144 meter (exactly) was chosen because it # was approximately halfway between the British and US values; it had the # added advantage of making 1 inch = 25.4 mm (exactly). Since 1959, the # "international" foot has been exactly 0.3048 meters. At the same time, # it was decided that any data expressed in feet derived from geodetic # surveys within the US would continue to use the old definition and call # the old unit the "survey foot." # # Until 1 January 2023, the US continued to define the statute # mile, furlong, chain, rod, link, and fathom in terms of the US survey # foot. Since then, use of the US survey foot has been officially # deprecated, with its use limited to historical and legacy applications. # These units are now defined in terms of the international foot. # # Sources: # NIST Special Publication 447, Sects. 5, 7, and 8. # NIST Handbook 44, 2024 ed., Appendix C. # Canadian Journal of Physics, 1959, 37:(1) 84, 10.1139/p59-014. inch 2.54 cm # Exact, international inch (1959) in inch foot 12 inch feet foot ft foot yard 3 ft yd yard mile 5280 ft # The mile was enlarged from 5000 ft # to this number in order to make # it an even number of furlongs. # (The Roman mile is 5000 romanfeet.) line 1|12 inch # Also defined as '.1 in' or as '1e-8 Wb' rod 16.5 ft pole rod perch rod furlong 40 rod # From "furrow long" statutemile mile league 3 mile # Intended to be an hour's walk # surveyor's measure # The US survey foot is officially deprecated as of 1 January 2023 US 1200|3937 m/ft # These four values will convert US- US # international measures to survey- US # US Survey measures geodetic- US int 3937|1200 ft/m # Convert US Survey measures to int- int # international measures # values based on the US survey foot are deprecated as of 1 January 2023 surveyorschain 66 surveyft surveychain surveyorschain surveyorspole 1|4 surveyorschain surveyorslink 1|100 surveyorschain USacre 10 surveychain^2 USacrefoot USacre surveyfoot chain 66 ft link 1|100 chain ch chain intacre 10 chain^2 # Acre based on international ft intacrefoot acre foot acrefoot intacrefoot acre intacre ac acre section mile^2 township 36 section homestead 160 acre # Area of land granted by the 1862 Homestead # Act of the United States Congress gunterschain surveyorschain engineerschain 100 ft engineerslink 1|100 engineerschain ramsdenschain engineerschain ramsdenslink engineerslink gurleychain 33 feet # Andrew Ellicott chain is the gurleylink 1|50 gurleychain # same length wingchain 66 feet # Chain from 1664, introduced by winglink 1|80 wingchain # Vincent Wing, also found in a # 33 foot length with 40 links. # early US length standards # The US has had four standards for the yard: one by Troughton of London # (1815); bronze yard #11 (1856); the Mendhall yard (1893), consistent # with the definition of the meter in the metric joint resolution of # Congress in 1866, but defining the yard in terms of the meter; and the # international yard (1959), which standardized definitions for Australia, # Canada, New Zealand, South Africa, the UK, and the US. # Sources: Pat Naughtin (2009), Which Inch?: # https://metricationmatters.org/docs/WhichInch.pdf, # Lewis E. Barbrow and Lewis V. Judson (1976). NBS Special # Publication 447, Weights and Measures Standards of the United States: A # Brief History. troughtonyard 914.42190 mm bronzeyard11 914.39980 mm mendenhallyard surveyyard internationalyard yard # nautical measure fathom 6 ft # Originally defined as the distance from # fingertip to fingertip with arms fully # extended. nauticalmile 1852 m # Supposed to be one minute of latitude at # the equator. That value is about 1855 m. # Early estimates of Earth's circumference # were a bit off. The value of 1852 m was # made the international standard in 1929. # The US did not accept this value until # 1954. The UK switched in 1970. # The cable is used for depth in water and has a wide range of definitions intcable 1|10 nauticalmile # international cable uscable 120 fathom # value after 1 January 2023 surveycable 120 USfathom # value before 1 January 2023 UScable surveycable cableslength cable cablelength cable navycablelength cable brcable 1|10 brnauticalmile admiraltycable brcable marineleague 3 nauticalmile geographicalmile brnauticalmile knot nauticalmile / hr click km # US military slang klick click # Avoirdupois weight pound 0.45359237 kg # Exact, International Pound (1959) lb pound # From the Latin libra grain 1|7000 pound # The grain is the same in all three # weight systems. It was originally # defined as the weight of a barley # corn taken from the middle of the # ear. ounce 1|16 pound oz ounce dram 1|16 ounce dr dram ushundredweight 100 pounds cwt hundredweight shorthundredweight ushundredweight uston shortton shortton 2000 lb quarterweight 1|4 uston shortquarterweight 1|4 shortton shortquarter shortquarterweight # Troy Weight. In 1828 the troy pound was made the first United States # standard weight. It was to be used to regulate coinage. troypound 5760 grain troyounce 1|12 troypound ozt troyounce pennyweight 1|20 troyounce # Abbreviated "d" in reference to a dwt pennyweight # Frankish coin called the "denier" # minted in the late 700's. There # were 240 deniers to the pound. assayton mg ton / troyounce # mg / assayton = troyounce / ton usassayton mg uston / troyounce brassayton mg brton / troyounce fineounce troyounce # A troy ounce of 99.5% pure gold # Some other jewelers units metriccarat 0.2 gram # Defined in 1907 metricgrain 50 mg carat metriccarat ct carat jewelerspoint 1|100 carat silversmithpoint 1|4000 inch momme 3.75 grams # Traditional Japanese unit based # on the chinese mace. It is used for # pearls in modern times and also for # silk density. The definition here # was adopted in 1891. # Apothecaries' weight appound troypound apounce troyounce apdram 1|8 apounce apscruple 1|3 apdram # Liquid measure usgallon 231 in^3 # US liquid measure is derived from gal gallon # the British wine gallon of 1707. quart 1|4 gallon # See the "winegallon" entry below pint 1|2 quart # more historical information. gill 1|4 pint usquart 1|4 usgallon uspint 1|2 usquart usgill 1|4 uspint usfluidounce 1|16 uspint fluiddram 1|8 usfloz minimvolume 1|60 fluiddram qt quart pt pint floz fluidounce usfloz usfluidounce fldr fluiddram liquidbarrel 31.5 usgallon usbeerbarrel 2 beerkegs beerkeg 15.5 usgallon # Various among brewers ponykeg 1|2 beerkeg winekeg 12 usgallon petroleumbarrel 42 usgallon # Originated in Pennsylvania oil barrel petroleumbarrel # fields, from the winetierce bbl barrel ushogshead 2 liquidbarrel usfirkin 9 usgallon # Dry measures: The Winchester Bushel was defined by William III in 1702 and # legally adopted in the US in 1836. usbushel 2150.42 in^3 # Volume of 8 inch cylinder with 18.5 bu bushel # inch diameter (rounded) peck 1|4 bushel uspeck 1|4 usbushel brpeck 1|4 brbushel pk peck drygallon 1|2 uspeck dryquart 1|4 drygallon drypint 1|2 dryquart drybarrel 7056 in^3 # Used in US for fruits, vegetables, # and other dry commodities except for # cranberries. cranberrybarrel 5826 in^3 # US cranberry barrel heapedbushel 1.278 usbushel# The following explanation for this # value was provided by Wendy Krieger # based on # guesswork. The cylindrical vessel is # 18.5 inches in diameter and 1|2 inch # thick. A heaped bushel includes the # contents of this cylinder plus a heap # on top. The heap is a cone 19.5 # inches in diameter and 6 inches # high. With these values, the volume # of the bushel is 684.5 pi in^3 and # the heap occupies 190.125 pi in^3. # Therefore, the heaped bushel is # 874.625|684.5 bushels. This value is # approximately 1.2777575 and it rounds # to the value listed for the size of # the heaped bushel. Sometimes the # heaped bushel is reported as 1.25 # bushels. This same explanation gives # that value if the heap is taken to # have an 18.5 inch diameter. # Grain measures. The bushel as it is used by farmers in the USA is actually # a measure of mass which varies for different commodities. Canada uses the # same bushel masses for most commodities, but not for oats. wheatbushel 60 lb soybeanbushel 60 lb cornbushel 56 lb ryebushel 56 lb barleybushel 48 lb oatbushel 32 lb ricebushel 45 lb canada_oatbushel 34 lb # Wine and Spirits measure ponyvolume 1 usfloz jigger 1.5 usfloz # Can vary between 1 and 2 usfloz shot jigger # Sometimes 1 usfloz eushot 25 ml # EU standard spirits measure fifth 1|5 usgallon winebottle 750 ml # US industry standard, 1979 winesplit 1|4 winebottle magnum 1.5 liter # Standardized in 1979, but given # as 2 qt in some references metrictenth 375 ml metricfifth 750 ml metricquart 1 liter # Old British bottle size reputedquart 1|6 brgallon reputedpint 1|2 reputedquart brwinebottle reputedquart # Very close to 1|5 winegallon # French champagne bottle sizes split 200 ml jeroboam 2 magnum rehoboam 3 magnum methuselah 4 magnum imperialbottle 4 magnum salmanazar 6 magnum balthazar 8 magnum nebuchadnezzar 10 magnum solomon 12 magnum melchior 12 magnum sovereign 17.5 magnum primat 18 magnum goliath 18 magnum melchizedek 20 magnum midas 20 magnum # The wine glass doesn't seem to have an official standard, but the same value # is suggested by several sources in the US. wineglass 150 mL # In the UK, serving size offerings legally mandated by The Weights and # Measures (Specified Quantities) (Unwrapped Bread and Intoxicating # Liquor) Order 2011, effective 1st October 2011. The quantities--not # the names--are mandated. Lawful size offerings are these or multiples # thereof, but other sizes can be provided at the express request of a # buyer. smallwineglass 125 mL mediumwineglass 175 mL # Values vary considerably among countries and even more so in practice. The # "standard" US value gives 5 glasses per standard 750 ml bottle. Old practice # in the UK was 125 ml per glass, or 6 glasses per bottle. Some sources suggest # a more recent common value of 250 ml per glass, or 3 glasses per # bottle; as a multiple of 125 ml, this would be a lawful serving size offering. # # The value refers to the size of the serving, not the total volume of the # glass, which is typically not filled above the height of its greatest # diameter. # # A unit of alcohol is a specified amount of pure ethyl alcohol, expressed as a # mass or volumetric equivalent. Many countries use the same concept but use # different terms. "Alcohol unit" is used officially in the UK; the US, Canada, # and Australia use "standard drink." Values vary considerably among # countries. The UK value of 8 g is nominally the amount of alcohol that a # typical adult can metabolize in one hour. alcoholunitus 14 g / ethanoldensity alcoholunitca 13.6 g / ethanoldensity alcoholunituk 8 g / ethanoldensity alcoholunitau 10 g / ethanoldensity # Common serving sizes have roughly equivalent amounts of alcohol, as # illustrated by US examples for wine (12% Alcohol By Volume), beer (5% ABV), # and spirits (80 proof). # # alcoholunitus / 12% = 147.8 mL, close to the "standard" serving of 150 mL. # alcoholunitus / 5% = 11.995346 floz, close to a standard 12 floz bottle or can # alcoholunitus / 80 proof = 1.4994182 floz, close to a standard "shot" or jigger # https://www.rethinkingdrinking.niaaa.nih.gov/ # https://www.cdc.gov/alcohol/faqs.htm # https://www.canada.ca/en/health-canada/services/substance-use/alcohol/low-risk-alcohol-drinking-guidelines # https://www.drinkaware.co.uk/ # https://www.drinkaware.co.uk/facts/alcoholic-drinks-and-units # https://www.gov.uk/government/uploads/system/uploads/attachment_data/file/545937/UK_CMOs__report.pdf # https://adf.org.au/reducing-risk/alcohol/alcohol-guidelines/ # https://www.health.gov.au/topics/alcohol/about-alcohol/standard-drinks-guide # https://en.wikipedia.org/wiki/Unit_of_alcohol # https://en.wikipedia.org/wiki/Standard_drink # Coffee # # The recommended ratio of coffee to water. Values vary considerably; # one is from the Specialty Coffee Association of America: Brewing Best Practices # https://sca.coffee/research/protocols-best-practices coffeeratio 55 g/L # +/- 10% # other recommendations are more loose, e.g., # http://www.ncausa.org/About-Coffee/How-to-Brew-Coffee # # Water is "hard" if it contains various minerals, especially calcium # carbonate. # clarkdegree grains/brgallon # Content by weigh of calcium carbonate gpg grains/usgallon # Divide by water's density to convert to # a dimensionless concentration measure # # Shoe measures # shoeiron 1|48 inch # Used to measure leather in soles shoeounce 1|64 inch # Used to measure non-sole shoe leather # USA shoe sizes. These express the length of the shoe or the length # of the "last", the form that the shoe is made on. But note that # this only captures the length. It appears that widths change 1/4 # inch for each letter within the same size, and if you change the # length by half a size then the width changes between 1/8 inch and # 1/4 inch. But this may not be standard. If you know better, please # contact me. shoesize_delta 1|3 inch # USA shoe sizes differ by this amount shoe_men0 8.25 inch shoe_women0 (7+11|12) inch shoe_boys0 (3+11|12) inch shoe_girls0 (3+7|12) inch shoesize_men(n) units=[1;inch] shoe_men0 + n shoesize_delta ; \ (shoesize_men+(-shoe_men0))/shoesize_delta shoesize_women(n) units=[1;inch] shoe_women0 + n shoesize_delta ; \ (shoesize_women+(-shoe_women0))/shoesize_delta shoesize_boys(n) units=[1;inch] shoe_boys0 + n shoesize_delta ; \ (shoesize_boys+(-shoe_boys0))/shoesize_delta shoesize_girls(n) units=[1;inch] shoe_girls0 + n shoesize_delta ; \ (shoesize_girls+(-shoe_girls0))/shoesize_delta # European shoe size. According to # http://www.shoeline.com/footnotes/shoeterm.shtml # shoe sizes in Europe are measured with Paris points which simply measure # the length of the shoe. europeshoesize 2|3 cm # # USA slang units # buck US$ fin 5 US$ sawbuck 10 US$ usgrand 1000 US$ greenback US$ key kg # usually of marijuana, 60's lid 1 oz # Another 60's weed unit footballfield usfootballfield usfootballfield 100 yards canadafootballfield 110 yards # And 65 yards wide marathon 26 miles + 385 yards # # British # # The length measure in the UK was defined by a bronze bar manufactured in # 1844. Various conversions were sanctioned for convenience at different # times, which makes conversions before 1963 a confusing matter. Apparently # previous conversions were never explicitly revoked. Four different # conversion factors appear below. Multiply them times an imperial length # units as desired. The Weights and Measures Act of 1963 switched the UK away # from their bronze standard and onto a definition of the yard in terms of the # meter. This happened after an international agreement in 1959 to align the # world's measurement systems. UK UKlength_SJJ UK- UK british- UK UKlength_B 0.9143992 meter / yard # Benoit found the yard to be # 0.9143992 m at a weights and # measures conference around # 1896. Legally sanctioned # in 1898. UKlength_SJJ 0.91439841 meter / yard # In 1922, Seers, Jolly and # Johnson found the yard to be # 0.91439841 meters. # Used starting in the 1930's. UKlength_K meter / 39.37079 inch # In 1816 Kater found this ratio # for the meter and inch. This # value was used as the legal # conversion ratio when the # metric system was legalized # for contract in 1864. UKlength_C meter / 1.09362311 yard # In 1866 Clarke found the meter # to be 1.09362311 yards. This # conversion was legalized # around 1878. brnauticalmile 6080 ft # Used until 1970 when the UK brknot brnauticalmile / hr # switched to the international admiraltymile brnauticalmile # nautical mile. admiraltyknot brknot seamile 6000 ft shackle 15 fathoms # Adopted 1949 by British navy # British Imperial weight is mostly the same as US weight. A few extra # units are added here. clove 7 lb stone 14 lb tod 28 lb brquarterweight 1|4 brhundredweight brhundredweight 8 stone longhundredweight brhundredweight longton 20 brhundredweight brton longton # British Imperial volume measures brminim 1|60 brdram brscruple 1|3 brdram fluidscruple brscruple brdram 1|8 brfloz brfluidounce 1|20 brpint brfloz brfluidounce brgill 1|4 brpint brpint 1|2 brquart brquart 1|4 brgallon brgallon 4.54609 l # The British Imperial gallon was # defined in 1824 to be the volume of # water which weighed 10 pounds at 62 # deg F with a pressure of 30 inHg. # It was also defined as 277.274 in^3, # Which is slightly in error. In # 1963 it was defined to be the volume # occupied by 10 pounds of distilled # water of density 0.998859 g/ml weighed # in air of density 0.001217 g/ml # against weights of density 8.136 g/ml. # This gives a value of approximately # 4.5459645 liters, but the old liter # was in force at this time. In 1976 # the definition was changed to exactly # 4.54609 liters using the new # definition of the liter (1 dm^3). brbarrel 36 brgallon # Used for beer brbushel 8 brgallon brheapedbushel 1.278 brbushel brquarter 8 brbushel brchaldron 36 brbushel # Obscure British volume measures. These units are generally traditional # measures whose definitions have fluctuated over the years. Often they # depended on the quantity being measured. They are given here in terms of # British Imperial measures. For example, the puncheon may have historically # been defined relative to the wine gallon or beer gallon or ale gallon # rather than the British Imperial gallon. bag 4 brbushel bucket 4 brgallon kilderkin 2 brfirkin last 40 brbushel noggin brgill pottle 0.5 brgallon pin 4.5 brgallon puncheon 72 brgallon seam 8 brbushel coomb 4 brbushel boll 6 brbushel firlot 1|4 boll brfirkin 9 brgallon # Used for ale and beer cran 37.5 brgallon # measures herring, about 750 fish brwinehogshead 52.5 brgallon # This value is approximately equal brhogshead brwinehogshead # to the old wine hogshead of 63 # wine gallons. This adjustment # is listed in the OED and in # "The Weights and Measures of # England" by R. D. Connor brbeerhogshead 54 brgallon brbeerbutt 2 brbeerhogshead registerton 100 ft^3 # Used for internal capacity of ships shippington 40 ft^3 # Used for ship's cargo freight or timber brshippington 42 ft^3 # freightton shippington # Both register ton and shipping ton derive # from the "tun cask" of wine. displacementton 35 ft^3 # Approximate volume of a longton weight of # sea water. Measures water displaced by # ships. waterton 224 brgallon strike 70.5 l # 16th century unit, sometimes # defined as .5, 2, or 4 bushels # depending on the location. It # probably doesn't make a lot of # sense to define in terms of imperial # bushels. Zupko gives a value of # 2 Winchester grain bushels or about # 70.5 liters. amber 4 brbushel# Used for dry and liquid capacity [18] # British volume measures with "imperial" imperialminim brminim imperialscruple brscruple imperialdram brdram imperialfluidounce brfluidounce imperialfloz brfloz imperialgill brgill imperialpint brpint imperialquart brquart imperialgallon brgallon imperialbarrel brbarrel imperialbushel brbushel imperialheapedbushel brheapedbushel imperialquarter brquarter imperialchaldron brchaldron imperialwinehogshead brwinehogshead imperialhogshead brhogshead imperialbeerhogshead brbeerhogshead imperialbeerbutt brbeerbutt imperialfirkin brfirkin # obscure British lengths barleycorn 1|3 UKinch # Given in Realm of Measure as the # difference between successive shoe sizes nail 1|16 UKyard # Originally the width of the thumbnail, # or 1|16 ft. This took on the general # meaning of 1|16 and settled on the # nail of a yard or 1|16 yards as its # final value. [12] UKpole 16.5 UKft # This was 15 Saxon feet, the Saxon rope 20 UKft # foot (aka northern foot) being longer englishell 45 UKinch flemishell 27 UKinch ell englishell # supposed to be measure from elbow to # fingertips span 9 UKinch # supposed to be distance from thumb # to pinky with full hand extension goad 4.5 UKft # used for cloth, possibly named after the # stick used for prodding animals. # misc obscure British units hide 120 acre # English unit of land area dating to the 7th # century, originally the amount of land # that a single plowman could cultivate, # which varied from 60-180 acres regionally. # Standardized at Normon conquest. virgate 1|4 hide nook 1|2 virgate rood furlong rod # Area of a strip a rod by a furlong englishcarat troyounce/151.5 # Originally intended to be 4 grain # but this value ended up being # used in the London diamond market mancus 2 oz mast 2.5 lb nailkeg 100 lbs basebox 31360 in^2 # Used in metal plating # alternate spellings gramme gram litre liter dioptre diopter sulphur sulfur # # Units derived the human body (may not be very accurate) # geometricpace 5 ft # distance between points where the same # foot hits the ground pace 2.5 ft # distance between points where alternate # feet touch the ground USmilitarypace 30 in # United States official military pace USdoubletimepace 36 in # United States official doubletime pace fingerbreadth 7|8 in # The finger is defined as either the width fingerlength 4.5 in # or length of the finger finger fingerbreadth palmwidth hand # The palm is a unit defined as either the width palmlength 8 in # or the length of the hand hand 4 inch # width of hand shaftment 6 inch # Distance from tip of outstretched thumb to the # opposite side of the palm of the hand. The # ending -ment is from the old English word # for hand. [18] smoot 5 ft + 7 in # Created as part of an MIT fraternity prank. # In 1958 Oliver Smoot was used to measure # the length of the Harvard Bridge, which was # marked off in Smoot lengths. These # markings have been maintained on the bridge # since then and repainted by subsequent # incoming fraternity members. During a # bridge renovation the new sidewalk was # scored every Smoot rather than at the # customary 6 ft spacing. tomcruise 5 ft + 7.75 in # Height of Tom Cruise # # Cooking measures # # Common abbreviations tbl tablespoon tbsp tablespoon tblsp tablespoon Tb tablespoon tsp teaspoon saltspoon 1|4 tsp # US measures uscup 8 usfloz ustablespoon 1|16 uscup usteaspoon 1|3 ustablespoon ustbl ustablespoon ustbsp ustablespoon ustblsp ustablespoon ustsp usteaspoon metriccup 250 ml stickbutter 1|4 lb # Butter in the USA is sold in one # pound packages that contain four # individually wrapped pieces. The # pieces are marked into tablespoons, # making it possible to measure out # butter by volume by slicing the # butter. legalcup 240 ml # The cup used on nutrition labeling legaltablespoon 1|16 legalcup legaltbsp legaltablespoon # Scoop size. Ice cream scoops in the US are marked with numbers # indicating the number of scoops required to fill a US quart. scoop(n) units=[1;cup] domain=[4,100] range=[0.04,1] \ 32 usfloz / n ; 32 usfloz / scoop # US can sizes. number1can 10 usfloz number2can 19 usfloz number2.5can 3.5 uscups number3can 4 uscups number5can 7 uscups number10can 105 usfloz # British measures brcup 1|2 brpint brteacup 1|3 brpint brtablespoon 15 ml # Also 5|8 brfloz, approx 17.7 ml brteaspoon 1|3 brtablespoon # Also 1|4 brtablespoon brdessertspoon 2 brteaspoon dessertspoon brdessertspoon dsp dessertspoon brtsp brteaspoon brtbl brtablespoon brtbsp brtablespoon brtblsp brtablespoon # Australian australiatablespoon 20 ml austbl australiatablespoon austbsp australiatablespoon austblsp australiatablespoon australiateaspoon 1|4 australiatablespoon austsp australiateaspoon # Italian etto 100 g # Used for buying items like meat and etti etto # cheese. # Chinese catty 0.5 kg oldcatty 4|3 lbs # Before metric conversion. tael 1|16 oldcatty # Should the tael be defined both ways? mace 0.1 tael oldpicul 100 oldcatty picul 100 catty # Chinese usage # Indian seer 14400 grain # British Colonial standard ser seer maund 40 seer pakistanseer 1 kg pakistanmaund 40 pakistanseer chittak 1|16 seer tola 1|5 chittak ollock 1|4 liter # Is this right? # Japanese japancup 200 ml # densities of cooking ingredients from The Cake Bible by Rose Levy Beranbaum # so you can convert '2 cups sugar' to grams, for example, or in the other # direction grams could be converted to 'cup flour_scooped'. butter 8 oz/uscup butter_clarified 6.8 oz/uscup cocoa_butter 9 oz/uscup shortening 6.75 oz/uscup # vegetable shortening oil 7.5 oz/uscup cakeflour_sifted 3.5 oz/uscup # The density of flour depends on the cakeflour_spooned 4 oz/uscup # measuring method. "Scooped", or cakeflour_scooped 4.5 oz/uscup # "dip and sweep" refers to dipping a flour_sifted 4 oz/uscup # measure into a bin, and then sweeping flour_spooned 4.25 oz/uscup # the excess off the top. "Spooned" flour_scooped 5 oz/uscup # means to lightly spoon into a measure breadflour_sifted 4.25 oz/uscup # and then sweep the top. Sifted means breadflour_spooned 4.5 oz/uscup # sifting the flour directly into a breadflour_scooped 5.5 oz/uscup # measure and then sweeping the top. cornstarch 120 grams/uscup dutchcocoa_sifted 75 g/uscup # These are for Dutch processed cocoa dutchcocoa_spooned 92 g/uscup dutchcocoa_scooped 95 g/uscup cocoa_sifted 75 g/uscup # These are for nonalkalized cocoa cocoa_spooned 82 g/uscup cocoa_scooped 95 g/uscup heavycream 232 g/uscup milk 242 g/uscup sourcream 242 g/uscup molasses 11.25 oz/uscup cornsyrup 11.5 oz/uscup honey 11.75 oz/uscup sugar 200 g/uscup powdered_sugar 4 oz/uscup brownsugar_light 217 g/uscup # packed brownsugar_dark 239 g/uscup baking_powder 4.6 grams / ustsp salt 6 g / ustsp koshersalt 2.8 g / ustsp # Diamond Crystal kosher salt koshersalt_morton 4.8 g / ustsp # Morton kosher salt # Values are from the nutrition info # on the packages # Egg weights and volumes for a USA large egg egg 50 grams # without shell eggwhite 30 grams eggyolk 18.6 grams eggvolume 3 ustablespoons + 1|2 ustsp eggwhitevolume 2 ustablespoons eggyolkvolume 3.5 ustsp # Alcohol density ethanoldensity 0.7893 g/cm^3 # From CRC Handbook, 91st Edition alcoholdensity ethanoldensity # # Density measures. Density has traditionally been measured on a variety of # bizarre nonlinear scales. # # Density of a sugar syrup is frequently measured in candy making procedures. # In the USA the boiling point of the syrup is measured. Some recipes instead # specify the density using degrees Baume. Conversion between degrees Baume # and the boiling point measure has proved elusive. This table appeared in one # text, and provides a fragmentary relationship to the concentration. # # temp(C) conc (%) # 100 30 # 101 40 # 102 50 # 103 60 # 106 70 # 112 80 # 123 90 # 140 95 # 151 97 # 160 98.2 # 166 99.5 # 171 99.6 # # The best source identified to date came from "Boiling point elevation of # technical sugarcane solutions and its use in automatic pan boiling" by # Michael Saska. International Sugar Journal, 2002, 104, 1247, pp 500-507. # # But I'm using equation (3) which is credited to Starzak and Peacock, # "Water activity coefficient in aqueous solutions of sucrose--A comprehensive # data analysis. Zuckerindustrie, 122, 380-387. (I couldn't find this # document.) # # Note that the range of validity is uncertain, but answers are in agreement # with the above table all the way to 99.6. # # The original equation has a parameter for the boiling point of water, which # of course varies with altitude. It also includes various other model # parameters. The input is the molar concentration of sucrose in the solution, # (moles sucrose) / (total moles). # # Bsp 3797.06 degC # Csp 226.28 degC # QQ -17638 J/mol # asp -1.0038 # bsp -0.24653 # tbw 100 degC # boiling point of water # sugar_bpe_orig(x) ((1-QQ/R Bsp * x^2 (1+asp x + bsp x^2) (tbw + Csp) \ # /(tbw+stdtemp)) / (1+(tbw + Csp)/Bsp *ln(1-x))-1) * (tbw + Csp) # # To convert mass concentration (brix) to molar concentration # # sc(x) (x / 342.3) / (( x/342.3) + (100-x)/18.02); \ # 100 sc 342.3|18.02 / (sc (342.3|18.02-1)+1) # # Here is a simplified version of this equation where the temperature of boiling # water has been fixed at 100 degrees Celsius and the argument is now the # concentration (brix). # # sugar_bpe(x) ((1+ 0.48851085 * sc(x)^2 (1+ -1.0038 sc(x) + -0.24653 sc(x)^2)) \ # / (1+0.08592964 ln(1-sc(x)))-1) 326.28 K # # # The formula is not invertible, so to implement it in units we unfortunately # must turn it into a table. # This table gives the boiling point elevation as a function of the sugar syrup # concentration expressed as a percentage. sugar_conc_bpe[K] \ 0 0.0000 5 0.0788 10 0.1690 15 0.2729 20 0.3936 25 0.5351 \ 30 0.7027 35 0.9036 40 1.1475 42 1.2599 44 1.3825 46 1.5165 \ 48 1.6634 50 1.8249 52 2.0031 54 2.2005 56 2.4200 58 2.6651 \ 60 2.9400 61 3.0902 62 3.2499 63 3.4198 64 3.6010 65 3.7944 \ 66 4.0012 67 4.2227 68 4.4603 69 4.7156 70 4.9905 71 5.2870 \ 72 5.6075 73 5.9546 74 6.3316 75 6.7417 76 7.1892 77 7.6786 \ 78.0 8.2155 79.0 8.8061 80.0 9.4578 80.5 9.8092 81.0 10.1793 \ 81.5 10.5693 82.0 10.9807 82.5 11.4152 83.0 11.8743 83.5 12.3601 \ 84.0 12.8744 84.5 13.4197 85.0 13.9982 85.5 14.6128 86.0 15.2663 \ 86.5 15.9620 87.0 16.7033 87.5 17.4943 88.0 18.3391 88.5 19.2424 \ 89.0 20.2092 89.5 21.2452 90.0 22.3564 90.5 23.5493 91.0 24.8309 \ 91.5 26.2086 92.0 27.6903 92.5 29.2839 93.0 30.9972 93.5 32.8374 \ 94.0 34.8104 94.5 36.9195 95.0 39.1636 95.5 41.5348 96.0 44.0142 \ 96.5 46.5668 97.0 49.1350 97.5 51.6347 98.0 53.9681 98.1 54.4091 \ 98.2 54.8423 98.3 55.2692 98.4 55.6928 98.5 56.1174 98.6 56.5497 \ 98.7 56.9999 98.8 57.4828 98.9 58.0206 99.0 58.6455 99.1 59.4062 \ 99.2 60.3763 99.3 61.6706 99.4 63.4751 99.5 66.1062 99.6 70.1448 \ 99.7 76.7867 # Using the brix table we can use this to produce a mapping from boiling point # to density which makes all of the units interconvertible. Because the brix # table stops at 95 this approach works up to a boiling point elevation of 39 K # or a boiling point of 139 C / 282 F, which is the "soft crack" stage in candy # making. The "hard crack" stage continues up to 310 F. # Boiling point elevation sugar_bpe(T) units=[K;g/cm^3] domain=[0,39.1636] range=[0.99717,1.5144619] \ brix(~sugar_conc_bpe(T)); sugar_conc_bpe(~brix(sugar_bpe)) # Absolute boiling point (produces an absolute temperature) sugar_bp(T) units=[K;g/cm^3] domain=[373.15,412.3136] \ range=[0.99717,1.5144619] \ brix(~sugar_conc_bpe(T-tempC(100))) ;\ sugar_conc_bpe(~brix(sugar_bp))+tempC(100) # In practice dealing with the absolute temperature is annoying because it is # not possible to convert to a nested function, so you're stuck retyping the # absolute temperature in Kelvins to convert to celsius or Fahrenheit. To # prevent this we supply definitions that build in the temperature conversion # and produce results in the Fahrenheit and Celsius scales. So using these # measures, to convert 46 degrees Baume to a Fahrenheit boiling point: # # You have: baume(45) # You want: sugar_bpF # 239.05647 # sugar_bpF(T) units=[1;g/cm^3] domain=[212,282.49448] range=[0.99717,1.5144619]\ brix(~sugar_conc_bpe(tempF(T)+-tempC(100))) ;\ ~tempF(sugar_conc_bpe(~brix(sugar_bpF))+tempC(100)) sugar_bpC(T) units=[1;g/cm^3] domain=[100,139.1636] range=[0.99717,1.5144619]\ brix(~sugar_conc_bpe(tempC(T)+-tempC(100))) ;\ ~tempC(sugar_conc_bpe(~brix(sugar_bpC))+tempC(100)) # Degrees Baume is used in European recipes to specify the density of a sugar # syrup. An entirely different definition is used for densities below # 1 g/cm^3. An arbitrary constant appears in the definition. This value is # equal to 145 in the US, but was according to [], the old scale used in # Holland had a value of 144, and the new scale or Gerlach scale used 146.78. baumeconst 145 # US value baume(d) units=[1;g/cm^3] domain=[0,145) range=[1,) \ (baumeconst/(baumeconst+-d)) g/cm^3 ; \ (baume+((-g)/cm^3)) baumeconst / baume # It's not clear if this value was ever used with negative degrees. twaddell(x) units=[1;g/cm^3] domain=[-200,) range=[0,) \ (1 + 0.005 x) g / cm^3 ; \ 200 (twaddell / (g/cm^3) +- 1) # The degree quevenne is a unit for measuring the density of milk. # Similarly it's unclear if negative values were allowed here. quevenne(x) units=[1;g/cm^3] domain=[-1000,) range=[0,) \ (1 + 0.001 x) g / cm^3 ; \ 1000 (quevenne / (g/cm^3) +- 1) # Degrees brix measures sugar concentration by weigh as a percentage, so a # solution that is 3 degrees brix is 3% sugar by weight. This unit was named # after Adolf Brix who invented a hydrometer that read this percentage # directly. This data is from Table 114 of NIST Circular 440, "Polarimetry, # Saccharimetry and the Sugars". It gives apparent specific gravity at 20 # degrees Celsius of various sugar concentrations. As rendered below this # data is converted to apparent density at 20 degrees Celsius using the # density figure for water given in the same NIST reference. They use the # word "apparent" to refer to measurements being made in air with brass # weights rather than vacuum. brix[0.99717g/cm^3]\ 0 1.00000 1 1.00390 2 1.00780 3 1.01173 4 1.01569 5 1.01968 \ 6 1.02369 7 1.02773 8 1.03180 9 1.03590 10 1.04003 11 1.04418 \ 12 1.04837 13 1.05259 14 1.05683 15 1.06111 16 1.06542 17 1.06976 \ 18 1.07413 19 1.07853 20 1.08297 21 1.08744 22 1.09194 23 1.09647 \ 24 1.10104 25 1.10564 26 1.11027 27 1.11493 28 1.11963 29 1.12436 \ 30 1.12913 31 1.13394 32 1.13877 33 1.14364 34 1.14855 35 1.15350 \ 36 1.15847 37 1.16349 38 1.16853 39 1.17362 40 1.17874 41 1.18390 \ 42 1.18910 43 1.19434 44 1.19961 45 1.20491 46 1.21026 47 1.21564 \ 48 1.22106 49 1.22652 50 1.23202 51 1.23756 52 1.24313 53 1.24874 \ 54 1.25439 55 1.26007 56 1.26580 57 1.27156 58 1.27736 59 1.28320 \ 60 1.28909 61 1.29498 62 1.30093 63 1.30694 64 1.31297 65 1.31905 \ 66 1.32516 67 1.33129 68 1.33748 69 1.34371 70 1.34997 71 1.35627 \ 72 1.36261 73 1.36900 74 1.37541 75 1.38187 76 1.38835 77 1.39489 \ 78 1.40146 79 1.40806 80 1.41471 81 1.42138 82 1.42810 83 1.43486 \ 84 1.44165 85 1.44848 86 1.45535 87 1.46225 88 1.46919 89 1.47616 \ 90 1.48317 91 1.49022 92 1.49730 93 1.50442 94 1.51157 95 1.51876 # Density measure invented by the American Petroleum Institute. Lighter # petroleum products are more valuable, and they get a higher API degree. # # The intervals of range and domain should be open rather than closed. # apidegree(x) units=[1;g/cm^3] domain=[-131.5,) range=[0,) \ 141.5 g/cm^3 / (x+131.5) ; \ 141.5 (g/cm^3) / apidegree + (-131.5) # # Average densities of various woods (dried) # Data from The Wood Database https://www.wood-database.com # # North American Hardwoods wood_cherry 35 lb/ft^3 wood_redoak 44 lb/ft^3 wood_whiteoak 47 lb/ft^3 wood_blackwalnut 38 lb/ft^3 wood_walnut wood_blackwalnut wood_birch 43 lb/ft^3 wood_hardmaple 44 lb/ft^3 wood_bigleafmaple 34 lb/ft^3 wood_boxeldermaple 30 lb/ft^3 wood_redmaple 38 lb/ft^3 wood_silvermaple 33 lb/ft^3 wood_stripedmaple 32 lb/ft^3 wood_softmaple (wood_bigleafmaple \ + wood_boxeldermaple \ + wood_redmaple \ + wood_silvermaple \ + wood_stripedmaple) / 5 wood_poplar 29 lb/ft^3 wood_beech 45 lb/ft^3 # North American Softwoods wood_jeffreypine 28 lb/ft^3 wood_ocotepine 44 lb/ft^3 wood_ponderosapine 28 lb/ft^3 wood_loblollypine 35 lb/ft^3 wood_longleafpine 41 lb/ft^3 wood_shortleafpine 35 lb/ft^3 wood_slashpine 41 lb/ft^3 wood_yellowpine (wood_loblollypine \ + wood_longleafpine \ + wood_shortleafpine \ + wood_slashpine) / 4 wood_redpine 34 lb/ft^3 wood_easternwhitepine 25 lb/ft^3 wood_westernwhitepine 27 lb/ft^3 wood_whitepine (wood_easternwhitepine + wood_westernwhitepine) / 2 wood_douglasfir 32 lb/ft^3 wood_blackspruce 28 lb/ft^3 wood_engelmannspruce 24 lb/ft^3 wood_redspruce 27 lb/ft^3 wood_sitkaspruce 27 lb/ft^3 wood_whitespruce 27 lb/ft^3 wood_spruce (wood_blackspruce \ + wood_engelmannspruce \ + wood_redspruce \ + wood_sitkaspruce \ + wood_whitespruce) / 5 # Other woods wood_basswood 26 lb/ft^3 wood_balsa 9 lb/ft^3 wood_ebony_gaboon 60 lb/ft^3 wood_ebony_macassar 70 lb/ft^3 wood_mahogany 37 lb/ft^3 # True (Honduran) mahogany, # Swietenia macrophylla wood_teak 41 lb/ft^3 wood_rosewood_brazilian 52 lb/ft^3 wood_rosewood_honduran 64 lb/ft^3 wood_rosewood_indian 52 lb/ft^3 wood_cocobolo 69 lb/ft^3 wood_bubinga 56 lb/ft^3 wood_zebrawood 50 lb/ft^3 wood_koa 38 lb/ft^3 wood_snakewood 75.7 lb/ft^3 wood_lignumvitae 78.5 lb/ft^3 wood_blackwood 79.3 lb/ft^3 wood_blackironwood 84.5 lb/ft^3 # Krugiodendron ferreum, listed # in database as the heaviest wood # # Modulus of elasticity of selected woods. # Data from The Wood Database https://www.wood-database.com # # North American Hardwoods wood_mod_beech 1.720e6 lbf/in^2 wood_mod_birchyellow 2.010e6 lbf/in^2 wood_mod_birch wood_mod_birchyellow wood_mod_cherry 1.490e6 lbf/in^2 wood_mod_hardmaple 1.830e6 lbf/in^2 wood_mod_bigleafmaple 1.450e6 lbf/in^2 wood_mod_boxeldermaple 1.050e6 lbf/in^2 wood_mod_redmaple 1.640e6 lbf/in^2 wood_mod_silvermaple 1.140e6 lbf/in^2 wood_mod_softmaple (wood_mod_bigleafmaple \ + wood_mod_boxeldermaple \ + wood_mod_redmaple \ + wood_mod_silvermaple) / 4 wood_mod_redoak 1.761e6 lbf/in^2 wood_mod_whiteoak 1.762e6 lbf/in^2 wood_mod_poplar 1.580e6 lbf/in^2 wood_mod_blackwalnut 1.680e6 lbf/in^2 wood_mod_walnut wood_mod_blackwalnut # North American Softwoods wood_mod_jeffreypine 1.240e6 lbf/in^2 wood_mod_ocotepine 2.209e6 lbf/in^2 wood_mod_ponderosapine 1.290e6 lbf/in^2 wood_mod_loblollypine 1.790e6 lbf/in^2 wood_mod_longleafpine 1.980e6 lbf/in^2 wood_mod_shortleafpine 1.750e6 lbf/in^2 wood_mod_slashpine 1.980e6 lbf/in^2 wood_mod_yellowpine (wood_mod_loblollypine \ + wood_mod_longleafpine \ + wood_mod_shortleafpine \ + wood_mod_slashpine) / 4 wood_mod_redpine 1.630e6 lbf/in^2 wood_mod_easternwhitepine 1.240e6 lbf/in^2 wood_mod_westernwhitepine 1.460e6 lbf/in^2 wood_mod_whitepine (wood_mod_easternwhitepine + \ wood_mod_westernwhitepine) / 2 wood_mod_douglasfir 1.765e6 lbf/in^2 wood_mod_blackspruce 1.523e6 lbf/in^2 wood_mod_englemannspruce 1.369e6 lbf/in^2 wood_mod_redspruce 1.560e6 lbf/in^2 wood_mod_sitkaspruce 1.600e6 lbf/in^2 wood_mod_whitespruce 1.315e6 lbf/in^2 wood_mod_spruce (wood_mod_blackspruce \ + wood_mod_englemannspruce \ + wood_mod_redspruce + wood_mod_sitkaspruce \ + wood_mod_whitespruce) / 5 # Other woods wood_mod_balsa 0.538e6 lbf/in^2 wood_mod_basswood 1.460e6 lbf/in^2 wood_mod_blackwood 2.603e6 lbf/in^2 # African, Dalbergia melanoxylon wood_mod_bubinga 2.670e6 lbf/in^2 wood_mod_cocobolo 2.712e6 lbf/in^2 wood_mod_ebony_gaboon 2.449e6 lbf/in^2 wood_mod_ebony_macassar 2.515e6 lbf/in^2 wood_mod_blackironwood 2.966e6 lbf/in^2 # Krugiodendron ferreum wood_mod_koa 1.503e6 lbf/in^2 wood_mod_lignumvitae 2.043e6 lbf/in^2 wood_mod_mahogany 1.458e6 lbf/in^2 # True (Honduran) mahogany, # Swietenia macrophylla wood_mod_rosewood_brazilian 2.020e6 lbf/in^2 wood_mod_rosewood_honduran 3.190e6 lbf/in^2 wood_mod_rosewood_indian 1.668e6 lbf/in^2 wood_mod_snakewood 3.364e6 lbf/in^2 wood_mod_teak 1.781e6 lbf/in^2 wood_mod_zebrawood 2.374e6 lbf/in^2 # # Area of countries and other regions. This is the "total area" which # includes land and water areas within international boundaries and # coastlines. Data from January, 2019. # # except as noted, sources are # https://en.wikipedia.org/wiki/List_of_countries_and_dependencies_by_area # US Central Intelligence Agency: The World Factbook # https://www.cia.gov/the-world-factbook/ area_russia 17098246 km^2 area_antarctica 14000000 km^2 # area_canada is covered below as sum of province and territory areas area_china 9596961 km^2 # area_unitedstates is covered below as sum of state areas # includes only the 50 states and District of Columbia area_us area_unitedstates area_brazil 8515767 km^2 area_australia 7692024 km^2 # area_europeanunion is covered below as sum of member areas area_india 3287263 km^2 area_argentina 2780400 km^2 area_kazakhstan 2724900 km^2 area_algeria 2381741 km^2 area_drcongo 2344858 km^2 area_greenland 2166086 km^2 area_saudiarabia 2149690 km^2 area_mexico 1964375 km^2 area_indonesia 1910931 km^2 area_sudan 1861484 km^2 area_libya 1759540 km^2 area_iran 1648195 km^2 area_mongolia 1564110 km^2 area_peru 1285216 km^2 area_chad 1284000 km^2 area_niger 1267000 km^2 area_angola 1246700 km^2 area_mali 1240192 km^2 area_southafrica 1221037 km^2 area_colombia 1141748 km^2 area_ethiopia 1104300 km^2 area_bolivia 1098581 km^2 area_mauritania 1030700 km^2 area_egypt 1002450 km^2 area_tanzania 945087 km^2 area_nigeria 923768 km^2 area_venezuela 916445 km^2 area_pakistan 881912 km^2 area_namibia 825615 km^2 area_mozambique 801590 km^2 area_turkey 783562 km^2 area_chile 756102 km^2 area_zambia 752612 km^2 area_myanmar 676578 km^2 area_burma area_myanmar area_afghanistan 652230 km^2 area_southsudan 644329 km^2 area_france 640679 km^2 area_somalia 637657 km^2 area_centralafrica 622984 km^2 area_ukraine 603500 km^2 area_crimea 27000 km^2 # occupied by Russia; included in # (Encyclopedia Britannica) area_madagascar 587041 km^2 area_botswana 581730 km^2 area_kenya 580367 km^2 area_yemen 527968 km^2 area_thailand 513120 km^2 area_spain 505992 km^2 area_turkmenistan 488100 km^2 area_cameroon 475422 km^2 area_papuanewguinea 462840 km^2 area_sweden 450295 km^2 area_uzbekistan 447400 km^2 area_morocco 446550 km^2 area_iraq 438317 km^2 area_paraguay 406752 km^2 area_zimbabwe 390757 km^2 area_japan 377973 km^2 area_germany 357114 km^2 area_congorepublic 342000 km^2 area_finland 338424 km^2 area_vietnam 331212 km^2 area_malaysia 330803 km^2 area_norway 323802 km^2 area_ivorycoast 322463 km^2 area_poland 312696 km^2 area_oman 309500 km^2 area_italy 301339 km^2 area_philippines 300000 km^2 area_ecuador 276841 km^2 area_burkinafaso 274222 km^2 area_newzealand 270467 km^2 area_gabon 267668 km^2 area_westernsahara 266000 km^2 area_guinea 245857 km^2 # area_unitedkingdom is covered below area_uganda 241550 km^2 area_ghana 238533 km^2 area_romania 238397 km^2 area_laos 236800 km^2 area_guyana 214969 km^2 area_belarus 207600 km^2 area_kyrgyzstan 199951 km^2 area_senegal 196722 km^2 area_syria 185180 km^2 area_golanheights 1150 km^2 # occupied by Israel; included in # Syria (Encyclopedia Britannica) area_cambodia 181035 km^2 area_uruguay 176215 km^2 area_somaliland 176120 km^2 area_suriname 163820 km^2 area_tunisia 163610 km^2 area_bangladesh 147570 km^2 area_nepal 147181 km^2 area_tajikistan 143100 km^2 area_greece 131990 km^2 area_nicaragua 130373 km^2 area_northkorea 120540 km^2 area_malawi 118484 km^2 area_eritrea 117600 km^2 area_benin 114763 km^2 area_honduras 112492 km^2 area_liberia 111369 km^2 area_bulgaria 110879 km^2 area_cuba 109884 km^2 area_guatemala 108889 km^2 area_iceland 103000 km^2 area_southkorea 100210 km^2 area_hungary 93028 km^2 area_portugal 92090 km^2 area_jordan 89342 km^2 area_serbia 88361 km^2 area_azerbaijan 86600 km^2 area_austria 83871 km^2 area_uae 83600 km^2 area_czechia 78865 km^2 area_czechrepublic area_czechia area_panama 75417 km^2 area_sierraleone 71740 km^2 area_ireland 70273 km^2 area_georgia 69700 km^2 area_srilanka 65610 km^2 area_lithuania 65300 km^2 area_latvia 64559 km^2 area_togo 56785 km^2 area_croatia 56594 km^2 area_bosnia 51209 km^2 area_costarica 51100 km^2 area_slovakia 49037 km^2 area_dominicanrepublic 48671 km^2 area_estonia 45227 km^2 area_denmark 43094 km^2 area_netherlands 41850 km^2 area_switzerland 41284 km^2 area_bhutan 38394 km^2 area_taiwan 36193 km^2 area_guineabissau 36125 km^2 area_moldova 33846 km^2 area_belgium 30528 km^2 area_lesotho 30355 km^2 area_armenia 29743 km^2 area_solomonislands 28896 km^2 area_albania 28748 km^2 area_equitorialguinea 28051 km^2 area_burundi 27834 km^2 area_haiti 27750 km^2 area_rwanda 26338 km^2 area_northmacedonia 25713 km^2 area_djibouti 23200 km^2 area_belize 22966 km^2 area_elsalvador 21041 km^2 area_israel 20770 km^2 area_slovenia 20273 km^2 area_fiji 18272 km^2 area_kuwait 17818 km^2 area_eswatini 17364 km^2 area_easttimor 14919 km^2 area_bahamas 13943 km^2 area_montenegro 13812 km^2 area_vanatu 12189 km^2 area_qatar 11586 km^2 area_gambia 11295 km^2 area_jamaica 10991 km^2 area_kosovo 10887 km^2 area_lebanon 10452 km^2 area_cyprus 9251 km^2 area_puertorico 9104 km^2 # United States territory; not included # in United States area area_westbank 5860 km^2 # (CIA World Factbook) area_hongkong 2755 km^2 area_luxembourg 2586 km^2 area_singapore 716 km^2 area_gazastrip 360 km^2 # (CIA World Factbook) area_malta 316 km^2 # smallest EU country area_liechtenstein 160 km^2 area_monaco 2.02 km^2 area_vaticancity 0.44 km^2 # Members as of 1 Feb 2020 area_europeanunion area_austria + area_belgium + area_bulgaria \ + area_croatia + area_cyprus + area_czechia + area_denmark \ + area_estonia + area_finland + area_france + area_germany \ + area_greece + area_hungary + area_ireland + area_italy \ + area_latvia + area_lithuania + area_luxembourg \ + area_malta + area_netherlands + area_poland \ + area_portugal + area_romania + area_slovakia \ + area_slovenia + area_spain + area_sweden area_eu area_europeanunion # # Areas of the individual US states # # https://en.wikipedia.org/wiki/List_of_U.S._states_and_territories_by_area # # United States Summary: 2010, Population and Housing Unit Counts, Table 18, p. 41 # Issued September 2012 area_alaska 1723336.8 km^2 area_texas 695661.6 km^2 area_california 423967.4 km^2 area_montana 380831.1 km^2 area_newmexico 314917.4 km^2 area_arizona 295233.5 km^2 area_nevada 286379.7 km^2 area_colorado 269601.4 km^2 area_oregon 254799.2 km^2 area_wyoming 253334.5 km^2 area_michigan 250486.8 km^2 area_minnesota 225162.8 km^2 area_utah 219881.9 km^2 area_idaho 216442.6 km^2 area_kansas 213100.0 km^2 area_nebraska 200329.9 km^2 area_southdakota 199728.7 km^2 area_washington 184660.8 km^2 area_northdakota 183107.8 km^2 area_oklahoma 181037.2 km^2 area_missouri 180540.3 km^2 area_florida 170311.7 km^2 area_wisconsin 169634.8 km^2 area_georgia_us 153910.4 km^2 area_illinois 149995.4 km^2 area_iowa 145745.9 km^2 area_newyork 141296.7 km^2 area_northcarolina 139391.0 km^2 area_arkansas 137731.8 km^2 area_alabama 135767.4 km^2 area_louisiana 135658.7 km^2 area_mississippi 125437.7 km^2 area_pennsylvania 119280.2 km^2 area_ohio 116097.7 km^2 area_virginia 110786.6 km^2 area_tennessee 109153.1 km^2 area_kentucky 104655.7 km^2 area_indiana 94326.2 km^2 area_maine 91633.1 km^2 area_southcarolina 82932.7 km^2 area_westvirginia 62755.5 km^2 area_maryland 32131.2 km^2 area_hawaii 28313.0 km^2 area_massachusetts 27335.7 km^2 area_vermont 24906.3 km^2 area_newhampshire 24214.2 km^2 area_newjersey 22591.4 km^2 area_connecticut 14357.4 km^2 area_delaware 6445.8 km^2 area_rhodeisland 4001.2 km^2 area_districtofcolumbia 177.0 km^2 area_unitedstates area_alabama + area_alaska + area_arizona \ + area_arkansas + area_california + area_colorado \ + area_connecticut + area_delaware \ + area_districtofcolumbia + area_florida \ + area_georgia_us + area_hawaii + area_idaho \ + area_illinois + area_indiana + area_iowa \ + area_kansas + area_kentucky + area_louisiana \ + area_maine + area_maryland + area_massachusetts \ + area_michigan + area_minnesota + area_mississippi \ + area_missouri + area_montana + area_nebraska \ + area_nevada + area_newhampshire + area_newjersey \ + area_newmexico + area_newyork + area_northcarolina \ + area_northdakota + area_ohio + area_oklahoma \ + area_oregon + area_pennsylvania + area_rhodeisland \ + area_southcarolina + area_southdakota \ + area_tennessee + area_texas + area_utah \ + area_vermont + area_virginia + area_washington \ + area_westvirginia + area_wisconsin + area_wyoming # Total area of Canadian province and territories # # Statistics Canada, "Land and freshwater area, by province and territory", # 2016-10-07: # # https://www150.statcan.gc.ca/n1/pub/11-402-x/2012000/chap/geo/tbl/tbl06-eng.htm area_ontario 1076395 km^2 # confederated 1867-Jul-01 area_quebec 1542056 km^2 # confederated 1867-Jul-01 area_novascotia 55284 km^2 # confederated 1867-Jul-01 area_newbrunswick 72908 km^2 # confederated 1867-Jul-01 area_canada_original area_ontario + area_quebec + area_novascotia \ + area_newbrunswick area_manitoba 647797 km^2 # confederated 1870-Jul-15 area_britishcolumbia 944735 km^2 # confederated 1871-Jul-20 area_princeedwardisland 5660 km^2 # confederated 1873-Jul-01 area_canada_additional area_manitoba + area_britishcolumbia \ + area_princeedwardisland area_alberta 661848 km^2 # confederated 1905-Sep-01 area_saskatchewan 651036 km^2 # confederated 1905-Sep-01 area_newfoundlandandlabrador 405212 km^2 # confederated 1949-Mar-31 area_canada_recent area_alberta + area_saskatchewan \ + area_newfoundlandandlabrador area_canada_provinces area_canada_original + area_canada_additional \ + area_canada_recent area_northwestterritories 1346106 km^2 # NT confederated 1870-Jul-15 area_yukon 482443 km^2 # YT confederated 1898-Jun-13 area_nunavut 2093190 km^2 # NU confederated 1999-Apr-01 area_canada_territories area_northwestterritories + area_yukon \ + area_nunavut area_canada area_canada_provinces + area_canada_territories # area-uk-countries.units - UK country (/province) total areas # https://en.wikipedia.org/wiki/Countries_of_the_United_Kingdom#Statistics # GB is official UK country code for some purposes but internally is a Kingdom # # areas from A Beginners Guide to UK Geography 2019 v1.0, Office for National Statistics # England: country; 0927-Jul-12 united; 1603-Mar-24 union of crowns area_england 132947.76 km^2 # # Wales: 1282 conquered; 1535 union; principality until 2011 area_wales 21224.48 km^2 # # England and Wales: nation; 1535 union area_englandwales area_england + area_wales # # Scotland: country; ~900 united; 1603-Mar-24 union of crowns area_scotland 80226.36 km^2 # # Great Britain: kingdom; excludes NI; # 1707 Treaty and Acts of Union: union of parliaments area_greatbritain area_england + area_wales + area_scotland area_gb area_greatbritain # # Northern Ireland: province; Ireland: 1177 Henry II lordship; # 1542 Henry VIII kingdom; 1652 Cromwell commonwealth; # 1691 William III kingdom; 1800 Acts of Union: UK of GB & Ireland; # 1921 Irish Free State independent of UK area_northernireland 14133.38 km^2 # # United Kingdom of GB & NI: 1800 Acts of Union: UK of GB & Ireland; # 1921 Irish Free State independent of UK area_unitedkingdom area_greatbritain + area_northernireland area_uk area_unitedkingdom # # Units derived from imperial system # ouncedal oz ft / s^2 # force which accelerates an ounce # at 1 ft/s^2 poundal lb ft / s^2 # same thing for a pound tondal longton ft / s^2 # and for a ton pdl poundal osi ounce force / inch^2 # used in aviation psi pound force / inch^2 psia psi # absolute pressure # Note that gauge pressure can be given # using the gaugepressure() and # psig() nonlinear unit definitions tsi ton force / inch^2 reyn psi sec slug lbf s^2 / ft slugf slug force slinch lbf s^2 / inch # Mass unit derived from inch second slinchf slinch force # pound-force system. Used in space # applications where in/sec^2 was a # natural acceleration measure. geepound slug lbf lb force tonf ton force lbm lb kip 1000 lbf # from kilopound ksi kip / in^2 mil 0.001 inch thou 0.001 inch tenth 0.0001 inch # one tenth of one thousandth of an inch millionth 1e-6 inch # one millionth of an inch circularinch 1|4 pi in^2 # area of a one-inch diameter circle circleinch circularinch # A circle with diameter d inches has # an area of d^2 circularinches cylinderinch circleinch inch # Cylinder h inch tall, d inches diameter # has volume d^2 h cylinder inches circularmil 1|4 pi mil^2 # area of one-mil diameter circle cmil circularmil MCM kcmil # older initialism for thousand circular mills cental 100 pound centner cental # Shotgun gauge measures the inside diameter of the barrel by counting # the number of spherical lead balls you can make to fit that barrel # using a pound of lead. Equivalently, this means that an n gauge gun # has a bore diameter that fits a ball of lead that weighs 1|n pounds shotgungauge(ga) units=[1;m] domain=(0,] range=(0,] \ 2 ~spherevol(1 pound / ga leaddensity) ; \ 1 pound / leaddensity spherevol(shotgungauge/2) shotgunga() shotgungauge caliber 0.01 inch # for measuring bullets duty ft lbf celo ft / s^2 jerk ft / s^3 australiapoint 0.01 inch # The "point" is used to measure rainfall # in Australia sabin ft^2 # Measure of sound absorption equal to the # absorbing power of one square foot of # a perfectly absorbing material. The # sound absorptivity of an object is the # area times a dimensionless # absorptivity coefficient. standardgauge 4 ft + 8.5 in # Standard width between railroad track flag 5 ft^2 # Construction term referring to sidewalk. rollwallpaper 30 ft^2 # Area of roll of wall paper fillpower in^3 / ounce # Density of down at standard pressure. # The best down has 750-800 fillpower. pinlength 1|16 inch # A #17 pin is 17/16 in long in the USA. buttonline 1|40 inch # The line was used in 19th century USA # to measure width of buttons. beespace 1|4 inch # Bees will fill any space that is smaller # than the bee space and leave open # spaces that are larger. The size of # the space varies with species. diamond 8|5 ft # Marking on US tape measures that is # useful to carpenters who wish to place # five studs in an 8 ft distance. Note # that the numbers appear in red every # 16 inches as well, giving six # divisions in 8 feet. retmaunit 1.75 in # Height of rack mountable equipment. U retmaunit # Equipment should be 1|32 inch narrower RU U # than its U measurement indicates to # allow for clearance, so 4U=(6+31|32)in # RETMA stands for the former name of # the standardizing organization, Radio # Electronics Television Manufacturers # Association. This organization is now # called the Electronic Industries # Alliance (EIA) and the rack standard # is specified in EIA RS-310-D. count per pound # For measuring the size of shrimp flightlevel 100 ft # Flight levels are used to ensure safe FL flightlevel # vertical separation between aircraft # despite variations in local air # pressure. Flight levels define # altitudes based on a standard air # pressure so that altimeter calibration # is not needed. This means that # aircraft at separated flight levels # are guaranteed to be separated. # Hence the definition of 100 feet is # a nominal, not true, measure. # Customarily written with no space in # the form FL290, which will not work in # units. But note "FL 290" will work. # # Other units of work, energy, power, etc # # Calorie: approximate energy to raise a gram of water one degree celsius calorie cal_th # Default is the thermochemical calorie cal calorie calorie_th 4.184 J # Thermochemical calorie, defined in 1930 thermcalorie calorie_th # by Frederick Rossini as 4.1833 J to cal_th calorie_th # avoid difficulties associated with the # uncertainty in the heat capacity of # water. In 1948 the value of the joule # was changed, so the thermochemical # calorie was redefined to 4.184 J. # This kept the energy measured by this # unit the same. calorie_IT 4.1868 J # International (Steam) Table calorie, cal_IT calorie_IT # defined in 1929 as watt-hour/860 or # equivalently 180|43 joules. At this # time the international joule had a # different value than the modern joule, # and the values were different in the # USA and in Europe. In 1956 at the # Fifth International Conference on # Properties of Steam the exact # definition given here was adopted. calorie_15 4.18580 J # Energy to go from 14.5 to 15.5 degC cal_15 calorie_15 calorie_fifteen cal_15 calorie_20 4.18190 J # Energy to go from 19.5 to 20.5 degC cal_20 calorie_20 calorie_twenty calorie_20 calorie_4 4.204 J # Energy to go from 3.5 to 4.5 degC cal_4 calorie_4 calorie_four calorie_4 cal_mean 4.19002 J # 1|100 energy to go from 0 to 100 degC Calorie kilocalorie # the food Calorie thermie 1e6 cal_15 # Heat required to raise the # temperature of a tonne of # water from 14.5 to 15.5 degC. # btu definitions: energy to raise a pound of water 1 degF btu btu_IT # International Table BTU is the default britishthermalunit btu btu_IT cal_IT lb degF / gram K btu_th cal_th lb degF / gram K btu_mean cal_mean lb degF / gram K btu_15 cal_15 lb degF / gram K btu_ISO 1055.06 J # Exact, rounded ISO definition based # on the IT calorie quad quadrillion btu ECtherm 1e5 btu_ISO # Exact definition UStherm 1.054804e8 J # Exact definition therm UStherm # Water latent heat from [23] water_fusion_heat 6.01 kJ/mol / (18.015 g/mol) # At 0 deg C water_vaporization_heat 2256.4 J/g # At saturation, 100 deg C, 101.42 kPa # Specific heat capacities of various substances # SPECIFIC_HEAT ENERGY / MASS / TEMPERATURE_DIFFERENCE SPECIFIC_HEAT_CAPACITY ENERGY / MASS / TEMPERATURE_DIFFERENCE specificheat_water calorie / g K water_specificheat specificheat_water # Values from www.engineeringtoolbox.com/specific-heat-metals-d_152.html specificheat_aluminum 0.91 J/g K specificheat_antimony 0.21 J/g K specificheat_barium 0.20 J/g K specificheat_beryllium 1.83 J/g K specificheat_bismuth 0.13 J/g K specificheat_cadmium 0.23 J/g K specificheat_cesium 0.24 J/g K specificheat_chromium 0.46 J/g K specificheat_cobalt 0.42 J/g K specificheat_copper 0.39 J/g K specificheat_gallium 0.37 J/g K specificheat_germanium 0.32 J/g K specificheat_gold 0.13 J/g K specificheat_hafnium 0.14 J/g K specificheat_indium 0.24 J/g K specificheat_iridium 0.13 J/g K specificheat_iron 0.45 J/g K specificheat_lanthanum 0.195 J/g K specificheat_lead 0.13 J/g K specificheat_lithium 3.57 J/g K specificheat_lutetium 0.15 J/g K specificheat_magnesium 1.05 J/g K specificheat_manganese 0.48 J/g K specificheat_mercury 0.14 J/g K specificheat_molybdenum 0.25 J/g K specificheat_nickel 0.44 J/g K specificheat_osmium 0.13 J/g K specificheat_palladium 0.24 J/g K specificheat_platinum 0.13 J/g K specificheat_plutonum 0.13 J/g K specificheat_potassium 0.75 J/g K specificheat_rhenium 0.14 J/g K specificheat_rhodium 0.24 J/g K specificheat_rubidium 0.36 J/g K specificheat_ruthenium 0.24 J/g K specificheat_scandium 0.57 J/g K specificheat_selenium 0.32 J/g K specificheat_silicon 0.71 J/g K specificheat_silver 0.23 J/g K specificheat_sodium 1.21 J/g K specificheat_strontium 0.30 J/g K specificheat_tantalum 0.14 J/g K specificheat_thallium 0.13 J/g K specificheat_thorium 0.13 J/g K specificheat_tin 0.21 J/g K specificheat_titanium 0.54 J/g K specificheat_tungsten 0.13 J/g K specificheat_uranium 0.12 J/g K specificheat_vanadium 0.39 J/g K specificheat_yttrium 0.30 J/g K specificheat_zinc 0.39 J/g K specificheat_zirconium 0.27 J/g K specificheat_ethanol 2.3 J/g K specificheat_ammonia 4.6 J/g K specificheat_freon 0.91 J/g K # R-12 at 0 degrees Fahrenheit specificheat_gasoline 2.22 J/g K specificheat_iodine 2.15 J/g K specificheat_oliveoil 1.97 J/g K # en.wikipedia.org/wiki/Heat_capacity#Table_of_specific_heat_capacities specificheat_hydrogen 14.3 J/g K specificheat_helium 5.1932 J/g K specificheat_argon 0.5203 J/g K specificheat_tissue 3.5 J/g K specificheat_diamond 0.5091 J/g K specificheat_granite 0.79 J/g K specificheat_graphite 0.71 J/g K specificheat_ice 2.11 J/g K specificheat_asphalt 0.92 J/g K specificheat_brick 0.84 J/g K specificheat_concrete 0.88 J/g K specificheat_glass_silica 0.84 J/g K specificheat_glass_flint 0.503 J/g K specificheat_glass_pyrex 0.753 J/g K specificheat_gypsum 1.09 J/g K specificheat_marble 0.88 J/g K specificheat_sand 0.835 J/g K specificheat_soil 0.835 J/g K specificheat_wood 1.7 J/g K specificheat_sucrose 1.244 J/g K # www.sugartech.co.za/heatcapacity/indexphp # Energy densities of various fuels # # Most of these fuels have varying compositions or qualities and hence their # actual energy densities vary. These numbers are hence only approximate. # # E1. http://www.aps.org/policy/reports/popa-reports/energy/units.cfm # E2. https://web.archive.org/web/20100825042309/http://www.ior.com.au/ecflist.html tonoil 1e10 cal_IT # Ton oil equivalent. A conventional # value for the energy released by toe tonoil # burning one metric ton of oil. [18,E1] # Note that energy per mass of petroleum # products is fairly constant. # Variations in volumetric energy # density result from variations in the # density (kg/m^3) of different fuels. # This definition is given by the # IEA/OECD. toncoal 7e9 cal_IT # Energy in metric ton coal from [18]. # This is a nominal value which # is close to the heat content # of coal used in the 1950's barreloil 5.8 Mbtu # Conventional value for barrel of crude # oil [E1]. Actual range is 5.6 - 63. naturalgas_HHV 1027 btu/ft3 # Energy content of natural gas. HHV naturalgas_LHV 930 btu/ft3 # is for Higher Heating Value and naturalgas naturalgas_HHV # includes energy from condensation # combustion products. LHV is for Lower # Heating Value and excludes these. # American publications typically report # HHV whereas European ones report LHV. charcoal 30 GJ/tonne woodenergy_dry 20 GJ/tonne # HHV, a cord weights about a tonne woodenergy_airdry 15 GJ/tonne # 20% moisture content coal_bituminous 27 GJ / tonne coal_lignite 15 GJ / tonne coal_US 22 GJ / uston # Average for US coal (short ton), 1995 ethanol_HHV 84000 btu/usgallon ethanol_LHV 75700 btu/usgallon diesel 130500 btu/usgallon gasoline_LHV 115000 btu/usgallon gasoline_HHV 125000 btu/usgallon gasoline gasoline_HHV heating 37.3 MJ/liter fueloil 39.7 MJ/liter # low sulphur propane 93.3 MJ/m^3 butane 124 MJ/m^3 # The US EPA defines a "miles per gallon equivalent" for alternative # energy vehicles: mpg_e miles / gallon gasoline_LHV MPGe mpg_e # These values give total energy from uranium fission. Actual efficiency # of nuclear power plants is around 30%-40%. Note also that some reactors # use enriched uranium around 3% U-235. Uranium during processing or use # may be in a compound of uranium oxide or uranium hexafluoride, in which # case the energy density would be lower depending on how much uranium is # in the compound. uranium_pure 200 MeV avogadro / (235.0439299 g/mol) # Pure U-235 uranium_natural 0.7% uranium_pure # Natural uranium: 0.7% U-235 # Celsius heat unit: energy to raise a pound of water 1 degC celsiusheatunit cal lb degC / gram K chu celsiusheatunit # "Apparent" average power in an AC circuit, the product of rms voltage # and rms current, equal to the true power in watts when voltage and # current are in phase. In a DC circuit, always equal to the true power. VA volt ampere kWh kilowatt hour # The horsepower is supposedly the power of one horse pulling. Obviously # different people had different horses. horsepower 550 foot pound force / sec # Invented by James Watt mechanicalhorsepower horsepower hp horsepower metrichorsepower 75 kilogram force meter / sec # PS=Pferdestaerke in electrichorsepower 746 W # Germany boilerhorsepower 9809.50 W waterhorsepower 746.043 W brhorsepower horsepower # Value corrected Dec, 2019. Was 745.7 W. donkeypower 250 W chevalvapeur metrichorsepower # # Heat Transfer # # Thermal conductivity, K, measures the rate of heat transfer across # a material. The heat transferred is # Q = K dT A t / L # where dT is the temperature difference across the material, A is the # cross sectional area, t is the time, and L is the length (thickness). # Thermal conductivity is a material property. THERMAL_CONDUCTIVITY POWER / AREA (TEMPERATURE_DIFFERENCE/LENGTH) THERMAL_RESISTIVITY 1/THERMAL_CONDUCTIVITY # Thermal conductance is the rate at which heat flows across a given # object, so the area and thickness have been fixed. It depends on # the size of the object and is hence not a material property. THERMAL_CONDUCTANCE POWER / TEMPERATURE_DIFFERENCE THERMAL_RESISTANCE 1/THERMAL_CONDUCTANCE # Thermal admittance is the rate of heat flow per area across an # object whose thickness has been fixed. Its reciprocal, thermal # insulation, is used to for measuring the heat transfer per area # of sheets of insulation or cloth that are of specified thickness. THERMAL_ADMITTANCE THERMAL_CONDUCTIVITY / LENGTH THERMAL_INSULANCE THERMAL_RESISTIVITY LENGTH THERMAL_INSULATION THERMAL_RESISTIVITY LENGTH Rvalue degF ft^2 hr / btu Uvalue 1/Rvalue europeanUvalue watt / m^2 K RSI degC m^2 / W clo 0.155 degC m^2 / W # Supposed to be the insulance # required to keep a resting person # comfortable indoors. The value # given is from NIST and the CRC, # but [5] gives a slightly different # value of 0.875 ft^2 degF hr / btu. tog 0.1 degC m^2 / W # Also used for clothing. # Thermal diffusivity measures the rate of heat transfer inside a # material. It is the thermal conductivity divided by the volumentric # heat capacity, and appears in the heat equation: # # du/dt = alpha (d^2 u / dx^2) # # where alpha is the thermal diffusivity. (Derivatives are partial derivatives.) THERMAL_DIFFUSIVITY THERMAL_CONDUCTIVITY / DENSITY SPECIFIC_HEAT_CAPACITY # Thermal Conductivity of a few materials diamond_natural_thermal_conductivity 2200 W / m K diamond_synthetic_thermal_conductivity 3320 W / m K # 99% pure C12 silver_thermal_conductivity 406 W / m K aluminum_thermal_conductivity 205 W / m K copper_thermal_conductivity 385 W / m K gold_thermal_conductivity 314 W / m K iron_thermal_conductivity 79.5 W / m K stainless_304_thermal_conductivity 15.5 W / m K # average value # Thermal diffusivity of a few materials # https://en.wikipedia.org/wiki/Thermal_diffusivity # Values for diamond from https://doi.org/10.1007/BF00351908 diamond_synthetic_thermal_diffusivity 1200 mm^2 / s diamond_natural_thermal_diffusivity 780 mm^2 / s helium_thermal_diffusivity 190 mm^2 / s # At 300 K, 1 atm silver_thermal_diffusivity 165.63 mm^2 / s # 99.9% pure gold_thermal_diffusivity 127 mm^2 / s copper_thermal_diffusivity 111 mm^2 / s aluminum_thermal_diffusivity 97 mm^2 / s iron_thermal_diffusivity 23 mm^2 / s air_thermal_diffusivity 19 mm^2 / s stainless_304_thermal_diffusivity 4.2 mm^2 / s ice_thermal_diffusivity 1.02 mm^2 / s # At 0 C glass_thermal_diffusivity 0.34 mm^2 / s water_thermal_diffusivity 0.143 mm^2 / s # At 25 C nylon_thermal_diffusivity 0.09 mm^2 / s pine_thermal_diffusivity 0.082 mm^2 / s # yellow pine # The bel was defined by engineers of Bell Laboratories to describe the # reduction in audio level over a length of one mile. It was originally # called the transmission unit (TU) but was renamed around 1923 to honor # Alexander Graham Bell. The bel proved inconveniently large so the decibel # has become more common. The decibel is dimensionless since it reports a # ratio, but it is used in various contexts to report a signal's power # relative to some reference level. bel(x) units=[1;1] range=(0,) 10^(x); log(bel) # Basic bel definition decibel(x) units=[1;1] range=(0,) 10^(x/10); 10 log(decibel) # Basic decibel dB() decibel # Abbreviation dBW(x) units=[1;W] range=(0,) dB(x) W ; ~dB(dBW/W) # Reference = 1 W dBk(x) units=[1;W] range=(0,) dB(x) kW ; ~dB(dBk/kW) # Reference = 1 kW dBf(x) units=[1;W] range=(0,) dB(x) fW ; ~dB(dBf/fW) # Reference = 1 fW dBm(x) units=[1;W] range=(0,) dB(x) mW ; ~dB(dBm/mW) # Reference = 1 mW dBmW(x) units=[1;W] range=(0,) dBm(x) ; ~dBm(dBmW) # Reference = 1 mW dBJ(x) units=[1;J] range=(0,) dB(x) J; ~dB(dBJ/J) # Energy relative # to 1 joule. Used for power spectral # density since W/Hz = J # When used to measure amplitude, voltage, or current the signal is squared # because power is proportional to the square of these measures. The root # mean square (RMS) voltage is typically used with these units. dB_amplitude(x) units=[1;1] dB(0.5 x) ; ~dB(dB_amplitude^2) dBV(x) units=[1;V] range=(0,) dB(0.5 x) V;~dB(dBV^2 / V^2) # Reference = 1 V dBmV(x) units=[1;V] range=(0,) dB(0.5 x) mV;~dB(dBmV^2/mV^2)# Reference = 1 mV dBuV(x) units=[1;V] range=(0,) dB(0.5 x) microV ; ~dB(dBuV^2 / microV^2) # Reference = 1 microvolt # Here are dB measurements for current. Be aware that dbA is also # a unit for frequency weighted sound pressure. dBA(x) units=[1;A] range=(0,) dB(0.5 x) A;~dB(dBA^2 / A^2) # Reference = 1 A dBmA(x) units=[1;A] range=(0,) dB(0.5 x) mA;~dB(dBmA^2/mA^2)# Reference = 1 mA dBuA(x) units=[1;A] range=(0,) dB(0.5 x) microA ; ~dB(dBuA^2 / microA^2) # Reference = 1 microamp # Referenced to the voltage that causes 1 mW dissipation in a 600 ohm load. # Originally defined as dBv but changed to prevent confusion with dBV. # The "u" is for unloaded. dBu(x) units=[1;V] range=(0,) dB(0.5 x) sqrt(mW 600 ohm) ; \ ~dB(dBu^2 / mW 600 ohm) dBv(x) units=[1;V] range=(0,) dBu(x) ; ~dBu(dBv) # Synonym for dBu # Measurements for sound in air, referenced to the threshold of human hearing # Note that sound in other media typically uses 1 micropascal as a reference # for sound pressure. Units dBA, dBB, dBC, refer to different frequency # weightings meant to approximate the human ear's response. # sound pressure level dBSPL(x) units=[1;Pa] range=(0,) dB(0.5 x) 20 microPa ; \ ~dB(dBSPL^2 / (20 microPa)^2) # sound intensity level dBSIL(x) units=[1;W/m^2] range=(0,) dB(x) 1e-12 W/m^2; \ ~dB(dBSIL / (1e-12 W/m^2)) # sound power level (The W in SWL is for the reference power, 1 W.) dBSWL(x) units=[1;W] range=(0,) dB(x) 1e-12 W; ~dB(dBSWL/1e-12 W) # The neper is another similar logarithmic unit. Note that the neper # is defined based on the ratio of amplitudes rather than the power # ratio like the decibel. This means that if the data is power, and # you convert to nepers you should take the square root of the data # to convert to amplitude. If you want to convert nepers to a power # measurement you need to square the resulting output. neper(x) units=[1;1] range=(0,) exp(x); ln(neper) centineper(x) units=[1;1] range=(0,) exp(x/100); 100 ln(centineper) Np() neper cNp() centineper Np_power(x) units=[1;1] Np(2 x) ; ~Np(Np_power)/2 # Misc other measures ENTROPY ENERGY / TEMPERATURE clausius 1e3 cal/K # A unit of physical entropy langley thermcalorie/cm^2 # Used in radiation theory poncelet 100 kg force m / s tonrefrigeration uston 144 btu / lb day # One ton refrigeration is # the rate of heat extraction required # turn one ton of water to ice in # a day. Ice is defined to have a # latent heat of 144 btu/lb. tonref tonrefrigeration refrigeration tonref / ton frigorie 1000 cal_15 # Used in refrigeration engineering. airwatt 8.5 (ft^3/min) inH2O # Measure of vacuum power as # pressure times air flow. # The unit "tnt" is defined so that you can write "tons tnt". The # question of which ton, exactly, is intended. The answer is that # nobody knows: # # Quoting the footnote from page 13 of # The Effects of Nuclear Weapons, 3rd ed. # https://www.fourmilab.ch/etexts/www/effects/eonw_1.pdf # # The majority of the experimental and theoretical values of the # explosive energy released by TNT range from 900 to 1,100 calories per # gram. At one time, there was some uncertainty as to whether the term # "kiloton" of TNT referred to a short kiloton (2*10^6 pounds), a metric # kiloton (2.205*10^6 pounds), or a long kiloton (2.24*10^6 pounds). In # order to avoid ambiguity, it was agreed that the term "kiloton" would # refer to the release of 10^12 calories of explosive energy. This is # equivalent to 1 short kiloton of TNT if the energy release is 1,102 # calories per gram or to 1 long kiloton if the energy is 984 calories # per gram of TNT. # # It is therefore not well-defined how much energy a "gram of tnt" is, # though this term does appear in some references. tnt 1e9 cal_th / ton # Defined exact value # Nuclear weapon yields davycrocket 10 ton tnt # lightest US tactical nuclear weapon hiroshima 15.5 kiloton tnt # Uranium-235 fission bomb nagasaki 21 kiloton tnt # Plutonium-239 fission bomb fatman nagasaki littleboy hiroshima ivyking 500 kiloton tnt # most powerful fission bomb castlebravo 15 megaton tnt # most powerful US test tsarbomba 50 megaton tnt # most powerful test ever: USSR, # 30 October 1961 b53bomb 9 megaton tnt # http://rarehistoricalphotos.com/gadget-first-atomic-bomb/ trinity 18 kiloton tnt # July 16, 1945 gadget trinity # # Permeability: The permeability or permeance, n, of a substance determines # how fast vapor flows through the substance. The formula W = n A dP # holds where W is the rate of flow (in mass/time), n is the permeability, # A is the area of the flow path, and dP is the vapor pressure difference. # perm_0C grain / hr ft^2 inHg perm_zero perm_0C perm_0 perm_0C perm perm_0C perm_23C grain / hr ft^2 in Hg23C perm_twentythree perm_23C # # Counting measures # pair 2 brace 2 nest 3 # often used for items like bowls that # nest together hattrick 3 # Used in sports, especially cricket and ice # hockey to report the number of goals. dicker 10 dozen 12 bakersdozen 13 score 20 flock 40 timer 40 shock 60 toncount 100 # Used in sports in the UK longhundred 120 # From a germanic counting system gross 144 greatgross 12 gross tithe 1|10 # From Anglo-Saxon word for tenth # Paper counting measure shortquire 24 quire 25 shortream 480 ream 500 perfectream 516 bundle 2 reams bale 5 bundles # # Paper measures # # USA paper sizes lettersize 8.5 inch 11 inch legalsize 8.5 inch 14 inch ledgersize 11 inch 17 inch executivesize 7.25 inch 10.5 inch Apaper 8.5 inch 11 inch Bpaper 11 inch 17 inch Cpaper 17 inch 22 inch Dpaper 22 inch 34 inch Epaper 34 inch 44 inch # Correspondence envelope sizes. #10 is the standard business # envelope in the USA. envelope6_25size 3.5 inch 6 inch envelope6_75size 3.625 inch 6.5 inch envelope7size 3.75 inch 6.75 inch envelope7_75size 3.875 inch 7.5 inch envelope8_625size 3.625 inch 8.625 inch envelope9size 3.875 inch 8.875 inch envelope10size 4.125 inch 9.5 inch envelope11size 4.5 inch 10.375 inch envelope12size 4.75 inch 11 inch envelope14size 5 inch 11.5 inch envelope16size 6 inch 12 inch # Announcement envelope sizes (no relation to metric paper sizes like A4) envelopeA1size 3.625 inch 5.125 inch # same as 4bar envelopeA2size 4.375 inch 5.75 inch envelopeA6size 4.75 inch 6.5 inch envelopeA7size 5.25 inch 7.25 inch envelopeA8size 5.5 inch 8.125 inch envelopeA9size 5.75 inch 8.75 inch envelopeA10size 6 inch 9.5 inch # Baronial envelopes envelope4bar 3.625 inch 5.125 inch # same as A1 envelope5_5bar 4.375 inch 5.75 inch envelope6bar 4.75 inch 6.5 inch # Coin envelopes envelope1baby 2.25 inch 3.5 inch # same as #1 coin envelope00coin 1.6875 inch 2.75 inch envelope1coin 2.25 inch 3.5 inch envelope3coin 2.5 inch 4.25 inch envelope4coin 3 inch 4.5 inch envelope4_5coin 3 inch 4.875 inch envelope5coin 2.875 inch 5.25 inch envelope5_5coin 3.125 inch 5.5 inch envelope6coin 3.375 inch 6 inch envelope7coin 3.5 inch 6.5 inch # The metric paper sizes are defined so that if a sheet is cut in half # along the short direction, the result is two sheets which are # similar to the original sheet. This means that for any metric size, # the long side is close to sqrt(2) times the length of the short # side. Each series of sizes is generated by repeated cuts in half, # with the values rounded down to the nearest millimeter. A0paper 841 mm 1189 mm # The basic size in the A series A1paper 594 mm 841 mm # is defined to have an area of A2paper 420 mm 594 mm # one square meter. A3paper 297 mm 420 mm A4paper 210 mm 297 mm A5paper 148 mm 210 mm A6paper 105 mm 148 mm A7paper 74 mm 105 mm A8paper 52 mm 74 mm A9paper 37 mm 52 mm A10paper 26 mm 37 mm B0paper 1000 mm 1414 mm # The basic B size has an area B1paper 707 mm 1000 mm # of sqrt(2) square meters. B2paper 500 mm 707 mm B3paper 353 mm 500 mm B4paper 250 mm 353 mm B5paper 176 mm 250 mm B6paper 125 mm 176 mm B7paper 88 mm 125 mm B8paper 62 mm 88 mm B9paper 44 mm 62 mm B10paper 31 mm 44 mm C0paper 917 mm 1297 mm # The basic C size has an area C1paper 648 mm 917 mm # of sqrt(sqrt(2)) square meters. C2paper 458 mm 648 mm C3paper 324 mm 458 mm # Intended for envelope sizes C4paper 229 mm 324 mm C5paper 162 mm 229 mm C6paper 114 mm 162 mm C7paper 81 mm 114 mm C8paper 57 mm 81 mm C9paper 40 mm 57 mm C10paper 28 mm 40 mm # gsm (Grams per Square Meter), a sane, metric paper weight measure gsm grams / meter^2 # In the USA, a collection of crazy historical paper measures are used. Paper # is measured as a weight of a ream of that particular type of paper. This is # sometimes called the "substance" or "basis" (as in "substance 20" paper). # The standard sheet size or "basis size" varies depending on the type of # paper. As a result, 20 pound bond paper and 50 pound text paper are actually # about the same weight. The different sheet sizes were historically the most # convenient for printing or folding in the different applications. These # different basis weights are standards maintained by American Society for # Testing Materials (ASTM) and the American Forest and Paper Association # (AF&PA). poundbookpaper lb / 25 inch 38 inch ream lbbook poundbookpaper poundtextpaper poundbookpaper lbtext poundtextpaper poundoffsetpaper poundbookpaper # For offset printing lboffset poundoffsetpaper poundbiblepaper poundbookpaper # Designed to be lightweight, thin, lbbible poundbiblepaper # strong and opaque. poundtagpaper lb / 24 inch 36 inch ream lbtag poundtagpaper poundbagpaper poundtagpaper lbbag poundbagpaper poundnewsprintpaper poundtagpaper lbnewsprint poundnewsprintpaper poundposterpaper poundtagpaper lbposter poundposterpaper poundtissuepaper poundtagpaper lbtissue poundtissuepaper poundwrappingpaper poundtagpaper lbwrapping poundwrappingpaper poundwaxingpaper poundtagpaper lbwaxing poundwaxingpaper poundglassinepaper poundtagpaper lbglassine poundglassinepaper poundcoverpaper lb / 20 inch 26 inch ream lbcover poundcoverpaper poundindexpaper lb / 25.5 inch 30.5 inch ream lbindex poundindexpaper poundindexbristolpaper poundindexpaper lbindexbristol poundindexpaper poundbondpaper lb / 17 inch 22 inch ream # Bond paper is stiff and lbbond poundbondpaper # durable for repeated poundwritingpaper poundbondpaper # filing, and it resists lbwriting poundwritingpaper # ink penetration. poundledgerpaper poundbondpaper lbledger poundledgerpaper poundcopypaper poundbondpaper lbcopy poundcopypaper poundblottingpaper lb / 19 inch 24 inch ream lbblotting poundblottingpaper poundblankspaper lb / 22 inch 28 inch ream lbblanks poundblankspaper poundpostcardpaper lb / 22.5 inch 28.5 inch ream lbpostcard poundpostcardpaper poundweddingbristol poundpostcardpaper lbweddingbristol poundweddingbristol poundbristolpaper poundweddingbristol lbbristol poundbristolpaper poundboxboard lb / 1000 ft^2 lbboxboard poundboxboard poundpaperboard poundboxboard lbpaperboard poundpaperboard # When paper is marked in units of M, it means the weight of 1000 sheets of the # given size of paper. To convert this to paper weight, divide by the size of # the paper in question. paperM lb / 1000 # In addition paper weight is reported in "caliper" which is simply the # thickness of one sheet, typically in inches. Thickness is also reported in # "points" where a point is 1|1000 inch. These conversions are supplied to # convert these units roughly (using an approximate density) into the standard # paper weight values. pointthickness 0.001 in paperdensity 0.8 g/cm^3 # approximate--paper densities vary! papercaliper in paperdensity paperpoint pointthickness paperdensity # # Printing # fournierpoint 0.1648 inch / 12 # First definition of the printers # point made by Pierre Fournier who # defined it in 1737 as 1|12 of a # cicero which was 0.1648 inches. olddidotpoint 1|72 frenchinch # Francois Ambroise Didot, one of # a family of printers, changed # Fournier's definition around 1770 # to fit to the French units then in # use. bertholdpoint 1|2660 m # H. Berthold tried to create a # metric version of the didot point # in 1878. INpoint 0.4 mm # This point was created by a # group directed by Fermin Didot in # 1881 and is associated with the # imprimerie nationale. It doesn't # seem to have been used much. germandidotpoint 0.376065 mm # Exact definition appears in DIN # 16507, a German standards document # of 1954. Adopted more broadly in # 1966 by ??? metricpoint 3|8 mm # Proposed in 1977 by Eurograf oldpoint 1|72.27 inch # The American point was invented printerspoint oldpoint # by Nelson Hawks in 1879 and texpoint oldpoint # dominates USA publishing. # It was standardized by the American # Typefounders Association at the # value of 0.013837 inches exactly. # Knuth uses the approximation given # here (which is very close). The # comp.fonts FAQ claims that this # value is supposed to be 1|12 of a # pica where 83 picas is equal to 35 # cm. But this value differs from # the standard. texscaledpoint 1|65536 texpoint # The TeX typesetting system uses texsp texscaledpoint # this for all computations. computerpoint 1|72 inch # The American point was rounded point computerpoint computerpica 12 computerpoint # to an even 1|72 inch by computer postscriptpoint computerpoint # people at some point. pspoint postscriptpoint twip 1|20 point # TWentieth of an Imperial Point Q 1|4 mm # Used in Japanese phototypesetting # Q is for quarter frenchprinterspoint olddidotpoint didotpoint germandidotpoint # This seems to be the dominant value europeanpoint didotpoint # for the point used in Europe cicero 12 didotpoint stick 2 inches # Type sizes excelsior 3 oldpoint brilliant 3.5 oldpoint diamondtype 4 oldpoint pearl 5 oldpoint agate 5.5 oldpoint # Originally agate type was 14 lines per # inch, giving a value of 1|14 in. ruby agate # British nonpareil 6 oldpoint mignonette 6.5 oldpoint emerald mignonette # British minion 7 oldpoint brevier 8 oldpoint bourgeois 9 oldpoint longprimer 10 oldpoint smallpica 11 oldpoint pica 12 oldpoint english 14 oldpoint columbian 16 oldpoint greatprimer 18 oldpoint paragon 20 oldpoint meridian 44 oldpoint canon 48 oldpoint # German type sizes nonplusultra 2 didotpoint brillant 3 didotpoint diamant 4 didotpoint perl 5 didotpoint nonpareille 6 didotpoint kolonel 7 didotpoint petit 8 didotpoint borgis 9 didotpoint korpus 10 didotpoint corpus korpus garamond korpus mittel 14 didotpoint tertia 16 didotpoint text 18 didotpoint kleine_kanon 32 didotpoint kanon 36 didotpoint grobe_kanon 42 didotpoint missal 48 didotpoint kleine_sabon 72 didotpoint grobe_sabon 84 didotpoint # # Information theory units. Note that the name "entropy" is used both # to measure information and as a physical quantity. # INFORMATION bit nat (1/ln(2)) bits # Entropy measured base e hartley log2(10) bits # Entropy of a uniformly ban hartley # distributed random variable # over 10 symbols. dit hartley # from Decimal digIT # # Computer # bps bit/sec # Sometimes the term "baud" is # incorrectly used to refer to # bits per second. Baud refers # to symbols per second. Modern # modems transmit several bits # per symbol. byte 8 bit # Not all machines had 8 bit B byte # bytes, but these days most of # them do. But beware: for # transmission over modems, a # few extra bits are used so # there are actually 10 bits per # byte. octet 8 bits # The octet is always 8 bits nybble 4 bits # Half of a byte. Sometimes # equal to different lengths # such as 3 bits. nibble nybble nyp 2 bits # Donald Knuth asks in an exercise # for a name for a 2 bit # quantity and gives the "nyp" # as a solution due to Gregor # Purdy. Not in common use. meg megabyte # Some people consider these # units along with the kilobyte gig gigabyte # to be defined according to # powers of 2 with the kilobyte # equal to 2^10 bytes, the # megabyte equal to 2^20 bytes and # the gigabyte equal to 2^30 bytes # but these usages are forbidden # by SI. Binary prefixes have # been defined by IEC to replace # the SI prefixes. Use them to # get the binary units KiB, MiB, # GiB, etc. jiffy 0.01 sec # This is defined in the Jargon File jiffies jiffy # (http://www.jargon.org) as being the # duration of a clock tick for measuring # wall-clock time. Supposedly the value # used to be 1|60 sec or 1|50 sec # depending on the frequency of AC power, # but then 1|100 sec became more common. # On linux systems, this term is used and # for the Intel based chips, it does have # the value of .01 sec. The Jargon File # also lists two other definitions: # millisecond, and the time taken for # light to travel one foot. cdaudiospeed 44.1 kHz 2*16 bits # CD audio data rate at 44.1 kHz with 2 # samples of sixteen bits each. cdromspeed 75 2048 bytes / sec # For data CDs (mode1) 75 sectors are read # each second with 2048 bytes per sector. # Audio CDs do not have sectors, but # people sometimes divide the bit rate by # 75 and claim a sector length of 2352. # Data CDs have a lower rate due to # increased error correction overhead. # There is a rarely used mode (mode2) with # 2336 bytes per sector that has fewer # error correction bits than mode1. dvdspeed 1385 kB/s # This is the "1x" speed of a DVD using # constant linear velocity (CLV) mode. # Modern DVDs may vary the linear velocity # as they go from the inside to the # outside of the disc. # See http://www.osta.org/technology/dvdqa/dvdqa4.htm FIT / 1e9 hour # Failures In Time, number of failures per billion hours # # The IP address space is divided into subnets. The number of hosts # in a subnet depends on the length of the subnet prefix. This is # often written as /N where N is the number of bits in the prefix. # # https://en.wikipedia.org/wiki/Subnetwork # # These definitions gives the number of hosts for a subnet whose # prefix has the specified length in bits. # ipv4subnetsize(prefix_len) units=[1;1] domain=[0,32] range=[1,4294967296] \ 2^(32-prefix_len) ; 32-log2(ipv4subnetsize) ipv4classA ipv4subnetsize(8) ipv4classB ipv4subnetsize(16) ipv4classC ipv4subnetsize(24) ipv6subnetsize(prefix_len) units=[1;1] domain=[0,128] \ range=[1,340282366920938463463374607431768211456] \ 2^(128-prefix_len) ; 128-log2(ipv6subnetsize) # # Musical measures. Musical intervals expressed as ratios. Multiply # two intervals together to get the sum of the interval. The function # musicalcent can be used to convert ratios to cents. # # Perfect intervals octave 2 majorsecond musicalfifth^2 / octave majorthird 5|4 minorthird 6|5 musicalfourth 4|3 musicalfifth 3|2 majorsixth musicalfourth majorthird minorsixth musicalfourth minorthird majorseventh musicalfifth majorthird minorseventh musicalfifth minorthird pythagoreanthird majorsecond musicalfifth^2 / octave syntoniccomma pythagoreanthird / majorthird pythagoreancomma musicalfifth^12 / octave^7 # Equal tempered definitions semitone octave^(1|12) musicalcent(x) units=[1;1] range=(0,) semitone^(x/100) ; \ 100 log(musicalcent)/log(semitone) # # Musical note lengths. # wholenote ! MUSICAL_NOTE_LENGTH wholenote halfnote 1|2 wholenote quarternote 1|4 wholenote eighthnote 1|8 wholenote sixteenthnote 1|16 wholenote thirtysecondnote 1|32 wholenote sixtyfourthnote 1|64 wholenote dotted 3|2 doubledotted 7|4 breve doublewholenote semibreve wholenote minimnote halfnote crotchet quarternote quaver eighthnote semiquaver sixteenthnote demisemiquaver thirtysecondnote hemidemisemiquaver sixtyfourthnote semidemisemiquaver hemidemisemiquaver # # yarn and cloth measures # # yarn linear density woolyarnrun 1600 yard/pound # 1600 yds of "number 1 yarn" weighs # a pound. yarncut 300 yard/pound # Less common system used in # Pennsylvania for wool yarn cottonyarncount 840 yard/pound linenyarncount 300 yard/pound # Also used for hemp and ramie worstedyarncount 1680 ft/pound metricyarncount meter/gram denier 1|9 tex # used for silk and rayon manchesteryarnnumber drams/1000 yards # old system used for silk pli lb/in typp 1000 yd/lb # abbreviation for Thousand Yard Per Pound asbestoscut 100 yd/lb # used for glass and asbestos yarn tex gram / km # rational metric yarn measure, meant drex 0.1 tex # to be used for any kind of yarn poumar lb / 1e6 yard # yarn and cloth length skeincotton 80*54 inch # 80 turns of thread on a reel with a # 54 in circumference (varies for other # kinds of thread) cottonbolt 120 ft # cloth measurement woolbolt 210 ft bolt cottonbolt heer 600 yards cut 300 yards # used for wet-spun linen yarn lea 300 yards sailmakersyard 28.5 in sailmakersounce oz / sailmakersyard 36 inch silkmomme momme / 25 yards 1.49 inch # Traditional silk weight silkmm silkmomme # But it is also defined as # lb/100 yd 45 inch. The two # definitions are slightly different # and neither one seems likely to be # the true source definition. # # drug dosage # mcg microgram # Frequently used for vitamins iudiptheria 62.8 microgram # IU is for international unit iupenicillin 0.6 microgram iuinsulin 41.67 microgram drop 1|20 ml # The drop was an old "unit" that was # replaced by the minim. But I was # told by a pharmacist that in his # profession, the conversion of 20 # drops per ml is actually used. bloodunit 450 ml # For whole blood. For blood # components, a blood unit is the # quantity of the component found in a # blood unit of whole blood. The # human body contains about 12 blood # units of whole blood. # # misc medical measure # frenchcathetersize 1|3 mm # measure used for the outer diameter # of a catheter charriere frenchcathetersize # # fixup units for times when prefix handling doesn't do the job # hectare hectoare hektare hectoare decare dekaare dekare dekaare megohm megaohm kilohm kiloohm microhm microohm megalerg megaerg # 'L' added to make it pronounceable [18]. # # Money # # Note that US$ is the primitive unit so other currencies are # generally given in US$. # unitedstatesdollar US$ usdollar US$ $ dollar mark germanymark #bolivar venezuelabolivar # Not all databases are #venezuelabolivarfuerte 1e-5 bolivar # supplying these #bolivarfuerte 1e-5 bolivar # The currency was revalued #oldbolivar 1|1000 bolivarfuerte # twice peseta spainpeseta rand southafricarand escudo portugalescudo guilder netherlandsguilder hollandguilder netherlandsguilder peso mexicopeso yen japanyen lira turkeylira rupee indiarupee drachma greecedrachma franc francefranc markka finlandmarkka britainpound unitedkingdompound greatbritainpound unitedkingdompound unitedkingdompound ukpound poundsterling britainpound yuan chinayuan # Unicode Currency Names !utf8 icelandkróna icelandkrona polandzłoty polandzloty tongapa’anga tongapa'anga #venezuelabolívar venezuelabolivar vietnamđồng vietnamdong mongoliatögrög mongoliatugrik sãotomé&príncipedobra saotome&principedobra !endutf8 UKP GBP # Not an ISO code, but looks like one, and # sometimes used on usenet. !include currency.units # Money on the gold standard, used in the late 19th century and early # 20th century. olddollargold 23.22 grains goldprice # Used until 1934 newdollargold 96|7 grains goldprice # After Jan 31, 1934 dollargold newdollargold poundgold 113 grains goldprice # British pound # Precious metals goldounce goldprice troyounce silverounce silverprice troyounce platinumounce platinumprice troyounce XAU goldounce XPT platinumounce XAG silverounce # Nominal masses of US coins. Note that dimes, quarters and half dollars # have weight proportional to value. Before 1965 it was $40 / kg. USpennyweight 2.5 grams # Since 1982, 48 grains before USnickelweight 5 grams USdimeweight US$ 0.10 / (20 US$ / lb) # Since 1965 USquarterweight US$ 0.25 / (20 US$ / lb) # Since 1965 UShalfdollarweight US$ 0.50 / (20 US$ / lb) # Since 1971 USdollarweight 8.1 grams # Weight of Susan B. Anthony and # Sacagawea dollar coins # British currency quid britainpound # Slang names fiver 5 quid tenner 10 quid monkey 500 quid brgrand 1000 quid bob shilling shilling 1|20 britainpound # Before decimalisation, there oldpence 1|12 shilling # were 20 shillings to a pound, farthing 1|4 oldpence # each of twelve old pence guinea 21 shilling # Still used in horse racing crown 5 shilling florin 2 shilling groat 4 oldpence tanner 6 oldpence brpenny 0.01 britainpound pence brpenny tuppence 2 pence tuppenny tuppence ha'penny halfbrpenny hapenny ha'penny oldpenny oldpence oldtuppence 2 oldpence oldtuppenny oldtuppence threepence 3 oldpence # threepence never refers to new money threepenny threepence oldthreepence threepence oldthreepenny threepence oldhalfpenny halfoldpenny oldha'penny oldhalfpenny oldhapenny oldha'penny brpony 25 britainpound # Canadian currency loony 1 canadadollar # This coin depicts a loon toony 2 canadadollar # Cryptocurrency satoshi 1e-8 bitcoin XBT bitcoin # nonstandard code # Inflation. # # Currently US inflation as reported by the BLS CPI index is available. # The UScpi() table reports the USA consumer price index. Note that # if you specify a year like 2015, that refers to the CPI reported # for December of 2014 (which is released in mid January 2015), # so it refers to the point right at the start of the given year. # Months are increments of 1|12 on the year, so the January 2015 # release will be 2015+1|12 = 2015.08333. !include cpi.units USCPI() UScpi USCPI_now UScpi_now USCPI_lastdate UScpi_lastdate cpi() UScpi CPI() UScpi cpi_now UScpi_now CPI_now UScpi_now cpi_lastdate UScpi_lastdate CPI_lastdate UScpi_lastdate # These definitions hide the CPI index and directly convert US dollars # from a specified date to current dollars. You can use this to convert # historical dollars to present value or to convert money in the past # between two dates. dollars_in() USdollars_in US$in() USdollars_in $in() USdollars_in # This definition gives the dimensionless US inflation factor since the # specified date. inflation_since() USinflation_since # # Units used for measuring volume of wood # cord 4*4*8 ft^3 # 4 ft by 4 ft by 8 ft bundle of wood facecord 1|2 cord cordfoot 1|8 cord # One foot long section of a cord cordfeet cordfoot housecord 1|3 cord # Used to sell firewood for residences, # often confusingly called a "cord" boardfoot ft^2 inch # Usually 1 inch thick wood boardfeet boardfoot fbm boardfoot # feet board measure stack 4 yard^3 # British, used for firewood and coal [18] rick 4 ft 8 ft 16 inches # Stack of firewood, supposedly # sometimes called a face cord, but this # value is equal to 1|3 cord. Name # comes from an old Norse word for a # stack of wood. stere m^3 timberfoot ft^3 # Used for measuring solid blocks of wood standard 120 12 ft 11 in 1.5 in # This is the St Petersburg or # Pittsburg standard. Apparently the # term is short for "standard hundred" # which was meant to refer to 100 pieces # of wood (deals). However, this # particular standard is equal to 120 # deals which are 12 ft by 11 in by 1.5 # inches (not the standard deal). hoppusfoot (4/pi) ft^3 # Volume calculation suggested in 1736 hoppusboardfoot 1|12 hoppusfoot # forestry manual by Edward Hoppus, for hoppuston 50 hoppusfoot # estimating the usable volume of a log. # It results from computing the volume # of a cylindrical log of length, L, and # girth (circumference), G, by V=L(G/4)^2. # The hoppus ton is apparently still in # use for shipments from Southeast Asia. # In Britain, the deal is apparently any piece of wood over 6 feet long, over # 7 wide and 2.5 inches thick. The OED doesn't give a standard size. A piece # of wood less than 7 inches wide is called a "batten". This unit is now used # exclusively for fir and pine. deal 12 ft 11 in 2.5 in # The standard North American deal [OED] wholedeal 12 ft 11 in 1.25 in # If it's half as thick as the standard # deal it's called a "whole deal"! splitdeal 12 ft 11 in 5|8 in # And half again as thick is a split deal. # Used for shellac mixing rate poundcut pound / gallon lbcut poundcut # # Gas and Liquid flow units # FLUID_FLOW VOLUME / TIME # Some obvious volumetric gas flow units (cu is short for cubic) cumec m^3/s cusec ft^3/s # Conventional abbreviations for fluid flow units gph gal/hr gpm gal/min mgd megagal/day brgph brgallon/hr brgpm brgallon/min brmgd mega brgallon/day usgph usgallon/hr usgpm usgallon/min usmgd mega usgallon/day cfs ft^3/s cfh ft^3/hour cfm ft^3/min lpm liter/min lfm ft/min # Used to report air flow produced by fans. # Multiply by cross sectional area to get a # flow in cfm. pru mmHg / (ml/min) # peripheral resistance unit, used in # medicine to assess blood flow in # the capillaries. # Miner's inch: This is an old historic unit used in the Western United # States. It is generally defined as the rate of flow through a one square # inch hole at a specified depth such as 4 inches. In the late 19th century, # volume of water was sometimes measured in the "24 hour inch". Values for the # miner's inch were fixed by state statues. (This information is from a web # site operated by the Nevada Division of Water Planning: The Water Words # Dictionary at http://water.nv.gov/WaterPlanDictionary.aspx, specifically # http://water.nv.gov/programs/planning/dictionary/wwords-M.pdf. All # but minersinchNV are s.v. Miner's Inch [Western United States]) minersinchAZ 1.5 ft^3/min minersinchCA 1.5 ft^3/min minersinchMT 1.5 ft^3/min minersinchNV 1.5 ft^3/min minersinchOR 1.5 ft^3/min minersinchID 1.2 ft^3/min minersinchKS 1.2 ft^3/min minersinchNE 1.2 ft^3/min minersinchNM 1.2 ft^3/min minersinchND 1.2 ft^3/min minersinchSD 1.2 ft^3/min minersinchUT 1.2 ft^3/min minersinchCO 1 ft^3/sec / 38.4 # 38.4 miner's inches = 1 ft^3/sec minersinchBC 1.68 ft^3/min # British Columbia # Oceanographic flow sverdrup 1e6 m^3 / sec # Used to express flow of ocean # currents. Named after Norwegian # oceanographer H. Sverdrup. # In vacuum science and some other applications, gas flow is measured # as the product of volumetric flow and pressure. This is useful # because it makes it easy to compare with the flow at standard # pressure (one atmosphere). It also directly relates to the number # of gas molecules per unit time, and hence to the mass flow if the # molecular mass is known. GAS_FLOW PRESSURE FLUID_FLOW sccm atm cc/min # 's' is for "standard" to indicate sccs atm cc/sec # flow at standard pressure scfh atm ft^3/hour # scfm atm ft^3/min slpm atm liter/min slph atm liter/hour lusec liter micron Hg / s # Used in vacuum science # US Standard Atmosphere (1976) # Atmospheric temperature and pressure vs. geometric height above sea level # This definition covers only the troposphere (the lowest atmospheric # layer, up to 11 km), and assumes the layer is polytropic. # A polytropic process is one for which PV^k = const, where P is the # pressure, V is the volume, and k is the polytropic exponent. The # polytropic index is n = 1 / (k - 1). As noted in the Wikipedia article # https://en.wikipedia.org/wiki/Polytropic_process, some authors reverse # the definitions of "exponent" and "index." The functions below assume # the following parameters: # temperature lapse rate, -dT/dz, in troposphere lapserate 6.5 K/km # US Std Atm (1976) # air molecular weight, including constituent mol wt, given # in Table 3, p. 3; CH4 (16.04303) and N2O (44.0128) from # Table 15, p. 33. Values for molecular weights are slightly # different from current values, so the original numerical # values are retained. air_1976 78.084 % 28.0134 \ + 20.9476 % 31.9988 \ + 9340 ppm 39.948 \ + 314 ppm 44.00995 \ + 18.18 ppm 20.183 \ + 5.24 ppm 4.0026 \ + 1.5 ppm 16.04303 \ + 1.14 ppm 83.80 \ + 0.5 ppm 2.01594 \ + 0.27 ppm 44.0128 \ + 0.087 ppm 131.30 # from US Standard Atmosphere, 1962, Table I.2.7, p. 9 air_1962 78.084 % 28.0134 \ + 20.9476 % 31.9988 \ + 9340 ppm 39.948 \ + 314 ppm 44.00995 \ + 18.18 ppm 20.183 \ + 5.24 ppm 4.0026 \ + 2 ppm 16.04303 \ + 1.14 ppm 83.80 \ + 0.5 ppm 2.01594 \ + 0.5 ppm 44.0128 \ + 0.087 ppm 131.30 # Average molecular weight of air # # Concentration of greenhouse gases CO2, CH4, and N20 are from # https://gml.noaa.gov/ccgg/trends/global.html (accessed 2023-04-10); # others are from NASA Earth Fact Sheet # https://nssdc.gsfc.nasa.gov/planetary/factsheet/earthfact.html (accessed 2023-04-10) # Numbers do not add up to exactly 100% due to roundoff and uncertainty. Water # is highly variable, typically makes up about 1% air_2023 78.08% nitrogen 2 \ + 20.95% oxygen 2 \ + 9340 ppm argon \ + 419 ppm (carbon + oxygen 2) \ + 18.18 ppm neon \ + 5.24 ppm helium \ + 1.92 ppm (carbon + 4 hydrogen) \ + 1.14 ppm krypton \ + 0.55 ppm hydrogen 2 \ + 0.34 ppm (nitrogen 2 + oxygen) # from NASA Earth Fact Sheet (accessed 28 August 2015) # http://nssdc.gsfc.nasa.gov/planetary/factsheet/earthfact.html air_2015 78.08% nitrogen 2 \ + 20.95% oxygen 2 \ + 9340 ppm argon \ + 400 ppm (carbon + oxygen 2) \ + 18.18 ppm neon \ + 5.24 ppm helium \ + 1.7 ppm (carbon + 4 hydrogen) \ + 1.14 ppm krypton \ + 0.55 ppm hydrogen 2 air air_2023 # universal gas constant R_1976 8.31432e3 N m/(kmol K) # polytropic index n polyndx_1976 air_1976 (kg/kmol) gravity/(R_1976 lapserate) - 1 # If desired, redefine using current values for air mol wt and R polyndx polyndx_1976 # polyndx air (kg/kmol) gravity/(R lapserate) - 1 # for comparison with various references polyexpnt (polyndx + 1) / polyndx # The model assumes the following reference values: # sea-level temperature and pressure stdatmT0 288.15 K stdatmP0 atm # "effective radius" for relation of geometric to geopotential height, # at a latitude at which g = 9.80665 m/s (approximately 45.543 deg); no # relation to actual radius earthradUSAtm 6356766 m # Temperature vs. geopotential height h # Assumes 15 degC at sea level # Based on approx 45 deg latitude # Lower limits of domain and upper limits of range are those of the # tables in US Standard Atmosphere (NASA 1976) stdatmTH(h) units=[m;K] domain=[-5000,11e3] range=[217,321] \ stdatmT0+(-lapserate h) ; (stdatmT0+(-stdatmTH))/lapserate # Temperature vs. geometric height z; based on approx 45 deg latitude stdatmT(z) units=[m;K] domain=[-5000,11e3] range=[217,321] \ stdatmTH(geop_ht(z)) ; ~geop_ht(~stdatmTH(stdatmT)) # Pressure vs. geopotential height h # Assumes 15 degC and 101325 Pa at sea level # Based on approx 45 deg latitude # Lower limits of domain and upper limits of range are those of the # tables in US Standard Atmosphere (NASA 1976) stdatmPH(h) units=[m;Pa] domain=[-5000,11e3] range=[22877,177764] \ atm (1 - (lapserate/stdatmT0) h)^(polyndx + 1) ; \ (stdatmT0/lapserate) (1+(-(stdatmPH/stdatmP0)^(1/(polyndx + 1)))) # Pressure vs. geometric height z; based on approx 45 deg latitude stdatmP(z) units=[m;Pa] domain=[-5000,11e3] range=[22877,177764] \ stdatmPH(geop_ht(z)); ~geop_ht(~stdatmPH(stdatmP)) # Geopotential height from geometric height # Based on approx 45 deg latitude # Lower limits of domain and range are somewhat arbitrary; they # correspond to the limits in the US Std Atm tables geop_ht(z) units=[m;m] domain=[-5000,) range=[-5004,) \ (earthradUSAtm z) / (earthradUSAtm + z) ; \ (earthradUSAtm geop_ht) / (earthradUSAtm + (-geop_ht)) # The standard value for the sea-level acceleration due to gravity is # 9.80665 m/s^2, but the actual value varies with latitude (Harrison 1949) # R_eff = 2 g_phi / denom # g_phi = 978.0356e-2 (1+0.0052885 sin(lat)^2+(-0.0000059) sin(2 lat)^2) # or # g_phi = 980.6160e-2 (1+(-0.0026373) cos(2 lat)+0.0000059 cos(2 lat)^2) # denom = 3.085462e-6+2.27e-9 cos(2 lat)+(-2e-12) cos(4 lat) (minutes?) # There is no inverse function; the standard value applies at a latitude # of about 45.543 deg g_phi(lat) units=[deg;m/s2] domain=[0,90] noerror \ 980.6160e-2 (1+(-0.0026373) cos(2 lat)+0.0000059 cos(2 lat)^2) m/s2 # effective Earth radius for relation of geometric height to # geopotential height, as function of latitude (Harrison 1949) earthradius_eff(lat) units=[deg;m] domain=[0,90] noerror \ m 2 9.780356 (1+0.0052885 sin(lat)^2+(-0.0000059) sin(2 lat)^2) / \ (3.085462e-6 + 2.27e-9 cos(2 lat) + (-2e-12) cos(4 lat)) # References # Harrison, L.P. 1949. Relation Between Geopotential and Geometric # Height. In Smithsonian Meteorological Tables. List, Robert J., ed. # 6th ed., 4th reprint, 1968. Washington, DC: Smithsonian Institution. # NASA. US National Aeronautics and Space Administration. 1976. # US Standard Atmosphere 1976. Washington, DC: US Government Printing Office. # Gauge pressure functions # # Gauge pressure is measured relative to atmospheric pressure. In the English # system, where pressure is often given in pounds per square inch, gauge # pressure is often indicated by 'psig' to distinguish it from absolute # pressure, often indicated by 'psia'. At the standard atmospheric pressure # of 14.696 psia, a gauge pressure of 0 psig is an absolute pressure of 14.696 # psia; an automobile tire inflated to 31 psig has an absolute pressure of # 45.696 psia. # # With gaugepressure(), the units must be specified (e.g., gaugepressure(1.5 # bar)); with psig(), the units are taken as psi, so the example above of tire # pressure could be given as psig(31). # # If the normal elevation is significantly different from sea level, change # Patm appropriately, and adjust the lower domain limit on the gaugepressure # definition. Patm atm gaugepressure(x) units=[Pa;Pa] domain=[-101325,) range=[0,) \ x + Patm ; gaugepressure+(-Patm) psig(x) units=[1;Pa] domain=[-14.6959487755135,) range=[0,) \ gaugepressure(x psi) ; ~gaugepressure(psig) / psi # Pressure for underwater diving seawater 0.1 bar / meter msw meter seawater fsw foot seawater # # Wire Gauge # # This area is a nightmare with huge charts of wire gauge diameters # that usually have no clear origin. There are at least 5 competing wire gauge # systems to add to the confusion. The use of wire gauge is related to the # manufacturing method: a metal rod is heated and drawn through a hole. The # size change can't be too big. To get smaller wires, the process is repeated # with a series of smaller holes. Generally larger gauges mean smaller wires. # The gauges often have values such as "00" and "000" which are larger sizes # than simply "0" gauge. In the tables that appear below, these gauges must be # specified as negative numbers (e.g. "00" is -1, "000" is -2, etc). # Alternatively, you can use the following units: # g0 (0) # 1/0 g00 (-1) # 2/0 g000 (-2) # 3/0 g0000 (-3) # 4/0 g00000 (-4) # 5/0 g000000 (-5) # 6/0 g0000000 (-6) # 7/0 # or g1_0 (-1) # 1/0 g2_0 (-1) # 2/0 g3_0 (-2) # 3/0 g4_0 (-3) # 4/0 g5_0 (-4) # 5/0 g6_0 (-5) # 6/0 g7_0 (-6) # 7/0 # American Wire Gauge (AWG), formerly known as Brown & Sharpe Gauge, appears to # be the most important gauge. ASTM B 258 specifies that this gauge is based # on geometric interpolation between gauge 0000, which is 0.46 inches exactly, # and gauge 36 which is 0.005 inches exactly. Therefore, the diameter in # inches of a wire is given by the formula 1|200 92^((36-g)/39). Note that # 92^(1/39) is close to 2^(1/6), so diameter is approximately halved for every # 6 gauges. For the repeated zero values, e.g., "000", use negative numbers # (or the gxx... units) in the formula, as described above. In North America, # sizes larger than 0000 ("4/0") are usually given in terms of circular mils, # beginning with 250 kcmil. # # ASTM B 258 also specifies rounding rules which seem to be ignored by makers # of tables. Gauges up to 44 are to be specified with up to 4 significant # figures, but no closer than 0.0001 inch. Gauges from 44 to 56 are to be # rounded to the nearest 0.00001 inch. # # In addition to being used to measure wire thickness, this gauge is used to # measure the thickness of sheets of aluminum, copper, and most metals other # than steel, iron and zinc. # This converts AWG to a lineal dimension (diameter, in the case of wire). wiregauge(g) units=[1;m] range=(0,) \ 1|200 92^((36+(-g))/39) in; 36+(-39)ln(200 wiregauge/in)/ln(92) wirega() wiregauge awg() wiregauge # In North America, sizes larger than 0000 AWG are usually given in area in # kcmil (formerly, MCM). Outside North America, wire sizes are usually given # in area in mm^2, covered by IEC 60228, Conductors of Insulated Cables. # # This converts AWG to area; in general, there is no exact # correspondence of AWG to standard metric sizes. wiregaugeA(ga) units=[1;m^2] range=(0,) \ circlearea_d(awg(ga)); \ ~awg(~circlearea_d(wiregaugeA)) wiregaA() wiregaugeA awgA() wiregaugeA # Next we have the SWG, the Imperial or British Standard Wire Gauge. This one # is piecewise linear. It was used for aluminum sheets but also shows up for # wire used in jewelry. brwiregauge[in] \ -6 0.5 \ -5 0.464 \ -3 0.4 \ -2 0.372 \ 3 0.252 \ 6 0.192 \ 10 0.128 \ 14 0.08 \ 19 0.04 \ 23 0.024 \ 26 0.018 \ 28 0.0148 \ 30 0.0124 \ 39 0.0052 \ 49 0.0012 \ 50 0.001 swg() brwiregauge # The following is from the Appendix to ASTM B 258 # # For example, in U.S. gage, the standard for sheet metal is based on the # weight of the metal, not on the thickness. 16-gage is listed as # approximately .0625 inch thick and 40 ounces per square foot (the original # standard was based on wrought iron at .2778 pounds per cubic inch; steel # has almost entirely superseded wrought iron for sheet use, at .2833 pounds # per cubic inch). Smaller numbers refer to greater thickness. There is no # formula for converting gage to thickness or weight. # # It's rather unclear from the passage above whether the plate gauge values are # therefore wrong if steel is being used. Reference [15] states that steel is # in fact measured using this gauge (under the name Manufacturers' Standard # Gauge) with a density of 501.84 lb/ft3 = 0.2904 lb/in3 used for steel. # But this doesn't seem to be the correct density of steel (.2833 lb/in3 is # closer). # # This gauge was established in 1893 for purposes of taxation. # Old plate gauge for iron plategauge[(oz/ft^2)/(480*lb/ft^3)] \ -5 300 \ 1 180 \ 14 50 \ 16 40 \ 17 36 \ 20 24 \ 26 12 \ 31 7 \ 36 4.5 \ 38 4 # Manufacturers Standard Gage stdgauge[(oz/ft^2)/(501.84*lb/ft^3)] \ -5 300 \ 1 180 \ 14 50 \ 16 40 \ 17 36 \ 20 24 \ 26 12 \ 31 7 \ 36 4.5 \ 38 4 # A special gauge is used for zinc sheet metal. Notice that larger gauges # indicate thicker sheets. zincgauge[in] \ 1 0.002 \ 10 0.02 \ 15 0.04 \ 19 0.06 \ 23 0.1 \ 24 0.125 \ 27 0.5 \ 28 1 # # Imperial drill bit sizes are reported in inches or in a numerical or # letter gauge. # drillgauge[in] \ 1 0.2280 \ 2 0.2210 \ 3 0.2130 \ 4 0.2090 \ 5 0.2055 \ 6 0.2040 \ 7 0.2010 \ 8 0.1990 \ 9 0.1960 \ 10 0.1935 \ 11 0.1910 \ 12 0.1890 \ 13 0.1850 \ 14 0.1820 \ 15 0.1800 \ 16 0.1770 \ 17 0.1730 \ 18 0.1695 \ 19 0.1660 \ 20 0.1610 \ 22 0.1570 \ 23 0.1540 \ 24 0.1520 \ 25 0.1495 \ 26 0.1470 \ 27 0.1440 \ 28 0.1405 \ 29 0.1360 \ 30 0.1285 \ 31 0.1200 \ 32 0.1160 \ 33 0.1130 \ 34 0.1110 \ 35 0.1100 \ 36 0.1065 \ 38 0.1015 \ 39 0.0995 \ 40 0.0980 \ 41 0.0960 \ 42 0.0935 \ 43 0.0890 \ 44 0.0860 \ 45 0.0820 \ 46 0.0810 \ 48 0.0760 \ 51 0.0670 \ 52 0.0635 \ 53 0.0595 \ 54 0.0550 \ 55 0.0520 \ 56 0.0465 \ 57 0.0430 \ 65 0.0350 \ 66 0.0330 \ 68 0.0310 \ 69 0.0292 \ 70 0.0280 \ 71 0.0260 \ 73 0.0240 \ 74 0.0225 \ 75 0.0210 \ 76 0.0200 \ 78 0.0160 \ 79 0.0145 \ 80 0.0135 \ 88 0.0095 \ 104 0.0031 drillA 0.234 in drillB 0.238 in drillC 0.242 in drillD 0.246 in drillE 0.250 in drillF 0.257 in drillG 0.261 in drillH 0.266 in drillI 0.272 in drillJ 0.277 in drillK 0.281 in drillL 0.290 in drillM 0.295 in drillN 0.302 in drillO 0.316 in drillP 0.323 in drillQ 0.332 in drillR 0.339 in drillS 0.348 in drillT 0.358 in drillU 0.368 in drillV 0.377 in drillW 0.386 in drillX 0.397 in drillY 0.404 in drillZ 0.413 in # Screw sizes # # In the USA, diameters for small wood screws, tapping screws, drive screws, # and machine screws are reported using a gauge number. The dimensions are # covered by ASME B 18.6.1, Wood Screws (Inch Series) and ASME B 18.6.3, # Machine Screws, Tapping Screws, and Metallic Drive Screws (Inch Series). # Machine screw sizes larger than 12 are reported in fractional inches; metric # machine screws are reported as Mxx, where xx is the diameter in mm. # # Not all sizes apply to all screw types. The valid range for machine screws # is 0000-12, with only even values for sizes greater than 5. The valid range # for wood, tapping, and drive screws is 0-24, with only even values for sizes # greater than 9. # # The formula below is easily inferred from tables in ASME B 18.6.1 or ASME # B 18.6.3. The allowed range of sizes is 0000-24, but as noted above, not # all results may be meaningful. For sizes 0000-00, use a negative value of 1 # less than the number of zeros (e.g., for #000, use -2) or the gxx or gx_0 # units as with American Wire Gauge. screwgauge(g) units=[1;m] domain=[-3,24] range=[0.0005334,0.0094488] \ (.06 + .013 g) in ; (screwgauge/in + (-.06)) / .013 # Nominal pipe size (NPS), formerly iron pipe size (IPS) is a North American # set of standard outside diameters (OD) for pipes. The sizes are covered by # ASME B 36.10, Welded and Seamless Wrought Steel Pipe. The wall thickness # (and hence the inside diameter) is determined by the schedule. The value is # dimensionless but roughly corresponds to the outside diameter in inches. # For smaller pipe sizes, there is only an approximate relationship between # nominal and actual diameters: for NPS 1/8 to 12, the NPS and OD values are # different; for NPS 14 and greater, the OD in inches is the same as the NPS. # For example, the actual OD of an NPS 12 pipe is 12.75 inches; the OD of an # NPS 14 pipe is 14 inches. For a given NPS, the outside diameter is # constant; the inside diameter varies with schedule. # # For steel tubing, the OD is the actual size. # # ASME B36.10 gives OD and wall thickness; inside diameters in tables nps40, # nps80, nps40s, and nps80s are calculated from those values # NPS: Nominal Pipe Size # outside diameter: all schedules npsOD[in] \ 0.125 0.405 \ 0.25 0.540 \ 0.375 0.675 \ 0.5 0.840 \ 0.75 1.050 \ 1 1.315 \ 1.25 1.660 \ 1.5 1.900 \ 2 2.375 \ 2.5 2.875 \ 3 3.500 \ 3.5 4.000 \ 4 4.500 \ 5 5.563 \ 6 6.625 \ 8 8.625 \ 10 10.750 \ 12 12.750 \ 14 14.000 \ 16 16.000 \ 18 18.000 \ 20 20.000 \ 24 24.000 # inside diameter: schedule 40 steel and PVC nps40[in] \ 0.125 0.269 \ 0.25 0.364 \ 0.375 0.493 \ 0.5 0.622 \ 0.75 0.824 \ 1 1.049 \ 1.25 1.380 \ 1.5 1.610 \ 2 2.067 \ 2.5 2.469 \ 3 3.068 \ 3.5 3.548 \ 4 4.026 \ 5 5.047 \ 6 6.065 \ 8 7.981 \ 10 10.020 \ 12 11.938 \ 14 13.124 \ 16 15.000 \ 18 16.876 \ 20 18.812 \ 24 22.626 # inside diameter: schedule 80 steel and PVC nps80[in] \ 0.125 0.215 \ 0.25 0.302 \ 0.375 0.423 \ 0.5 0.546 \ 0.75 0.742 \ 1 0.957 \ 1.25 1.278 \ 1.5 1.500 \ 2 1.939 \ 2.5 2.323 \ 3 2.900 \ 3.5 3.364 \ 4 3.826 \ 5 4.813 \ 6 5.761 \ 8 7.625 \ 10 9.564 \ 12 11.376 \ 14 12.500 \ 16 14.314 \ 18 16.126 \ 20 17.938 \ 24 21.564 # inside diameter: schedule 40s (stainless steel) nps40s[in] \ 0.125 0.269 \ 0.25 0.364 \ 0.375 0.493 \ 0.5 0.622 \ 0.75 0.824 \ 1 1.049 \ 1.25 1.380 \ 1.5 1.610 \ 2 2.067 \ 2.5 2.469 \ 3 3.068 \ 3.5 3.548 \ 4 4.026 \ 5 5.047 \ 6 6.065 \ 8 7.981 \ 10 10.020 \ 12 12.000 \ 14 13.250 \ 16 15.250 \ 18 17.250 \ 20 19.250 \ 24 23.250 # inside diameter: schedule 80s (stainless steel) nps80s[in] \ 0.125 0.215 \ 0.25 0.302 \ 0.375 0.423 \ 0.5 0.546 \ 0.75 0.742 \ 1 0.957 \ 1.25 1.278 \ 1.5 1.500 \ 2 1.939 \ 2.5 2.323 \ 3 2.900 \ 3.5 3.364 \ 4 3.826 \ 5 4.813 \ 6 5.761 \ 8 7.625 \ 10 9.750 \ 12 11.750 \ 14 13.000 \ 16 15.000 \ 18 17.000 \ 20 19.000 \ 24 23.000 # iron pipe size ("IPS") aliases ipsOD() npsOD ips40() nps40 ips80() nps80 ips40s() nps40s ips80s() nps80s # diamètre nominal/nominal diameter/Nennweite/NW/nominal bore/NB to NPS # metric sizes are given in dimensionless values that very roughly correspond # to OD in mm. The table below can be used to find pipe sizes in metric # units, e.g., npsOD(DN(15)) = 21.336 mm DN[1] \ 6 0.125 \ 8 0.25 \ 10 0.375 \ 15 0.5 \ 20 0.75 \ 25 1 \ 32 1.25 \ 40 1.5 \ 50 2 \ 65 2.5 \ 80 3 \ 90 3.5 \ 100 4 \ 115 4.5 \ 125 5 \ 150 6 \ 200 8 \ 250 10 \ 300 12 \ 350 14 \ 400 16 \ 450 18 \ 500 20 \ 550 22 \ 600 24 NB() DN NW() DN # standard dimension ratio: OD to ID # SDR = actual diameter / min wall thickness (nominally) # copper tubing # Copper Tube Handbook https://copper.org/applications/plumbing/cth/homepage.php # Copper Development Association https://copper.org/ # for types K, L, and M, OD is 1/8" greater than nominal # for ACR, OD is nominal OD copperTubeOD[in] \ 0.375 0.500 \ 0.5 0.625 \ 0.75 0.875 \ 1 1.125 \ 1.25 1.375 \ 1.5 1.625 \ 2 2.125 \ 2.5 2.625 \ 3 3.125 \ 3.5 3.625 \ 4 4.125 \ 5 5.125 \ 6 6.125 \ 8 8.125 \ 10 10.125 \ 12 12.125 # copper tubing type K: ID copperTypeK[in] \ 0.25 0.305 \ 0.375 0.402 \ 0.5 0.527 \ 0.625 0.652 \ 0.75 0.745 \ 1 0.995 \ 1.25 1.245 \ 1.5 1.481 \ 2 1.959 \ 2.5 2.435 \ 3 2.907 \ 3.5 3.385 \ 4 3.857 \ 5 4.805 \ 6 5.741 \ 8 7.583 \ 10 9.449 \ 12 11.315 # copper tubing type L: ID copperTypeL[in] \ 0.25 0.315 \ 0.375 0.430 \ 0.5 0.545 \ 0.625 0.666 \ 0.75 0.785 \ 1 1.025 \ 1.25 1.265 \ 1.5 1.505 \ 2 1.985 \ 2.5 2.465 \ 3 2.945 \ 3.5 3.425 \ 4 3.905 \ 5 4.875 \ 6 5.845 \ 8 7.725 \ 10 9.625 \ 12 11.565 # copper tubing type M: ID copperTypeM[in] \ 0.375 0.450 \ 0.5 0.569 \ 0.75 0.811 \ 1 1.055 \ 1.25 1.291 \ 1.5 1.527 \ 2 2.009 \ 2.5 2.495 \ 3 2.981 \ 3.5 3.459 \ 4 3.935 \ 5 4.907 \ 6 5.881 \ 8 7.785 \ 10 9.701 \ 12 11.617 # copper tubing: air conditioning and refrigeration: ID # ID is the same as for type L of the same actual OD copperTypeACR[in] \ 0.25 0.200 \ 0.375 0.315 \ 0.5 0.430 \ 0.625 0.545 \ 0.75 0.666 \ 0.875 0.785 \ 1.125 1.025 \ 1.375 1.265 \ 1.625 1.505 \ 2.125 1.985 \ 2.625 2.465 \ 3.125 2.945 \ 3.625 3.425 \ 4.125 3.905 copperOD() copperTubeOD copperK() copperTypeK copperL() copperTypeL copperM() copperTypeM copperACR() copperTypeACR # # Abrasive grit size # # Standards governing abrasive grit sizes are complicated, specifying # fractions of particles that are passed or retained by different mesh # sizes. As a result, it is not possible to make precise comparisons # of different grit standards. The tables below allow the # determination of rough equivlants by using median particle size. # # Standards in the USA are determined by the Unified Abrasives # Manufacturers' Association (UAMA), which resulted from the merger of # several previous organizations. One of the old organizations was # CAMI (Coated Abrasives Manufacturers' Institute). # # UAMA has a web page with plots showing abrasive particle ranges for # various different grits and comparisons between standards. # # https://uama.org/abrasives-101/ # # Abrasives are grouped into "bonded" abrasives for use with grinding # wheels and "coated" abrasives for sandpapers and abrasive films. # The industry uses different grit standards for these two # categories. # # Another division is between "macrogrits", grits below 240 and # "microgrits", which are above 240. Standards differ, as do methods # for determining particle size. In the USA, ANSI B74.12 is the # standard governing macrogrits. ANSI B74.10 covers bonded microgrit # abrasives, and ANSI B74.18 covers coated microgrit abrasives. It # appears that the coated standard is identical to the bonded standard # for grits up through 600 but then diverges significantly. # # European grit sizes are determined by the Federation of European # Producers of Abrasives. http://www.fepa-abrasives.org # # They give two standards, the "F" grit for bonded abrasives and the # "P" grit for coated abrasives. This data is taken directly from # their web page. # FEPA P grit for coated abrasives is commonly seen on sandpaper in # the USA where the paper will be marked P600, for example. FEPA P # grits are said to be more tightly constrained than comparable ANSI # grits so that the particles are more uniform in size and hence give # a better finish. grit_P[micron] \ 12 1815 \ 16 1324 \ 20 1000 \ 24 764 \ 30 642 \ 36 538 \ 40 425 \ 50 336 \ 60 269 \ 80 201 \ 100 162 \ 120 125 \ 150 100 \ 180 82 \ 220 68 \ 240 58.5 \ 280 52.2 \ 320 46.2 \ 360 40.5 \ 400 35 \ 500 30.2 \ 600 25.8 \ 800 21.8 \ 1000 18.3 \ 1200 15.3 \ 1500 12.6 \ 2000 10.3 \ 2500 8.4 # The F grit is the European standard for bonded abrasives such as # grinding wheels grit_F[micron] \ 4 4890 \ 5 4125 \ 6 3460 \ 7 2900 \ 8 2460 \ 10 2085 \ 12 1765 \ 14 1470 \ 16 1230 \ 20 1040 \ 22 885 \ 24 745 \ 30 625 \ 36 525 \ 40 438 \ 46 370 \ 54 310 \ 60 260 \ 70 218 \ 80 185 \ 90 154 \ 100 129 \ 120 109 \ 150 82 \ 180 69 \ 220 58 \ 230 53 \ 240 44.5 \ 280 36.5 \ 320 29.2 \ 360 22.8 \ 400 17.3 \ 500 12.8 \ 600 9.3 \ 800 6.5 \ 1000 4.5 \ 1200 3 \ 1500 2.0 \ 2000 1.2 # According to the UAMA web page, the ANSI bonded and ANSI coated standards # are identical to FEPA F in the macrogrit range (under 240 grit), so these # values are taken from the FEPA F table. The values for 240 and above are # from the UAMA web site and represent the average of the "d50" range # endpoints listed there. ansibonded[micron] \ 4 4890 \ 5 4125 \ 6 3460 \ 7 2900 \ 8 2460 \ 10 2085 \ 12 1765 \ 14 1470 \ 16 1230 \ 20 1040 \ 22 885 \ 24 745 \ 30 625 \ 36 525 \ 40 438 \ 46 370 \ 54 310 \ 60 260 \ 70 218 \ 80 185 \ 90 154 \ 100 129 \ 120 109 \ 150 82 \ 180 69 \ 220 58 \ 240 50 \ 280 39.5 \ 320 29.5 \ 360 23 \ 400 18.25 \ 500 13.9 \ 600 10.55 \ 800 7.65 \ 1000 5.8 \ 1200 3.8 grit_ansibonded() ansibonded # Like the bonded grit, the coated macrogrits below 240 are taken from the # FEPA F table. Data above this is from the UAMA site. Note that the coated # and bonded standards are evidently the same from 240 up to 600 grit, but # starting at 800 grit, the coated standard diverges. The data from UAMA show # that 800 grit coated has an average size slightly larger than the average # size of 600 grit coated/bonded. However, the 800 grit has a significantly # smaller particle size variation. # # Because of this non-monotonicity from 600 grit to 800 grit this definition # produces a warning about the lack of a unique inverse. ansicoated[micron] noerror \ 4 4890 \ 5 4125 \ 6 3460 \ 7 2900 \ 8 2460 \ 10 2085 \ 12 1765 \ 14 1470 \ 16 1230 \ 20 1040 \ 22 885 \ 24 745 \ 30 625 \ 36 525 \ 40 438 \ 46 370 \ 54 310 \ 60 260 \ 70 218 \ 80 185 \ 90 154 \ 100 129 \ 120 109 \ 150 82 \ 180 69 \ 220 58 \ 240 50 \ 280 39.5 \ 320 29.5 \ 360 23 \ 400 18.25 \ 500 13.9 \ 600 10.55 \ 800 11.5 \ 1000 9.5 \ 2000 7.2 \ 2500 5.5 \ 3000 4 \ 4000 3 \ 6000 2 \ 8000 1.2 grit_ansicoated() ansicoated # # Is this correct? This is the JIS Japanese standard used on waterstones # jisgrit[micron] \ 150 75 \ 180 63 \ 220 53 \ 280 48 \ 320 40 \ 360 35 \ 400 30 \ 600 20 \ 700 17 \ 800 14 \ 1000 11.5 \ 1200 9.5 \ 1500 8 \ 2000 6.7 \ 2500 5.5 \ 3000 4 \ 4000 3 \ 6000 2 \ 8000 1.2 # The "Finishing Scale" marked with an A (e.g. A75). This information # is from the web page of the sand paper manufacturer Klingspor # https://www.klingspor.com/ctemplate1.aspx?page=default/html/gritGradingSystems_en-US.html # # I have no information about what this scale is used for. grit_A[micron]\ 16 15.3 \ 25 21.8 \ 30 23.6 \ 35 25.75 \ 45 35 \ 60 46.2 \ 65 53.5 \ 75 58.5 \ 90 65 \ 110 78 \ 130 93 \ 160 127 \ 200 156 # # Grits for DMT brand diamond sharpening stones from # https://www.dmtsharp.com/resources/dmt-catalog-product-information.html # "DMT Diamond Grits" PDF download dmtxxcoarse 120 micron # 120 mesh dmtsilver dmtxxcoarse dmtxx dmtxxcoarse dmtxcoarse 60 micron # 220 mesh dmtx dmtxcoarse dmtblack dmtxcoarse dmtcoarse 45 micron # 325 mesh dmtc dmtcoarse dmtblue dmtcoarse dmtfine 25 micron # 600 mesh dmtred dmtfine dmtf dmtfine dmtefine 9 micron # 1200 mesh dmte dmtefine dmtgreen dmtefine dmtceramic 7 micron # 2200 mesh dmtcer dmtceramic dmtwhite dmtceramic dmteefine 3 micron # 8000 mesh dmttan dmteefine dmtee dmteefine # # The following values come from a page in the Norton Stones catalog, # available at their web page, http://www.nortonstones.com. # hardtranslucentarkansas 6 micron # Natural novaculite (silicon quartz) softarkansas 22 micron # stones extrafineindia 22 micron # India stones are Norton's manufactured fineindia 35 micron # aluminum oxide product mediumindia 53.5 micron coarseindia 97 micron finecrystolon 45 micron # Crystolon stones are Norton's mediumcrystalon 78 micron # manufactured silicon carbide product coarsecrystalon 127 micron # The following are not from the Norton catalog hardblackarkansas 6 micron hardwhitearkansas 11 micron washita 35 micron # # Mesh systems for measuring particle sizes by sifting through a wire # mesh or sieve # # The Tyler system and US Sieve system are based on four steps for # each factor of 2 change in the size, so each size is 2^1|4 different # from the adjacent sizes. Unfortunately, the mesh numbers are # arbitrary, so the sizes cannot be expressed with a functional form. # Various references round the values differently. The mesh numbers # are supposed to correspond to the number of holes per inch, but this # correspondence is only approximate because it doesn't include the # wire size of the mesh. # The Tyler Mesh system was apparently introduced by the WS Tyler # company, but it appears that they no longer use it. They follow the # ASTM E11 standard. meshtyler[micron] \ 2.5 8000 \ 3 6727 \ 3.5 5657 \ 4 4757 \ 5 4000 \ 6 3364 \ 7 2828 \ 8 2378 \ 9 2000 \ 10 1682 \ 12 1414 \ 14 1189 \ 16 1000 \ 20 841 \ 24 707 \ 28 595 \ 32 500 \ 35 420 \ 42 354 \ 48 297 \ 60 250 \ 65 210 \ 80 177 \ 100 149 \ 115 125 \ 150 105 \ 170 88 \ 200 74 \ 250 63 \ 270 53 \ 325 44 \ 400 37 # US Sieve size, ASTM E11 # # The WS Tyler company prints the list from ASTM E11 in # A Calculator for ASTM E11 Standard Sieve Designations # https://blog.wstyler.com/particle-analysis/astm-e11-standard-designations sieve[micron] \ 3.5 5600 \ 4 4750 \ 5 4000 \ 6 3350 \ 7 2800 \ 8 2360 \ 10 2000 \ 12 1700 \ 14 1400 \ 16 1180 \ 18 1000 \ 20 850 \ 25 710 \ 30 600 \ 35 500 \ 40 425 \ 45 355 \ 50 300 \ 60 250 \ 70 212 \ 80 180 \ 100 150 \ 120 125 \ 140 106 \ 170 90 \ 200 75 \ 230 63 \ 270 53 \ 325 45 \ 400 38 \ 450 32 \ 500 25 \ 625 20 # These last two values are not in the standard series # but were included in the ASTM standard because they meshUS() sieve # were in common usage. # British Mesh size, BS 410: 1986 # This system appears to correspond to the Tyler and US system, but # with different mesh numbers. # # http://www.panadyne.com/technical/panadyne_international_sieve_chart.pdf # meshbritish[micron] \ 3 5657 \ 3.5 4757 \ 4 4000 \ 5 3364 \ 6 2828 \ 7 2378 \ 8 2000 \ 10 1682 \ 12 1414 \ 14 1189 \ 16 1000 \ 18 841 \ 22 707 \ 25 595 \ 30 500 \ 36 420 \ 44 354 \ 52 297 \ 60 250 \ 72 210 \ 85 177 \ 100 149 \ 120 125 \ 150 105 \ 170 88 \ 200 74 \ 240 63 \ 300 53 \ 350 44 \ 400 37 # French system, AFNOR NFX11-501: 1970 # The system appears to be based on size doubling every 3 mesh # numbers, though the values have been aggressively rounded. # It's not clear if the unrounded values would be considered # incorrect, so this is given as a table rather than a function. # Functional form: # meshtamis(mesh) units=[1;m] 5000 2^(1|3 (mesh-38)) micron # # http://www.panadyne.com/technical/panadyne_international_sieve_chart.pdf meshtamis[micron] \ 17 40 \ 18 50 \ 19 63 \ 20 80 \ 21 100 \ 22 125 \ 23 160 \ 24 200 \ 25 250 \ 26 315 \ 27 400 \ 28 500 \ 29 630 \ 30 800 \ 31 1000 \ 32 1250 \ 33 1600 \ 34 2000 \ 35 2500 \ 36 3150 \ 37 4000 \ 38 5000 # # Ring size. All ring sizes are given as the circumference of the ring. # # USA ring sizes. Several slightly different definitions seem to be in # circulation. According to [15], the interior diameter of size n ring in # inches is 0.32 n + 0.458 for n ranging from 3 to 13.5 by steps of 0.5. The # size 2 ring is inconsistently 0.538in and no 2.5 size is listed. # # However, other sources list 0.455 + 0.0326 n and 0.4525 + 0.0324 n as the # diameter and list no special case for size 2. (Or alternatively they are # 1.43 + .102 n and 1.4216+.1018 n for measuring circumference in inches.) One # reference claimed that the original system was that each size was 1|10 inch # circumference, but that source doesn't have an explanation for the modern # system which is somewhat different. ringsize(n) units=[1;in] domain=[2,) range=[1.6252,) \ (1.4216+.1018 n) in ; (ringsize/in + (-1.4216))/.1018 # Old practice in the UK measured rings using the "Wheatsheaf gauge" with sizes # specified alphabetically and based on the ring inside diameter in steps of # 1|64 inch. This system was replaced in 1987 by British Standard 6820 which # specifies sizes based on circumference. Each size is 1.25 mm different from # the preceding size. The baseline is size C which is 40 mm circumference. # The new sizes are close to the old ones. Sometimes it's necessary to go # beyond size Z to Z+1, Z+2, etc. sizeAring 37.50 mm sizeBring 38.75 mm sizeCring 40.00 mm sizeDring 41.25 mm sizeEring 42.50 mm sizeFring 43.75 mm sizeGring 45.00 mm sizeHring 46.25 mm sizeIring 47.50 mm sizeJring 48.75 mm sizeKring 50.00 mm sizeLring 51.25 mm sizeMring 52.50 mm sizeNring 53.75 mm sizeOring 55.00 mm sizePring 56.25 mm sizeQring 57.50 mm sizeRring 58.75 mm sizeSring 60.00 mm sizeTring 61.25 mm sizeUring 62.50 mm sizeVring 63.75 mm sizeWring 65.00 mm sizeXring 66.25 mm sizeYring 67.50 mm sizeZring 68.75 mm # Japanese sizes start with size 1 at a 13mm inside diameter and each size is # 1|3 mm larger in diameter than the previous one. They are multiplied by pi # to give circumference. jpringsize(n) units=[1;mm] domain=[1,) range=[0.040840704,) \ (38|3 + n/3) pi mm ; 3 jpringsize/ pi mm + (-38) # The European ring sizes are the length of the circumference in mm minus 40. euringsize(n) units=[1;mm] (n+40) mm ; euringsize/mm + (-40) # # Abbreviations # mph mile/hr brmpg mile/brgallon usmpg mile/usgallon mpg mile/gal kph km/hr fL footlambert fpm ft/min fps ft/s rpm rev/min rps rev/sec mi mile smi mile nmi nauticalmile mbh 1e3 btu/hour mcm 1e3 circularmil ipy inch/year # used for corrosion rates ccf 100 ft^3 # used for selling water [18] Mcf 1000 ft^3 # not million cubic feet [18] kp kilopond kpm kp meter Wh W hour hph hp hour plf lb / foot # pounds per linear foot # # Compatibility units with Unix version # pa Pa ev eV hg Hg oe Oe mh mH rd rod pf pF gr grain nt N hz Hz hd hogshead dry drygallon/gallon nmile nauticalmile beV GeV bev beV coul C # # Radioactivity units # event !dimensionless becquerel event /s # Activity of radioactive source Bq becquerel # curie 3.7e10 Bq # Defined in 1910 as the radioactivity Ci curie # emitted by the amount of radon that is # in equilibrium with 1 gram of radium. rutherford 1e6 Bq # RADIATION_DOSE gray gray J/kg # Absorbed dose of radiation Gy gray # rad 1e-2 Gy # From Radiation Absorbed Dose rep 8.38 mGy # Roentgen Equivalent Physical, the amount # of radiation which , absorbed in the # body, would liberate the same amount # of energy as 1 roentgen of X rays # would, or 97 ergs. sievert J/kg # Dose equivalent: dosage that has the Sv sievert # same effect on human tissues as 200 rem 1e-2 Sv # keV X-rays. Different types of # radiation are weighted by the # Relative Biological Effectiveness # (RBE). # # Radiation type RBE # X-ray, gamma ray 1 # beta rays, > 1 MeV 1 # beta rays, < 1 MeV 1.08 # neutrons, < 1 MeV 4-5 # neutrons, 1-10 MeV 10 # protons, 1 MeV 8.5 # protons, .1 MeV 10 # alpha, 5 MeV 15 # alpha, 1 MeV 20 # # The energies are the kinetic energy # of the particles. Slower particles # interact more, so they are more # effective ionizers, and hence have # higher RBE values. # # rem stands for Roentgen Equivalent # Mammal banana_dose 0.1e-6 sievert # Informal measure of the dose due to # eating one average sized banana roentgen 2.58e-4 C / kg # Ionizing radiation that produces # 1 statcoulomb of charge in 1 cc of # dry air at stp. rontgen roentgen # Sometimes it appears spelled this way sievertunit 8.38 rontgen # Unit of gamma ray dose delivered in one # hour at a distance of 1 cm from a # point source of 1 mg of radium # enclosed in platinum .5 mm thick. eman 1e-7 Ci/m^3 # radioactive concentration mache 3.7e-7 Ci/m^3 # # Atomic weights. The atomic weight of an element is the ratio of the mass of # a mole of the element to 1|12 of a mole of Carbon 12. For each element, we # list the atomic weights of all of the isotopes. The Standard Atomic Weights # apply to the elements in the isotopic composition that occurs naturally on # Earth. These are computed values based on the isotopic distribution, and # may vary for specific samples. Elements which do not occur naturally do # not have Standard Atomic Weights. For these elements, if data on the most # stable isotope is available, is given. Otherwise, the user must specify the # desired isotope. !include elements.units # Density of the elements # # Note some elements occur in multiple forms (allotropes) with different # densities, and they are accordingly listed multiple times. # Density of gas phase elements at STP hydrogendensity 0.08988 g/l heliumdensity 0.1786 g/l neondensity 0.9002 g/l nitrogendensity 1.2506 g/l oxygendensity 1.429 g/l fluorinedensity 1.696 g/l argondensity 1.784 g/l chlorinedensity 3.2 g/l kryptondensity 3.749 g/l xenondensity 5.894 g/l radondensity 9.73 g/l # Density of liquid phase elements near room temperature brominedensity 3.1028 g/cm^3 mercurydensity 13.534 g/cm^3 # Density of solid elements near room temperature lithiumdensity 0.534 g/cm^3 potassiumdensity 0.862 g/cm^3 sodiumdensity 0.968 g/cm^3 rubidiumdensity 1.532 g/cm^3 calciumdensity 1.55 g/cm^3 magnesiumdensity 1.738 g/cm^3 phosphorus_white_density 1.823 g/cm^3 berylliumdensity 1.85 g/cm^3 sulfur_gamma_density 1.92 g/cm^3 cesiumdensity 1.93 g/cm^3 carbon_amorphous_density 1.95 g/cm^3 # average value sulfur_betadensity 1.96 g/cm^3 sulfur_alpha_density 2.07 g/cm^3 carbon_graphite_density 2.267 g/cm^3 phosphorus_red_density 2.27 g/cm^3 # average value silicondensity 2.3290 g/cm^3 phosphorus_violet_density 2.36 g/cm^3 borondensity 2.37 g/cm^3 strontiumdensity 2.64 g/cm^3 phosphorus_black_density 2.69 g/cm^3 aluminumdensity 2.7 g/cm^3 bariumdensity 3.51 g/cm^3 carbon_diamond_density 3.515 g/cm^3 scandiumdensity 3.985 g/cm^3 selenium_vitreous_density 4.28 g/cm^3 selenium_alpha_density 4.39 g/cm^3 titaniumdensity 4.406 g/cm^3 yttriumdensity 4.472 g/cm^3 selenium_gray_density 4.81 g/cm^3 iodinedensity 4.933 g/cm^3 europiumdensity 5.264 g/cm^3 germaniumdensity 5.323 g/cm^3 radiumdensity 5.5 g/cm^3 arsenicdensity 5.727 g/cm^3 tin_alpha_density 5.769 g/cm^3 galliumdensity 5.91 g/cm^3 vanadiumdensity 6.11 g/cm^3 lanthanumdensity 6.162 g/cm^3 telluriumdensity 6.24 g/cm^3 zirconiumdensity 6.52 g/cm^3 antimonydensity 6.697 g/cm^3 ceriumdensity 6.77 g/cm^3 praseodymiumdensity 6.77 g/cm^3 ytterbiumdensity 6.9 g/cm^3 neodymiumdensity 7.01 g/cm^3 zincdensity 7.14 g/cm^3 chromiumdensity 7.19 g/cm^3 manganesedensity 7.21 g/cm^3 promethiumdensity 7.26 g/cm^3 tin_beta_density 7.265 g/cm^3 indiumdensity 7.31 g/cm^3 samariumdensity 7.52 g/cm^3 irondensity 7.874 g/cm^3 gadoliniumdensity 7.9 g/cm^3 terbiumdensity 8.23 g/cm^3 dysprosiumdensity 8.54 g/cm^3 niobiumdensity 8.57 g/cm^3 cadmiumdensity 8.65 g/cm^3 holmiumdensity 8.79 g/cm^3 cobaltdensity 8.9 g/cm^3 nickeldensity 8.908 g/cm^3 erbiumdensity 9.066 g/cm^3 polonium_alpha_density 9.196 g/cm^3 thuliumdensity 9.32 g/cm^3 polonium_beta_density 9.398 g/cm^3 bismuthdensity 9.78 g/cm^3 lutetiumdensity 9.841 g/cm^3 actiniumdensity 10 g/cm^3 molybdenumdensity 10.28 g/cm^3 silverdensity 10.49 g/cm^3 technetiumdensity 11 g/cm^3 leaddensity 11.34 g/cm^3 thoriumdensity 11.7 g/cm^3 thalliumdensity 11.85 g/cm^3 americiumdensity 12 g/cm^3 palladiumdensity 12.023 g/cm^3 rhodiumdensity 12.41 g/cm^3 rutheniumdensity 12.45 g/cm^3 berkelium_beta_density 13.25 g/cm^3 hafniumdensity 13.31 g/cm^3 curiumdensity 13.51 g/cm^3 berkelium_alphadensity 14.78 g/cm^3 californiumdensity 15.1 g/cm^3 protactiniumdensity 15.37 g/cm^3 tantalumdensity 16.69 g/cm^3 uraniumdensity 19.1 g/cm^3 tungstendensity 19.3 g/cm^3 golddensity 19.30 g/cm^3 plutoniumdensity 19.816 g/cm^3 neptuniumdensity 20.45 g/cm^3 # alpha form, only one at room temp rheniumdensity 21.02 g/cm^3 platinumdensity 21.45 g/cm^3 iridiumdensity 22.56 g/cm^3 osmiumdensity 22.59 g/cm^3 # A few alternate names tin_gray tin_alpha_density tin_white tin_beta_density graphitedensity carbon_graphite_density diamonddensity carbon_diamond_density # Predicted density of elements that have not been made in sufficient # quantities for measurement. franciumdensity 2.48 g/cm^3 # liquid, predicted melting point 8 degC astatinedensity 6.35 g/cm^3 einsteiniumdensity 8.84 g/cm^3 fermiumdensity 9.7 g/cm^3 nobeliumdensity 9.9 g/cm^3 mendeleviumdensity 10.3 g/cm^3 lawrenciumdensity 16 g/cm^3 rutherfordiumdensity 23.2 g/cm^3 roentgeniumdensity 28.7 g/cm^3 dubniumdensity 29.3 g/cm^3 darmstadtiumdensity 34.8 g/cm^3 seaborgiumdensity 35 g/cm^3 bohriumdensity 37.1 g/cm^3 meitneriumdensity 37.4 g/cm^3 hassiumdensity 41 g/cm^3 # # population units # people 1 person people death people capita people percapita per capita # TGM dozen based unit system listed on the "dozenal" forum # http://www.dozenalsociety.org.uk/apps/tgm.htm. These units are # proposed as an allegedly more rational alternative to the SI system. Tim 12^-4 hour # Time Grafut gravity Tim^2 # Length based on gravity Surf Grafut^2 # area Volm Grafut^3 # volume Vlos Grafut/Tim # speed Denz Maz/Volm # density Mag Maz gravity # force Maz Volm kg / oldliter # mass based on water # Abbreviations # Tm Tim # Conflicts with Tm = Terameter Gf Grafut Sf Surf Vm Volm Vl Vlos Mz Maz Dz Denz # Dozen based unit prefixes Zena- 12 Duna- 12^2 Trina- 12^3 Quedra- 12^4 Quena- 12^5 Hesa- 12^6 Seva- 12^7 Aka- 12^8 Neena- 12^9 Dexa- 12^10 Lefa- 12^11 Zennila- 12^12 Zeni- 12^-1 Duni- 12^-2 Trini- 12^-3 Quedri- 12^-4 Queni- 12^-5 Hesi- 12^-6 Sevi- 12^-7 Aki- 12^-8 Neeni- 12^-9 Dexi- 12^-10 Lefi- 12^-11 Zennili- 12^-12 # # Traditional Japanese units (shakkanhou) # # The traditional system of weights and measures is called shakkanhou from the # shaku and the ken. Japan accepted SI units in 1891 and legalized conversions # to the traditional system. In 1909 the inch-pound system was also legalized, # so Japan had three legally approved systems. A change to the metric system # started in 1921 but there was a lot of resistance. The Measurement Law of # October 1999 prohibits sales in anything but SI units. However, the old # units still live on in construction and as the basis for paper sizes of books # and tools used for handicrafts. # # Note that units below use the Hepburn romanization system. Some other # systems would render "mou", "jou", and "chou" as "mo", "jo" and "cho". # # # http://hiramatu-hifuka.com/onyak/onyindx.html # Japanese Proportions. These are still in everyday use. They also # get used as units to represent the proportion of the standard unit. wari_proportion 1|10 wari wari_proportion bu_proportion 1|100 # The character bu can also be read fun or bun # but usually "bu" is used for units. rin_proportion 1|1000 mou_proportion 1|10000 # Japanese Length Measures # # The length system is called kanejaku or # square and originated in China. It was # adopted as Japan's official measure in 701 # by the Taiho Code. This system is still in # common use in architecture and clothing. shaku 1|3.3 m mou 1|10000 shaku rin 1|1000 shaku bu_distance 1|100 shaku sun 1|10 shaku jou_distance 10 shaku jou jou_distance kanejakusun sun # Alias to emphasize architectural name kanejaku shaku kanejakujou jou # http://en.wikipedia.org/wiki/Taiwanese_units_of_measurement taichi shaku # http://zh.wikipedia.org/wiki/台尺 taicun sun # http://zh.wikipedia.org/wiki/台制 !utf8 台尺 taichi # via Hanyu Pinyin romanizations 台寸 taicun !endutf8 # In context of clothing, shaku is different from architecture kujirajaku 10|8 shaku kujirajakusun 1|10 kujirajaku kujirajakubu 1|100 kujirajaku kujirajakujou 10 kujirajaku tan_distance 3 kujirajakujou ken 6 shaku # Also sometimes 6.3, 6.5, or 6.6 # http://www.homarewood.co.jp/syakusun.htm # mostly unused chou_distance 60 ken chou chou_distance ri 36 chou # Japanese Area Measures # Tsubo is still used for land size, though the others are more # recognized by their homonyms in the other measurements. gou_area 1|10 tsubo tsubo 36 shaku^2 # Size of two tatami = ken^2 ?? se 30 tsubo tan_area 10 se chou_area 10 tan_area # http://en.wikipedia.org/wiki/Taiwanese_units_of_measurement ping tsubo # http://zh.wikipedia.org/wiki/坪 jia 2934 ping # http://zh.wikipedia.org/wiki/甲_(单位) fen 1|10 jia # http://zh.wikipedia.org/wiki/分 fen_area 1|10 jia # Protection against future collisions !utf8 坪 ping # via Hanyu Pinyin romanizations 甲 jia 分 fen 分地 fen_area # Protection against future collisions !endutf8 # Japanese architecture is based on a "standard" size of tatami mat. # Room sizes today are given in number of tatami, and this number # determines the spacing between colums and hence sizes of sliding # doors and paper screens. However, every region has its own slightly # different tatami size. Edoma, used in and around Tokyo and # Hokkaido, is becoming a nationwide standard. Kyouma is used around # Kyoto, Osaka and Kyuushu, and Chuukyouma is used around Nagoya. # Note that the tatami all have the aspect ratio 2:1 so that the mats # can tile the room with some of them turned 90 degrees. # # http://www.moon2.net/tatami/infotatami/structure.html edoma (5.8*2.9) shaku^2 kyouma (6.3*3.15) shaku^2 chuukyouma (6*3) shaku^2 jou_area edoma tatami jou_area # Japanese Volume Measures # The "shou" is still used for such things as alcohol and seasonings. # Large quantities of paint are still purchased in terms of "to". shaku_volume 1|10 gou_volume gou_volume 1|10 shou gou gou_volume shou (4.9*4.9*2.7) sun^3 # The character shou which is # the same as masu refers to a # rectangular wooden cup used to # measure liquids and cereal. # Sake is sometimes served in a masu # Note that it happens to be # EXACTLY 7^4/11^3 liters. to 10 shou koku 10 to # No longer used; historically a measure of rice # Japanese Weight Measures # # https://web.archive.org/web/20040927115452/http://wyoming.hp.infoseek.co.jp/zatugaku/zamoney.html # https://en.wikipedia.org/wiki/Japanese_units_of_measurement # Not really used anymore. rin_weight 1|10 bu_weight bu_weight 1|10 monme fun 1|10 monme monme momme kin 160 monme kan 1000 monme kwan kan # This was the old pronunciation of the unit. # The old spelling persisted a few centuries # longer and was not changed until around # 1950. # http://en.wikipedia.org/wiki/Taiwanese_units_of_measurement # says: "Volume measure in Taiwan is largely metric". taijin kin # http://zh.wikipedia.org/wiki/台斤 tailiang 10 monme # http://zh.wikipedia.org/wiki/台斤 taiqian monme # http://zh.wikipedia.org/wiki/台制 !utf8 台斤 taijin # via Hanyu Pinyin romanizations 台兩 tailiang 台錢 taiqian !endutf8 # # Australian unit # australiasquare (10 ft)^2 # Used for house area # # A few German units as currently in use. # zentner 50 kg doppelzentner 2 zentner pfund 500 g # The klafter, which was used in central Europe, was derived from the span of # outstretched arms. # # https://en.wikipedia.org/wiki/Obsolete_Austrian_units_of_measurement # https://www.llv.li/files/abi/klafter-m2-en.pdf austriaklafter 1.89648384 m # Exact definition, 23 July 1871 austriafoot 1|6 austriaklafter prussiaklafter 1.88 m prussiafoot 1|6 prussiaklafter bavariaklafter 1.751155 m bavariafoot 1|6 bavariaklafter hesseklafter 2.5 m hessefoot 1|6 hesseklafter switzerlandklafter metricklafter switzerlandfoot 1|6 switzerlandklafter swissklafter switzerlandklafter swissfoot 1|6 swissklafter metricklafter 1.8 m austriayoke 8 austriaklafter * 200 austriaklafter liechtensteinsquareklafter 3.596652 m^2 # Used until 2017 to measure land area liechtensteinklafter sqrt(liechtensteinsquareklafter) # The klafter was also used to measure volume of wood, generally being a stack # of wood one klafter wide, one klafter long, with logs 3 feet (half a klafter) # in length prussiawoodklafter 0.5 prussiaklafter^3 austriawoodklafter 0.5 austriaklafter^3 festmeter m^3 # modern measure of wood, solid cube raummeter 0.7 festmeter # Air space between the logs, stacked schuettraummeter 0.65 raummeter # A cubic meter volume of split and cut # firewood in a loose, unordered # pile, not stacked. This is called # "tipped". !utf8 schüttraummeter schuettraummeter !endutf8 # # Swedish (Sweden) pre-metric units of 1739. # The metric system was adopted in 1878. # https://sv.wikipedia.org/wiki/Verkm%C3%A5tt # verklinje 2.0618125 mm verktum 12 verklinje kvarter 6 verktum fot 2 kvarter aln 2 fot famn 3 aln # # Some traditional Russian measures # # If you would like to help expand this section and understand # cyrillic transliteration, let me know. These measures are meant to # reflect common usage, e.g. in translated literature. # dessiatine 2400 sazhen^2 # Land measure dessjatine dessiatine funt 409.51718 grams # similar to pound zolotnik 1|96 funt # used for precious metal measure pood 40 funt # common in agricultural measure arshin (2 + 1|3) feet sazhen 3 arshin # analogous to fathom verst 500 sazhen # of similar use to mile versta verst borderverst 1000 sazhen russianmile 7 verst # # Old French distance measures, from French Weights and Measures # Before the Revolution by Zupko # frenchfoot 144|443.296 m # pied de roi, the standard of Paris. pied frenchfoot # Half of the hashimicubit, frenchfeet frenchfoot # instituted by Charlemagne. frenchinch 1|12 frenchfoot # This exact definition comes from frenchthumb frenchinch # a law passed on 10 Dec 1799 which pouce frenchthumb # fixed the meter at # 3 frenchfeet + 11.296 lignes. frenchline 1|12 frenchinch # This is supposed to be the size ligne frenchline # of the average barleycorn frenchpoint 1|12 frenchline toise 6 frenchfeet arpent 180^2 pied^2 # The arpent is 100 square perches, # but the perche seems to vary a lot # and can be 18 feet, 20 feet, or 22 # feet. This measure was described # as being in common use in Canada in # 1934 (Websters 2nd). The value # given here is the Paris standard # arpent. frenchgrain 1|18827.15 kg # Weight of a wheat grain, hence # smaller than the British grain. frenchpound 9216 frenchgrain # # Before the Imperial Weights and Measures Act of 1824, various different # weights and measures were in use in different places. # # Scots linear measure scotsinch 1.00540054 UKinch scotslink 1|100 scotschain scotsfoot 12 scotsinch scotsfeet scotsfoot scotsell 37 scotsinch scotsfall 6 scotsell scotschain 4 scotsfall scotsfurlong 10 scotschain scotsmile 8 scotsfurlong # Scots area measure scotsrood 40 scotsfall^2 scotsacre 4 scotsrood # Irish linear measure irishinch UKinch irishpalm 3 irishinch irishspan 3 irishpalm irishfoot 12 irishinch irishfeet irishfoot irishcubit 18 irishinch irishyard 3 irishfeet irishpace 5 irishfeet irishfathom 6 irishfeet irishpole 7 irishyard # Only these values irishperch irishpole # are different from irishchain 4 irishperch # the British Imperial irishlink 1|100 irishchain # or English values for irishfurlong 10 irishchain # these lengths. irishmile 8 irishfurlong # # Irish area measure irishrood 40 irishpole^2 irishacre 4 irishrood # English wine capacity measures (Winchester measures) winepint 1|2 winequart winequart 1|4 winegallon winegallon 231 UKinch^3 # Sometimes called the Winchester Wine Gallon, # it was legalized in 1707 by Queen Anne, and # given the definition of 231 cubic inches. It # had been in use for a while as 8 pounds of wine # using a merchant's pound, but the definition of # the merchant's pound had become uncertain. A # pound of 15 tower ounces (6750 grains) had been # common, but then a pound of 15 troy ounces # (7200 grains) gained popularity. Because of # the switch in the value of the merchants pound, # the size of the wine gallon was uncertain in # the market, hence the official act in 1707. # The act allowed that a six inch tall cylinder # with a 7 inch diameter was a lawful wine # gallon. (This comes out to 230.9 in^3.) # Note also that in Britain a legal conversion # was established to the 1824 Imperial gallon # then taken as 277.274 in^3 so that the wine # gallon was 0.8331 imperial gallons. This is # 231.1 cubic inches (using the international # inch). winerundlet 18 winegallon winebarrel 31.5 winegallon winetierce 42 winegallon winehogshead 2 winebarrel winepuncheon 2 winetierce winebutt 2 winehogshead winepipe winebutt winetun 2 winebutt # English beer and ale measures used 1803-1824 and used for beer before 1688 beerpint 1|2 beerquart beerquart 1|4 beergallon beergallon 282 UKinch^3 beerbarrel 36 beergallon beerhogshead 1.5 beerbarrel # English ale measures used from 1688-1803 for both ale and beer alepint 1|2 alequart alequart 1|4 alegallon alegallon beergallon alebarrel 34 alegallon alehogshead 1.5 alebarrel # Scots capacity measure scotsgill 1|4 mutchkin mutchkin 1|2 choppin choppin 1|2 scotspint scotspint 1|2 scotsquart scotsquart 1|4 scotsgallon scotsgallon 827.232 UKinch^3 scotsbarrel 8 scotsgallon jug scotspint # Scots dry capacity measure scotswheatlippy 137.333 UKinch^3 # Also used for peas, beans, rye, salt scotswheatlippies scotswheatlippy scotswheatpeck 4 scotswheatlippy scotswheatfirlot 4 scotswheatpeck scotswheatboll 4 scotswheatfirlot scotswheatchalder 16 scotswheatboll scotsoatlippy 200.345 UKinch^3 # Also used for barley and malt scotsoatlippies scotsoatlippy scotsoatpeck 4 scotsoatlippy scotsoatfirlot 4 scotsoatpeck scotsoatboll 4 scotsoatfirlot scotsoatchalder 16 scotsoatboll # Scots Tron weight trondrop 1|16 tronounce tronounce 1|20 tronpound tronpound 9520 grain tronstone 16 tronpound # Irish liquid capacity measure irishnoggin 1|4 irishpint irishpint 1|2 irishquart irishquart 1|2 irishpottle irishpottle 1|2 irishgallon irishgallon 217.6 UKinch^3 irishrundlet 18 irishgallon irishbarrel 31.5 irishgallon irishtierce 42 irishgallon irishhogshead 2 irishbarrel irishpuncheon 2 irishtierce irishpipe 2 irishhogshead irishtun 2 irishpipe # Irish dry capacity measure irishpeck 2 irishgallon irishbushel 4 irishpeck irishstrike 2 irishbushel irishdrybarrel 2 irishstrike irishquarter 2 irishbarrel # English Tower weights, abolished in 1528 towerpound 5400 grain towerounce 1|12 towerpound towerpennyweight 1|20 towerounce towergrain 1|32 towerpennyweight # English Mercantile weights, used since the late 12th century mercpound 6750 grain mercounce 1|15 mercpound mercpennyweight 1|20 mercounce # English weights for lead leadstone 12.5 lb fotmal 70 lb leadwey 14 leadstone fothers 12 leadwey # English Hay measure newhaytruss 60 lb # New and old here seem to refer to "new" newhayload 36 newhaytruss # hay and "old" hay rather than a new unit oldhaytruss 56 lb # and an old unit. oldhayload 36 oldhaytruss # English wool measure woolclove 7 lb woolstone 2 woolclove wooltod 2 woolstone woolwey 13 woolstone woolsack 2 woolwey woolsarpler 2 woolsack woollast 6 woolsarpler # # Ancient history units: There tends to be uncertainty in the definitions # of the units in this section # These units are from [11] # Roman measure. The Romans had a well defined distance measure, but their # measures of weight were poor. They adopted local weights in different # regions without distinguishing among them so that there are half a dozen # different Roman "standard" weight systems. romanfoot 296 mm # There is some uncertainty in this definition romanfeet romanfoot # from which all the other units are derived. pes romanfoot # This value appears in numerous sources. In "The pedes romanfoot # Roman Land Surveyors", Dilke gives 295.7 mm. romaninch 1|12 romanfoot # The subdivisions of the Roman foot have the romandigit 1|16 romanfoot # same names as the subdivisions of the pound, romanpalm 1|4 romanfoot # but we can't have the names for different romancubit 18 romaninch # units. romanpace 5 romanfeet # Roman double pace (basic military unit) passus romanpace romanperch 10 romanfeet stade 125 romanpaces stadia stade stadium stade romanmile 8 stadia # 1000 paces romanleague 1.5 romanmile schoenus 4 romanmile # Other values for the Roman foot (from Dilke) earlyromanfoot 29.73 cm pesdrusianus 33.3 cm # or 33.35 cm, used in Gaul & Germany in 1st c BC lateromanfoot 29.42 cm # Roman areas actuslength 120 romanfeet # length of a Roman furrow actus 120*4 romanfeet^2 # area of the furrow squareactus 120^2 romanfeet^2 # actus quadratus acnua squareactus iugerum 2 squareactus iugera iugerum jugerum iugerum jugera iugerum heredium 2 iugera # heritable plot heredia heredium centuria 100 heredia centurium centuria # Roman volumes sextarius 35.4 in^3 # Basic unit of Roman volume. As always, sextarii sextarius # there is uncertainty. Six large Roman # measures survive with volumes ranging from # 34.4 in^3 to 39.55 in^3. Three of them # cluster around the size given here. # # But the values for this unit vary wildly # in other sources. One reference gives 0.547 # liters, but then says the amphora is a # cubic Roman foot. This gives a value for the # sextarius of 0.540 liters. And the # encyclopedia Britannica lists 0.53 liters for # this unit. Both [7] and [11], which were # written by scholars of weights and measures, # give the value of 35.4 cubic inches. cochlearia 1|48 sextarius cyathi 1|12 sextarius acetabula 1|8 sextarius quartaria 1|4 sextarius quartarius quartaria heminae 1|2 sextarius hemina heminae cheonix 1.5 sextarii # Dry volume measures (usually) semodius 8 sextarius semodii semodius modius 16 sextarius modii modius # Liquid volume measures (usually) congius 12 heminae congii congius amphora 8 congii amphorae amphora # Also a dry volume measure culleus 20 amphorae quadrantal amphora # Roman weights libra 5052 grain # The Roman pound varied significantly librae libra # from 4210 grains to 5232 grains. Most of romanpound libra # the standards were obtained from the weight uncia 1|12 libra # of particular coins. The one given here is unciae uncia # based on the Gold Aureus of Augustus which romanounce uncia # was in use from BC 27 to AD 296. deunx 11 uncia dextans 10 uncia dodrans 9 uncia bes 8 uncia seprunx 7 uncia semis 6 uncia quincunx 5 uncia triens 4 uncia quadrans 3 uncia sextans 2 uncia sescuncia 1.5 uncia semuncia 1|2 uncia siscilius 1|4 uncia sextula 1|6 uncia semisextula 1|12 uncia scriptulum 1|24 uncia scrupula scriptulum romanobol 1|2 scrupula romanaspound 4210 grain # Old pound based on bronze coinage, the # earliest money of Rome BC 338 to BC 268. # Egyptian length measure egyptianroyalcubit 20.63 in # plus or minus .2 in egyptianpalm 1|7 egyptianroyalcubit egyptiandigit 1|4 egyptianpalm egyptianshortcubit 6 egyptianpalm doubleremen 29.16 in # Length of the diagonal of a square with remendigit 1|40 doubleremen # side length of 1 royal egyptian cubit. # This is divided into 40 digits which are # not the same size as the digits based on # the royal cubit. # Greek length measures greekfoot 12.45 in # Listed as being derived from the greekfeet greekfoot # Egyptian Royal cubit in [11]. It is greekcubit 1.5 greekfoot # said to be 3|5 of a 20.75 in cubit. pous greekfoot podes greekfoot orguia 6 greekfoot greekfathom orguia stadion 100 orguia akaina 10 greekfeet plethron 10 akaina greekfinger 1|16 greekfoot homericcubit 20 greekfingers # Elbow to end of knuckles. shortgreekcubit 18 greekfingers # Elbow to start of fingers. ionicfoot 296 mm doricfoot 326 mm olympiccubit 25 remendigit # These olympic measures were not as olympicfoot 2|3 olympiccubit # common as the other greek measures. olympicfinger 1|16 olympicfoot # They were used in agriculture. olympicfeet olympicfoot olympicdakylos olympicfinger olympicpalm 1|4 olympicfoot olympicpalestra olympicpalm olympicspithame 3|4 foot olympicspan olympicspithame olympicbema 2.5 olympicfeet olympicpace olympicbema olympicorguia 6 olympicfeet olympicfathom olympicorguia olympiccord 60 olympicfeet olympicamma olympiccord olympicplethron 100 olympicfeet olympicstadion 600 olympicfeet # Greek capacity measure greekkotyle 270 ml # This approximate value is obtained xestes 2 greekkotyle # from two earthenware vessels that khous 12 greekkotyle # were reconstructed from fragments. metretes 12 khous # The kotyle is a day's corn ration choinix 4 greekkotyle # for one man. hekteos 8 choinix medimnos 6 hekteos # Greek weight. Two weight standards were used, an Aegina standard based # on the Beqa shekel and an Athens (attic) standard. aeginastater 192 grain # Varies up to 199 grain aeginadrachmae 1|2 aeginastater aeginaobol 1|6 aeginadrachmae aeginamina 50 aeginastaters aeginatalent 60 aeginamina # Supposedly the mass of a cubic foot # of water (whichever foot was in use) atticstater 135 grain # Varies 134-138 grain atticdrachmae 1|2 atticstater atticobol 1|6 atticdrachmae atticmina 50 atticstaters attictalent 60 atticmina # Supposedly the mass of a cubic foot # of water (whichever foot was in use) # "Northern" cubit and foot. This was used by the pre-Aryan civilization in # the Indus valley. It was used in Mesopotamia, Egypt, North Africa, China, # central and Western Europe until modern times when it was displaced by # the metric system. northerncubit 26.6 in # plus/minus .2 in northernfoot 1|2 northerncubit sumeriancubit 495 mm kus sumeriancubit sumerianfoot 2|3 sumeriancubit assyriancubit 21.6 in assyrianfoot 1|2 assyriancubit assyrianpalm 1|3 assyrianfoot assyriansusi 1|20 assyrianpalm susi assyriansusi persianroyalcubit 7 assyrianpalm # Arabic measures. The arabic standards were meticulously kept. Glass weights # accurate to .2 grains were made during AD 714-900. hashimicubit 25.56 in # Standard of linear measure used # in Persian dominions of the Arabic # empire 7-8th cent. Is equal to two # French feet. blackcubit 21.28 in arabicfeet 1|2 blackcubit arabicfoot arabicfeet arabicinch 1|12 arabicfoot arabicmile 4000 blackcubit silverdirhem 45 grain # The weights were derived from these two tradedirhem 48 grain # units with two identically named systems # used for silver and used for trade purposes silverkirat 1|16 silverdirhem silverwukiyeh 10 silverdirhem silverrotl 12 silverwukiyeh arabicsilverpound silverrotl tradekirat 1|16 tradedirhem tradewukiyeh 10 tradedirhem traderotl 12 tradewukiyeh arabictradepound traderotl # Miscellaneous ancient units parasang 3.5 mile # Persian unit of length usually thought # to be between 3 and 3.5 miles biblicalcubit 21.8 in hebrewcubit 17.58 in li 10|27.8 mile # Chinese unit of length # 100 li is considered a day's march liang 11|3 oz # Chinese weight unit # Medieval time units. According to the OED, these appear in Du Cange # by Papias. timepoint 1|5 hour # also given as 1|4 timeminute 1|10 hour timeostent 1|60 hour timeounce 1|8 timeostent timeatom 1|47 timeounce # Given in [15], these subdivisions of the grain were supposedly used # by jewelers. The mite may have been used but the blanc could not # have been accurately measured. mite 1|20 grain droit 1|24 mite periot 1|20 droit blanc 1|24 periot # # Localization # !var UNITS_ENGLISH US hundredweight ushundredweight ton uston scruple apscruple fluidounce usfluidounce gallon usgallon bushel usbushel quarter quarterweight cup uscup tablespoon ustablespoon teaspoon usteaspoon dollar US$ cent $ 0.01 penny cent minim minimvolume pony ponyvolume grand usgrand firkin usfirkin hogshead ushogshead cable uscable !endvar !var UNITS_ENGLISH GB hundredweight brhundredweight ton brton scruple brscruple fluidounce brfluidounce gallon brgallon bushel brbushel quarter brquarter chaldron brchaldron cup brcup teacup brteacup tablespoon brtablespoon teaspoon brteaspoon dollar US$ cent $ 0.01 penny brpenny minim minimnote pony brpony grand brgrand firkin brfirkin hogshead brhogshead cable brcable !endvar !varnot UNITS_ENGLISH GB US !message Unknown value for environment variable UNITS_ENGLISH. Should be GB or US. !endvar !utf8 ⅛- 1|8 ¼- 1|4 ⅜- 3|8 ½- 1|2 ⅝- 5|8 ¾- 3|4 ⅞- 7|8 ⅙- 1|6 ⅓- 1|3 ⅔- 2|3 ⅚- 5|6 ⅕- 1|5 ⅖- 2|5 ⅗- 3|5 ⅘- 4|5 # U+2150- 1|7 For some reason these characters are getting # U+2151- 1|9 flagged as invalid UTF8. # U+2152- 1|10 #⅐- 1|7 # fails under MacOS #⅑- 1|9 # fails under MacOS #⅒- 1|10 # fails under MacOS ℯ exp(1) # U+212F, base of natural log µ- micro # micro sign U+00B5 μ- micro # small mu U+03BC ångström angstrom Å angstrom # angstrom symbol U+212B Å angstrom # A with ring U+00C5 röntgen roentgen K K # Kelvin symbol, U+212A ℃ degC ℉ degF °C degC °F degF °K K # °K is incorrect notation °R degR ℓ liter # unofficial abbreviation used in some places Ω ohm # Ohm symbol U+2126 Ω ohm # Greek capital omega U+03A9 ℧ mho G₀ G0 H₀ H0 Z₀ Z0 a₀ a0 n₀ n0 ε₀ epsilon0 μ₀ mu0 Φ₀ Phi0 R∞ Rinfinity R_∞ Rinfinity λ_C lambda_C μ_B mu_B ν_133Cs nu_133Cs ʒ dram # U+0292 ℈ scruple ℥ ounce ℔ lb ℎ h ℏ hbar τ tau π pi # Greek letter pi 𝜋 pi # mathematical italic small pi α alpha σ sigma ‰ 1|1000 ‱ 1|10000 # # Unicode currency symbols # ¢ cent £ britainpound ¥ japanyen € euro ₩ southkoreawon ₪ israelnewshekel ₤ lira # ₺ turkeylira # fails under MacOS ₨ rupee # unofficial legacy rupee sign # ₹ indiarupee # official rupee sign # MacOS fail #؋ afghanafghani # fails under MacOS ฿ thailandbaht ₡ costaricacolon ₣ francefranc ₦ nigerianaira ₧ spainpeseta ₫ vietnamdong ₭ laokip ₮ mongoliatugrik ₯ greecedrachma ₱ philippinepeso # ₲ paraguayguarani # fails under MacOS #₴ ukrainehryvnia # fails under MacOS #₵ ghanacedi # fails under MacOS #₸ kazakhstantenge # fails under MacOS #₼ azerbaijanmanat # fails under MacOS #₽ russiaruble # fails under MacOS #₾ georgialari # fails under MacOS ﷼ iranrial ﹩ $ ¢ ¢ £ £ ¥ ¥ ₩ ₩ # # Square Unicode symbols starting at U+3371 # ㍱ hPa ㍲ da ㍳ au ㍴ bar # ㍵ oV??? ㍶ pc #㍷ dm invalid on Mac #㍸ dm^2 invalid on Mac #㍹ dm^3 invalid on Mac ㎀ pA ㎁ nA ㎂ µA ㎃ mA ㎄ kA ㎅ kB ㎆ MB ㎇ GB ㎈ cal ㎉ kcal ㎊ pF ㎋ nF ㎌ µF ㎍ µg ㎎ mg ㎏ kg ㎐ Hz ㎑ kHz ㎒ MHz ㎓ GHz ㎔ THz ㎕ µL ㎖ mL ㎗ dL ㎘ kL ㎙ fm ㎚ nm ㎛ µm ㎜ mm ㎝ cm ㎞ km ㎟ mm^2 ㎠ cm^2 ㎡ m^2 ㎢ km^2 ㎣ mm^3 ㎤ cm^3 ㎥ m^3 ㎦ km^3 ㎧ m/s ㎨ m/s^2 ㎩ Pa ㎪ kPa ㎫ MPa ㎬ GPa ㎭ rad ㎮ rad/s ㎯ rad/s^2 ㎰ ps ㎱ ns ㎲ µs ㎳ ms ㎴ pV ㎵ nV ㎶ µV ㎷ mV ㎸ kV ㎹ MV ㎺ pW ㎻ nW ㎼ µW ㎽ mW ㎾ kW ㎿ MW ㏀ kΩ ㏁ MΩ ㏃ Bq ㏄ cc ㏅ cd ㏆ C/kg ㏈() dB ㏉ Gy ㏊ ha # ㏋ HP?? ㏌ in # ㏍ KK?? # ㏎ KM??? ㏏ kt ㏐ lm # ㏑ ln # ㏒ log ㏓ lx ㏔ mb ㏕ mil ㏖ mol ㏗() pH ㏙ ppm # ㏚ PR??? ㏛ sr ㏜ Sv ㏝ Wb #㏞ V/m Invalid on Mac #㏟ A/m Invalid on Mac #㏿ gal Invalid on Mac !endutf8 ############################################################################ # # Unit list aliases # # These provide a shorthand for conversions to unit lists. # ############################################################################ !unitlist uswt lb;oz !unitlist hms hr;min;sec !unitlist time year;day;hr;min;sec !unitlist dms deg;arcmin;arcsec !unitlist ftin ft;in;1|8 in !unitlist ftin4 ft;in;1|4 in !unitlist ftin8 ft;in;1|8 in !unitlist ftin16 ft;in;1|16 in !unitlist ftin32 ft;in;1|32 in !unitlist ftin64 ft;in;1|64 in !unitlist inchfine in;1|8 in;1|16 in;1|32 in;1|64 in !unitlist by2 1;1|2;1|4;1|8;1|16;1|32;1|64;1|128;1|256 !unitlist usvol cup;3|4 cup;2|3 cup;1|2 cup;1|3 cup;1|4 cup;\ tbsp;tsp;1|2 tsp;1|4 tsp;1|8 tsp ############################################################################ # # The following units were in the Unix units database but do not appear in # this file: # # wey used for cheese, salt and other goods. Measured mass or # waymass volume depending on what was measured and where the measuring # took place. A wey of cheese ranged from 200 to 324 pounds. # # sack No precise definition # # spindle The length depends on the type of yarn # # block Defined variously on different computer systems # # erlang A unit of telephone traffic defined variously. # Omitted because there are no other units for this # dimension. Is this true? What about CCS = 1/36 erlang? # Erlang is supposed to be dimensionless. One erlang means # a single channel occupied for one hour. # ############################################################################ # # The following have been suggested or considered and deemed out of scope. # They will not be added to GNU units. # # Conversions between different calendar systems used in different countries or # different historical periods are out of scope for units and will not be added. # # Wind chill and heat index cannot be handled because they are bivarite, # with dependence on both the temperature and wind speed or humidity. # # Plain english text output like "one hectare is equivalent to one hundred # million square centimeters" is out of scope. # units-2.24/units.txt0000664000175000017500000050712614720535071014005 0ustar adrianadrianUNITS(1) General Commands Manual UNITS(1) NAME units -- unit conversion and calculation program SYNOPSIS units [from-unit [to-unit]] units [-hcemnSpqsv1trUVI] [-d digits] [-f units file] [-L logfile] [-l locale] [-o format] [-u unit system] [from-unit [to-unit]] units [--help] [--check] [--check-verbose] [--verbose-check] [--digits digits] [--exponential] [--file units file] [--log logfile] [--locale locale] [--minus] [--oldstar] [--newstar] [--nolists] [--show-factor] [--conformable] [--output-format format] [--product] [--quiet] [--silent] [--strict] [--verbose] [--compact] [--one-line] [--terse] [--round] [--unitsfile] [--units units system] [--version] [--info] [from-unit [to-unit]] DESCRIPTION The units program converts quantities expressed in various systems of measurement to their equivalents in other systems of measurement. Like many similar programs, it can handle multiplicative scale changes. It can also handle nonlinear conversions such as Fahrenheit to Celsius; see Temperature Conversions. The program can also perform conversions from and to sums of units, such as converting between meters and feet plus inches. But Fahrenheit to Celsius is linear, you insist. Not so. A transfor- mation T is linear if T(x + y) = T(x) + T(y) and this fails for T(x) = ax + b. This transformation is affine, but not linear--see https://en.wikipedia.org/wiki/Linear_map. Basic operation is simple: you enter the units that you want to convert from and the units that you want to convert to. You can use the pro- gram interactively with prompts, or you can use it from the command line. Beyond simple unit conversions, units can be used as a general-purpose scientific calculator that keeps track of units in its calculations. You can form arbitrary complex mathematical expressions of dimensions including sums, products, quotients, powers, and even roots of dimen- sions. Thus you can ensure accuracy and dimensional consistency when working with long expressions that involve many different units that may combine in complex ways; for an illustration, see Complicated Unit Expressions. The units are defined in several external data files. You can use the extensive data files that come with the program, or you can provide your own data file to suit your needs. You can also use your own data file to supplement the standard data files. You can change the default behavior of units with various options given on the command line. See Invoking Units for a description of the avail- able options. ADDITIONAL DOCUMENTATION This manual is also available in PDF and HTML: INTERACTING WITH UNITS To invoke units for interactive use, type units at your shell prompt. The program will print something like this: Currency exchange rates from FloatRates (USD base) on 2023-07-08 3612 units, 109 prefixes, 122 nonlinear units You have: At the 'You have:' prompt, type the quantity and units that you are converting from. For example, if you want to convert ten meters to feet, type 10 meters. Next, units will print 'You want:'. You should type the units you want to convert to. To convert to feet, you would type feet. If the readline library was compiled in, then tab will com- plete unit names. See Readline Support for more information about read- line. To quit the program type quit or exit at either prompt. The result will be displayed in two ways. The first line of output, which is marked with a '*' to indicate multiplication, gives the result of the conversion you have asked for. The second line of output, which is marked with a '/' to indicate division, gives the inverse of the conversion factor. If you convert 10 meters to feet, units will print * 32.808399 / 0.03048 which tells you that 10 meters equals about 32.8 feet. The second num- ber gives the conversion in the opposite direction. In this case, it tells you that 1 foot is equal to about 0.03 dekameters since the dekameter is 10 meters. It also tells you that 1/32.8 is about 0.03. The units program prints the inverse because sometimes it is a more convenient number. In the example above, for example, the inverse value is an exact conversion: a foot is exactly 0.03048 dekameters. But the number given the other direction is inexact. If you convert grains to pounds, you will see the following: You have: grains You want: pounds * 0.00014285714 / 7000 From the second line of the output, you can immediately see that a grain is equal to a seven thousandth of a pound. This is not so obvi- ous from the first line of the output. If you find the output format confusing, try using the '--verbose' option: You have: grain You want: aeginamina grain = 0.00010416667 aeginamina grain = (1 / 9600) aeginamina If you request a conversion between units that measure reciprocal di- mensions, then units will display the conversion results with an extra note indicating that reciprocal conversion has been done: You have: 6 ohms You want: siemens reciprocal conversion * 0.16666667 / 6 Reciprocal conversion can be suppressed by using the '--strict' option. As usual, use the '--verbose' option to get more comprehensible output: You have: tex You want: typp reciprocal conversion 1 / tex = 496.05465 typp 1 / tex = (1 / 0.0020159069) typp You have: 20 mph You want: sec/mile reciprocal conversion 1 / 20 mph = 180 sec/mile 1 / 20 mph = (1 / 0.0055555556) sec/mile If you enter incompatible unit types, the units program will print a message indicating that the units are not conformable and it will dis- play the reduced form for each unit: You have: ergs/hour You want: fathoms kg^2 / day conformability error 2.7777778e-11 kg m^2 / sec^3 2.1166667e-05 kg^2 m / sec If you only want to find the reduced form or definition of a unit, sim- ply press Enter at the 'You want:' prompt. Here is an example: You have: jansky You want: Definition: fluxunit = 1e-26 W/m^2 Hz = 1e-26 kg / s^2 The output from units indicates that the jansky is defined to be equal to a fluxunit which in turn is defined to be a certain combination of watts, meters, and hertz. The fully reduced (and in this case somewhat more cryptic) form appears on the far right. If the ultimate defini- tion and the fully reduced form are identical, the latter is not shown: You have: B You want: Definition: byte = 8 bit The fully reduced form is shown if it and the ultimate definition are equivalent but not identical: You have: N You want: Definition: newton = kg m / s^2 = 1 kg m / s^2 Some named units are treated as dimensionless in some situations. These units include the radian and steradian. These units will be treated as equal to 1 in units conversions. Power is equal to torque times angular velocity. This conversion can only be performed if the radian is dimensionless. You have: (14 ft lbf) (12 radians/sec) You want: watts * 227.77742 / 0.0043902509 It is also possible to compute roots and other non-integer powers of dimensionless units; this allows computations such as the altitude of geosynchronous orbit: You have: cuberoot(G earthmass / (circle/siderealday)^2) - earthradius You want: miles * 22243.267 / 4.4957425e-05 Named dimensionless units are not treated as dimensionless in other contexts. They cannot be used as exponents so for example, 'meter^radian' is forbidden. If you want a list of options you can type ? at the 'You want:' prompt. The program will display a list of named units that are conformable with the unit that you entered at the 'You have:' prompt above. Con- formable unit combinations will not appear on this list. Typing help at either prompt displays a short help message. You can also type help followed by a unit name. This will invoke a pager on the units data base at the point where that unit is defined. You can read the definition and comments that may give more details or histori- cal information about the unit. If your pager allows, you may want to scroll backwards, e.g. with 'b', because sometimes a longer comment about a unit or group of units will appear before the definition. You can generally quit out of the pager by pressing 'q'. Typing search text will display a list of all of the units whose names contain text as a substring along with their definitions. This may help in the case where you aren't sure of the right unit name. Many command-line options can be set by typing set option=value; typing set option will show the value for that option. Typing set will show a list of options that can be set; options set to other than default val- ues will have a prepended '*'. See Setting Options Interactively for more information. USING UNITS NON-INTERACTIVELY The units program can perform units conversions non-interactively from the command line. To do this, type the command, type the original unit expression, and type the new units you want. If a units expression contains non-alphanumeric characters, you may need to protect it from interpretation by the shell using single or double quote characters. If you type units "2 liters" quarts then units will print * 2.1133764 / 0.47317647 and then exit. The output tells you that 2 liters is about 2.1 quarts, or alternatively that a quart is about 0.47 times 2 liters. units does not require a space between a numerical value and the unit, so the previous example can be given as units 2liters quarts to avoid having to quote the first argument. If the conversion is successful, units will return success (zero) to the calling environment. If you enter non-conformable units, then units will print a message giving the reduced form of each unit and it will return failure (nonzero) to the calling environment. If the '--conformable' option is given, only one unit expression is al- lowed, and units will print all units conformable with that expression; it is equivalent to giving ? at the 'You want:' prompt. For example, units --conformable gauss B_FIELD tesla Gs gauss T tesla gauss abvolt sec / cm^2 stT stattesla statT stattesla stattesla statWb/cm^2 tesla Wb/m^2 If you give more than one unit expression with the '--conformable' op- tion, the program will exit with an error message and return failure. This option has no effect in interactive mode. If the '--terse' ('-t') option is given with the '--conformable' op- tion, conformable units are shown without definitions; with the previ- ous example, this would give units --terse --conformable gauss B_FIELD Gs T gauss stT statT stattesla tesla When the '--conformable' option is not given and you invoke units with only one argument, units will print the definition of the specified unit. It will return failure if the unit is not defined and success if the unit is defined. UNIT DEFINITIONS The conversion information is read from several units data files: 'definitions.units', 'elements.units', 'currency.units', and 'cpi.units', which are usually located in the '/usr/share/units' direc- tory. If you invoke units with the '-V' option, it will print the lo- cation of these files. The default main file includes definitions for all familiar units, abbreviations and metric prefixes. It also in- cludes many obscure or archaic units. Many common spelled-out numbers (e.g., 'seventeen') are recognized. Physical Constants Many constants of nature are defined, including these: pi ratio of circumference of a circle to its diameter c speed of light e charge on an electron force acceleration of gravity mole Avogadro's number water pressure per unit height of water Hg pressure per unit height of mercury au astronomical unit k Boltzman's constant mu0 permeability of vacuum epsilon0 permittivity of vacuum G Gravitational constant mach speed of sound The standard data file includes numerous other constants. Also in- cluded are the densities of various ingredients used in baking so that '2 cups flour_sifted' can be converted to 'grams'. This is not an ex- haustive list. Consult the units data file to see the complete list, or to see the definitions that are used. Atomic Masses of the Elements The data file 'elements.units' includes atomic masses for most elements and most known isotopes. If the mole fractions of constituent isotopes are known, an elemental mass is calculated from the sum of the products of the mole fractions and the masses of the constituent isotopes. If the mole fractions are not known, the mass of the most stable isotope-- if known--is given as the elemental mass. For radioactive elements with atomic numbers 95 or greater, the mass number of the most stable isotope is not specified, because the list of studied isotopes is still incomplete. If no stable isotope is known, no elemental mass is given, and you will need to choose the most appropriate isotope. The data are obtained from the US National Institute for Standards and Technology (NIST): https://physics.nist.gov/cgi-bin/Composi- tions/stand_alone.pl?ele=&all=all&ascii=ascii2&isotype=all. The 'elements.units' file can be generated from these data using the elem- cvt command included with the distribution. Currency Exchange Rates and Consumer Price Index The data file 'currency.units' includes currency conversion rates; the file 'cpi.units' includes the US Consumer Price Index (CPI), published by the US Bureau of Labor Statistics. The data are updated monthly by the BLS; see Updating Currency Exchange Rates and CPI for information on updating 'currency.units' and 'cpi.units'. English Customary Units English customary units differ in various ways among different regions. In Britain a complex system of volume measurements featured different gallons for different materials such as a wine gallon and ale gallon that different by twenty percent. This complexity was swept away in 1824 by a reform that created an entirely new gallon, the British Impe- rial gallon defined as the volume occupied by ten pounds of water. Meanwhile in the USA the gallon is derived from the 1707 Winchester wine gallon, which is 231 cubic inches. These gallons differ by about twenty percent. By default if units runs in the 'en_GB' locale you will get the British volume measures. If it runs in the 'en_US' locale you will get the US volume measures. In other locales the default val- ues are the US definitions. If you wish to force different defini- tions, then set the environment variable UNITS_ENGLISH to either 'US' or 'GB' to set the desired definitions independent of the locale. Before 1959, the value of a yard (and other units of measure defined in terms of it) differed slightly among English-speaking countries. In 1959, Australia, Canada, New Zealand, the United Kingdom, the United States, and South Africa adopted the Canadian value of 1 yard = 0.9144 m (exactly), which was approximately halfway between the values used by the UK and the US; it had the additional advantage of making 1 inch = 2.54 cm (exactly). This new standard was termed the Interna- tional Yard. Australia, Canada, and the UK then defined all customary lengths in terms of the International Yard (Australia did not define the furlong or rod); because many US land surveys were in terms of the pre-1959 units, the US continued to define customary surveyors' units (furlong, chain, rod, pole, perch, and link) in terms of the previous value for the foot, which was termed the US survey foot. The US de- fined a US survey mile as 5280 US survey feet, and defined a statute mile as a US survey mile. The US values for these units differed from the international values by about 2 ppm. The 1959 redefinition of the foot was legally binding in the US but al- lowed continued use of the previous definition of the foot for geodetic surveying. It was assumed that this use would be temporary, but use persisted, leading to confusion and errors, and it was at odds with the intent of uniform standards. Since January 1, 2023, the US survey foot has been officially deprecated (85 FR 62698), with its use limited to historical and legacy applications. The units program has always used the international values for these units; the legacy US values can be obtained by using either the 'US' or the 'survey' prefix. In either case, the simple familiar relationships among the units are maintained, e.g., 1 'furlong' = 660 'ft', and 1 'USfurlong' = 660 'USft', though the metric equivalents differ slightly between the two cases. The 'US' prefix or the 'survey' prefix can also be used to obtain the US survey mile and the value of the US yard prior to 1959, e.g., 'USmile' or 'surveymile' (but not 'USsurveymile'). To get the US value of the statute mile, use either 'USstatutemile' or 'USmile'. The pre-1959 UK values for these units can be obtained with the prefix 'UK'. Except for distances that extend over hundreds of miles (such as in the US State Plane Coordinate System), the differences in the miles are usually insignificant: You have: 100 surveymile - 100 mile You want: inch * 12.672025 / 0.078913984 The US acre was officially defined in terms of the US survey foot, but units has used a definition based on the international foot; the units definition is now the same as the official US value. If you want the previous US acre, use 'USacre' and similarly use 'USacrefoot' for the previous US version of that unit. The difference between these units is about 4 parts per million. Miscellaneous Notes on Unit Definitions The 'pound' is a unit of mass. To get force, multiply by the force conversion unit 'force' or use the shorthand 'lbf'. (Note that 'g' is already taken as the standard abbreviation for the gram.) The unit 'ounce' is also a unit of mass. The fluid ounce is 'fluidounce' or 'floz'. When British capacity units differ from their US counterparts, such as the British Imperial gallon, the unit is defined both ways with 'br' and 'us' prefixes. Your locale settings will determine the value of the unprefixed unit. Currency is prefixed with its country name: 'belgiumfranc', 'britainpound'. When searching for a unit, if the specified string does not appear ex- actly as a unit name, then the units program will try to remove a trailing 's', 'es'. Next units will replace a trailing 'ies' with 'y'. If that fails, units will check for a prefix. The database includes all of the standard metric prefixes. Only one prefix is permitted per unit, so 'micromicrofarad' will fail. However, prefixes can appear alone with no unit following them, so 'micro*microfarad' will work, as will 'micro microfarad'. To find out which units and prefixes are available, read the default units data files; the main data file is extensively annotated. UNIT EXPRESSIONS Operators You can enter more complicated units by combining units with operations such as multiplication, division, powers, addition, subtraction, and parentheses for grouping. You can use the customary symbols for these operators when units is invoked with its default options. Addition- ally, units supports some extensions, including high priority multipli- cation using a space, and a high priority numerical division operator ('|') that can simplify some expressions. You multiply units using a space or an asterisk ('*'). The next exam- ple shows both forms: You have: arabicfoot * arabictradepound * force You want: ft lbf * 0.7296 / 1.370614 You can divide units using the slash ('/') or with 'per': You have: furlongs per fortnight You want: m/s * 0.00016630986 / 6012.8727 You can use parentheses for grouping: You have: (1/2) kg / (kg/meter) You want: league * 0.00010356166 / 9656.0833 White space surrounding operators is optional, so the previous example could have used '(1/2)kg/(kg/meter)'. As a consequence, however, hy- phenated spelled-out numbers (e.g., 'forty-two') cannot be used; 'forty-two' is interpreted as '40 - 2'. Multiplication using a space has a higher precedence than division us- ing a slash and is evaluated left to right; in effect, the first '/' character marks the beginning of the denominator of a unit expression. This makes it simple to enter a quotient with several terms in the de- nominator: 'J / mol K'. The '*' and '/' operators have the same prece- dence, and are evaluated left to right; if you multiply with '*', you must group the terms in the denominator with parentheses: 'J / (mol * K)'. The higher precedence of the space operator may not always be advanta- geous. For example, 'm/s s/day' is equivalent to 'm / s s day' and has dimensions of length per time cubed. Similarly, '1/2 meter' refers to a unit of reciprocal length equivalent to 0.5/meter, perhaps not what you would intend if you entered that expression. The get a half meter you would need to use parentheses: '(1/2) meter'. The '*' operator is convenient for multiplying a sequence of quotients. For example, 'm/s * s/day' is equivalent to 'm/day'. Similarly, you could write '1/2 * meter' to get half a meter. The units program supports another option for numerical fractions: you can indicate division of numbers with the vertical bar ('|'), so if you wanted half a meter you could write '1|2 meter'. You cannot use the vertical bar to indicate division of non-numerical units (e.g., 'm|s' results in an error message). Powers of units can be specified using the '^' character, as shown in the following example, or by simple concatenation of a unit and its ex- ponent: 'cm3' is equivalent to 'cm^3'; if the exponent is more than one digit, the '^' is required. You can also use '**' as an exponent oper- ator. You have: cm^3 You want: gallons * 0.00026417205 / 3785.4118 Concatenation only works with a single unit name: if you write '(m/s)2', units will treat it as multiplication by 2. When a unit in- cludes a prefix, exponent operators apply to the combination, so 'centimeter3' gives cubic centimeters. If you separate the prefix from the unit with any multiplication operator (e.g., 'centi meter^3'), the prefix is treated as a separate unit, so the exponent applies only to the unit without the prefix. The second example is equivalent to 'centi * (meter^3)', and gives a hundredth of a cubic meter, not a cu- bic centimeter. The units program is limited internally to products of 99 units; accordingly, expressions like 'meter^100' or 'joule^34' (rep- resented internally as 'kg^34 m^68 / s^68') will fail. The '|' operator has the highest precedence, so you can write the square root of two thirds as '2|3^1|2'. The '^' operator has the sec- ond highest precedence, and is evaluated right to left, as usual: You have: 5 * 2^3^2 You want: Definition: 2560 With a dimensionless base unit, any dimensionless exponent is meaning- ful (e.g., 'pi^exp(2.371)'). Even though angle is sometimes treated as dimensionless, exponents cannot have dimensions of angle: You have: 2^radian ^ Exponent not dimensionless If the base unit is not dimensionless, the exponent must be a rational number p/q, and the dimension of the unit must be a power of q, so 'gallon^2|3' works but 'acre^2|3' fails. An exponent using the slash ('/') operator (e.g., 'gallon^(2/3)') is also acceptable; the parenthe- ses are needed because the precedence of '^' is higher than that of '/'. Since units cannot represent dimensions with exponents greater than 99, a fully reduced exponent must have q < 100. When raising a non-dimensionless unit to a power, units attempts to convert a decimal exponent to a rational number with q < 100. If this is not possible units displays an error message: You have: ft^1.234 Base unit not dimensionless; rational exponent required A decimal exponent must match its rational representation to machine precision, so 'acre^1.5' works but 'gallon^0.666' does not. Sums and Differences of Units You may sometimes want to add values of different units that are out- side the SI. You may also wish to use units as a calculator that keeps track of units. Sums of conformable units are written with the '+' character, and differences with the '-' character. You have: 2 hours + 23 minutes + 32 seconds You want: seconds * 8612 / 0.00011611705 You have: 12 ft + 3 in You want: cm * 373.38 / 0.0026782366 You have: 2 btu + 450 ft lbf You want: btu * 2.5782804 / 0.38785542 The expressions that are added or subtracted must reduce to identical expressions in primitive units, or an error message will be displayed: You have: 12 printerspoint - 4 heredium ^ Invalid sum of non-conformable units If you add two values of vastly different scale you may exceed the available precision of floating point (about 15 digits). The effect is that the addition of the smaller value makes no change to the larger value; in other words, the smaller value is treated as if it were zero. You have: lightyear + cm No warning is given, however. As usual, the precedence for '+' and '-' is lower than that of the other operators. A fractional quantity such as 2 1/2 cups can be given as '(2+1|2) cups'; the parentheses are nec- essary because multiplication has higher precedence than addition. If you omit the parentheses, units attempts to add '2' and '1|2 cups', and you get an error message: You have: 2+1|2 cups ^ Invalid sum or difference of non-conformable units The expression could also be correctly written as '(2+1/2) cups'. If you write '2 1|2 cups' the space is interpreted as multiplication so the result is the same as '1 cup'. The '+' and '-' characters sometimes appears in exponents like '3.43e+8'. This leads to an ambiguity in an expression like '3e+2 yC'. The unit 'e' is a small unit of charge, so this can be regarded as equivalent to '(3e+2) yC' or '(3 e)+(2 yC)'. This ambiguity is re- solved by always interpreting '+' and '-' as part of an exponent if possible. Numbers as Units For units, numbers are just another kind of unit. They can appear as many times as you like and in any order in a unit expression. For ex- ample, to find the volume of a box that is 2 ft by 3 ft by 12 ft in steres, you could do the following: You have: 2 ft 3 ft 12 ft You want: stere * 2.038813 / 0.49048148 You have: $ 5 / yard You want: cents / inch * 13.888889 / 0.072 And the second example shows how the dollar sign in the units conver- sion can precede the five. Be careful: units will interpret '$5' with no space as equivalent to 'dollar^5'. Built-in Functions Several built-in functions are provided: 'sin', 'cos', 'tan', 'asin', 'acos', 'atan', 'sinh', 'cosh', 'tanh', 'asinh', 'acosh', 'atanh', 'exp', 'ln', 'log', 'abs', 'round', 'floor', 'ceil', 'factorial', 'Gamma', 'lnGamma', 'erf', and 'erfc'; the function 'lnGamma' is the natural logarithm of the 'Gamma' function. The 'sin', 'cos', and 'tan' functions require either a dimensionless argument or an argument with dimensions of angle. You have: sin(30 degrees) You want: Definition: 0.5 You have: sin(pi/2) You want: Definition: 1 You have: sin(3 kg) ^ Unit not dimensionless The other functions on the list require dimensionless arguments. The inverse trigonometric functions return arguments with dimensions of an- gle. The 'ln' and 'log' functions give natural log and log base 10 respec- tively. To obtain logs for any integer base, enter the desired base immediately after 'log'. For example, to get log base 2 you would write 'log2' and to get log base 47 you could write 'log47'. You have: log2(32) You want: Definition: 5 You have: log3(32) You want: Definition: 3.1546488 You have: log4(32) You want: Definition: 2.5 You have: log32(32) You want: Definition: 1 You have: log(32) You want: Definition: 1.50515 You have: log10(32) You want: Definition: 1.50515 If you wish to take roots of units, you may use the 'sqrt' or 'cuberoot' functions. These functions require that the argument have the appropriate root. You can obtain higher roots by using fractional exponents: You have: sqrt(acre) You want: feet * 208.71074 / 0.0047913202 You have: (400 W/m^2 / stefanboltzmann)^(1/4) You have: Definition: 289.80882 K You have: cuberoot(hectare) ^ Unit not a root Previous Result You can insert the result of the previous conversion using the under- score ('_'). It is useful when you want to convert the same input to several different units, for example You have: 2.3 tonrefrigeration You want: btu/hr * 27600 / 3.6231884e-005 You have: _ You want: kW * 8.0887615 / 0.12362832 Suppose you want to do some deep frying that requires an oil depth of 2 inches. You have 1/2 gallon of oil, and want to know the largest-di- ameter pan that will maintain the required depth. The nonlinear unit 'circlearea' gives the radius of the circle (see Other Nonlinear Units, for a more detailed description) in SI units; you want the diameter in inches: You have: 1|2 gallon / 2 in You want: circlearea 0.10890173 m You have: 2 _ You want: in * 8.5749393 / 0.1166189 In most cases, surrounding white space is optional, so the previous ex- ample could have used '2_'. If '_' follows a non-numerical unit sym- bol, however, the space is required: You have: m_ ^ Parse error You can use the '_' symbol any number of times; for example, You have: m You want: Definition: 1 m You have: _ _ You want: Definition: 1 m^2 Using '_' before a conversion has been performed (e.g., immediately af- ter invocation) generates an error: You have: _ ^ No previous result; '_' not set Accordingly, '_' serves no purpose when units is invoked non-interac- tively. If units is invoked with the '--verbose' option (see Invoking Units), the value of '_' is not expanded: You have: mile You want: ft mile = 5280 ft mile = (1 / 0.00018939394) ft You have: _ You want: m _ = 1609.344 m _ = (1 / 0.00062137119) m You can give '_' at the 'You want:' prompt, but it usually is not very useful. Complicated Unit Expressions The units program is especially helpful in ensuring accuracy and dimen- sional consistency when converting lengthy unit expressions. For exam- ple, one form of the Darcy-Weisbach fluid-flow equation is Delta P = (8 / pi)^2 (rho fLQ^2) / d^5, where Delta P is the pressure drop, rho is the mass density, f is the (dimensionless) friction factor, L is the length of the pipe, Q is the volumetric flow rate, and d is the pipe diameter. You might want to have the equation in the form Delta P = A1 rho fLQ^2 / d^5 that accepted the user's normal units; for typical units used in the US, the required conversion could be something like You have: (8/pi^2)(lbm/ft^3)ft(ft^3/s)^2(1/in^5) You want: psi * 43.533969 / 0.022970568 The parentheses allow individual terms in the expression to be entered naturally, as they might be read from the formula. Alternatively, the multiplication could be done with the '*' rather than a space; then parentheses are needed only around 'ft^3/s' because of its exponent: You have: 8/pi^2 * lbm/ft^3 * ft * (ft^3/s)^2 /in^5 You want: psi * 43.533969 / 0.022970568 Without parentheses, and using spaces for multiplication, the previous conversion would need to be entered as You have: 8 lb ft ft^3 ft^3 / pi^2 ft^3 s^2 in^5 You want: psi * 43.533969 / 0.022970568 Variables Assigned at Run Time Unit definitions are fixed once units has finished reading the units data file(s), but at run time you can assign unit expressions to vari- ables whose names begin with an underscore, using the syntax _name = This can help manage a long calculation by saving intermediate quanti- ties as variables that you can use later. For example, to determine the shot-noise-limited signal-to-noise ratio (SNR) of an imaging system using a helium-neon laser, you could do You have: _lambda = 632.8 nm # laser wavelength You have: _nu = c / _lambda # optical frequency You have: _photon_energy = h * _nu You have: _power = 550 uW You have: _photon_count = _power * 500 ns / _photon_energy You have: _snr = sqrt(_photon_count) You have: _snr You want: Definition: sqrt(_photon_count) = 29597.922 Except for beginning with an underscore, runtime variables follow the same naming rules as units. Because names beginning with '_' are re- served for these variables and unit names cannot begin with '_', run- time variables can never hide unit definitions. Runtime variables are undefined until you make an assignment to them, so if you give a name beginning with an underscore and no assignment has been made, you get an error message. When you assign a unit expression to a runtime variable, units checks the expression to determine whether it is valid, but the resulting def- inition is stored as a text string that is not reduced to primitive units. The text will be processed anew each time you use the variable in a conversion or calculation; this means that if your definition de- pends on other runtime variables (or the special variable '_'), the re- sult of calculating with your variable will change if any of those variables change. A dependence need not be direct. Continuing the example of the laser above, suppose you have done the calculation as shown. You now wonder what happens if you switch to an argon laser: You have: _lambda = 454.6 nm You have: _snr You want: Definition: sqrt(_photon_count) = 25086.651 If you then change the power: You have: _power = 1 mW You have: _snr You want: Definition: sqrt(_photon_count) = 33826.834 Instead of having to reenter or edit a lengthy expression when you per- form another calculation, you need only enter values that change; in this respect, runtime variables are similar to a spreadsheet. The more times a variable appears in an expression that depends on it, the greater the benefit of having a calculation using that expression reflect changes to that variable. For example, the length of day- light--the time the Sun is above the horizon--at a given latitude and declination of the Sun is given by L = acos((sin h - sin sin ) / (cos cos )) where L is the day length, h is the altitude, is the latitude, and is the Sun's declination. The result above is in sidereal time; the length in solar time is ob- tained by multiplying by siderealday / day By convention, the Sun's altitude at rise or set is -50' to allow for atmospheric refraction and the semidiameter of its disk. At the summer solstice in the northern hemisphere, the Sun's declination is approxi- mately 23.44; to find the length of the longest day of the year for a latitude of 55, you could do You have: _alt = -50 arcmin You have: _lat = 55 deg You have: _decl = 23.44 deg You have: _num = sin(_alt) - sin(_lat) sin(_decl) You have: _denom = cos(_lat) cos(_decl) You have: _sday = 2 (acos(_num / _denom) / circle) 24 hr You have: _day = _sday siderealday / day You have: _day You want: hms 17 hr + 19 min + 34.895151 sec At the winter solstice, the Sun's declination is approximately -23.44, so you could calculate the length of the shortest day of the year using: You have: _decl = -23.44 deg You have: _day You want: hms 7 hr + 8 min + 40.981084 sec Latitude and declination each appear twice in the expression for _day; the result in the examples above is updated by changing only the value of the declination. It may seem easier--and less subject to error--to simply specify the new value of _decl as the negative of the current value (e.g., '_decl = -_decl'). This doesn't work; when you make an assignment with the '=' operator, the definition is stored as entered, including possi- ble dependencies on variables. But if you attempt an assignment that is ultimately self-referential, the current definition is retained, and you get an error message. For example, You have: _decl = 23.44 deg You have: _decl = -_decl Circular unit definition You can overcome this by using the ':=' operator, which reduces the right hand side to primitive units before making the assignment, elimi- nating any dependencies on variables. Returning to the example above, You have: _decl = 23.44 deg You have: _decl = -_decl Circular unit definition You have: _decl := -_decl You have: _decl You want: deg * -23.44 / -0.042662116 This works to much the same effect as if the assignment had been en- tered literally, e.g., You have: _decl = -23.44 deg but the actual definition is in primitive units--in this case, radians: You have: _decl = 23.44 deg You have: _decl := -_decl You have: _decl You want: Definition: -0.40910517666747087 radian = -0.40910518 radian Definitions are text strings, and a redefinition using ':=' is given with enough digits maintain the full precision of the current defini- tion when converted back to a number; because it is a string, all dig- its are displayed when showing the definition, regardless of the numer- ical display precision, so you may see more digits than expected. A runtime variable must be assigned before it can be used in an assign- ment; in the first of the three examples above, giving the general equation before the values for _alt, _lat, and _decl had been assigned would result in an error message. Backwards Compatibility: '*' and '-' The original units assigned multiplication a higher precedence than di- vision using the slash. This differs from the usual precedence rules, which give multiplication and division equal precedence, and can be confusing for people who think of units as a calculator. The star operator ('*') included in this units program has, by default, the same precedence as division, and hence follows the usual precedence rules. For backwards compatibility you can invoke units with the '--oldstar' option. Then '*' has a higher precedence than division, and the same precedence as multiplication using the space. Historically, the hyphen ('-') has been used in technical publications to indicate products of units, and the original units program treated it as a multiplication operator. Because units provides several other ways to obtain unit products, and because '-' is a subtraction operator in general algebraic expressions, units treats the binary '-' as a sub- traction operator by default. For backwards compatibility use the '--product' option, which causes units to treat the binary '-' operator as a product operator. When '-' is a multiplication operator it has the same precedence as multiplication with a space, giving it a higher precedence than division. When '-' is used as a unary operator it negates its operand. Regard- less of the units options, if '-' appears after '(' or after '+', then it will act as a negation operator. So you can always compute 20 de- grees minus 12 minutes by entering '20 degrees + -12 arcmin'. You must use this construction when you define new units because you cannot know what options will be in force when your definition is processed. NONLINEAR UNIT CONVERSIONS Nonlinear units are represented using functional notation. They make possible nonlinear unit conversions such as temperature. Temperature Conversions Conversions between temperatures are different from linear conversions between temperature increments--see the example below. The absolute temperature conversions are handled by units starting with 'temp', and you must use functional notation. The temperature-increment conver- sions are done using units starting with 'deg' and they do not require functional notation. You have: tempF(45) You want: tempC 7.2222222 You have: 45 degF You want: degC * 25 / 0.04 Think of 'tempF(x)' not as a function but as a notation that indicates that x should have units of 'tempF' attached to it. See Defining Non- linear Units. The first conversion shows that if it's 45 degrees Fahrenheit outside, it's 7.2 degrees Celsius. The second conversion indicates that a change of 45 degrees Fahrenheit corresponds to a change of 25 degrees Celsius. The conversion from 'tempF(x)' is to ab- solute temperature, so that You have: tempF(45) You want: degR * 504.67 / 0.0019814929 gives the same result as You have: tempF(45) You want: tempR * 504.67 / 0.0019814929 But if you convert 'tempF(x)' to 'degC', the output is probably not what you expect: You have: tempF(45) You want: degC * 280.37222 / 0.0035666871 The result is the temperature in K, because 'degC' is defined as 'K', the kelvin. For consistent results, use the 'tempX' units when convert- ing to a temperature rather than converting a temperature increment. The 'tempC()' and 'tempF()' definitions are limited to positive abso- lute temperatures, and giving a value that would result in a negative absolute temperature generates an error message: You have: tempC(-275) ^ Argument of function outside domain US Consumer Price Index units includes the US Consumer Price Index published by the US Bureau of Labor Statistics. Several functions that use this value are pro- vided: 'cpi', 'cpi_now', 'inflation_since', and 'dollars_in'. The 'cpi' function gives the CPI for a specified decimal year. A deci- mal year is given as the year plus the fractional part of the year; be- cause of leap years and the different lengths of months, calculating an exact value for the fractional part can be tedious, but for the pur- poses of CPI, an approximate value is usually adequate. For example, 1 January 2000 is 2000.0, 1 April 2000 is 2000.25, 1 July 2000 is 2000.4986, and 1 October 2000 is 2000.75. Note also that the CPI data update monthly; values in between months are linearly interpolated. In the middle of 1975, the CPI was You have: cpi(1975.5) You want: Definition: 53.6 The value of the CPI for a month is usually published sometime around the 20th day of the following month; the latest value of the CPI is available with 'cpi_now'. On 7 January 2024, the value was You have: cpi_now You want: Definition: UScpi_now = 307.051 This means that the CPI was 307.015 on 1 December 2023. The 'cpi_now' variable can only present the most recent data available, so it can lag the current CPI by several weeks. The decimal year of the last update is available with 'cpi_lastdate'. The 'inflation_since' function provides a convenient way to determine the inflation factor from a specified decimal year to the latest value in the CPI table. For example, on 7 January 2024: You have: inflation_since(1970) You want: Definition: 8.1445889 In other words, goods that cost 1 US$ in 1970 would cost 8.14 US$ on 1 December 2023. The 'inflation_since' function can be used to determine an annual rate of inflation. The earliest US CPI data are from about 1913.1; the ap- proximate time between then and 7 January 2024 is 110.9 years. The ap- proximate annual inflation rate for that period is then You have: inflation_since(1913.1)^1|110.9 - 1 You want: % * 3.1548115 / 0.31697614 The inflation rate for any time period can be found from the ratio of the CPI at the end of the period to that of the beginning: You have: (cpi(1982)/cpi(1972))^1|10 - 1 You want: % * 8.6247033 / 0.11594602 The period 1972-1982 was indeed one of high inflation. The 'dollars_in' function is similar to 'inflation_since' but its out- put is in US$ rather than dimensionless: You have: dollars_in(1970) You want: Definition: 8.1445889 US$ A typical use might be You have: 250 dollars_in(1970) You want: $ * 2036.1472 / 0.00049112362 Because 'dollars_in' includes the units, you should not include them at the 'You have:' prompt. You can also use 'dollars_in' to convert be- tween two specified years: You have: 250 dollars_in(1970) You want: dollars_in(1950) * 156.49867 / 0.0063898305 which shows that 250 US$ in 1970 would have equivalent purchasing power to 156 US$ in 1950. Other Nonlinear Units Some other examples of nonlinear units are numerous different ring sizes and wire gauges, screw gauges, pipe and tubing sizes, the grit sizes used for abrasives, the decibel scale, shoe size, scales for the density of sugar (e.g., baume). The standard data file also supplies units for computing the area of a circle and the volume of a sphere. See the standard units data file for more details. Diameters of American wire sizes can be found using the 'wiregauge()' function or its alias 'awg()': You have: wiregauge(11) You want: inches * 0.090742002 / 11.020255 You have: 1 mm You want: wiregauge 18.201919 Wire and screw gauges with multiple zeroes are signified using negative numbers, where two zeroes ("00"; "2/0") is '-1', three zeros ("000"; "3/0") is '-2', and so on. Alternatively, you can use the synonyms 'g00', 'g000', or 'g2_0', 'g3_0', and so on that are defined in the standard units data file. You have: brwiregauge(g00) You want: inches * 0.348 / 2.8735632 In North America, wire sizes larger than 0000 ("4/0") are usually given in terms of area, either in kcmil or the older initialism MCM (thousand circular mils). Outside of North America, all wire sizes are usually given in terms of area in mm^2. Wire area can be obtained using 'wiregaugeA()' or its alias 'awgA()': You have: awgA(g6_0) You want: kcmil * 336.45718 / 0.0029721464 You have: awgA(12) You want: mm^2 * 3.3087729 / 0.30222685 The closest standard metric sizes are 2.5 mm^2 and 4 mm^2; in general, there isn't an exact correlation between American and metric wire sizes. Though based on the long-established iron pipe size (IPS) given in inches, nominal pipe size (NPS) is a dimensionless quantity that corre- sponds to the inch size. Pipe size can be equivalently specified using metric diametre nominal (DN), which roughly corresponds to the diameter in mm. For a given pipe size, outside diameter is constant while in- side diameter varies with schedule. For example, for NPS 21/2 pipe, You have: npsOD(2+1|2) You want: in * 2.875 / 0.34782609 You have: nps40(2+1|2) You want: in * 2.469 / 0.40502228 You have: nps80(2+1|2) You want: in * 2.323 / 0.43047783 Pipe size can be given equivalently in terms of the metric DN by using the 'DN()' function, which converts nominal metric size to nominal inch size: You have: npsOD(DN(65)) You want: mm * 73.025 / 0.01369394 You have: _ You want: in * 2.875 / 0.34782609 Unlike with wire sizes, actual NPS and metric DN pipe dimensions are the same. You have: grit_P(600) You want: grit_ansicoated 342.76923 The last example shows the conversion from P graded sand paper, which is the European standard and may be marked "P600" on the back, to the USA standard. You can compute the area of a circle using the nonlinear unit, 'circlearea'. You can also do this using the circularinch or cir- cleinch. The next example shows two ways to compute the area of a cir- cle with a five inch radius and one way to compute the volume of a sphere with a radius of one meter. You have: circlearea(5 in) You want: in2 * 78.539816 / 0.012732395 You have: 10^2 circleinch You want: in2 * 78.539816 / 0.012732395 You have: spherevol(meter) You want: ft3 * 147.92573 / 0.0067601492 The inverse of a nonlinear conversion is indicated by prefixing a tilde ('~') to the nonlinear unit name: You have: ~wiregauge(0.090742002 inches) You want: Definition: 11 You can give a nonlinear unit definition without an argument or paren- theses, and press Enter at the 'You want:' prompt to get the definition of a nonlinear unit; if the definition is not valid for all real num- bers, the range of validity is also given. If the definition requires specific units this information is also displayed: You have: tempC Definition: tempC(x) = x K + stdtemp defined for x >= -273.15 You have: ~tempC Definition: ~tempC(tempC) = (tempC +(-stdtemp))/K defined for tempC >= 0 K You have: circlearea Definition: circlearea(r) = pi r^2 r has units m To see the definition of the inverse use the '~' notation. In this case the parameter in the functional definition will usually be the name of the unit. Note that the inverse for 'tempC' shows that it re- quires units of 'K' in the specification of the allowed range of val- ues. Nonlinear unit conversions are described in more detail in Defin- ing Nonlinear Units. UNIT LISTS: CONVERSION TO SUMS OF UNITS Outside of the SI, it is sometimes desirable to convert a single unit to a sum of units--for example, feet to feet plus inches. The conver- sion from sums of units was described in Sums and Differences of Units, and is a simple matter of adding the units with the '+' sign: You have: 12 ft + 3 in + 3|8 in You want: ft * 12.28125 / 0.081424936 Although you can similarly write a sum of units to convert to, the re- sult will not be the conversion to the units in the sum, but rather the conversion to the particular sum that you have entered: You have: 12.28125 ft You want: ft + in + 1|8 in * 11.228571 / 0.089058524 The unit expression given at the 'You want:' prompt is equivalent to asking for conversion to multiples of '1 ft + 1 in + 1|8 in', which is 1.09375 ft, so the conversion in the previous example is equivalent to You have: 12.28125 ft You want: 1.09375 ft * 11.228571 / 0.089058524 In converting to a sum of units like miles, feet and inches, you typi- cally want the largest integral value for the first unit, followed by the largest integral value for the next, and the remainder converted to the last unit. You can do this conversion easily with units using a special syntax for lists of units. You must list the desired units in order from largest to smallest, separated by the semicolon (';') char- acter: You have: 12.28125 ft You want: ft;in;1|8 in 12 ft + 3 in + 3|8 in The conversion always gives integer coefficients on the units in the list, except possibly the last unit when the conversion is not exact: You have: 12.28126 ft You want: ft;in;1|8 in 12 ft + 3 in + 3.00096 * 1|8 in The order in which you list the units is important: You have: 3 kg You want: oz;lb 105 oz + 0.051367866 lb You have: 3 kg You want: lb;oz 6 lb + 9.8218858 oz Listing ounces before pounds produces a technically correct result, but not a very useful one. You must list the units in descending order of size in order to get the most useful result. Ending a unit list with the separator ';' has the same effect as re- peating the last unit on the list, so 'ft;in;1|8 in;' is equivalent to 'ft;in;1|8 in;1|8 in'. With the example above, this gives You have: 12.28126 ft You want: ft;in;1|8 in; 12 ft + 3 in + 3|8 in + 0.00096 * 1|8 in in effect separating the integer and fractional parts of the coeffi- cient for the last unit. If you instead prefer to round the last coef- ficient to an integer you can do this with the '--round' ('-r') option. With the previous example, the result is You have: 12.28126 ft You want: ft;in;1|8 in 12 ft + 3 in + 3|8 in (rounded down to nearest 1|8 in) When you use the '-r' option, repeating the last unit on the list has no effect (e.g., 'ft;in;1|8 in;1|8 in' is equivalent to 'ft;in;1|8 in'), and hence neither does ending a list with a ';'. With a single unit and the '-r' option, a terminal ';' does have an effect: it causes units to treat the single unit as a list and produce a rounded value for the single unit. Without the extra ';', the '-r' option has no ef- fect on single unit conversions. This example shows the output using the '-r' option: You have: 12.28126 ft You want: in * 147.37512 / 0.0067854058 You have: 12.28126 ft You want: in; 147 in (rounded down to nearest in) Each unit that appears in the list must be conformable with the first unit on the list, and of course the listed units must also be conform- able with the unit that you enter at the 'You have:' prompt. You have: meter You want: ft;kg ^ conformability error ft = 0.3048 m kg = 1 kg You have: meter You want: lb;oz conformability error 1 m 0.45359237 kg In the first case, units reports the disagreement between units appear- ing on the list. In the second case, units reports disagreement be- tween the unit you entered and the desired conversion. This conforma- bility error is based on the first unit on the unit list. Other common candidates for conversion to sums of units are angles and time: You have: 23.437754 deg You want: deg;arcmin;arcsec 23 deg + 26 arcmin + 15.9144 arcsec You have: 7.2319 hr You want: hr;min;sec 7 hr + 13 min + 54.84 sec Some applications for unit lists may be less obvious. Suppose that you have a postal scale and wish to ensure that it's accurate at 1 oz, but have only metric calibration weights. You might try You have: 1 oz You want: 100 g;50 g; 20 g;10 g;5 g;2 g;1 g; 20 g + 5 g + 2 g + 1 g + 0.34952312 * 1 g You might then place one each of the 20 g, 5 g, 2 g, and 1 g weights on the scale and hope that it indicates close to You have: 20 g + 5 g + 2 g + 1 g You want: oz; 0.98767093 oz Appending ';' to 'oz' forces a one-line display that includes the unit; here the integer part of the result is zero, so it is not displayed. If a non-empty list item differs vastly in scale from the quantity from which the list is to be converted, you may exceed the available preci- sion of floating point (about 15 digits), in which case you will get a warning, e.g., You have: lightyear You want: mile;100 inch;10 inch;mm;micron 5.8786254e+12 mile + 390 * 100 inch (at 15-digit precision limit) Cooking Measure In North America, recipes for cooking typically measure ingredients by volume, and use units that are not always convenient multiples of each other. Suppose that you have a recipe for 6 and you wish to make a portion for 1. If the recipe calls for 2 1/2 cups of an ingredient, you might wish to know the measurements in terms of measuring devices you have available, you could use units and enter You have: (2+1|2) cup / 6 You want: cup;1|2 cup;1|3 cup;1|4 cup;tbsp;tsp;1|2 tsp;1|4 tsp 1|3 cup + 1 tbsp + 1 tsp By default, if a unit in a list begins with fraction of the form 1|x and its multiplier is an integer, the fraction is given as the product of the multiplier and the numerator; for example, You have: 12.28125 ft You want: ft;in;1|8 in; 12 ft + 3 in + 3|8 in In many cases, such as the example above, this is what is wanted, but sometimes it is not. For example, a cooking recipe for 6 might call for 5 1/4 cup of an ingredient, but you want a portion for 2, and your 1-cup measure is not available; you might try You have: (5+1|4) cup / 3 You want: 1|2 cup;1|3 cup;1|4 cup 3|2 cup + 1|4 cup This result might be fine for a baker who has a 1 1/2-cup measure (and recognizes the equivalence), but it may not be as useful to someone with more limited set of measures, who does want to do additional cal- culations, and only wants to know "How many 1/2-cup measures to I need to add?" After all, that's what was actually asked. With the '--show- factor' option, the factor will not be combined with a unity numerator, so that you get You have: (5+1|4) cup / 3 You want: 1|2 cup;1|3 cup;1|4 cup 3 * 1|2 cup + 1|4 cup A user-specified fractional unit with a numerator other than 1 is never overridden, however--if a unit list specifies '3|4 cup;1|2 cup', a re- sult equivalent to 1 1/2 cups will always be shown as '2 * 3|4 cup' whether or not the '--show-factor' option is given. Unit List Aliases A unit list such as cup;1|2 cup;1|3 cup;1|4 cup;tbsp;tsp;1|2 tsp;1|4 tsp can be tedious to enter. The units program provides shorthand names for some common combinations: hms time: hours, minutes, seconds dms angle: degrees, minutes, seconds time time: years, days, hours, minutes and seconds usvol US cooking volume: cups and smaller uswt US weight: pounds and ounces ftin length: feet, inches and 1/8 inches ftin2 length: feet, inches and 1/2 inches ftin4 length: feet, inches and 1/4 inches ftin8 length: feet, inches and 1/8 inches ftin16 length: feet, inches and 1/16 inches ftin32 length: feet, inches and 1/32 inches ftin64 length: feet, inches and 1/64 inches inchfine length: inches subdivided to 1/64 inch Using these shorthands, or unit list aliases, you can do the following conversions: You have: anomalisticyear You want: time 1 year + 25 min + 3.4653216 sec You have: 1|6 cup You want: usvol 2 tbsp + 2 tsp Suppose you want to drill a clearance hole for a #10 screw and have about 1/64 inch clearance; you could try You have: screwgauge(10) + 1|64 in You want: ftin64 13.16 * 1|64 in You have: _ You want: ftin32 6.58 * 1|32 in If a slightly tight fit is acceptable, a 13/64-inch drill would do the job; if not, a 7/32-inch drill would work with a slightly looser fit. You can define your own unit list aliases; see Defining Unit List Aliases. You cannot combine a unit list alias with other units: it must appear alone at the 'You want:' prompt. You can display the definition of a unit list alias by entering it at the 'You have:' prompt: You have: dms Definition: unit list, deg;arcmin;arcsec When you specify compact output with '--compact', '--terse' or '-t' and perform conversion to a unit list, units lists the conversion factors for each unit in the list, separated by semicolons. You have: year You want: day;min;sec 365;348;45.974678 Unlike the case of regular output, zeros are included in this output list: You have: liter You want: cup;1|2 cup;1|4 cup;tbsp 4;0;0;3.6280454 ALTERNATIVE UNIT SYSTEMS CGS Units The SI--an extension of the MKS (meter-kilogram-second) system--has largely supplanted the older CGS (centimeter-gram-second) system, but CGS units are still used in a few specialized fields, especially in physics where they lead to a more elegant formulation of Maxwell's equations. Conversions between SI and CGS involving mechanical units are straightforward, involving powers of 10 (e.g., 1 m = 100 cm). Con- versions involving electromagnetic units are more complicated, and units supports four different systems of CGS units: electrostatic units (ESU), electromagnetic units (EMU), the Gaussian system and the Heavi- side-Lorentz system. The differences between these systems arise from different choices made for proportionality constants in electromagnetic equations. Coulomb's law gives electrostatic force between two charges separated by a distance delim $$ r: F = k_C q_1 q_2 / r^2. Ampere's law gives the electromagnetic force per unit length between two current-carrying conductors separated by a distance r: F/l = 2 k_A I_1 I_2 / r. The two constants, k_C and k_A, are related by the square of the speed of light: k_A = k_C / c^2. In the SI, the constants have dimensions, and an additional base unit, the ampere, measures electric current. The CGS systems do not define new base units, but express charge and current as derived units in terms of mass, length, and time. In the ESU system, the constant for Coulomb's law is chosen to be unity and dimensionless, which defines the unit of charge. In the EMU system, the constant for Ampere's law is chosen to be unity and dimensionless, which defines a unit of cur- rent. The Gaussian system usually uses the ESU units for charge and current; it chooses another constant so that the units for the electric and magnetic fields are the same. The Heaviside-Lorentz system is "ra- tionalized" so that factors of 4{pi} do not appear in Maxwell's equa- tions. The SI system is similarly rationalized, but the other CGS sys- tems are not. In the Heaviside-Lorentz (HLU) system the factor of 4{pi} appears in Coulomb's law instead; this system differs from the Gaussian system by factors of the square root of 4{pi} The dimensions of electrical quantities in the various CGS systems are different from the SI dimensions for the same units; strictly, conver- sions between these systems and SI are not possible. But units in dif- ferent systems relate to the same physical quantities, so there is a correspondence between these units. The units program defines the units so that you can convert between corresponding units in the vari- ous systems. The CGS definitions involve cm^(1/2) and g^(1/2), which is problematic because units does not normally support fractional roots of base units. The '--units' ('-u') option allows selection of a CGS unit system and works around this restriction by introducing base units for the square roots of length and mass: 'sqrt_cm' and 'sqrt_g'. The centimeter then becomes 'sqrt_cm^2' and the gram, 'sqrt_g^2'. This allows working from equations using the units in the CGS system, and enforcing dimensional conformity within that system. Recognized CGS arguments to the '--units' option are 'gauss[ian]', 'esu', 'emu', 'lhu'; the argument is case insensitive. You can also give 'si' which just enforces the de- fault SI mode and displays '(SI)' at the 'You have:' prompt to empha- size the units mode. Some other types of units are also supported as described below. Giving an unrecognized system generates a warning, and units uses SI units. The changes resulting from the '--units' option are actually controlled by the UNITS_SYSTEM environment variable. If you frequently work with one of the supported CGS units systems, you may set this environment variable rather than giving the '--units' option at each invocation. As usual, an option given on the command line overrides the setting of the environment variable. For example, if you would normally work with Gaussian units but might occasionally work with SI, you could set UNITS_SYSTEM to 'gaussian' and specify SI with the '--units' option. Unlike the argument to the '--units' option, the value of UNITS_SYSTEM is case sensitive, so setting a value of 'EMU' will have no effect other than to give an error message and set SI units. The CGS definitions appear as conditional settings in the standard units data file, which you can consult for more information on how these units are defined, or on how to define an alternate units system. The ESU system derives the electromagnetic units from its unit of charge, the statcoulomb, which is defined from Coulomb's law. The statcoulomb equals dyne^(1/2) cm, or cm^(3/2) g^(1/2) s^(-1). The unit of current, the statampere, is statcoulomb sec, analogous to the rela- tionship in SI. Other electrical units are then derived in a manner similar to that for SI units; the units use the SI names prefixed by 'stat-', e.g., 'statvolt' or 'statV'. The prefix 'st-' is also recog- nized (e.g., 'stV'). The EMU system derives the electromagnetic units from its unit of cur- rent, the abampere, which is defined in terms of Ampere's law. The abampere is equal to dyne^(1/2), or cm^(1/2) g^(1/2) s^(-1). delim off The unit of charge, the abcoulomb, is abampere sec, again analogous to the SI relationship. Other electrical units are then derived in a man- ner similar to that for SI units; the units use the SI names prefixed by 'ab-', e.g., 'abvolt' or 'abV'. The magnetic field units include the gauss, the oersted and the maxwell. The Gaussian units system, which was also known as the Symmetric Sys- tem, uses the same charge and current units as the ESU system (e.g., 'statC', 'statA'); it differs by defining the magnetic field so that it has the same units as the electric field. The resulting magnetic field units are the same ones used in the EMU system: the gauss, the oersted and the maxwell. The Heaviside-Lorentz system appears to lack named units. We define five basic units, 'hlu_charge', 'hlu_current', 'hlu_volt', 'hlu_efield' and 'hlu_bfield' for conversions with this system. It is important to remember that with all of the CGS systems, the units may look the same but mean something different. The HLU system and Gaussian systems both measure magnetic field using the same CGS dimensions, but the amount of magnetic field with the same units is different in the two systems. The CGS systems define units that measure the same thing but may have conflicting dimensions. Furthermore, the dimensions of the electromag- netic CGS units are never compatible with SI. But if you measure charge in two different systems you have measured the same physical thing, so there is a correspondence between the units in the different systems, and units supports conversions between corresponding units. When running with SI, units defines all of the CGS units in terms of SI. When you select a CGS system, units defines the SI units and the other CGS system units in terms of the system you have selected. (Gaussian) You have: statA You want: abA * 3.335641e-11 / 2.9979246e+10 (Gaussian) You have: abA You want: sqrt(dyne) conformability error 2.9979246e+10 sqrt_cm^3 sqrt_g / s^2 1 sqrt_cm sqrt_g / s In the above example, units converts between the current units statA and abA even though the abA, from the EMU system, has incompatible di- mensions. This works because in Gaussian mode, the abA is defined in terms of the statA, so it does not have the correct definition for EMU; consequently, you cannot convert the abA to its EMU definition. One challenge of conversion is that because the CGS system has fewer base units, quantities that have different dimensions in SI may have the same dimension in a CGS system. And yet, they may not have the same conversion factor. For example, the unit for the E field and B fields are the same in the Gaussian system, but the conversion factors to SI are quite different. This means that correct conversion is only possible if you keep track of what quantity is being measured. You cannot convert statV/cm to SI without indicating which type of field the unit measures. To aid in dimensional analysis, units defines vari- ous dimension units such as 'LENGTH', 'TIME', and 'CHARGE' to be the appropriate dimension in SI. The electromagnetic dimensions such as 'B_FIELD' or 'E_FIELD' may be useful aids both for conversion and di- mensional analysis in CGS. You can convert them to or from CGS in or- der to perform SI conversions that in some cases will not work directly due to dimensional incompatibilities. This example shows how the Gaussian system uses the same units for all of the fields, but they all have different conversion factors with SI. (Gaussian) You have: statV/cm You want: E_FIELD * 29979.246 / 3.335641e-05 (Gaussian) You have: statV/cm You want: B_FIELD * 0.0001 / 10000 (Gaussian) You have: statV/cm You want: H_FIELD * 79.577472 / 0.012566371 (Gaussian) You have: statV/cm You want: D_FIELD * 2.6544187e-07 / 3767303.1 The next example shows that the oersted cannot be converted directly to the SI unit of magnetic field, A/m, because the dimensions conflict. We cannot redefine the ampere to make this work because then it would not convert with the statampere. But you can still do this conversion as shown below. (Gaussian) You have: oersted You want: A/m conformability error 1 sqrt_g / s sqrt_cm 29979246 sqrt_cm sqrt_g / s^2 (Gaussian) You have: oersted You want: H_FIELD * 79.577472 / 0.012566371 Natural Units Like the CGS units, "natural" units are an alternative to the SI system used primarily physicists in different fields, with different systems tailored to different fields of study. These systems are "natural" be- cause the base measurements are defined using physical constants in- stead of arbitrary values such as the meter or second. In different branches of physics, different physical constants are more fundamental, which has given rise to a variety of incompatible natural unit systems. The supported systems are the "natural" units (which seem to have no better name) used in high energy physics and cosmology, the Planck units, often used by scientists working with gravity, and the Hartree atomic units are favored by those working in physical chemistry and condensed matter physics. You can select the various natural units using the '--units' option in the same way that you select the CGS units. The "natural" units come in two types, a rationalized system derived from the Heaviside-Lorentz units and an unrationalized system derived from the Gaussian system. You can select these using 'natural' and 'natural-gauss' respectively. For conversions in SI mode, several unit names starting with 'natural' are available. This "natural" system is defined by setting {hbar}, c and the Boltzman constant to 1. Only a single base unit remains: the electron volt. The Planck units exist in a variety of forms, and units supports two. Both supported forms are rationalized, in that factors of 4{pi} do not appear in Maxwell's equations. However, Planck units can also differ based on how the gravitational constant is treated. This system is similar to the natural units in that c, {hbar}, and Boltzman's constant are set to 1, but in this system, Newton's gravitational constant, G is also fixed. In the "reduced" Planck system, delim $$ 8{pi}G = 1 whereas in the unreduced system G = 1. The reduced system eliminates factors of 8{pi} delim off from the Einstein field equations for gravi- tation, so this is similar to the process of forming rationalized units to simplify Maxwell's equations. To obtain the unreduced system use the name 'planck' and for the reduced Planck units, 'planck-red'. Units such as 'planckenergy' and 'planckenergy_red' enable you to con- vert the unreduced and reduced Planck energy unit in SI mode between the various systems. In Planck units, all measurements are dimension- less. The final natural unit system is the Hartree atomic units. Like the Planck units, all measurements in the Hartree units are dimensionless, but this system is defined by defined from completely different physi- cal constants: the electron mass, Planck's constant, the electron charge, and the Coulomb constant are the defining physical quantities, which are all set to unity. To invoke this system with the '--units' option use the name 'hartree'. Prompt Prefix If a unit system is specified with the '--units' option, the selected system's name is prepended to the 'You have:' prompt as a reminder, e.g., (Gaussian) You have: stC You want: Definition: statcoulomb = sqrt(dyne) cm = 1 sqrt_cm^3 sqrt_g / s You can suppressed the prefix by including a line !prompt with no argument in a site or personal units data file. The prompt can be conditionally suppressed by including such a line within '!var' ... '!endvar' constructs, e.g., !var UNITS_SYSTEM gaussian gauss !prompt !endvar This might be appropriate if you normally use Gaussian units and find the prefix distracting but want to be reminded when you have selected a different CGS system. LOGGING CALCULATIONS The '--log' option allows you to save the results of calculations in a file; this can be useful if you need a permanent record of your work. For example, the fluid-flow conversion in Complicated Unit Expressions, is lengthy, and if you were to use it in designing a piping system, you might want a record of it for the project file. If the interactive session # Conversion factor A1 for pressure drop # dP = A1 rho f L Q^2/d^5 You have: (8/pi^2) (lbm/ft^3)ft(ft^3/s)^2(1/in^5) # Input units You want: psi * 43.533969 / 0.022970568 were logged, the log file would contain ### Log started Fri Oct 02 15:55:35 2015 # Conversion factor A1 for pressure drop # dP = A1 rho f L Q^2/d^5 From: (8/pi^2) (lbm/ft^3)ft(ft^3/s)^2(1/in^5) # Input units To: psi * 43.533969 / 0.022970568 The time is written to the log file when the file is opened. The use of comments can help clarify the meaning of calculations for the log. The log includes conformability errors between the units at the 'You have:' and 'You want:' prompts, but not other errors, includ- ing lack of conformability of items in sums or differences or among items in a unit list. For example, a conversion between zenith angle and elevation angle could involve You have: 90 deg - (5 deg + 22 min + 9 sec) ^ Invalid sum or difference of non-conformable units You have: 90 deg - (5 deg + 22 arcmin + 9 arcsec) You want: dms 84 deg + 37 arcmin + 51 arcsec You have: _ You want: deg * 84.630833 / 0.011816024 You have: The log file would contain From: 90 deg - (5 deg + 22 arcmin + 9 arcsec) To: deg;arcmin;arcsec 84 deg + 37 arcmin + 51 arcsec From: _ To: deg * 84.630833 / 0.011816024 The initial entry error (forgetting that minutes have dimension of time, and that arcminutes must be used for dimensions of angle) does not appear in the output. When converting to a unit list alias, units expands the alias in the log file. The 'From:' and 'To:' tags are written to the log file even if the '--quiet' option is given. If the log file exists when units is in- voked, the new results are appended to the log file. The time is writ- ten to the log file each time the file is opened. The '--log' option is ignored when units is used non-interactively. INVOKING UNITS You invoke units like this: units [options] [from-unit [to-unit]] If the from-unit and to-unit are omitted, the program will use interac- tive prompts to determine which conversions to perform. See Interac- tive Use. If both from-unit and to-unit are given, units will print the result of that single conversion and then exit. If only from-unit appears on the command line, units will display the definition of that unit and exit. Units specified on the command line may need to be quoted to protect them from shell interpretation and to group them into two arguments. Note also that the '--quiet' option is enabled by de- fault if you specify from-unit on the command line. See Command Line Use. The default behavior of units can be changed by various options given on the command line. In most cases, the options may be given in either short form (a single '-' followed by a single character) or long form ('--' followed by a word or hyphen-separated words). Short-form op- tions are cryptic but require less typing; long-form options require more typing but are more explanatory and may be more mnemonic. With long-form options you need only enter sufficient characters to uniquely identify the option to the program. For example, '--out %f' works, but '--o %f' fails because units has other long options beginning with 'o'. However, '--q' works because '--quiet' is the only long option begin- ning with 'q'. Some options require arguments to specify a value (e.g., '-d 12' or '--digits 12'). Short-form options that do not take arguments may be concatenated (e.g., '-erS' is equivalent to '-e -r -S'); the last op- tion in such a list may be one that takes an argument (e.g., '-ed 12'). With short-form options, the space between an option and its argument is optional (e.g., '-d12' is equivalent to '-d 12'). Long-form options may not be concatenated, and the space between a long-form option and its argument is required. Short-form and long-form options may be in- termixed on the command line. Options may be given in any order, but when incompatible options (e.g., '--output-format' and '--exponential') are given in combination, behavior is controlled by the last option given. For example, '-o%.12f -e' gives exponential format with the de- fault eight significant digits). Many options can be set interactively; this can be especially helpful for Windows users who start units from a shortcut. See Setting Options Interactively for more information. The following options are available: -c, --check Check that all units and prefixes defined in units data files reduce to primitive units. Display a list of all units that cannot be reduced and a list of units with circular definitions. Also display some other diagnostics about suspicious definitions in the units data file. Only definitions active in the current locale are checked. You should always run units with this op- tion after modifying a units data file. Some errors may hide other errors, so you should run units with this option again after correcting any errors, and keep doing so until there are no errors. --check-verbose, --verbose-check Like the '--check' option, this option displays a list of units that cannot be reduced. But it also lists the units as they are checked. Because the '--check' option now catches circular unit definitions that previously caused units to hang, this option is no longer necessary. It is retained only for compatibility with previous versions. -d ndigits, --digits ndigits Set the number of significant digits in the output to the value specified (which must be greater than zero). For example, '-d 12' sets the number of significant digits to 12. With expo- nential output, units displays one digit to the left of the dec- imal point and eleven digits to the right of the decimal point. On most systems, the maximum number of internally meaningful digits is 15; if you specify a greater number than your system's maximum, units will print a warning and set the number to the largest meaningful value. To directly set the maximum value, give an argument of max (e.g., '-d max'). Be aware, of course, that "significant" here refers only to the display of numbers; if results depend on physical constants not known to this preci- sion, the physically meaningful precision may be less than that shown. The '--digits' option is incompatible with the '--out- put-format' option; if you give them both, the format is con- trolled by the last option given. -e, --exponential Set the numeric output format to exponential (i.e., scientific notation), like that used in the Unix units program. The de- fault precision is eight significant digits (seven digits to the right of the decimal point); this can be changed with the '--digits' option. The '--exponential' option is incompatible with the '--output-format' option; if you give them both, the format is controlled by the last option given. -o format, --output-format format This option affords complete control over the numeric output format using the specified format. The format is a single float- ing point numeric format for the printf function in the C pro- gramming language. All compilers support the format types 'g' and 'G' to specify significant digits, 'e' and 'E' for scien- tific notation, and 'f' for fixed-point decimal. The ISO C99 standard introduced the 'F' type for fixed-point decimal and the 'a' and 'A' types for hexadecimal floating point; these types are allowed with compilers that support them. The default for- mat is '%.8g'; for greater precision, you could specify '-o %.15g'. Unlike with the '--digits' option, you can specify any desired precision, though not all digits may be meaningful. See Numeric Output Format and the documentation for printf for more detailed descriptions of the format specification. The '--output-format' option affords the greatest control of the output appearance, but requires at least rudimentary knowledge of the printf format syntax. If you don't want to bother with the printf syntax, you can specify greater precision more simply with the '--digits' option or select exponential format with '--exponential'. The '--output-format' option is incompatible with the '--exponential' and '--digits' options; if you give ei- ther in combination with '--output-format', the format is con- trolled by the last option given. -f filename, --file filename Instruct units to load the units file filename. You can specify up to 25 units files on the command line. When you use this op- tion, units will load only the files you list on the command line; it will not load the standard file or your personal units file unless you explicitly list them. If filename is the empty string ('-f ""'), the default main units file (or that specified by UNITSFILE) will be loaded in addition to any others specified with '-f'. -L logfile, --log logfile Save the results of calculations in the file logfile; this can be useful if it is important to have a record of unit conver- sions or other calculations that are to be used extensively or in a critical activity such as a program or design project. If logfile exits, the new results are appended to the file. This option is ignored when units is used non-interactively. See Logging Calculations for a more detailed description and some examples. -H filename, --history filename Instruct units to save history to filename, so that a record of your commands is available for retrieval across different units invocations. To prevent the history from being saved set file- name to the empty string ('-H ""'). This option has no effect if readline is not available. -h, --help Print out a summary of the options for units. -m, --minus Causes '-' to be interpreted as a subtraction operator. This is the default behavior. -p, --product Causes '-' to be interpreted as a multiplication operator when it has two operands. It will act as a negation operator when it has only one operand: '(-3)'. By default '-' is treated as a subtraction operator. --oldstar Causes '*' to have the old-style precedence, higher than the precedence of division so that '1/2*3' will equal '1/6'. --newstar Forces '*' to have the new (default) precedence that follows the usual rules of algebra: the precedence of '*' is the same as the precedence of '/', so that '1/2*3' will equal '3/2'. -r, --round When converting to a combination of units given by a unit list, round the value of the last unit in the list to the nearest in- teger. -S, --show-factor When converting to a combination of units specified in a list, always show a non-unity factor before a unit that begins with a fraction with a unity denominator. By default, if the unit in a list begins with fraction of the form 1|x and its multiplier is an integer other than 1, the fraction is given as the product of the multiplier and the numerator (e.g., '3|8 in' rather than '3 * 1|8 in'). In some cases, this is not what is wanted; for ex- ample, the results for a cooking recipe might show '3 * 1|2 cup' as '3|2 cup'. With the '--show-factor' option, a result equiva- lent to 1.5 cups will display as '3 * 1|2 cup' rather than '3|2 cup'. A user-specified fractional unit with a numerator other than 1 is never overridden, however--if a unit list speci- fies '3|4 cup;1|2 cup', a result equivalent to 1 1/2 cups will always be shown as '2 * 3|4 cup' whether or not the '--show-fac- tor' option is given. --conformable In non-interactive mode, show all units conformable with the original unit expression. Only one unit expression is allowed; if you give more than one, units will exit with an error message and return failure. -v, --verbose Give slightly more verbose output when converting units. When combined with the '-c' option this gives the same effect as '--check-verbose'. When combined with '--version' produces a more detailed output, equivalent to the '--info' option. -V, --version Print the program version number, tell whether the readline li- brary has been included, tell whether UTF-8 support has been in- cluded; give the locale, the location of the default main units data file, and the location of the personal units data file; in- dicate if the personal units data file does not exist. When given in combination with the '--terse' option, the program prints only the version number and exits. When given in combination with the '--verbose' option, the pro- gram, the '--version' option has the same effect as the '--info' option below. -I, --info Print the information given with the '--version' option, show the pathname of the units program, show the status of the UNITSFILE and MYUNITSFILE environment variables, and additional information about how units locates the related files. On sys- tems running Microsoft Windows, the status of the UNITSLOCALE environment variable and information about the related locale map are also given. This option is usually of interest only to developers and administrators, but it can sometimes be useful for troubleshooting. Combining the '--version' and '--verbose' options has the same effect as giving '--info'. -U, --unitsfile Print the location of the default main units data file and exit; if the file cannot be found, print "Units data file not found". -u units-system, --units units-system Specify a CGS units system or natural units system. The sup- ported units systems are: gauss[ian], esu, emu, hlu, natural, natural-gauss, hartree, planck, planck-red, and si. See Alterna- tive Unit Systems for further information about these unit sys- tems. -l locale, --locale locale Force a specified locale such as 'en_GB' to get British defini- tions by default. This overrides the locale determined from system settings or environment variables. See Locale for a de- scription of locale format. -n, --nolists Disable conversion to unit lists. -s, --strict Suppress conversion of units to their reciprocal units. For ex- ample, units will normally convert hertz to seconds because these units are reciprocals of each other. The strict option requires that units be strictly conformable to perform a conver- sion, and will give an error if you attempt to convert hertz to seconds. -1, --one-line Give only one line of output (the forward conversion); do not print the reverse conversion. If a reciprocal conversion is performed, then units will still print the "reciprocal conver- sion" line. -t, --terse Print only a single conversion factor without any clutter, or if you request a definition, prints just the definition (including its units). This option can be used when calling units from an- other program so that the output is easy to parse. The command units --terse mile m produces the output '1690.344'. This op- tion has the combined effect of these options: '--strict' '--quiet' '--one-line' '--compact'. When combined with '--ver- sion' it produces a display showing only the program name and version number. --compact Give compact output featuring only the conversion factor; the multiplication and division signs are not shown, and there is no leading whitespace. If you convert to a unit list, then the output is a semicolon separated list of factors. This turns off the '--verbose' option. -q, --quiet, --silent Suppress the display of statistics about the number of units loaded, any messages printed by the units database, and the prompting of the user for units. This option does not affect how units displays the results. This option is turned on by de- fault if you invoke units with a unit expression on the command line. SETTING OPTIONS INTERACTIVELY Many command-line options can also be set interactively, obviating the need to quit and restart units to change the values. This can be espe- cially helpful for Windows users who start units from a shortcut. Typing set will display a list of all options that can be set interac- tively, as well as the current and possible values; options set to other than default values have an asterisk ('*') prepended. For exam- ple, You have: set q[uiet] = no (y|n) do/don't suppress prompting o[neline] = no (y|n) do/don't suppress the second line of output st[rict] = no (y|n) do/don't suppress reciprocal unit conversion (e.g. Hz<->s) t[erse] = no (y|n) do/don't give very terse output c[ompact] = no (y|n) do/don't suppress printing tab, SETFLAG, and '/' characters in results v[erbose] = 1 (0|1|2) amount of information shown *d[igits] = 9 number of significant digits in output e[ponential] = no (y|n) do/don't use exponential ("scientific") notation *f[ormat] = %.9g printf(3) format specification u[nitlists] = yes (y|n) do/don't allow conversion to unit lists r[ound] = no (y|n) do/don't round last element of unit list output to an integer sh[owfactor] = no (y|n) do/don't show non-unity factor before 1|x in multi-unit output Characters within the square brackets are optional, so settings can be changed by entering only one or two characters. The syntax for setting options is set option = value; the spaces around the '=' sign are optional. Some settings are Boolean, enabled by entering yes (or just y) and dis- abled by entering no (or just n). For example, You have: set quiet = y quiet = yes Other settings take an integer value; for example, You have: set d=11 digits = 11 format = %.11g The format setting takes a string, the format specification for the printf function in the C programming language; for example, You have: set format = %.9g format = %.9g Typing set option will display the current value of option, for example You have: set u unitlists = yes You have: set d digits = 8 format = %.8g For the digits and exponential options, the value of format is also shown. SCRIPTING WITH UNITS Despite its numerous options, units cannot cover every conceivable unit-conversion task. For example, suppose we have found some mysteri- ous scale, but cannot figure out the units in which it is reporting. We reach into our pocket, place a 3.75-gram coin on the scale, and ob- serve the scale reading '0.120'. How do we quickly determine the units? Or we might wonder if a unit has any "synonyms," i.e., other units with the same value. The capabilities of units are easily extended with simple scripting. Both questions above involve conformable units; on a system with Unix- like utilities, conversions to conformable units could be shown accom- plished with the following script: #!/bin/sh progname=`basename $0 .sh` umsg="Usage: $progname [] unit" if [ $# -lt 1 ] then echo "$progname: missing quantity to convert" echo "$umsg" exit 1 fi for unit in `units --conformable "$*" | cut -f 1 -d ' '` do echo "$*" # have -- quantity to convert echo $unit # want -- conformable unit done | units --terse --verbose When units is invoked with no non-option arguments, it reads have/want pairs, on alternating lines, from its standard input, so the task can be accomplished with only two invocations of units. This avoids the computational overhead of needlessly reprocessing the units database for each conformable unit, as well as the inherent system overhead of process invocation. By itself, the script is not very useful. But it could be used in com- bination with other commands to address specific tasks. For example, running the script through a simple output filter could help solve the scale problem above. If the script is named conformable, running $ conformable 3.75g | grep 0.120 gives 3.75g = 0.1205653 apounce 3.75g = 0.1205653 fineounce 3.75g = 0.1205653 ozt 3.75g = 0.1205653 tradewukiyeh 3.75g = 0.1205653 troyounce So we might conclude that the scale is calibrated in troy ounces. We might run $ units --verbose are Definition: 100 m^2 = 100 m^2 and wonder if 'are' has any synonyms, value. To find out, we could run $ conformable are | grep "= 1 " are = 1 a are = 1 are OUTPUT STYLES The output can be tweaked in various ways using command line options. With no options, the output looks like this $ units Currency exchange rates from FloatRates (USD base) on 2023-07-08 3612 units, 109 prefixes, 122 nonlinear units You have: 23ft You want: m * 7.0104 / 0.14264521 You have: m You want: ft;in 3 ft + 3.3700787 in This is arguably a bit cryptic; the '--verbose' option makes clear what the output means: $ units --verbose Currency exchange rates from FloatRates (USD base) on 2023-07-08 3612 units, 109 prefixes, 122 nonlinear units You have: 23 ft You want: m 23 ft = 7.0104 m 23 ft = (1 / 0.14264521) m You have: meter You want: ft;in meter = 3 ft + 3.3700787 in The '--quiet' option suppresses the clutter displayed when units starts, as well as the prompts to the user. This option is enabled by default when you give units on the command line. $ units --quiet 23 ft m * 7.0104 / 0.14264521 $ units 23ft m * 7.0104 / 0.14264521 The remaining style options allow you to display only numerical values without the tab or the multiplication and division signs, or to display just a single line showing the forward conversion: $ units --compact 23ft m 7.0104 0.14264521 $ units --compact m 'ft;in' 3;3.3700787 $ units --one-line 23ft m * 7.0104 $ units --one-line 23ft 1/m reciprocal conversion * 0.14264521 $ units --one-line 23ft kg conformability error 7.0104 m 1 kg Note that when converting to a unit list, the '--compact' option dis- plays a semicolon separated list of results. Also be aware that the 'one-line' option doesn't live up to its name if you execute a recipro- cal conversion or if you get a conformability error. The former case can be prevented using the '--strict' option, which suppresses recipro- cal conversions. Similarly you can suppress unit list conversion using '--nolists'. It is impossible to prevent the three line error output. $ units --compact --nolists m 'ft;in' Error in 'ft;in': Parse error $ units --one-line --strict 23ft 1/m The various style options can be combined appropriately. The ultimate combination is the '--terse' option, which combines '--strict', '--quiet', '--one-line', and '--compact' to produce the minimal output, just a single number for regular conversions and a semicolon separated list for conversion to unit lists. This will likely be the best choice for programs that want to call units and then process its result. $ units --terse 23ft m 7.0104 $ units --terse m 'ft;in' 3;3.3700787 $ units --terse 23ft 1/m conformability error 7.0104 m 1 / m $ units --terse '1 mile' 1609.344 m $ units --terse mile 5280 ft = 1609.344 m ADDING YOUR OWN DEFINITIONS Units Data Files The units and prefixes that units can convert are defined in the units data file, typically '/usr/share/units/definitions.units'. If you can't find this file, run units --version to get information on the file locations for your installation. Although you can extend or mod- ify this data file if you have appropriate user privileges, it's usu- ally better to put extensions in separate files so that the definitions will be preserved if you update units. You can include additional data files in the units database using the '!include' command in the standard units data file. For example !include /usr/local/share/units/local.units might be appropriate for a site-wide supplemental data file. The loca- tion of the '!include' statement in the standard units data file is im- portant; later definitions replace earlier ones, so any definitions in an included file will override definitions before the '!include' state- ment in the standard units data file. With normal invocation, no warn- ing is given about redefinitions; to ensure that you don't have an un- intended redefinition, run units -c after making changes to any units data file. If you want to add your own units in addition to or in place of stan- dard or site-wide supplemental units data files, you can include them in the '.units' file in your home directory. If this file exists it is read after the standard units data file, so that any definitions in this file will replace definitions of the same units in the standard data file or in files included from the standard data file. This file will not be read if any units files are specified on the command line. (Under Windows the personal units file is named 'unitdef.units'.) Run- ning units -V will display the location and name of your personal units file. The units program first tries to determine your home directory from the HOME environment variable. On systems running Microsoft Windows, if HOME does not exist, units attempts to find your home directory from HOMEDRIVE, HOMEPATH and USERPROFILE. You can specify an arbitrary file as your personal units data file with the MYUNITSFILE environment vari- able; if this variable exists, its value is used without searching your home directory. The default units data files are described in more de- tail in Data Files. Defining New Units and Prefixes A unit is specified on a single line by giving its name and an equiva- lence. Comments start with a '#' character, which can appear anywhere in a line. The backslash character ('\') acts as a continuation char- acter if it appears as the last character on a line, making it possible to spread definitions out over several lines if desired. A file can be included by giving the command '!include' followed by the file's name. The '!' must be the first character on the line. The file will be sought in the same directory as the parent file unless you give a full path. The name of the file to be included cannot contain spaces or the comment character '#'. Unit names cannot begin or end with an underscore ('_'), a comma (',') or a decimal point ('.'). Names must not contain any of the operator characters '+', '-', '*', '/', '|', '^', ';', '~', the comment charac- ter '#', or parentheses. To facilitate copying and pasting from docu- ments, several typographical characters are converted to operators: the figure dash (U+2012), minus ('-'; U+2212), and en dash ('-'; U+2013) are converted to the operator '-'; the multiplication sign ('x'; U+00D7), N-ary times operator (U+2A09), dot operator ('.'; U+22C5), and middle dot ('.'; U+00B7) are converted to the operator '*'; the divi- sion sign ('/'; U+00F7) is converted to the operator '/'; and the frac- tion slash (U+2044) is converted to the operator '|'; accordingly, none of these characters can appear in unit names. Names cannot begin with a digit, and if a name ends in a digit other than zero or one, the digit must be preceded by a string beginning with an underscore, and afterwards consisting only of digits, decimal points, or commas. For example, 'foo_2', 'foo_2,1', or 'foo_3.14' are valid names but 'foo2' or 'foo_a2' are invalid. The underscore is nec- essary because without it, units cannot determine whether 'foo2' is a unit name or represents 'foo^2'. Zero and one are exceptions because units never interprets them as exponents. You could define nitrous oxide as N2O nitrogen 2 + oxygen but would need to define nitrogen dioxide as NO_2 nitrogen + oxygen 2 Be careful to define new units in terms of old ones so that a reduction leads to the primitive units, which are marked with '!' characters. Dimensionless units are indicated by using the string '!dimensionless' for the unit definition. When adding new units, be sure to use the '-c' option to check that the new units reduce properly and that there are no circular definitions that lead to endless loops. Because some errors may hide other errors, you should run units with the '-c' option again after correcting any errors, and keep doing so until no errors are displayed. If you define any units that contain '+' characters in their defini- tions, carefully check them because the '-c' option will not catch non- conformable sums. Be careful with the '-' operator as well. When used as a binary operator, the '-' character can perform addition or multi- plication depending on the options used to invoke units. To ensure consistent behavior use '-' only as a unary negation operator when writing units definitions. To multiply two units leave a space or use the '*' operator with care, recalling that it has two possible prece- dence values and may require parentheses to ensure consistent behavior. To compute the difference of 'foo' and 'bar' write 'foo+(-bar)' or even 'foo+-bar'. You may wish to intentionally redefine a unit. When you do this, and use the '-c' option, units displays a warning message about the redefi- nition. You can suppress these warnings by redefining a unit using a '+' at the beginning of the unit name. Do not include any white space between the '+' and the redefined unit name. Here is an example of a short data file that defines some basic units: m ! # The meter is a primitive unit sec ! # The second is a primitive unit rad !dimensionless # A dimensionless primitive unit micro- 1e-6 # Define a prefix minute 60 sec # A minute is 60 seconds hour 60 min # An hour is 60 minutes inch 72 m # Inch defined incorrectly terms of meters ft 12 inches # The foot defined in terms of inches mile 5280 ft # And the mile +inch 0.0254 m # Correct redefinition, warning suppressed A unit that ends with a '-' character is a prefix. If a prefix defini- tion contains any '/' characters, be sure they are protected by paren- theses. If you define 'half- 1/2', then 'halfmeter' would be equiva- lent to '1 / (2 meter)'. Defining Nonlinear Units Some unit conversions of interest are nonlinear; for example, tempera- ture conversions between the Fahrenheit and Celsius scales cannot be done by simply multiplying by conversion factors. When you give a linear unit definition such as 'inch 2.54 cm' you are providing information that units uses to convert values in inches into primitive units of meters. For nonlinear units, you give a functional definition that provides the same information. Nonlinear units are represented using a functional notation. It is best to regard this notation not as a function call but as a way of adding units to a number, much the same way that writing a linear unit name after a number adds units to that number. Internally, nonlinear units are defined by a pair of functions that convert to and from lin- ear units in the database, so that an eventual conversion to primitive units is possible. Here is an example nonlinear unit definition: tempF(x) units=[1;K] domain=[-459.67,) range=[0,) \ (x+(-32)) degF + stdtemp ; (tempF+(-stdtemp))/degF + 32 A nonlinear unit definition comprises a unit name, a formal parameter name, two functions, and optional specifications for units, the domain, and the range (the domain of the inverse function). The functions tell units how to convert to and from the new unit. To produce valid re- sults, the arguments of these functions need to have the correct dimen- sions and be within the domains for which the functions are defined. The definition begins with the unit name followed immediately (with no spaces) by a '(' character. In the parentheses is the name of the for- mal parameter. Next is an optional specification of the units required by the functions in the definition. In the example above, the 'units=[1;K]' specification indicates that the 'tempF' function re- quires an input argument conformable with '1' (i.e., the argument is dimensionless), and that the inverse function requires an input argu- ment conformable with 'K'. For normal nonlinear units definition, the forward function will always take a dimensionless argument; in general, the inverse function will need units that match the quantity measured by your nonlinear unit. Specifying the units enables units to perform error checking on function arguments, and also to assign units to do- main and range specifications, which are described later. Next the function definitions appear. In the example above, the 'tempF' function is defined by tempF(x) = (x+(-32)) degF + stdtemp This gives a rule for converting 'x' in the units 'tempF' to linear units of absolute temperature, which makes it possible to convert from tempF to other units. To enable conversions to Fahrenheit, you must give a rule for the in- verse conversions. The inverse will be 'x(tempF)' and its definition appears after a ';' character. In our example, the inverse is x(tempF) = (tempF+(-stdtemp))/degF + 32 This inverse definition takes an absolute temperature as its argument and converts it to the Fahrenheit temperature. The inverse can be omitted by leaving out the ';' character and the inverse definition, but then conversions to the unit will not be possible. If the inverse definition is omitted, the '--check' option will display a warning. It is up to you to calculate and enter the correct inverse function to ob- tain proper conversions; the '--check' option tests the inverse at one point and prints an error if it is not valid there, but this is not a guarantee that your inverse is correct. With some definitions, the units may vary. For example, the definition square(x) x^2 can have any arbitrary units, and can also take dimensionless argu- ments. In such a case, you should not specify units. If a definition takes a root of its arguments, the definition is valid only for units that yield such a root. For example, squirt(x) sqrt(x) is valid for a dimensionless argument, and for arguments with even pow- ers of units. Some definitions may not be valid for all real numbers. In such cases, units can handle errors better if you specify an appropriate domain and range. You specify the domain and range as shown below: baume(d) units=[1;g/cm^3] domain=[0,130.5] range=[1,10] \ (145/(145-d)) g/cm^3 ; (baume+-g/cm^3) 145 / baume In this example the domain is specified after 'domain=' with the end- points given in brackets. In accord with mathematical convention, square brackets indicate a closed interval (one that includes its end- points), and parentheses indicate an open interval (one that does not include its endpoints). An interval can be open or closed on one or both ends; an interval that is unbounded on either end is indicated by omitting the limit on that end. For example, a quantity to which deci- bel (dB) is applied may have any value greater than zero, so the range is indicated by '(0,)': decibel(x) units=[1;1] range=(0,) 10^(x/10); 10 log(decibel) If the domain or range is given, the second endpoint must be greater than the first. The domain and range specifications can appear independently and in any order along with the units specification. The values for the domain and range endpoints are attached to the units given in the units speci- fication, and if necessary, the parameter value is adjusted for compar- ison with the endpoints. For example, if a definition includes 'units=[1;ft]' and 'range=[3,)', the range will be taken as 3 ft to in- finity. If the function is passed a parameter of '900 mm', that value will be adjusted to 2.9527559 ft, which is outside the specified range. If you omit the units specification from the previous example, units can not tell whether you intend the lower endpoint to be 3 ft or 3 mi- crofurlongs, and can not adjust the parameter value of 900 mm for com- parison. Without units, numerical values other than zero or plus or minus infinity for domain or range endpoints are meaningless, and ac- cordingly they are not allowed. If you give other values without units, then the definition will be ignored and you will get an error message. Although the units, domain, and range specifications are optional, it's best to give them when they are applicable; doing so allows units to perform better error checking and give more helpful error messages. Giving the domain and range also enables the '--check' option to find a point in the domain to use for its point check of your inverse defini- tion. You can make synonyms for nonlinear units by providing both the forward and inverse functions; inverse functions can be obtained using the '~' operator. So to create a synonym for 'tempF' you could write fahrenheit(x) units=[1;K] tempF(x); ~tempF(fahrenheit) This is useful for creating a nonlinear unit definition that differs slightly from an existing definition without having to repeat the orig- inal functions. For example, dBW(x) units=[1;W] range=[0,) dB(x) W ; ~dB(dBW/W) If you wish a synonym to refer to an existing nonlinear unit without modification, you can do so more simply by adding the synonym with ap- pended parentheses as a new unit, with the existing nonlinear unit-- without parentheses--as the definition. So to create a synonym for 'tempF' you could write fahrenheit() tempF The definition must be a nonlinear unit; for example, the synonym fahrenheit() meter will result in an error message when units starts. You may occasionally wish to define a function that operates on units. This can be done using a nonlinear unit definition. For example, the definition below provides conversion between radius and the area of a circle. This definition requires a length as input and produces an area as output, as indicated by the 'units=' specification. Specifying the range as the nonnegative numbers can prevent cryptic error mes- sages. circlearea(r) units=[m;m^2] range=[0,) pi r^2 ; sqrt(circlearea/pi) Defining Piecewise Linear Units Sometimes you may be interested in a piecewise linear unit such as many wire gauges. Piecewise linear units can be defined by specifying con- versions to linear units on a list of points. Conversion at other points will be done by linear interpolation. A partial definition of zinc gauge is zincgauge[in] 1 0.002, 10 0.02, 15 0.04, 19 0.06, 23 0.1 In this example, 'zincgauge' is the name of the piecewise linear unit. The definition of such a unit is indicated by the embedded '[' charac- ter. After the bracket, you should indicate the units to be attached to the numbers in the table. No spaces can appear before the ']' char- acter, so a definition like 'foo[kg meters]' is invalid; instead write 'foo[kg*meters]'. The definition of the unit consists of a list of pairs optionally separated by commas. This list defines a function for converting from the piecewise linear unit to linear units. The first item in each pair is the function argument; the second item is the value of the function at that argument (in the units specified in brackets). In this example, we define 'zincgauge' at five points. For example, we set 'zincgauge(1)' equal to '0.002 in'. Definitions like this may be more readable if written using continuation characters as zincgauge[in] \ 1 0.002 \ 10 0.02 \ 15 0.04 \ 19 0.06 \ 23 0.1 With the preceding definition, the following conversion can be per- formed: You have: zincgauge(10) You want: in * 0.02 / 50 You have: .01 inch You want: zincgauge 5 If you define a piecewise linear unit that is not strictly monotonic, then the inverse will not be well defined. If the inverse is requested for such a unit, units will return the smallest inverse. After adding nonlinear units definitions, you should normally run 'units --check' to check for errors. If the 'units' keyword is not given, the '--check' option checks a nonlinear unit definition using a dimensionless argument, and then checks using an arbitrary combination of units, as well as the square and cube of that combination; a warning is given if any of these tests fail. For example, Warning: function 'squirt(x)' defined as 'sqrt(x)' failed for some test inputs: squirt(7(kg K)^1): Unit not a root squirt(7(kg K)^3): Unit not a root Running 'units --check' will print a warning if a non-monotonic piece- wise linear unit is encountered. For example, the relationship between ANSI coated abrasive designation and mean particle size is non-mono- tonic in the vicinity of 800 grit: ansicoated[micron] \ . . . 600 10.55 \ 800 11.5 \ 1000 9.5 \ Running 'units --check' would give the error message Table 'ansicoated' lacks unique inverse around entry 800 Although the inverse is not well defined in this region, it's not re- ally an error. Viewing such error messages can be tedious, and if there are enough of them, they can distract from true errors. Error checking for nonlinear unit definitions can be suppressed by giving the 'noerror' keyword; for the examples above, this could be done as squirt(x) noerror domain=[0,) range=[0,) sqrt(x); squirt^2 ansicoated[micron] noerror \ . . . Use the 'noerror' keyword with caution. The safest approach after adding a nonlinear unit definition is to run 'units --check' and con- firm that there are no actual errors before adding the 'noerror' key- word. Defining Unit List Aliases Unit list aliases are treated differently from unit definitions, be- cause they are a data entry shorthand rather than a true definition for a new unit. A unit list alias definition begins with '!unitlist' and includes the alias and the definition; for example, the aliases in- cluded in the standard units data file are !unitlist hms hr;min;sec !unitlist time year;day;hr;min;sec !unitlist dms deg;arcmin;arcsec !unitlist ftin ft;in;1|8 in !unitlist usvol cup;3|4 cup;2|3 cup;1|2 cup;1|3 cup;1|4 cup;\ tbsp;tsp;1|2 tsp;1|4 tsp;1|8 tsp Unit list aliases are only for unit lists, so the definition must in- clude a ';'. Unit list aliases can never be combined with units or other unit list aliases, so the definition of 'time' shown above could not have been shortened to 'year;day;hms'. As usual, be sure to run 'units --check' to ensure that the units listed in unit list aliases are conformable. NUMERIC OUTPUT FORMAT By default, units shows results to eight significant digits in general number format. You can change this with the '--exponential', '--dig- its', and '--output-format' options. The first sets an exponential format (i.e., scientific notation) like that used in the original Unix units program, the second allows you to specify a different number of significant digits, and the last allows you to control the output ap- pearance using the format for the printf function in the C programming language. If you only want to change the number of significant digits or specify exponential format type, use the '--digits' and '--exponen- tial' options. The '--output-format' option affords the greatest con- trol of the output appearance, but requires at least rudimentary knowl- edge of the printf format syntax. See Invoking Units for descriptions of these options. Format Specification The format specification recognized with the '--output-format' option is a subset of that for printf. The format specification has the form %[flags][width][.precision]type; it must begin with '%', and must end with a floating-point type specifier: 'g' or 'G' to specify the number of significant digits, 'e' or 'E' for scientific notation, and 'f' for fixed-point decimal. The ISO C99 standard added the 'F' type for fixed-point decimal and the 'a' and 'A' types for hexadecimal floating point; these types are allowed with compilers that support them. Type length modifiers (e.g., 'L' to indicate a long double) are inapplicable and are not allowed. The default format for units is '%.8g'; for greater precision, you could specify '-o %.15g'. The 'g' and 'G' format types use exponential format whenever the exponent would be less than -4, so the value 0.000013 displays as '1.3e-005'. These types also use exponential no- tation when the exponent is greater than or equal to the precision, so with the default format, the value 5 x 10^7 displays as '50000000' and the value 5 x 10^8 displays as '5e+008'. If you prefer fixed-point display, you might specify '-o %.8f'; however, small numbers will dis- play very few significant digits, and values less than 5 x 10^-8 will show nothing but zeros. The format specification may include one or more optional flags: '+', ' ' (space), '#', '-', or '0' (the digit zero). The digit-grouping flag ''' is allowed with compilers that support it. Flags are followed by an optional value for the minimum field width, and an optional pre- cision specification that begins with a period (e.g., '.6'). The field width includes the digits, decimal point, the exponent, thousands sepa- rators (with the digit-grouping flag), and the sign if any of these are shown. Flags The '+' flag causes the output to have a sign ('+' or '-'). The space flag ' ' is similar to the '+' flag, except that when the value is pos- itive, it is prefixed with a space rather than a plus sign; this flag is ignored if the '+' flag is also given. The '+' or ' ' flag could be useful if conversions might include positive and negative results, and you wanted to align the decimal points in exponential notation. The '#' flag causes the output value to contain a decimal point in all cases; by default, the output contains a decimal point only if there are digits (which can be trailing zeros) to the right of the point. With the 'g' or 'G' types, the '#' flag also prevents the suppression of trailing zeros. The digit-grouping flag ''' shows a thousands sepa- rator in digits to the left of the decimal point. This can be useful when displaying large numbers in fixed-point decimal; for example, with the format '%f', You have: mile You want: microfurlong * 8000000.000000 / 0.000000 the magnitude of the first result may not be immediately obvious with- out counting the digits to the left of the decimal point. If the thou- sands separator is the comma (','), the output with the format '%'f' might be You have: mile You want: microfurlong * 8,000,000.000000 / 0.000000 making the magnitude readily apparent. Unfortunately, few compilers support the digit-grouping flag. With the '-' flag, the output value is left aligned within the speci- fied field width. If a field width greater than needed to show the output value is specified, the '0' (zero) flag causes the output value to be left padded with zeros until the specified field width is reached; for example, with the format '%011.6f', You have: troypound You want: grain * 5760.000000 / 0000.000174 The '0' flag has no effect if the '-' (left align) flag is given. Field Width By default, the output value is left aligned and shown with the minimum width necessary for the specified (or default) precision. If a field width greater than this is specified, the value shown is right aligned, and padded on the left with enough spaces to provide the specified field width. A width specification is typically used with fixed-point decimal to have columns of numbers align at the decimal point; this ar- guably is less useful with units than with long columnar output, but it may nonetheless assist in quickly assessing the relative magnitudes of results. For example, with the format '%12.6f', You have: km You want: in * 39370.078740 / 0.000025 You have: km You want: rod * 198.838782 / 0.005029 You have: km You want: furlong * 4.970970 / 0.201168 Precision The meaning of "precision" depends on the format type. With 'g' or 'G', it specifies the number of significant digits (like the '--digits' option); with 'e', 'E', 'f', or 'F', it specifies the maximum number of digits to be shown after the decimal point. With the 'g' and 'G' format types, trailing zeros are suppressed, so the results may sometimes have fewer digits than the specified preci- sion (as indicated above, the '#' flag causes trailing zeros to be dis- played). The default precision is 6, so '%g' is equivalent to '%.6g', and would show the output to six significant digits. Similarly, '%e' or '%f' would show the output with six digits after the decimal point. The C printf function allows a precision of arbitrary size, whether or not all of the digits are meaningful. With most compilers, the maximum internal precision with units is 15 decimal digits (or 13 hexadecimal digits). With the '--digits' option, you are limited to the maximum internal precision; with the '--output-format' option, you may specify a precision greater than this, but it may not be meaningful. In some cases, specifying excess precision can result in rounding artifacts. For example, a pound is exactly 7000 grains, but with the format '%.18g', the output might be You have: pound You want: grain * 6999.9999999999991 / 0.00014285714285714287 With the format '%.25g' you might get the following: You have: 1/3 You want: Definition: 0.333333333333333314829616256247 In this case the displayed value includes a series of digits that rep- resent the underlying binary floating-point approximation to 1/3 but are not meaningful for the desired computation. In general, the result with excess precision is system dependent. The precision affects only the display of numbers; if a result relies on physical constants that are not known to the specified precision, the number of physically meaningful digits may be less than the number of digits shown. See the documentation for printf for more detailed descriptions of the format specification. The '--output-format' option is incompatible with the '--exponential' or '--digits' options; if the former is given in combination with ei- ther of the latter, the format is controlled by the last option given. LOCALIZATION Some units have different values in different locations. The localiza- tion feature accommodates this by allowing a units data file to specify definitions that depend on the user's locale. Locale A locale is a subset of a user's environment that indicates the user's language and country, and some attendant preferences, such as the for- matting of dates. The units program attempts to determine the locale from the POSIX setlocale function; if this cannot be done, units exam- ines the environment variables LC_CTYPE and LANG. On POSIX systems, a locale is of the form language_country, where language is the two-char- acter code from ISO 639-1 and country is the two-character code from ISO 3166-1; language is lower case and country is upper case. For exam- ple, the POSIX locale for the United Kingdom is en_GB. On systems running Microsoft Windows, the value returned by setlocale is different from that on POSIX systems; units attempts to map the Win- dows value to a POSIX value by means of a table in the file 'locale_map.txt' in the same directory as the other data files. The file includes entries for many combinations of language and country, and can be extended to include other combinations. The 'locale_map.txt' file comprises two tab-separated columns; each entry is of the form Windows-locale POSIX-locale where POSIX-locale is as described above, and Windows-locale typically spells out both the language and country. For example, the entry for the United States is English_United States en_US You can force units to run in a desired locale by using the '-l' op- tion. In order to create unit definitions for a particular locale you begin a block of definitions in a unit datafile with '!locale' followed by a locale name. The '!' must be the first character on the line. The units program reads the following definitions only if the current lo- cale matches. You end the block of localized units with '!endlocale'. Here is an example, which defines the British gallon. !locale en_GB gallon 4.54609 liter !endlocale Additional Localization Sometimes the locale isn't sufficient to determine unit preferences. There could be regional preferences, or a company could have specific preferences. Though probably uncommon, such differences could arise with the choice of English customary units outside of English-speaking countries. To address this, units allows specifying definitions that depend on environment variable settings. The environment variables can be controlled based on the current locale, or the user can set them to force a particular group of definitions. A conditional block of definitions in a units data file begins with ei- ther '!var' or '!varnot' following by an environment variable name and then a space separated list of values. The leading '!' must appear in the first column of a units data file, and the conditional block is terminated by '!endvar'. Definitions in blocks beginning with '!var' are executed only if the environment variable is exactly equal to one of the listed values. Definitions in blocks beginning with '!varnot' are executed only if the environment variable does not equal any of the list values. The inch has long been a customary measure of length in many places. The word comes from the Latin uncia meaning "one twelfth," referring to its relationship with the foot. By the 20th century, the inch was of- ficially defined in English-speaking countries relative to the yard, but until 1959, the yard differed slightly among those countries. In France the customary inch, which was displaced in 1799 by the meter, had a different length based on a french foot. These customary defini- tions could be accommodated as follows: !var INCH_UNIT usa yard 3600|3937 m !endvar !var INCH_UNIT canada yard 0.9144 meter !endvar !var INCH_UNIT uk yard 0.91439841 meter !endvar !var INCH_UNIT canada uk usa foot 1|3 yard inch 1|12 foot !endvar !var INCH_UNIT france foot 144|443.296 m inch 1|12 foot line 1|12 inch !endvar !varnot INCH_UNIT usa uk france canada !message Unknown value for INCH_UNIT !endvar When units reads the above definitions it will check the environment variable INCH_UNIT and load only the definitions for the appropriate section. If INCH_UNIT is unset or is not set to one of the four values listed, then units will run the last block. In this case that block uses the '!message' command to display a warning message. Alterna- tively that block could set default values. In order to create default values that are overridden by user settings the data file can use the '!set' command, which sets an environment variable only if it is not already set; these settings are only for the current units invocation and do not persist. So if the example above were preceded by '!set INCH_UNIT france', then this would make 'france' the default value for INCH_UNIT. If the user had set the variable in the environment before invoking units, then units would use the user's value. To link these settings to the user's locale you combine the '!set' com- mand with the '!locale' command. If you wanted to combine the above example with suitable locales you could do by preceding the above defi- nition with the following: !locale en_US !set INCH_UNIT usa !endlocale !locale en_GB !set INCH_UNIT uk !endlocale !locale en_CA !set INCH_UNIT canada !endlocale !locale fr_FR !set INCH_UNIT france !endlocale !set INCH_UNIT france These definitions set the overall default for INCH_UNIT to 'france' and set default values for four locales appropriately. The overall default setting comes last so that it only applies when INCH_UNIT was not set by one of the other commands or by the user. If the variable given after '!var' or '!varnot' is undefined, then units prints an error message and ignores the definitions that follow. Use '!set' to create defaults to prevent this situation from arising. The '-c' option only checks the definitions that are active for the current environment and locale, so when adding new definitions take care to check that all cases give rise to a well defined set of defini- tions. ENVIRONMENT VARIABLES The units program uses the following environment variables: HOME Specifies the location of your home directory; it is used by units to find a personal units data file '.units'. On systems running Microsoft Windows, the file is 'unitdef.units', and if HOME does not exist, units tries to determine your home direc- tory from the HOMEDRIVE and HOMEPATH environment variables; if these variables do not exist, units finally tries USERPROFILE--typically 'C:\Users\username' (Windows Vista and Windows 7) or 'C:\Documents and Settings\username' (Windows XP). LC_CTYPE, LANG Checked to determine the locale if units cannot obtain it from the operating system. Sections of the default main units data file are specific to certain locales. MYUNITSFILE Specifies your personal units data file. If this variable ex- ists, units uses its value rather than searching your home di- rectory for '.units'. The personal units file will not be loaded if any data files are given using the '-f' option. PAGER Specifies the pager to use for help and for displaying the con- formable units. The help function browses the units database and calls the pager using the '+n'n syntax for specifying a line number. The default pager is more; PAGER can be used to specify alternatives such as less, pg, emacs, or vi. UNITS_ENGLISH Set to either 'US' or 'GB' to choose United States or British volume definitions, overriding the default from your locale. UNITSFILE Specifies the units data file to use (instead of the default). You can only specify a single units data file using this envi- ronment variable. If units data files are given using the '-f' option, the file specified by UNITSFILE will be not be loaded unless the '-f' option is given with the empty string (- 'units -f ""'). UNITSLOCALEMAP Windows only; this variable has no effect on Unix-like systems. Specifies the units locale map file to use (instead of the de- fault). This variable seldom needs to be set, but you can use it to ensure that the locale map file will be found if you spec- ify a location for the units data file using either the '-f' op- tion or the UNITSFILE environment variable, and that location does not also contain the locale map file. UNITS_SYSTEM This environment variable is used in the default main data file to select CGS measurement systems. Currently supported systems are 'esu', 'emu', 'gauss[ian]', 'hlu', 'natural', 'natural-gauss', 'planck', 'planck-red', 'hartree' and 'si'. The default is 'si'. DATA FILES The units program uses four default data files: the main data file, 'definitions.units'; the atomic masses of the elements, 'elements.units'; currency exchange rates, 'currency.units', and the US Consumer Price Index, 'cpi.units'. The last three files are loaded by means of '!include' directives in the main file (see Database Command Syntax). The program can also use an optional personal units data file '.units' ('unitdef.units' under Windows) located in the user's home di- rectory. The personal units data file is described in more detail in Units Data Files. On Unix-like systems, the data files are typically located in '/usr/share/units' if units is provided with the operating system, or in '/usr/local/share/units' if units is compiled from the source dis- tribution. Note that the currency file 'currency.units' is a symbolic link to another location. On systems running Microsoft Windows, the files may be in the same lo- cations if Unix-like commands are available, a Unix-like file structure is present (e.g., 'C:/usr/local'), and units is compiled from the source distribution. If Unix-like commands are not available, a more common location is 'C:\Program Files (x86)\GNU\units' (for 64-bit Win- dows installations) or 'C:\Program Files\GNU\units' (for 32-bit instal- lations). If units is obtained from the GNU Win32 Project (http://gnuwin32.sourceforge.net/), the files are commonly in 'C:\Program Files\GnuWin32\share\units'. If the default main units data file is not an absolute pathname, units will look for the file in the directory that contains the units pro- gram; if the file is not found there, units will look in a directory ../share/units relative to the directory with the units program. You can determine the location of the files by running 'units --version'. Running 'units --info' will give you additional in- formation about the files, how units will attempt to find them, and the status of the related environment variables. UNICODE SUPPORT The standard units data file is in Unicode, using UTF-8 encoding. Most definitions use only ASCII characters (i.e., code points U+0000 through U+007F); definitions using non-ASCII characters appear in blocks begin- ning with '!utf8' and ending with '!endutf8'. The non-ASCII definitions are loaded only if the platform and the lo- cale support UTF-8. Platform support is determined when units is com- piled; the locale is checked at every invocation of units. To see if your version of units includes Unicode support, invoke the program with the '--version' option. When Unicode support is available, units checks every line within UTF-8 blocks in all of the units data files for invalid or non-printing UTF-8 sequences; if such sequences occur, units ignores the entire line. In addition to checking validity, units determines the display width of non-ASCII characters to ensure proper positioning of the pointer in some error messages and to align columns for the 'search' and '?' com- mands. Microsoft Windows supports UTF-8 in console applications running in Windows Terminal; UTF-8 is not supported in applications running in the older Windows Console Host--see Unicode Support on Windows. The UTF-16 and UTF-32 encodings are not supported on any platforms. If Unicode support is available and definitions that contain non-ASCII UTF-8 characters are added to a units data file, those definitions should be enclosed within '!utf8' ... '!endutf8' to ensure that they are only loaded when Unicode support is available. As usual, the '!' must appear as the first character on the line. As discussed in Units Data Files, it's usually best to put such definitions in supplemental data files linked by an '!include' command or in a personal units data file. When Unicode support is not available, units makes no assumptions about character encoding, except that characters in the range 00-7F hexadeci- mal correspond to ASCII encoding. Non-ASCII characters are simply se- quences of bytes, and have no special meanings; for definitions in sup- plementary units data files, you can use any encoding consistent with this assumption. For example, if you wish to use non-ASCII characters in definitions when running units under Windows, you can use a charac- ter set such as Windows "ANSI" (code page 1252 in the US and Western Europe); if this is done, the console code page must be set to the same encoding for the characters to display properly. You can even use UTF-8, though some messages may be improperly aligned, and units will not detect invalid UTF-8 sequences. If you use UTF-8 encoding when Unicode support is not available, you should place any definitions with non-ASCII characters outside '!utf8' ... '!endutf8' blocks--otherwise, they will be ignored. Except for code examples, typeset material usually uses the Unicode symbols for mathematical operators. To facilitate copying and pasting from such sources, several typographical characters are converted to the ASCII operators used in units: the figure dash (U+2012), minus ('-'; U+2212), and en dash ('-'; U+2013) are converted to the operator '-'; the multiplication sign ('x'; U+00D7), N-ary times operator (U+2A09), dot operator ('.'; U+22C5), and middle dot ('.'; U+00B7) are converted to the operator '*'; the division sign ('/'; U+00F7) is con- verted to the operator '/'; and the fraction slash (U+2044) is con- verted to the operator '|'. Unicode Support on Windows Microsoft Windows supports UTF-8 in console applications running in Windows Terminal but not in applications running in the older Windows Console Host. In Windows Terminal, the code page must be set to 65001 for UTF-8 to be enabled. With the UTF-8 code page, running units -V might show GNU Units version 2.24 Without readline, with UTF-8, locale English_United States (en_US) Two values are shown for the locale: the first is the one returned by the system; the second is the POSIX value to which the system value is mapped. With a different code page, the result might be GNU Units version 2.24 Without readline, with UTF-8 (disabled), locale English_United States (en_US) To enable UTF-8: set code page to 65001 If units is running in Windows Console Host, regardless of the code page, the result might be GNU Units version 2.24 Without readline, with UTF-8 (disabled), locale English_United States (en_US) To enable UTF-8: run in Windows Terminal and set code page to 65001 The UTF-8 code page can be set by running chcp 65001. As of late 2024, the Windows build of units does not identify charac- ters--typically East Asian--that occupy more than one column, and error messages involving those characters may not be properly aligned. READLINE SUPPORT If the readline package has been compiled in, then when units is used interactively, numerous command line editing features are available. To check if your version of units includes readline, invoke the program with the '--version' option. For complete information about readline, consult the documentation for the readline package. Without any configuration, units will allow editing in the style of emacs. Of particular use with units are the completion commands. If you type a few characters and then hit ESC followed by ?, then units will display a list of all the units that start with the characters typed. For example, if you type metr and then request completion, you will see something like this: You have: metr metre metriccup metrichorsepower metrictenth metretes metricfifth metricounce metricton metriccarat metricgrain metricquart metricyarncount You have: metr If there is a unique way to complete a unit name, you can hit the TAB key and units will provide the rest of the unit name. If units beeps, it means that there is no unique completion. Pressing the TAB key a second time will print the list of all completions. The readline library also keeps a history of the values you enter. You can move through this history using the up and down arrows. The his- tory is saved to the file '.units_history' in your home directory so that it will persist across multiple units invocations. If you wish to keep work for a certain project separate you can change the history filename using the '--history' option. You could, for example, make an alias for units to units --history .units_history so that units would save separate history in the current directory. The length of each history file is limited to 5000 lines. Note also that if you run sev- eral concurrent copies of units each one will save its new history to the history file upon exit. UPDATING CURRENCY EXCHANGE RATES AND CPI Currency Exchange Rates The units program database includes currency exchange rates and prices for some precious metals. Of course, these values change over time, sometimes very rapidly, and units cannot provide real-time values. To update the exchange rates, run units_cur, which rewrites the file con- taining the currency rates, typically '/var/lib/units/currency.units' or '/usr/local/com/units/currency.units' on a Unix-like system or 'C:\Program Files (x86)\GNU\units\definitions.units' on a Windows sys- tem. This program requires Python 3 (https://www.python.org). The program must be run with suitable permissions to write the file. To keep the rates updated automatically, run it using a cron job on a Unix-like system, or a similar scheduling program on a different system. Reliable free sources of currency exchange rates have been annoyingly ephemeral. The program currently supports several sources: * ExchangeRate-API.com (https://www.exchangerate-api.com). The default currency server. Allows open access without an API key, with unlimited API requests. Rates update once a day, the US dollar ('USD') is the default base currency, and you can choose your base currency with the '-b' option described below. You can optionally sign up for an API key to access paid benefits such as faster data update rates. * FloatRates (https://www/floatrates.com). The US dollar ('USD') is the default base currency. You can change the base currency with the '-b' option described below. Allowable base currencies are listed on the FloatRates website. Exchange rates update daily. * The European Central Bank (https://www.ecb.europa.eu). The base currency is always the euro ('EUR'). Exchange rates up- date daily. This source offers a more limited list of currencies than the others. * Fixer (https://fixer.io). Registration for a free API key is required. With a free API key, base currency is the euro; exchange rates are updated hourly, the service has a limit of 1,000 API calls per month, and SSL encryp- tion (https protocol) is not available. Most of these restrictions are eliminated or reduced with paid plans. * open exchange rates (https://openexchangerates.org). Registration for a free API key is required. With a free API key, the base currency is the US dollar; exchange rates are updated hourly, and there is a limit of 1,000 API calls per month. Most of these restrictions are eliminated or reduced with paid plans. The default source is FloatRates; you can select a different one using '-s' option described below. Precious metals pricing is obtained from Packetizer (www.packe- tizer.com). This site updates once per day. US Consumer Price Index The units program includes the US Consumer Price Index (CPI) published by the US Bureau of Labor Statistics: specifically, the Consumer Price Index for All Urban Consumers (CPI-U), not seasonally adjusted--Series CUUR0000SA0. The units_cur command updates the CPI and saves the re- sult in 'cpi.units' in the same location as 'currency.units'. The data are obtained via the BLS Public Data API (https://www.bls.gov/develop- ers/). These data update once a month. When units_cur runs it will only attempt to update the CPI data if the current CPI data file is from a previous month, or if the current date is after the 18th of the month. Invoking units_cur You invoke units_cur like this: units_cur [options] [currency_file] [cpi_file] By default, the output is written to the default currency and CPI files described above; this is usually what you want, because this is where units looks for the files. If you wish, you can specify different filenames on the command line and units_cur will write the data to those files. If you give '-' for a file it will write to standard out- put. The following options are available: -h, --help Print a summary of the options for units_cur. -V, --version Print the units_cur version number. -v, --verbose Give slightly more verbose output when attempting to update cur- rency exchange rates. -s source, --source source Specify the source for currency exchange rates; currently sup- ported values are 'floatrates' (for FloatRates), 'eubank' (for the European Central Bank), 'fixer' (for Fixer), and 'openexchangerates' (for open exchange rates); the last two re- quire an API key to be given with the '-k' option. -b base, --base base Set the base currency (when allowed by the site providing the data). base should be a 3-letter ISO currency code, e.g., 'USD'. The specified currency will be the primitive currency unit used by units. You may find it convenient to specify your local currency. Conversions may be more accurate and you will be able to convert to your currency by simply hitting Enter at the 'You want:' prompt. This option is ignored if the source does not allow specifying the base currency. (Currently only floatrates supports this option.) -k key, --key key Set the API key to key for currency sources that require it. --blskey BLSkey Set the US Bureau of Labor Statistics (BLS) key for fetching CPI data. Without a BLS key you should be able to fetch the CPI data exactly one time per day. If you want to use a key you must request a personal key from BLS. DATABASE COMMAND SYNTAX unit definition Define a regular unit. prefix- definition Define a prefix. funcname(var) noerror units=[in-units,out-units] domain=[x1,x2] range=[y1,y2] definition(var) ; inverse(funcname) Define a nonlinear unit or unit function. The four optional keywords noerror, 'units=', 'range=' and 'domain=' can appear in any order. The definition of the inverse is optional. tabname[out-units] noerror pair-list Define a piecewise linear unit. The pair list gives the points on the table listed in ascending order. The noerror keyword is optional. !endlocale End a block of definitions beginning with '!locale' !endutf8 End a block of definitions begun with '!utf8' !endvar End a block of definitions begun with '!var' or '!varnot' !include file Include the specified file. !locale value Load the following definitions only of the locale is set to value. !message text Display text when the database is read unless the quiet option ('-q') is enabled. If you omit text, then units will display a blank line. Messages will also appear in the log file. !prompt text Prefix the 'You have:' prompt with the specified text. If you omit text, then any existing prefix is canceled. !set variable value Sets the environment variable, variable, to the specified value only if it is not already set. !unitlist alias definition Define a unit list alias. !utf8 Load the following definitions only if units is running with UTF-8 enabled. !var envar value-list Load the block of definitions that follows only if the environ- ment variable envar is set to one of the values listed in the space-separated value list. If envar is not set, units prints an error message and ignores the block of definitions. !varnot envar value-list Load the block of definitions that follows only if the environ- ment variable envar is set to value that is not listed in the space-separated value list. If envar is not set, units prints an error message and ignores the block of definitions. FILES /usr/local/share/units/definitions.units -- the standard units data file AUTHOR units was written by Adrian Mariano 20 November 2024 UNITS(1) units-2.24/units.c0000664000175000017500000062742114721206232013404 0ustar adrianadrian#define VERSION "2.24" /* * units, a program for units conversion * Copyright (C) 1996, 1997, 1999, 2000-2007, 2009, 2011-2020, 2022, 2024 * Free Software Foundation, Inc * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA * * This program was written by Adrian Mariano (adrianm@gnu.org) */ #define LICENSE "\ Copyright (C) 2024 Free Software Foundation, Inc.\n\ GNU Units comes with ABSOLUTELY NO WARRANTY.\n\ You may redistribute copies of GNU Units\n\ under the terms of the GNU General Public License." #define _XOPEN_SOURCE 600 #if defined (_WIN32) && defined (_MSC_VER) # include # include # include # include # define SUPPORT_UTF8 # define WINDOWS_TERMINAL "WT_SESSION" /* indicates if running in Windows Terminal */ #endif #if defined (_WIN32) && defined (HAVE_MKS_TOOLKIT) # include #endif # include #include #include #include #include #include #include #if defined (_WIN32) && defined (_MSC_VER) # include # define fileno _fileno # define isatty _isatty # define stat _stat #endif #ifdef HAVE_IOCTL # include # include #endif #ifndef NO_SETLOCALE # include #endif #ifdef SUPPORT_UTF8 /* Apparently this define is needed to get wcswidth() prototype */ # include # ifndef _WIN32 # include # endif # define UTF8VERSTR "with UTF-8" #else # define UTF8VERSTR "without UTF-8" #endif #ifdef READLINE # define RVERSTR "With readline" # include # include # define HISTORY_FILE ".units_history" #else # define RVERSTR "Without readline" #endif #include "getopt.h" #include "units.h" #ifndef UNITSFILE # define UNITSFILE "definitions.units" #endif #ifndef LOCALEMAP # define LOCALEMAP "locale_map.txt" #endif #ifndef DATADIR # ifdef _WIN32 # define DATADIR "..\\share\\units" # else # define DATADIR "../share/units" # endif #endif #if defined (_WIN32) && defined (_MSC_VER) # include # define getcwd _getcwd #else # include #endif #ifdef _WIN32 # define EXE_EXT ".exe" # define PATHSEP ';' # define DIRSEP '\\' # define DIRSEPSTR "\\" /* for building pathnames */ #else # define EXE_EXT "" # define PATHSEP ':' # define DIRSEP '/' # define DIRSEPSTR "/" /* for building pathnames */ #endif #define PRIMITIVECHAR '!' /* Character that marks irreducible units */ #define COMMENTCHAR '#' /* Comments marked by this character */ #define COMMANDCHAR '!' /* Unit database commands marked with this */ #define UNITSEPCHAR ';' /* Separator for unit lists. Include this */ /* char in rl_basic_word_break_characters */ /* and in nonunitchars defined in parse.y */ #define FUNCSEPCHAR ';' /* Separates forward and inverse definitions */ #define REDEFCHAR '+' /* Mark unit as redefinition to suppress warning message */ #ifdef _WIN32 # define DEFAULTPAGER "more" /* Default pager for Windows */ #else # define DEFAULTPAGER "/usr/bin/pager" /* Default pager for Unix */ #endif #define DEFAULTLOCALE "en_US" /* Default locale */ #define MAXINCLUDE 5 /* Max depth of include files */ #define MAXFILES 25 /* Max number of units files on command line */ #define NODIM "!dimensionless" /* Marks dimensionless primitive units, such */ /* as the radian, which are ignored when */ /* doing unit comparisons */ #define NOPOINT -1 /* suppress display of pointer in processunit*/ #define NOERRMSG -2 /* no error messages in checkunitlist() */ #define ERRMSG -3 #define SHOWFILES -4 #define MAXHISTORYFILE 5000 /* max length of history file for readline */ #define MAXPRODUCTREDUCTIONS 1000 /* If we make this many reductions, declare */ /* a circular reference */ /* values for output number format */ #define BASE_FORMATS "gGeEf" /* printf() format types recognized pre-C99 */ #define DEFAULTPRECISION 8 /* default significant digits for printf() */ #define DEFAULTTYPE 'g' /* default number format type for printf() */ #define MAXPRECISION DBL_DIG /* maximum number precision for printf() */ #define HOME_UNITS_ENV "MYUNITSFILE" /* Personal units file environment var */ #define NOERROR_KEYWORD "noerror " /* The trailing space is important */ #define CO_NOARG -1 #define HELPCOMMAND "help" /* Command to request help at prompt */ #define SEARCHCOMMAND "search" /* Command to request text search of units */ #define SETCOMMAND "set" /* Command to display or set command-line options */ #define UNITMATCH "?" /* Command to request conformable units */ /* values for issetting(), check_yn_choices(), setflag_yn(), and show_yn_setting() */ #define SETFLAG '*' /* Flag to indicate option set to other than default */ #define YES_STR "yes" #define NO_STR "no" #define YN_STR "y|n" /* short indication of values for Boolean settings shown with 'set' */ #define YN_CHOICES "\"y[es]\" or \"n[o]\"" /* long indication of values for Boolean settings shown in error message */ #define SETTING_STATUS_LEN 22 /* width of field showing current value of setting */ char *exit_commands[]={"quit","exit",0}; char *all_commands[]={"quit","exit",HELPCOMMAND,SEARCHCOMMAND,SETCOMMAND,UNITMATCH,0}; /* Key words for function definitions */ struct { char *word; char delimit; int checkopen; /* allow open intervals with parentheses */ } fnkeywords[]={ {"units=", FUNCSEPCHAR, 0}, {"domain=", ',', 1}, {"range=", ',',1}, {NOERROR_KEYWORD, ' ',CO_NOARG}, {0,0}}; #define FN_UNITS 0 #define FN_DOMAIN 1 #define FN_RANGE 2 #define FN_NOERROR 3 char *builtins[] = {"sin", "cos", "tan","ln", "log", "exp", "acos", "atan", "asin", "sqrt", "cuberoot", "per", "sinh", "cosh", "tanh", "asinh", "atanh", "acosh", 0}; struct { char *flags; /* printf() format flags */ char *format; /* printf() format specification for numeric output */ int width; /* printf() width from format */ int precision; /* printf() precision from format */ char type; /* printf() type from format */ } num_format; struct { /* Program command line option flags */ int interactive, unitlists, /* Perform unit list output if set */ oneline, /* Suppresses the second line of output */ quiet, /* Supress prompting (-q option) */ round, /* Round the last of unit list output to nearest integer */ showconformable, /* */ showfactor, /* */ strictconvert, /* Strict conversion (disables reciprocals) */ unitcheck, /* Enable unit checking: 1 for regular check, 2 for verbose*/ utf8, /* Enable UTF-8 support on Windows */ verbose, /* Flag for output verbosity */ readline; /* Using readline library? */ } flags; struct query { char *have, *want; int havewidth, wantwidth; }; #define UTF8MARKER "\xEF\xBB\xBF" /* UTF-8 marker inserted by some Windows */ /* programs at start of a UTF-8 file */ struct parseflag parserflags; /* parser options */ char *homeunitsfile = ".units"; /* Units filename in home directory */ char *homedir = NULL; /* User's home direcotry */ char *homedir_error = NULL; /* Error message for home directory search */ char *pager; /* Actual pager (from PAGER environment var) */ char *mylocale; /* Locale in effect (from LC_CTYPE or LANG) */ int utf8mode; /* Activate UTF8 support */ char *powerstring = "^"; /* Exponent character used in output */ char *unitsfiles[MAXFILES+1]; /* Null terminated list of units file names */ char *logfilename=NULL; /* Filename for logging */ FILE *logfile=NULL; /* File for logging */ char *promptprefix=NULL; /* Prefix added to prompt */ char *progname; /* Used in error messages */ char *fullprogname; /* Full path of program; printversion() uses */ char *progdir; /* Used to find supporting files */ char *datadir; /* Used to find supporting files */ char *deftext=" Definition: ";/* Output text when printing definition */ char *digits = "0123456789.,"; #define QUERYHAVE "You have: " /* Prompt text for units to convert from */ #define QUERYWANT "You want: " /* Prompt text for units to convert to */ #define LOGFROM "From: " /* tag for log file */ #define LOGTO "To: " /* tag for log file */ #define HASHSIZE 101 /* Values from K&R 2nd ed., Sect. 6.6 */ #define HASHNUMBER 31 #define SIMPLEHASHSIZE 128 #define simplehash(str) (*(str) & 127) /* "hash" value for prefixes */ #define POINTER "^" /* pointer to location of a parse error */ #define ERRNUMFMT "%.8g" /* Numerical format for certain error messages */ char *errormsg[]={ /* 0 */ "Successful completion", /* 1 */ "Parse error", /* 2 */ "Product overflow", /* 3 */ "Unit reduction error (bad unit definition)", /* 4 */ "Circular unit definition", /* 5 */ "Invalid sum or difference of non-conformable units", /* 6 */ "Unit not dimensionless", /* 7 */ "Unit not a root", /* 8 */ "Unknown unit", /* 9 */ "Bad argument", /* 10 */ "Weird nonlinear unit type (bug in program)", /* 11 */ "Function argument has wrong dimension", /* 12 */ "Argument of function outside domain", /* 13 */ "Nonlinear unit definition has unit error", /* 14 */ "No inverse defined", /* 15 */ "Parser memory overflow (recursive function definition?)", /* 16 */ "Argument wrong dimension or bad nonlinear unit definition", /* 17 */ "Cannot open units file", /* 18 */ "Units file contains errors", /* 19 */ "Memory allocation error", /* 20 */ "Malformed number", /* 21 */ "Unit name ends with a digit other than 0 or 1 without preceding '_'", /* 22 */ "No previous result; '_' not set", /* 23 */ "Base unit not dimensionless; rational exponent required", /* 24 */ "Base unit not a root", /* 25 */ "Exponent not dimensionless", /* 26 */ "Unknown function name", /* 27 */ "Overflow: number too large", /* 28 */ "Underflow: number too small" }; char *invalid_utf8 = "invalid/nonprinting UTF-8"; char *irreducible=0; /* Name of last irreducible unit */ /* Hash table for unit definitions. */ struct unitlist { char *name; /* unit name */ char *value; /* unit value */ int linenumber; /* line in units data file where defined */ char *file; /* file where defined */ struct unitlist *next; /* next item in list */ } *utab[HASHSIZE]; /* Table for prefix definitions. */ struct prefixlist { int len; /* length of name string */ char *name; /* prefix name */ char *value; /* prefix value */ int linenumber; /* line in units data file where defined */ char *file; /* file where defined */ struct prefixlist *next; /* next item in list */ } *ptab[SIMPLEHASHSIZE]; struct wantalias { char *name; char *definition; struct wantalias *next; int linenumber; char *file; }; struct wantalias *firstalias = 0; struct wantalias **aliaslistend = &firstalias; /* Next list entry goes here */ /* Table for function definitions */ struct func *ftab[SIMPLEHASHSIZE]; /* Used for passing parameters to the parser when we are in the process of parsing a unit function. If function_parameter is non-nil, then whenever the text in function_parameter appears in a unit expression it is replaced by the unit value stored in parameter_value. */ char *function_parameter = 0; struct unittype *parameter_value = 0; /* Stores the last result value for replacement with '_' */ int lastunitset = 0; struct unittype lastunit; char *NULLUNIT = ""; /* Used for units that are canceled during reduction */ #define startswith(string, prefix) (!strncmp(string, prefix, strlen(prefix))) #define lastchar(string) (*((string)+strlen(string)-1)) #define emptystr(string) (*(string)==0) #define nonempty(list) ((list) && *(list)) #define equal(a, b) (strcmp(a, b) == 0) #define equaln(a, b, n) (strncmp(a, b, n) == 0) #define equalnv(a, b, min, max) (strncmp(a, b, max < min ? min : max) == 0) #ifdef READLINE char *historyfile; /* Filename for readline history */ int init_history_length; /* Length of history read from the history file*/ int init_history_base; void save_history(void) { int newentries; int err; newentries = history_length-init_history_length; if (history_max_entries > 0){ newentries += history_base - init_history_base; if (newentries > history_max_entries) newentries = history_max_entries; } err = append_history(newentries,historyfile); if (err){ if (err == ENOENT) err = write_history(historyfile); if (err) { printf("Unable to write history to '%s': %s\n",historyfile,strerror(err)); return; } } history_truncate_file(historyfile,MAXHISTORYFILE); } #endif /* Increases the buffer by BUFGROW bytes and leaves the new pointer in buf and the new buffer size in bufsize. */ #define BUFGROW 100 void growbuffer(char **buf, int *bufsize) { int usemalloc; usemalloc = !*buf || !*bufsize; *bufsize += BUFGROW; if (usemalloc) *buf = malloc(*bufsize); else *buf = realloc(*buf,*bufsize); if (!*buf){ fprintf(stderr, "%s: memory allocation error (growbuffer)\n",progname); exit(EXIT_FAILURE); } } FILE * openfile(char *file,char *mode) { FILE *fileptr; struct stat statbuf; if (stat(file, &statbuf)==0 && statbuf.st_mode & S_IFDIR){ errno=EISDIR; return NULL; } fileptr = fopen(file,mode); return fileptr; } void logprintf(const char *format, ...) { va_list args; va_start(args, format); vprintf(format, args); va_end(args); if (logfile) { va_start(args, format); vfprintf(logfile, format, args); va_end(args); } } void logputchar(char c) { putchar(c); if (logfile) fputc(c, logfile); } void logputs(const char *s) { fputs(s, stdout); if (logfile) fputs(s, logfile); } /* Look for a subscript in the input string. A subscript starts with '_' and is followed by a sequence of only digits (matching the regexp "_[0-9]+"). The function returns 1 if it finds a subscript and zero otherwise. Note that it returns 1 for an input that is entirely subscript, with the '_' appearing in the first position. */ int hassubscript(const char *str) { const char *ptr = &lastchar(str); while (ptr>str){ if (!strchr(digits, *ptr)) return 0; ptr--; if (*ptr=='_') return 1; } return 0; } /* replace various Unicode operator symbols with stanard ASCII equivalents */ void replace_operators(char *input) { struct{ char *unicode; char replacement; } repl_table[]={ {"\xE2\x80\x92", '-'}, /* U+2012: figure dash */ {"\xE2\x80\x93", '-'}, /* U+2013: en dash */ {"\xE2\x88\x92", '-'}, /* U+2212: minus */ {"\xC3\x97", '*'}, /* U+00D7: times */ {"\xE2\xA8\x89" ,'*'}, /* U+2A09: N-ary times operator */ {"\xC2\xB7", '*'}, /* U+00B7: middle dot */ {"\xE2\x8B\x85", '*'}, /* U+22C5: dot operator */ {"\xC3\xB7", '/'}, /* U+00F7: division sign */ {"\xE2\x88\x95", '/'}, /* U+2215: division slash */ {"\xE2\x81\x84", '|'}, /* U+2044: fraction slash */ /* convert specialized spaces to ordinary spaces */ {"\xC2\xA0", ' '}, /* U+00A0, no-break space*/ {"\xE1\x9A\x80", ' '}, /* U+1680, ogham space mark */ {"\xE2\x80\x80", ' '}, /* U+2000, en quad */ {"\xE2\x80\x81", ' '}, /* U+2001, em quad */ {"\xE2\x80\x82", ' '}, /* U+2002, en space */ {"\xE2\x80\x83", ' '}, /* U+2003, em space */ {"\xE2\x80\x84", ' '}, /* U+2004, three-per-em space*/ {"\xE2\x80\x85", ' '}, /* U+2005, four-per-em space */ {"\xE2\x80\x86", ' '}, /* U+2006, six-per-em space */ {"\xE2\x80\x87", ' '}, /* U+2007, figure space */ {"\xE2\x80\x88", ' '}, /* U+2008, punctuation space */ {"\xE2\x80\x89", ' '}, /* U+2009, thin space*/ {"\xE2\x80\x8A", ' '}, /* U+200A, hair space */ {"\xE2\x80\xAF", ' '}, /* U+202F, narrow non-break space */ {"\xE2\x81\x9F", ' '}, /* U+205F, medium mathematical space */ {"\xE3\x80\x80", ' '}, /* U+3000, ideographic space */ /* treat zero-width characters as nothing? */ {"\xE2\x80\x8B", '\0'}, /* U+200B, zero-width space */ {"\xE2\x80\x8C", '\0'}, /* U+200D, zero-width non-joiner */ {0,0} }; char *inptr, *outptr, *ptr; for (int i=0; repl_table[i].unicode; i++) { inptr = outptr = input; do { ptr = strstr(inptr, repl_table[i].unicode); /* find next unicode symbol */ if (ptr) { while (inptr < ptr) /* copy the input up to the unicode */ *outptr++ = *inptr++; inptr = ptr + strlen(repl_table[i].unicode); /* skip over unicode */ if (repl_table[i].replacement) *outptr++ = repl_table[i].replacement; /* Output replacement */ } } while (ptr); /* If replacement were made, copy remaining input to end of string */ if (inptr > input) { while (*inptr) *outptr++ = *inptr++; *outptr = '\0'; } } } /* Replace all control chars with a space */ void replacectrlchars(char *string) { for(;*string;string++) if (iscntrl(*string)) *string = ' '; } /* Fetch a line of data with backslash for continuation. The parameter count is incremented to report the number of newlines that are read so that line numbers can be accurately reported. */ char * fgetscont(char *buf, int size, FILE *file, int *count) { if (!fgets(buf,size,file)) return 0; (*count)++; while(strlen(buf)>=2 && 0==strcmp(buf+strlen(buf)-2,"\\\n")){ (*count)++; buf[strlen(buf)-2] = 0; /* delete trailing \n and \ char */ if (strlen(buf)>=size-1) /* return if the buffer is full */ return buf; if (!fgets(buf+strlen(buf), size - strlen(buf), file)) return buf; /* already read some data so return success */ } if (lastchar(buf) == '\\') { /* If last char of buffer is \ then */ ungetc('\\', file); /* we don't know if it is followed by */ lastchar(buf) = 0; /* a \n, so put it back and try again */ } return buf; } /* Gets arbitrarily long input data into a buffer using growbuffer(). Returns 0 if no data is read. Increments count by the number of newlines read unless it points to NULL. Replaces tabs and newlines with spaces before returning the result. */ char * fgetslong(char **buf, int *bufsize, FILE *file, int *count) { int dummy; if (!count) count = &dummy; if (!*bufsize) growbuffer(buf,bufsize); if (!fgetscont(*buf, *bufsize, file, count)) return 0; while (lastchar(*buf) != '\n' && !feof(file)){ growbuffer(buf, bufsize); fgetscont(*buf+strlen(*buf), *bufsize-strlen(*buf), file, count); (*count)--; } /* These nonprinting characters must be removed so that the test for UTF-8 validity will work. */ replacectrlchars(*buf); return *buf; } /* Allocates memory and aborts if malloc fails. */ void * mymalloc(size_t bytes,const char *mesg) { void *pointer; pointer = malloc(bytes); if (!pointer){ fprintf(stderr, "%s: memory allocation error %s\n", progname, mesg); exit(EXIT_FAILURE); } return pointer; } /* Reallocates memory and aborts if realloc fails. */ void * myrealloc(void *pointer,size_t bytes,const char *mesg) { pointer = realloc(pointer, bytes); if (!pointer){ fprintf(stderr, "%s: memory allocation error %s\n", progname, mesg); exit(EXIT_FAILURE); } return pointer; } /* Duplicates a string */ char * dupstr(const char *str, const char *msg) { char *ret; if (msg) ret = mymalloc(strlen(str) + 1,msg); else ret = mymalloc(strlen(str) + 1,"(dupstr)"); strcpy(ret, str); return ret; } /* Duplicates a string that is not null-terminated, adding the null to the copy */ char * dupnstr(const char *string, size_t length, const char *msg) { char *newstr; if (msg) newstr = mymalloc(length+1,msg); else newstr = mymalloc(length+1,"(dupnstr)"); strncpy(newstr, string, length); newstr[length]=0; return newstr; } #ifdef SUPPORT_UTF8 /* The strwidth function gives the printed width of a UTF-8 byte sequence. It will return -1 if the sequence is an invalid UTF-8 sequence or if the sequence contains "nonprinting" characters. Note that \n and \t are "nonprinting" characters. */ int strwidth(const char *str) { wchar_t *widestr; int len; if (!utf8mode) return strlen(str); len = strlen(str)+1; widestr = mymalloc(sizeof(wchar_t)*len, "(strwidth)"); len = mbsrtowcs(widestr, &str, len, NULL); if (len==-1){ free(widestr); return -1; /* invalid multibyte sequence */ } # if defined _WIN32 && defined _MSC_VER len=wcslen(widestr); # else len=wcswidth(widestr, len); # endif free(widestr); return len; } #else # define strwidth strlen #endif /* hashing algorithm for units */ unsigned uhash(const char *str) { unsigned hashval; for (hashval = 0; *str; str++) hashval = *str + HASHNUMBER * hashval; return (hashval % HASHSIZE); } /* Lookup a unit in the units table. Returns the definition, or NULL if the unit isn't found in the table. */ struct unitlist * ulookup(const char *str) { struct unitlist *uptr; for (uptr = utab[uhash(str)]; uptr; uptr = uptr->next) if (strcmp(str, uptr->name) == 0) return uptr; return NULL; } /* Lookup a prefix in the prefix table. Finds the longest prefix that matches the beginning of the input string. Returns NULL if no prefixes match. */ struct prefixlist * plookup(const char *str) { struct prefixlist *prefix; struct prefixlist *bestprefix=NULL; int bestlength=0; for (prefix = ptab[simplehash(str)]; prefix; prefix = prefix->next) { if (prefix->len > bestlength && !strncmp(str, prefix->name, prefix->len)){ bestlength = prefix->len; bestprefix = prefix; } } return bestprefix; } /* Look up function in the function linked list */ struct func * fnlookup(const char *str) { struct func *funcptr; for(funcptr=ftab[simplehash(str)];funcptr;funcptr = funcptr->next) if (!strcmp(funcptr->name, str)) return funcptr; return 0; } struct wantalias * aliaslookup(const char *str) { struct wantalias *aliasptr; for(aliasptr = firstalias; aliasptr; aliasptr=aliasptr->next) if (!strcmp(aliasptr->name, str)) return aliasptr; return 0; } /* Insert a new function into the linked list of functions */ void addfunction(struct func *newfunc) { int val; val = simplehash(newfunc->name); newfunc->next = ftab[val]; ftab[val] = newfunc; } /* Free the fields in the function except for the name so that it can be redefined. It remains in position in the linked list. */ void freefunction(struct func *funcentry) { if (funcentry->table){ free(funcentry->table); free(funcentry->tableunit); } else { free(funcentry->forward.param); free(funcentry->forward.def); if (funcentry->forward.domain_min) free(funcentry->forward.domain_min); if (funcentry->forward.domain_max) free(funcentry->forward.domain_max); if (funcentry->inverse.domain_min) free(funcentry->inverse.domain_min); if (funcentry->inverse.domain_max) free(funcentry->inverse.domain_max); if (funcentry->forward.dimen) free(funcentry->forward.dimen); if (funcentry->inverse.dimen) free(funcentry->inverse.dimen); if (funcentry->inverse.def) free(funcentry->inverse.def); if (funcentry->inverse.param) free(funcentry->inverse.param); } } /* Remove leading and trailing spaces from the input */ void removespaces(char *in) { char *ptr; if (*in) { for(ptr = &lastchar(in); *ptr==' '; ptr--); /* Last non-space */ *(ptr+1)=0; if (*in==' '){ ptr = in + strspn(in," "); memmove(in, ptr, strlen(ptr)+1); } } } /* Looks up an inverse function given as a ~ character followed by spaces and then the function name. The spaces will be deleted as a side effect. If an inverse function is found returns the function pointer, otherwise returns null. */ struct func * invfnlookup(char *str) { if (*str != '~') return 0; removespaces(str+1); return fnlookup(str+1); } char * strip_comment(char *line) { char *comment = 0; if ((line = strchr(line,COMMENTCHAR))) { comment = line+1; *line = 0; } return comment; } /* Print string but replace two consecutive spaces with one space. */ void tightprint(FILE *outfile, char *string) { while(*string){ fputc(*string, outfile); if (*string != ' ') string++; else while(*string==' ') string++; } } /* Copy string to buf, replacing two or more consecutive spaces with one space. */ void tightbufprint(char *buf, char *string) { while(*string) { *buf++ = *string; if (*string != ' ') string++; else { while(*string==' ') string++; } } *buf = '\0'; } #define readerror (goterr=1) && errfile && fprintf #define VAGUE_ERR "%s: error in units file '%s' line %d\n", \ progname, file, linenum /* Print out error message encountered while reading the units file. */ /* Splits the line into two parts. The first part is space delimited. The second part is everything else. Removes trailing spaces from the second part. Returned items are null if no parameter was found. */ void splitline(char *line, char **first, char **second) { *second = 0; *first = strtok(line, " "); if (*first){ *second = strtok(0, "\n"); if (*second){ removespaces(*second); if (emptystr(*second)) *second = 0; } } } /* see if character is part of a valid decimal number */ int isdecimal(char c) { return strchr(digits, c) != NULL; } /* Check for some invalid unit names. Print error message. Returns 1 if unit name is bad, zero otherwise. */ int checkunitname(char *name, int linenum, char *file, FILE *errfile) { char nonunitchars[] = "~;+-*/|^)"; /* Also defined in parse.y with a few more characters */ char **ptr; char *cptr; if ((cptr=strpbrk(name, nonunitchars))){ if (errfile) fprintf(errfile, "%s: unit '%s' in units file '%s' on line %d ignored. It contains invalid character '%c'\n", progname, name, file, linenum, *cptr); return 1; } if (strchr(digits, name[0])){ if (errfile) fprintf(errfile, "%s: unit '%s' in units file '%s' on line %d ignored. It starts with a digit\n", progname, name, file, linenum); return 1; } for(ptr=builtins;*ptr;ptr++) if (!strcmp(name, *ptr)){ if (errfile) fprintf(errfile, "%s: redefinition of built-in function '%s' in file '%s' on line %d ignored.\n", progname, name, file, linenum); return 1; } for(ptr=all_commands;*ptr;ptr++) if (!strcmp(name, *ptr)){ if (errfile) fprintf(errfile, "%s: unit name '%s' in file '%s' on line %d may be hidden by command with the same name.\n", progname, name, file, linenum); } return 0; } int newunit(char *unitname, char *unitdef, int *count, int linenum, char *file,FILE *errfile, int redefine, int userunit) { struct unitlist *uptr; unsigned hashval; /* units ending with '_' create ambiguity for exponents */ if ((unitname[0]=='_' && !userunit) || lastchar(unitname)=='_'){ if (errfile) fprintf(errfile, "%s: unit '%s' on line %d of '%s' ignored. It starts or ends with '_'\n", progname, unitname, linenum, file); return E_BADFILE; } /* Units that end in [2-9] can never be accessed */ if (strchr(".,23456789", lastchar(unitname)) && !hassubscript(unitname)){ if (errfile) fprintf(errfile, "%s: unit '%s' on line %d of '%s' ignored. %s\n", progname, unitname, linenum, file,errormsg[E_UNITEND]); return E_BADFILE; } if (checkunitname(unitname, linenum, file, errfile)) return E_BADFILE; if ((uptr=ulookup(unitname))) { /* Is it a redefinition? */ if (flags.unitcheck && errfile && !redefine) fprintf(errfile, "%s: unit '%s' defined on line %d of '%s' is redefined on line %d of '%s'.\n", progname, unitname, uptr->linenumber,uptr->file, linenum, file); free(uptr->value); } else { /* make new units table entry */ uptr = (struct unitlist *) mymalloc(sizeof(*uptr),"(newunit)"); uptr->name = dupstr(unitname, "(newunit)"); /* install unit name/value pair in list */ hashval = uhash(uptr->name); uptr->next = utab[hashval]; utab[hashval] = uptr; (*count)++; } uptr->value = dupstr(unitdef, "(newunit)"); uptr->linenumber = linenum; uptr->file = file; return 0; } int newprefix(char *unitname, char *unitdef, int *count, int linenum, char *file,FILE *errfile, int redefine) { struct prefixlist *pfxptr; unsigned pval; lastchar(unitname) = 0; if (checkunitname(unitname,linenum,file,errfile)) return E_BADFILE; if ((pfxptr = plookup(unitname)) /* already there: redefinition */ && !strcmp(pfxptr->name, unitname)){ if (flags.unitcheck && errfile && !redefine) fprintf(errfile, "%s: prefix '%s-' defined on line %d of '%s' is redefined on line %d of '%s'.\n", progname, unitname, pfxptr->linenumber,pfxptr->file, linenum, file); free(pfxptr->value); } else { pfxptr = (struct prefixlist *) mymalloc(sizeof(*pfxptr),"(newprefix)"); pfxptr->name = dupstr(unitname, "(newprefix)"); pfxptr->len = strlen(unitname); pval = simplehash(unitname); pfxptr->next = ptab[pval]; ptab[pval] = pfxptr; (*count)++; } pfxptr->value = dupstr(unitdef, "(newprefix)"); pfxptr->linenumber = linenum; pfxptr->file = file; return 0; } /* parsepair() looks for data of the form [text1,text2] where the ',' is a specified delimiter. The second argument, text2, is optional and if it's missing then second is set to NULL. The parameters are allowed to be empty strings. The function returns the first character after the closing bracket if no errors occur or the NULL pointer on error. */ char * parsepair(char *input, char **first, char **second, int *firstopen, int *secondopen, char delimiter, int checkopen, char *unitname, int linenum, char *file,FILE *errfile) { char *start, *end, *middle; start = strpbrk(input, checkopen?"[(":"["); if (!start){ if (errfile) fprintf(errfile, "%s: expecting '[' %s in definition of '%s' in '%s' line %d\n", progname, checkopen ? "or '('":"", unitname, file, linenum); return 0; } if (*start=='(') *firstopen=1; else *firstopen=0; *start++=0; removespaces(input); if (!emptystr(input)){ if (errfile) fprintf(errfile, "%s: unexpected characters before '%c' in definition of '%s' in '%s' line %d\n", progname, *firstopen?'(':'[',unitname, file, linenum); return 0; } end = strpbrk(start, checkopen?"])":"]"); if (!end){ if (errfile) fprintf(errfile, "%s: expecting ']' %s in definition of '%s' in '%s' line %d\n", progname, checkopen?"or ')'":"",unitname, file, linenum); return 0; } if (*end==')') *secondopen=1; else *secondopen=0; *end++=0; middle = strchr(start,delimiter); if (middle){ *middle++=0; removespaces(middle); *second = middle; } else *second = 0; removespaces(start); *first = start; return end; } /* Extract numbers from two text strings and place them into pointers. Has two error codes for decreasing interval or bad numbers in the text strings. Returns 0 on success. */ #define EI_ERR_DEC 1 /* Decreasing interval */ #define EI_ERR_MALF 2 /* Malformed number */ int extract_interval(char *first, char *second, double **firstout, double **secondout) { double val; char *end; if (!emptystr(first)){ val = strtod(first, &end); if (*end) return EI_ERR_MALF; else { *firstout=(double *)mymalloc(sizeof(double), "(extract_interval)"); **firstout = val; } } if (nonempty(second)) { val = strtod(second, &end); if (*end) return EI_ERR_MALF; else if (*firstout && **firstout>=val) return EI_ERR_DEC; else { *secondout=(double *)mymalloc(sizeof(double), "(extract_interval)"); **secondout = val; } } return 0; } void copyfunctype(struct functype *dest, struct functype *src) { dest->domain_min_open = src->domain_min_open; dest->domain_max_open = src->domain_max_open; dest->param = dest->def = dest->dimen = NULL; dest->domain_min = dest->domain_max = NULL; if (src->param) dest->param = dupstr(src->param, "(copyfunctype)"); if (src->def) dest->def = dupstr(src->def, "(copyfunctype)"); if (src->dimen) dest->dimen = dupstr(src->dimen, "(copyfunctype)"); if (src->domain_min){ dest->domain_min = (double *) mymalloc(sizeof(double), "(copyfunctype)"); *dest->domain_min = *src->domain_min; } if (src->domain_max){ dest->domain_max = (double *) mymalloc(sizeof(double), "(copyfunctype)"); *dest->domain_max = *src->domain_max; } } int copyfunction(char *unitname, char *funcname, int *count, int linenum, char *file, FILE *errfile) { struct func *source, *funcentry; int i; if (checkunitname(unitname, linenum, file, errfile)) return E_BADFILE; removespaces(funcname); i = strlen(funcname)-2; /* strip trailing () if present */ if (i>0 && !strcmp(funcname+i,"()")) funcname[i]=0; source = fnlookup(funcname); if (!source) { if (errfile){ if (!strpbrk(funcname," ;][()+*/-^")) fprintf(errfile,"%s: bad definition for '%s' in '%s' line %d, function '%s' not defined\n", progname, unitname, file, linenum, funcname); else fprintf(errfile,"%s: bad function definition of '%s' in '%s' line %d\n", progname,unitname,file,linenum); } return E_BADFILE; } if ((funcentry=fnlookup(unitname))){ if (flags.unitcheck && errfile) fprintf(errfile, "%s: function '%s' defined on line %d of '%s' is redefined on line %d of '%s'.\n", progname, unitname, funcentry->linenumber,funcentry->file, linenum, file); freefunction(funcentry); } else { funcentry = (struct func*)mymalloc(sizeof(struct func),"(newfunction)"); funcentry->name = dupstr(unitname, "(copyfunction)"); addfunction(funcentry); (*count)++; } funcentry->linenumber = linenum; funcentry->file = file; funcentry->skip_error_check = source->skip_error_check; if (source->table){ funcentry->tablelen = source->tablelen; funcentry->tableunit = dupstr(source->tableunit, "(copyfunction)"); funcentry->table = (struct pair *) mymalloc(sizeof(struct pair)*funcentry->tablelen, "(copyfunction)"); for(i=0;itablelen;i++){ funcentry->table[i].location = source->table[i].location; funcentry->table[i].value = source->table[i].value; } } else { funcentry->table = 0; copyfunctype(&funcentry->forward, &source->forward); copyfunctype(&funcentry->inverse, &source->inverse); } return 0; } #define FREE_STUFF {if (forward_dim) free(forward_dim);\ if (inverse_dim) free(inverse_dim);\ if (domain_min) free(domain_min);\ if (domain_max) free(domain_max);\ if (range_min) free(range_min);\ if (range_max) free(range_max);} #define REPEAT_ERR \ if (errfile) fprintf(errfile, \ "%s: keyword '%s' repeated in definition of '%s' on line %d of '%s'.\n",\ progname,fnkeywords[i].word,unitname, linenum, file) int newfunction(char *unitname, char *unitdef, int *count, int linenum, char *file,FILE *errfile, int redefine) { char *start, *end, *inv, *forward_dim, *inverse_dim, *first, *second; double *domain_min, *domain_max, *range_min, *range_max; struct func *funcentry; int looking_for_keywords,i, firstopen, secondopen; int domain_min_open, domain_max_open, range_min_open, range_max_open; int noerror = 0; if (*unitname=='('){ if (errfile) fprintf(errfile, "%s: unit '%s' on line %d of '%s' ignored. It starts with a '('\n", progname, unitname, linenum, file); return E_BADFILE; } /* coverity[returned_null] */ start = strchr(unitname,'('); end = strchr(unitname,')'); *start++ = 0; if (checkunitname(unitname,linenum,file,errfile)) return E_BADFILE; if (start==end) /* no argument: function() so make a function copy */ return copyfunction(unitname, unitdef, count, linenum, file, errfile); if (!end || strlen(end)>1){ if (errfile) fprintf(errfile, "%s: bad function definition of '%s' in '%s' line %d\n", progname,unitname,file,linenum); return E_BADFILE; } *end=0; forward_dim = NULL; inverse_dim = NULL; domain_min = NULL; domain_max = NULL; range_min = NULL; range_max = NULL; domain_min_open = 0; domain_max_open = 0; range_min_open = 0; range_max_open = 0; looking_for_keywords=1; while (looking_for_keywords) { looking_for_keywords = 0; for(i=0;fnkeywords[i].word;i++){ if (startswith(unitdef, fnkeywords[i].word)){ looking_for_keywords = 1; /* found keyword so keep looking */ unitdef+=strlen(fnkeywords[i].word); if (fnkeywords[i].checkopen!=CO_NOARG){ unitdef = parsepair(unitdef,&first, &second, &firstopen, &secondopen, fnkeywords[i].delimit, fnkeywords[i].checkopen, unitname, linenum, file,errfile); if (!unitdef){ FREE_STUFF; return E_BADFILE; } removespaces(unitdef); } if (i==FN_NOERROR) noerror = 1; if (i==FN_UNITS){ if (forward_dim || inverse_dim){ REPEAT_ERR; return E_BADFILE; } forward_dim = dupstr(first, "(newfunction)"); if (second) inverse_dim = dupstr(second, "(newfunction)"); } if (i==FN_DOMAIN){ int err=0; if (domain_min || domain_max){ REPEAT_ERR; return E_BADFILE; } err = extract_interval(first,second,&domain_min, &domain_max); domain_min_open = firstopen; domain_max_open = secondopen; if (err) FREE_STUFF; if (err==EI_ERR_DEC){ if (errfile) fprintf(errfile, "%s: second endpoint for domain must be greater than the first\n in definition of '%s' in '%s' line %d\n", progname, unitname, file, linenum); return E_BADFILE; } if (err==EI_ERR_MALF){ if (errfile) fprintf(errfile, "%s: malformed domain in definition of '%s' in '%s' line %d\n", progname, unitname, file, linenum); return E_BADFILE; } } if (i==FN_RANGE){ int err=0; if (range_min || range_max){ REPEAT_ERR; FREE_STUFF; return E_BADFILE; } err = extract_interval(first,second,&range_min, &range_max); range_min_open = firstopen; range_max_open = secondopen; if (err) FREE_STUFF; if (err==EI_ERR_DEC){ if (errfile) fprintf(errfile, "%s: second endpoint for range must be greater than the first\n in definition of '%s' in '%s' line %d\n", progname, unitname, file, linenum); return E_BADFILE; } if (err==EI_ERR_MALF){ if (errfile) fprintf(errfile, "%s: malformed range in definition of '%s' in '%s' line %d\n", progname, unitname, file, linenum); return E_BADFILE; } } } } } if (emptystr(unitdef)){ if (errfile) fprintf(errfile, "%s: function '%s' lacks a definition at line %d of '%s'\n", progname, unitname, linenum, file); FREE_STUFF; return E_BADFILE; } if (*unitdef=='['){ if (errfile) fprintf(errfile, "%s: function '%s' missing keyword before '[' on line %d of '%s'\n", progname, unitname, linenum, file); FREE_STUFF; return E_BADFILE; } /* Check that if domain and range are specified and nonzero then the units are given. Otherwise these are meaningless. */ if (!forward_dim && ((domain_min && *domain_min) || (domain_max && *domain_max))){ if (errfile) fprintf(errfile,"%s: function '%s' defined on line %d of '%s' has domain with no units.\n", progname, unitname, linenum, file); FREE_STUFF; return E_BADFILE; } if (!inverse_dim && ((range_min && *range_min) || (range_max && *range_max))){ if (errfile) fprintf(errfile,"%s: function '%s' defined on line %d of '%s' has range with no units.\n", progname, unitname, linenum, file); FREE_STUFF; return E_BADFILE; } if ((funcentry=fnlookup(unitname))){ if (flags.unitcheck && errfile && !redefine) fprintf(errfile, "%s: function '%s' defined on line %d of '%s' is redefined on line %d of '%s'.\n", progname, unitname, funcentry->linenumber,funcentry->file, linenum, file); freefunction(funcentry); } else { funcentry = (struct func*)mymalloc(sizeof(struct func),"(newfunction)"); funcentry->name = dupstr(unitname, "(newfunction)"); addfunction(funcentry); (*count)++; } funcentry->table = 0; funcentry->skip_error_check = noerror; funcentry->forward.dimen = forward_dim; funcentry->inverse.dimen = inverse_dim; funcentry->forward.domain_min = domain_min; funcentry->forward.domain_max = domain_max; funcentry->inverse.domain_min = range_min; funcentry->inverse.domain_max = range_max; funcentry->forward.domain_min_open = domain_min_open; funcentry->forward.domain_max_open = domain_max_open; funcentry->inverse.domain_min_open = range_min_open; funcentry->inverse.domain_max_open = range_max_open; inv = strchr(unitdef,FUNCSEPCHAR); if (inv) *inv++ = 0; funcentry->forward.param = dupstr(start, "(newfunction)"); removespaces(unitdef); funcentry->forward.def = dupstr(unitdef, "(newfunction)"); if (inv){ removespaces(inv); funcentry->inverse.def = dupstr(inv, "(newfunction)"); funcentry->inverse.param = dupstr(unitname, "(newfunction)"); } else { funcentry->inverse.def = 0; funcentry->inverse.param = 0; } funcentry->linenumber = linenum; funcentry->file = file; return 0; } int newtable(char *unitname,char *unitdef, int *count, int linenum, char *file,FILE *errfile, int redefine) { char *start, *end; char *tableunit; int tablealloc, tabpt; struct pair *tab; struct func *funcentry; int noerror = 0; /* coverity[returned_null] */ tableunit = strchr(unitname,'['); end = strchr(unitname,']'); *tableunit++=0; if (checkunitname(unitname, linenum, file, errfile)) return E_BADFILE; if (!end){ if (errfile) fprintf(errfile,"%s: missing ']' in units file '%s' line %d\n", progname,file,linenum); return E_BADFILE; } if (strlen(end)>1){ if (errfile) fprintf(errfile, "%s: unexpected characters after ']' in units file '%s' line %d\n", progname,file,linenum); return E_BADFILE; } *end=0; tab = (struct pair *)mymalloc(sizeof(struct pair)*20, "(newtable)"); tablealloc=20; tabpt = 0; start = unitdef; if (startswith(start, NOERROR_KEYWORD)) { noerror = 1; start += strlen(NOERROR_KEYWORD); removespaces(start); } while (1) { if (tabpt>=tablealloc){ tablealloc+=20; tab = (struct pair *)realloc(tab,sizeof(struct pair)*tablealloc); if (!tab){ if (errfile) fprintf(errfile, "%s: memory allocation error (newtable)\n", progname); return E_MEMORY; } } tab[tabpt].location = strtod(start,&end); if (start==end || (!emptystr(end) && *end !=' ')){ if (!emptystr(start)) { if (strlen(start)>15) start[15]=0; /* Truncate for error msg display */ if (errfile) fprintf(errfile, "%s: cannot parse table definition %s at '%s' on line %d of '%s'\n", progname, unitname, start, linenum, file); free(tab); return E_BADFILE; } break; } if (tabpt>0 && tab[tabpt].location<=tab[tabpt-1].location){ if (errfile) fprintf(errfile,"%s: points don't increase (" ERRNUMFMT " to " ERRNUMFMT ") in units file '%s' line %d\n", progname, tab[tabpt-1].location, tab[tabpt].location, file, linenum); free(tab); return E_BADFILE; } start=end+strspn(end," "); tab[tabpt].value = strtod(start,&end); if (start==end){ if (errfile) fprintf(errfile,"%s: missing value after " ERRNUMFMT " in units file '%s' line %d\n", progname, tab[tabpt].location, file, linenum); free(tab); return E_BADFILE; } tabpt++; start=end+strspn(end," ,"); } if ((funcentry=fnlookup(unitname))){ if (flags.unitcheck && errfile && !redefine) fprintf(errfile, "%s: unit '%s' defined on line %d of '%s' is redefined on line %d of '%s'.\n", progname, unitname, funcentry->linenumber,funcentry->file, linenum, file); freefunction(funcentry); } else { funcentry = (struct func *)mymalloc(sizeof(struct func),"(newtable)"); funcentry->name = dupstr(unitname, "(newtable)"); addfunction(funcentry); (*count)++; } funcentry->tableunit = dupstr(tableunit, "(newtable)"); funcentry->tablelen = tabpt; funcentry->table = tab; funcentry->skip_error_check = noerror; funcentry->linenumber = linenum; funcentry->file = file; return 0; } int newalias(char *unitname, char *unitdef,int linenum, char *file,FILE *errfile) { struct wantalias *aliasentry; if (!strchr(unitdef, UNITSEPCHAR)){ if (errfile) fprintf(errfile, "%s: unit list missing '%c' on line %d of '%s'\n", progname, UNITSEPCHAR, linenum, file); return E_BADFILE; } if ((aliasentry=aliaslookup(unitname))){ /* duplicate alias */ if (flags.unitcheck && errfile) fprintf(errfile, "%s: unit list '%s' defined on line %d of '%s' is redefined on line %d of '%s'.\n", progname, unitname, aliasentry->linenumber, aliasentry->file, linenum, file); free(aliasentry->definition); } else { aliasentry = (struct wantalias *) mymalloc(sizeof(struct wantalias),"(newalias)"); aliasentry->name = dupstr(unitname, "(newalias)"); aliasentry->next = 0; *aliaslistend = aliasentry; aliaslistend = &aliasentry->next; } aliasentry->definition = dupstr(unitdef, "(newalias)"); aliasentry->linenumber = linenum; aliasentry->file = file; return 0; } /* Check environment variable name to see if its value appears on the space delimited text string pointed to by list. Returns 2 if the environment variable is not set, return 1 if its value appears on the list and zero otherwise. */ int checkvar(char *name, char *list) { char *listitem; name = getenv(name); if (!name) return 2; listitem = strtok(list," "); while (listitem){ if (!strcmp(name, listitem)) return 1; listitem = strtok(0," "); } return 0; } #ifdef NO_SETENV int setenv(const char *name, const char *val, int overwrite) { char *environment; if (!overwrite && getenv(name) != NULL) return 0; environment = (char *) malloc(strlen(name) + strlen(val) + 2); if (!environment) return 1; strcpy(environment, name); strcat(environment, "="); strcat(environment, val); /* putenv() doesn't copy its argument, so don't free environment */ #if defined (_WIN32) && defined (_MSC_VER) return _putenv(environment); #else return putenv(environment); #endif } #endif #ifdef _WIN32 # define isdirsep(c) ((c) == '/' || (c) == '\\') # define hasdirsep(s) strpbrk((s),"/\\") #else # define isdirsep(c) ((c) == '/') # define hasdirsep(s) strchr((s),'/') #endif #define isexe(s) ((strlen(s) == 4) && (tolower(s[1]) == 'e') \ && (tolower(s[2]) == 'x') && (tolower(s[3]) == 'e')) /* Returns a pointer to the end of the pathname part of the specified filename */ char * pathend(char *filename) { char *pointer; for(pointer=filename+strlen(filename);pointer>filename;pointer--){ if (isdirsep(*pointer)) { pointer++; break; } } return pointer; } int isfullpath(char *path) { #ifdef _WIN32 /* handle Windows drive specifier */ if (isalpha(*path) && *(path + 1) == ':') path += 2; #endif return isdirsep(*path); } /* Read in units data. file - Filename to load errfile - File to receive messages about errors in the units database. Set it to 0 to suppress errors. unitcount, prefixcount, funccount - Return statistics to the caller. Must initialize to zero before calling. depth - Used to prevent recursive includes. Call with it set to zero. The global variable progname is used in error messages. */ int readunits(char *file, FILE *errfile, int *unitcount, int *prefixcount, int *funccount, int depth) { FILE *unitfile; char *line = 0, *lineptr, *unitdef, *unitname, *permfile; int linenum, linebufsize, goterr, retcode; int locunitcount, locprefixcount, locfunccount, redefinition; int wronglocale = 0; /* If set then we are currently reading data */ int inlocale = 0; /* for the wrong locale so we should skip it */ int in_utf8 = 0; /* If set we are reading utf8 data */ int invar = 0; /* If set we are in data for an env variable.*/ int wrongvar = 0; /* If set then we are not processing */ locunitcount = 0; locprefixcount = 0; locfunccount = 0; linenum = 0; linebufsize = 0; goterr = 0; unitfile = openfile(file, "rt"); if (!unitfile){ if (errfile) fprintf(errfile, "%s: Unable to read units file '%s': %s\n", progname, file, strerror(errno)); return E_FILE; } growbuffer(&line,&linebufsize); /* coverity[alloc_fn] */ permfile = dupstr(file, "(readunits)"); /* This is a permanent copy to reference in */ /* the database. It is never freed. */ while (!feof(unitfile)) { if (!fgetslong(&line, &linebufsize, unitfile, &linenum)) break; if (linenum==1 && startswith(line, UTF8MARKER)){ lineptr = line + strlen(UTF8MARKER); memmove(line, lineptr, strlen(lineptr) + 1); } strip_comment(line); if (-1 == strwidth(line)){ readerror(errfile, "%s: %s on line %d of '%s'\n", progname, invalid_utf8, linenum, file); continue; } replace_operators(line); if (*line == COMMANDCHAR) { /* Process units file commands */ unitname = strtok(line+1, " "); if (!unitname){ readerror(errfile, VAGUE_ERR); continue; } /* Check for locale and utf8 declarations. Any other commands most likely belong after these tests. */ if (!strcmp(unitname,"var") || !strcmp(unitname,"varnot")){ int not = 0; if (unitname[3]=='n') not = 1; unitname=strtok(0," "); unitdef=strtok(0,""); /* Get rest of the line */ if (!unitname) readerror(errfile, "%s: no variable name specified on line %d of '%s'\n", progname, linenum, file); else if (!unitdef) readerror(errfile, "%s: no value specified on line %d of '%s'\n", progname, linenum, file); else if (invar) readerror(errfile, "%s: nested var statements not allowed, line %d of '%s'\n", progname, linenum, file); else { int check; invar = 1; check = checkvar(unitname, unitdef); if (check==2){ readerror(errfile, "%s: environment variable %s not set at line %d of '%s'\n", progname, unitname, linenum, file); wrongvar = 1; } else if (!(not^check)) wrongvar = 1; } continue; } else if (!strcmp(unitname, "endvar")){ if (!invar) readerror(errfile, "%s: unmatched !endvar on line %d of '%s'\n", progname, linenum, file); wrongvar = 0; invar = 0; continue; } else if (!strcmp(unitname,"locale")){ unitname = strtok(0, " "); if (!unitname) readerror(errfile, "%s: no locale specified on line %d of '%s'\n", progname, linenum, file); else if (inlocale) readerror(errfile, "%s: nested locales not allowed, line %d of '%s'\n", progname, linenum, file); else { inlocale = 1; if (strcmp(unitname,mylocale)) /* locales don't match */ wronglocale = 1; } continue; } else if (!strcmp(unitname, "endlocale")){ if (!inlocale) readerror(errfile, "%s: unmatched !endlocale on line %d of '%s'\n", progname, linenum, file); wronglocale = 0; inlocale = 0; continue; } else if (!strcmp(unitname, "utf8")){ if (in_utf8) readerror(errfile,"%s: nested utf8 not allowed, line %d of '%s'\n", progname, linenum, file); else in_utf8 = 1; continue; } else if (!strcmp(unitname, "endutf8")){ if (!in_utf8) readerror(errfile,"%s: unmatched !endutf8 on line %d of '%s'\n", progname, linenum, file); in_utf8 = 0; continue; } if (in_utf8 && !utf8mode) continue; if (wronglocale || wrongvar) continue; if (!strcmp(unitname,"prompt")){ unitname = strtok(0,""); /* Rest of the line */ if (promptprefix) free(promptprefix); if (!unitname) promptprefix=0; else promptprefix = dupstr(unitname, "(readunits)"); continue; } if (!strcmp(unitname,"message")){ unitname = strtok(0,""); /* Rest of the line */ if (!flags.quiet){ if (unitname) logputs(unitname); logputchar('\n'); } continue; } else if (!strcmp(unitname,"set")) { unitname = strtok(0," "); unitdef = strtok(0," "); if (!unitname) readerror(errfile, "%s: no variable name specified on line %d of '%s'\n", progname, linenum, file); else if (!unitdef) readerror(errfile, "%s: no value specified on line %d of '%s'\n", progname, linenum, file); else setenv(unitname, unitdef, 0); continue; } else if (!strcmp(unitname,"unitlist")){ splitline(0,&unitname, &unitdef); /* 0 continues strtok call */ if (!unitname || !unitdef) readerror(errfile,VAGUE_ERR); else { if (newalias(unitname, unitdef, linenum, permfile, errfile)) goterr = 1; } continue; } else if (!strcmp(unitname, "include")){ if (depth>MAXINCLUDE){ readerror(errfile, "%s: max include depth of %d exceeded in file '%s' line %d\n", progname, MAXINCLUDE, file, linenum); } else { int readerr; char *includefile; unitname = strtok(0, " "); if (!unitname){ readerror(errfile, "%s: missing include filename on line %d of '%s'\n", progname, linenum, file); continue; } includefile = mymalloc(strlen(file)+strlen(unitname)+1, "(readunits)"); if (isfullpath(unitname)) strcpy(includefile,unitname); else { strcpy(includefile,file); strcpy(pathend(includefile), unitname); } readerr = readunits(includefile, errfile, unitcount, prefixcount, funccount, depth+1); if (readerr == E_MEMORY){ fclose(unitfile); free(line); free(includefile); return readerr; } if (readerr == E_FILE) { readerror(errfile, "%s: file was included at line %d of file '%s'\n", progname,linenum, file); } if (readerr) goterr = 1; free(includefile); } } else /* not a valid command */ readerror(errfile,VAGUE_ERR); continue; } if (in_utf8 && !utf8mode) continue; if (wronglocale || wrongvar) continue; splitline(line, &unitname, &unitdef); if (!unitname) continue; if (*unitname == REDEFCHAR){ unitname++; redefinition=1; if (strlen(unitname)==0){ readerror(errfile, "%s: expecting name of unit to redefine after '+' at line %d of '%s'\n", progname, linenum,file); continue; } } else redefinition=0; if (!strcmp(unitname,"-")) { readerror(errfile, "%s: expecting prefix name before '-' at line %d of '%s'\n", progname, linenum,file); continue; } if (!unitdef){ readerror(errfile, "%s: unit '%s' lacks a definition at line %d of '%s'\n", progname, unitname, linenum, file); continue; } if (lastchar(unitname) == '-'){ /* it's a prefix definition */ if (newprefix(unitname,unitdef,&locprefixcount,linenum, permfile,errfile,redefinition)) goterr=1; } else if (strchr(unitname,'[')){ /* table definition */ retcode=newtable(unitname,unitdef,&locfunccount,linenum, permfile,errfile,redefinition); if (retcode){ if (retcode != E_BADFILE){ fclose(unitfile); free(line); return retcode; } goterr=1; } } else if (strchr(unitname,'(')){ /* function definition */ if (newfunction(unitname,unitdef,&locfunccount,linenum, permfile,errfile,redefinition)) goterr = 1; } else { /* ordinary unit definition */ if (newunit(unitname,unitdef,&locunitcount,linenum,permfile,errfile,redefinition,0)) goterr = 1; } } fclose(unitfile); free(line); if (unitcount) *unitcount+=locunitcount; if (prefixcount) *prefixcount+=locprefixcount; if (funccount) *funccount+=locfunccount; if (goterr) return E_BADFILE; else return 0; } /* Initialize a unit to be equal to 1. */ void initializeunit(struct unittype *theunit) { theunit->factor = 1.0; theunit->numerator[0] = theunit->denominator[0] = NULL; } /* Free a unit: frees all the strings used in the unit structure. Does not free the unit structure itself. */ void freeunit(struct unittype *theunit) { char **ptr; for(ptr = theunit->numerator; *ptr; ptr++) if (*ptr != NULLUNIT) free(*ptr); for(ptr = theunit->denominator; *ptr; ptr++) if (*ptr != NULLUNIT) free(*ptr); /* protect against repeated calls to freeunit() */ theunit->numerator[0] = 0; theunit->denominator[0] = 0; } /* Print out a unit */ void showunit(struct unittype *theunit) { char **ptr; int printedslash; int counter = 1; logprintf(num_format.format, theunit->factor); for (ptr = theunit->numerator; *ptr; ptr++) { if (ptr > theunit->numerator && **ptr && !strcmp(*ptr, *(ptr - 1))) counter++; else { if (counter > 1) logprintf("%s%d", powerstring, counter); if (**ptr) logprintf(" %s", *ptr); counter = 1; } } if (counter > 1) logprintf("%s%d", powerstring, counter); counter = 1; printedslash = 0; for (ptr = theunit->denominator; *ptr; ptr++) { if (ptr > theunit->denominator && **ptr && !strcmp(*ptr, *(ptr - 1))) counter++; else { if (counter > 1) logprintf("%s%d", powerstring, counter); if (**ptr) { if (!printedslash) logprintf(" /"); printedslash = 1; logprintf(" %s", *ptr); } counter = 1; } } if (counter > 1) logprintf("%s%d", powerstring, counter); } /* qsort comparison function */ int compare(const void *item1, const void *item2) { return strcmp(*(char **) item1, *(char **) item2); } /* Sort numerator and denominator of a unit so we can compare different units */ void sortunit(struct unittype *theunit) { char **ptr; int count; for (count = 0, ptr = theunit->numerator; *ptr; ptr++, count++); qsort(theunit->numerator, count, sizeof(char *), compare); for (count = 0, ptr = theunit->denominator; *ptr; ptr++, count++); qsort(theunit->denominator, count, sizeof(char *), compare); } /* Cancels duplicate units that appear in the numerator and denominator. The input unit must be sorted. */ void cancelunit(struct unittype *theunit) { char **den, **num; int comp; den = theunit->denominator; num = theunit->numerator; while (*num && *den) { comp = strcmp(*den, *num); if (!comp) { /* units match, so cancel them */ if (*den!=NULLUNIT) free(*den); if (*num!=NULLUNIT) free(*num); *den++ = NULLUNIT; *num++ = NULLUNIT; } else if (comp < 0) /* Move up whichever pointer is alphabetically */ den++; /* behind to look for future matches */ else num++; } } /* Looks up the definition for the specified unit including prefix processing and plural removal. Returns a pointer to the definition or a null pointer if the specified unit does not appear in the units table. Sometimes the returned pointer will be a pointer to the special buffer created to hold the data. This buffer grows as needed during program execution. Note that if you pass the output of lookupunit() back into the function again you will get correct results, but the data you passed in may get clobbered if it happened to be the internal buffer. */ static int bufsize=0; static char *buffer; /* buffer for lookupunit answers with prefixes */ /* Plural rules for english: add -s after x, sh, ch, ss add -es -y becomes -ies except after a vowel when you just add -s as usual */ char * lookupunit(char *unit,int prefixok) { char *copy; struct prefixlist *pfxptr; struct unitlist *uptr; if ((uptr = ulookup(unit))) return uptr->value; if (strwidth(unit)>2 && lastchar(unit) == 's') { copy = dupstr(unit, "(lookupunit)"); lastchar(copy) = 0; if (lookupunit(copy,prefixok)){ while(strlen(copy)+1 > bufsize) { growbuffer(&buffer, &bufsize); } strcpy(buffer, copy); /* Note: returning looked up result seems */ free(copy); /* better but it causes problems when it */ return buffer; /* contains PRIMITIVECHAR. */ } if (strlen(copy)>2 && lastchar(copy) == 'e') { lastchar(copy) = 0; if (lookupunit(copy,prefixok)){ while (strlen(copy)+1 > bufsize) { growbuffer(&buffer,&bufsize); } strcpy(buffer,copy); free(copy); return buffer; } } if (strlen(copy)>2 && lastchar(copy) == 'i') { lastchar(copy) = 'y'; if (lookupunit(copy,prefixok)){ while (strlen(copy)+1 > bufsize) { growbuffer(&buffer,&bufsize); } strcpy(buffer,copy); free(copy); return buffer; } } free(copy); } if (prefixok && (pfxptr = plookup(unit))) { copy = unit + pfxptr->len; if (emptystr(copy) || lookupunit(copy,0)) { char *tempbuf; while (strlen(pfxptr->value)+strlen(copy)+2 > bufsize){ growbuffer(&buffer, &bufsize); } tempbuf = dupstr(copy, "(lookupunit)"); /* copy might point into buffer */ strcpy(buffer, pfxptr->value); strcat(buffer, " "); strcat(buffer, tempbuf); free(tempbuf); return buffer; } } return 0; } /* Points entries of product[] to the strings stored in tomove[]. Leaves tomove pointing to a list of NULLUNITS. */ int moveproduct(char *product[], char *tomove[]) { char **dest, **src; dest=product; for(src = tomove; *src; src++){ if (*src == NULLUNIT) continue; for(; *dest && *dest != NULLUNIT; dest++); if (dest - product >= MAXSUBUNITS - 1) { return E_PRODOVERFLOW; } if (!*dest) *(dest + 1) = 0; *dest = *src; *src=NULLUNIT; } return 0; } /* Make a copy of a product list. Note that no error checking is done for overflowing the product list because it is assumed that the source list doesn't overflow, so the destination list shouldn't overflow either. (This assumption could be false if the destination is not actually at the start of a product buffer.) */ void copyproduct(char **dest, char **source) { for(;*source;source++,dest++) { if (*source==NULLUNIT) *dest = NULLUNIT; else *dest=dupstr(*source, "(copyproduct)"); } *dest=0; } /* Make a copy of a unit */ void unitcopy(struct unittype *dest, struct unittype *source) { dest->factor = source->factor; copyproduct(dest->numerator, source->numerator); copyproduct(dest->denominator, source->denominator); } /* Multiply left by right. In the process, all of the units are deleted from right (but it is not freed) */ int multunit(struct unittype *left, struct unittype *right) { int myerr; left->factor *= right->factor; myerr = moveproduct(left->numerator, right->numerator); if (!myerr) myerr = moveproduct(left->denominator, right->denominator); return myerr; } int divunit(struct unittype *left, struct unittype *right) { int myerr; left->factor /= right->factor; myerr = moveproduct(left->numerator, right->denominator); if (!myerr) myerr = moveproduct(left->denominator, right->numerator); return myerr; } /* reduces a product of symbolic units to primitive units. The three low bits are used to return flags: bit 0 set if reductions were performed without error. bit 1 set if no reductions are performed. bit 2 set if an unknown unit is discovered. Return values from multiple calls will be ORed together later. */ #define DIDREDUCTION (1<<0) #define NOREDUCTION (1<<1) #define REDUCTIONERROR (1<<2) #define CIRCULARDEF (1<<3) int reduceproduct(struct unittype *theunit, int flip) { char *toadd; char **product; int didsomething = NOREDUCTION; struct unittype newunit; int ret; int itcount=0; /* Count iterations to catch infinite loops */ if (flip) product = theunit->denominator; else product = theunit->numerator; for (; *product; product++) { for (;;) { if (!strlen(*product)) break; /* check for infinite loop */ itcount++; if (itcount>MAXPRODUCTREDUCTIONS) return CIRCULARDEF; toadd = lookupunit(*product,1); if (!toadd) { if (!irreducible) irreducible = dupstr(*product, "(reduceproduct)"); return REDUCTIONERROR; } if (strchr(toadd, PRIMITIVECHAR)) break; didsomething = DIDREDUCTION; if (*product != NULLUNIT) { free(*product); *product = NULLUNIT; } if (parseunit(&newunit, toadd, 0, 0)) return REDUCTIONERROR; if (flip) ret=divunit(theunit,&newunit); else ret=multunit(theunit,&newunit); freeunit(&newunit); if (ret) return REDUCTIONERROR; } } return didsomething; } #if 0 void showunitdetail(struct unittype *foo) { char **ptr; printf("%.17g ", foo->factor); for(ptr=foo->numerator;*ptr;ptr++) if (*ptr==NULLUNIT) printf("NULL "); else printf("`%s' ", *ptr); printf(" / "); for(ptr=foo->denominator;*ptr;ptr++) if (*ptr==NULLUNIT) printf("NULL "); else printf("`%s' ", *ptr); putchar('\n'); } #endif /* Reduces numerator and denominator of the specified unit. Returns 0 on success, or 1 on unknown unit error. */ int reduceunit(struct unittype *theunit) { int ret; if (irreducible) free(irreducible); irreducible=0; ret = DIDREDUCTION; /* Keep calling reduceproduct until it doesn't do anything */ while (ret & DIDREDUCTION) { ret = reduceproduct(theunit, 0); if (!(ret & REDUCTIONERROR)) ret |= reduceproduct(theunit, 1); if (ret & REDUCTIONERROR){ if (irreducible) return E_UNKNOWNUNIT; else return E_REDUCE; } else if (ret & CIRCULARDEF) return E_CIRCULARDEF; } return 0; } /* Returns one if the argument unit is defined in the data file as a dimensionless unit. This is determined by comparing its definition to the string NODIM. */ int ignore_dimless(char *name) { struct unitlist *ul; if (!name) return 0; ul = ulookup(name); if (ul && !strcmp(ul->value, NODIM)) return 1; return 0; } int ignore_nothing(char *name) { return 0; } int ignore_primitive(char *name) { struct unitlist *ul; if (!name) return 0; ul = ulookup(name); if (ul && strchr(ul->value, PRIMITIVECHAR)) return 1; return 0; } /* Compare two product lists, return zero if they match and one if they do not match. They may contain embedded NULLUNITs which are ignored in the comparison. Units defined as NODIM are also ignored in the comparison. */ int compareproducts(char **one, char **two, int (*isdimless)(char *name)) { int oneblank, twoblank; while (*one || *two) { oneblank = (*one==NULLUNIT) || isdimless(*one); twoblank = (*two==NULLUNIT) || isdimless(*two); if (!*one && !twoblank) return 1; if (!*two && !oneblank) return 1; if (oneblank) one++; else if (twoblank) two++; else if (strcmp(*one, *two)) return 1; else one++, two++; } return 0; } /* Return zero if units are compatible, nonzero otherwise. The units must be reduced, sorted and canceled for this to work. */ int compareunits(struct unittype *first, struct unittype *second, int (*isdimless)(char *name)) { return compareproducts(first->numerator, second->numerator, isdimless) || compareproducts(first->denominator, second->denominator, isdimless); } /* Reduce a unit as much as possible */ int completereduce(struct unittype *unit) { int err; if ((err=reduceunit(unit))) return err; sortunit(unit); cancelunit(unit); return 0; } /* Raise theunit to the specified power. This function does not fill in NULLUNIT gaps, which could be considered a deficiency. */ int expunit(struct unittype *theunit, int power) { char **numptr, **denptr; double thefactor; int i, uind, denlen, numlen; if (power==0){ freeunit(theunit); initializeunit(theunit); return 0; } numlen=0; for(numptr=theunit->numerator;*numptr;numptr++) numlen++; denlen=0; for(denptr=theunit->denominator;*denptr;denptr++) denlen++; thefactor=theunit->factor; for(i=1;ifactor *= thefactor; for(uind=0;uindnumerator[uind]!=NULLUNIT){ if (numptr-theunit->numerator>=MAXSUBUNITS-1) { *numptr=*denptr=0; return E_PRODOVERFLOW; } *numptr++=dupstr(theunit->numerator[uind], "(expunit)"); } } for(uind=0;uinddenominator[uind]!=NULLUNIT){ *denptr++=dupstr(theunit->denominator[uind], "(expunit)"); if (denptr-theunit->denominator>=MAXSUBUNITS-1) { *numptr=*denptr=0; return E_PRODOVERFLOW; } } } } *numptr=0; *denptr=0; return 0; } int unit2num(struct unittype *input) { struct unittype one; int err; initializeunit(&one); if ((err=completereduce(input))) return err; if (compareunits(input,&one,ignore_nothing)) return E_NOTANUMBER; freeunit(input); return 0; } int unitdimless(struct unittype *input) { struct unittype one; initializeunit(&one); if (compareunits(input, &one, ignore_dimless)) return 0; freeunit(input); /* Eliminate dimensionless units from list */ return 1; } /* The unitroot function takes the nth root of an input unit which has been completely reduced. Returns 1 if the unit is not a power of n. Input data can contain NULLUNITs. */ int subunitroot(int n,char *current[], char *out[]) { char **ptr; int count=0; while(*current==NULLUNIT) current++; /* skip past NULLUNIT entries */ ptr=current; while(*ptr){ while(*ptr){ if (*ptr!=NULLUNIT){ if (strcmp(*current,*ptr)) break; count++; } ptr++; } if (count % n != 0){ /* If not dimensionless generate error, otherwise */ if (!ignore_dimless(*current)) /* just skip over it */ return E_NOTROOT; } else { for(count /= n;count>0;count--) *(out++) = dupstr(*current, "(subunitroot)"); } current=ptr; } *out = 0; return 0; } int rootunit(struct unittype *inunit,int n) { struct unittype outunit; int err; initializeunit(&outunit); if ((err=completereduce(inunit))) return err; /* Roots of negative numbers fail in pow(), even odd roots */ if (inunit->factor < 0) return E_NOTROOT; outunit.factor = pow(inunit->factor,1.0/(double)n); if ((err = subunitroot(n, inunit->numerator, outunit.numerator))) return err; if ((err = subunitroot(n, inunit->denominator, outunit.denominator))) return err; freeunit(inunit); initializeunit(inunit); return multunit(inunit,&outunit); } /* Compute the inverse of a unit (1/theunit) */ void invertunit(struct unittype *theunit) { char **ptr, *swap; int numlen, length, ind; theunit->factor = 1.0/theunit->factor; length=numlen=0; for(ptr=theunit->denominator;*ptr;ptr++,length++); for(ptr=theunit->numerator;*ptr;ptr++,numlen++); if (numlen>length) length=numlen; for(ind=0;ind<=length;ind++){ swap = theunit->numerator[ind]; theunit->numerator[ind] = theunit->denominator[ind]; theunit->denominator[ind] = swap; } } int float2rat(double y, int *p, int *q) { int coef[20]; /* How long does this buffer need to be? */ int i,termcount,saveq; double fracpart,x; /* Compute continued fraction approximation */ x=y; termcount=0; while(1){ coef[termcount] = (int) floor(x); fracpart = x-coef[termcount]; if (fracpart < .001 || termcount==19) break; x = 1/fracpart; termcount++; } /* Compress continued fraction into rational p/q */ *p=0; *q=1; for(i=termcount;i>=1;i--) { saveq=*q; *q = coef[i] * *q + *p; *p = saveq; } *p+=*q*coef[0]; return *qfactor = pow(base->factor,exponent->factor); if (errno) return E_FUNC; } else if (errcode==E_NOTANUMBER) { /* Base not dimensionless */ if (!float2rat(exponent->factor,&p,&q)){ /* Exponent must be rational */ if (unitdimless(base)){ base->factor = pow(base->factor,exponent->factor); if (errno) return E_FUNC; } else return E_IRRATIONAL_EXPONENT; } else { if (q!=1) { errcode = rootunit(base, q); if (errcode == E_NOTROOT) return E_BASE_NOTROOT; if (errcode) return errcode; } errcode = expunit(base, abs(p)); if (errcode) return errcode; if (p<0) invertunit(base); } } else return errcode; return 0; } /* Old units program would give message about what each operand reduced to, showing that they weren't conformable. Can this be achieved here? */ int addunit(struct unittype *unita, struct unittype *unitb) { int err; if ((err=completereduce(unita))) return err; if ((err=completereduce(unitb))) return err; if (compareunits(unita,unitb,ignore_nothing)) return E_BADSUM; unita->factor += unitb->factor; freeunit(unitb); return 0; } double linearinterp(double a, double b, double aval, double bval, double c) { double lambda; lambda = (b-c)/(b-a); return lambda*aval + (1-lambda)*bval; } /* evaluate a user function */ #define INVERSE 1 #define FUNCTION 0 #define ALLERR 1 #define NORMALERR 0 int evalfunc(struct unittype *theunit, struct func *infunc, int inverse, int allerrors) { struct unittype result; struct functype *thefunc; int err; double value; int foundit, count; struct unittype *save_value; char *save_function; if (infunc->table) { /* Tables are short, so use dumb search algorithm */ err = parseunit(&result, infunc->tableunit, 0, 0); if (err) return E_BADFUNCDIMEN; if (inverse){ err = divunit(theunit, &result); if (err) return err; err = unit2num(theunit); if (err==E_NOTANUMBER) return E_BADFUNCARG; if (err) return err; value = theunit->factor; foundit=0; for(count=0;counttablelen-1;count++) if ((infunc->table[count].value<=value && value<=infunc->table[count+1].value) || (infunc->table[count+1].value<=value && value<=infunc->table[count].value)){ foundit=1; value = linearinterp(infunc->table[count].value, infunc->table[count+1].value, infunc->table[count].location, infunc->table[count+1].location, value); break; } if (!foundit) return E_NOTINDOMAIN; freeunit(&result); freeunit(theunit); theunit->factor = value; return 0; } else { err=unit2num(theunit); if (err) return err; value=theunit->factor; foundit=0; for(count=0;counttablelen-1;count++) if (infunc->table[count].location<=value && value<=infunc->table[count+1].location){ foundit=1; value = linearinterp(infunc->table[count].location, infunc->table[count+1].location, infunc->table[count].value, infunc->table[count+1].value, value); break; } if (!foundit) return E_NOTINDOMAIN; result.factor *= value; } } else { /* it's a function */ if (inverse){ thefunc=&(infunc->inverse); if (!thefunc->def) return E_NOINVERSE; } else thefunc=&(infunc->forward); err = completereduce(theunit); if (err) return err; if (thefunc->dimen){ err = parseunit(&result, thefunc->dimen, 0, 0); if (err) return E_BADFUNCDIMEN; err = completereduce(&result); if (err) return E_BADFUNCDIMEN; if (compareunits(&result, theunit, ignore_nothing)) return E_BADFUNCARG; value = theunit->factor/result.factor; } else value = theunit->factor; if (thefunc->domain_max && (value > *thefunc->domain_max || (thefunc->domain_max_open && value == *thefunc->domain_max))) return E_NOTINDOMAIN; if (thefunc->domain_min && (value < *thefunc->domain_min || (thefunc->domain_min_open && value == *thefunc->domain_min))) return E_NOTINDOMAIN; save_value = parameter_value; save_function = function_parameter; parameter_value = theunit; function_parameter = thefunc->param; err = parseunit(&result, thefunc->def, 0,0); function_parameter = save_function; parameter_value = save_value; if (err && (allerrors == ALLERR || err==E_PARSEMEM || err==E_PRODOVERFLOW || err==E_NOTROOT || err==E_BADFUNCTYPE)) return err; if (err) return E_FUNARGDEF; } freeunit(theunit); initializeunit(theunit); multunit(theunit, &result); return 0; } /* append a formatted string to a buffer; first character of buffer should be '\0' on first call */ void vbufprintf(char **buf, size_t *bufsize, char *fmt, ...) { va_list args; size_t oldlen, /* length of current buffer contents */ newlen, /* length of string to be added */ buflen; /* length of new buffer contents */ double growfactor = 1.5; static char *newbuf = NULL; char *oldbuf; oldlen = strlen(*buf); oldbuf = dupstr(*buf, "(vbufprintf)"); /* get length of formatted string to be appended to buffer */ va_start(args, fmt); newlen = vsnprintf(NULL, 0, fmt, args); va_end(args); /* allocate a buffer for the new string */ newbuf = (char *) malloc(newlen + 1); if (newbuf == NULL) { fprintf(stderr, "%s (vbufprintf): memory allocation error\n", progname); exit(EXIT_FAILURE); } /* expand main buffer if necessary */ if (*bufsize < oldlen + newlen + 1) { *bufsize = (size_t) ((oldlen + newlen) * growfactor + 1); *buf = (char *) realloc(*buf, *bufsize); if (*buf == NULL) { fprintf(stderr, "%s (vbufprintf): memory allocation error\n", progname); exit(EXIT_FAILURE); } } /* generate the new formatted string */ va_start(args, fmt); newlen = vsprintf(newbuf, fmt, args); va_end(args); /* copy old and new strings to buffer */ strcpy(*buf, oldbuf); strcat(*buf, newbuf); buflen = strlen(*buf); free(oldbuf); free(newbuf); } /* similar to showunit(), but it saves the string in a buffer rather than sending it to an output stream */ char * buildunitstr(struct unittype *theunit) { char **ptr; char *buf; int printedslash; int counter = 1; size_t bufsize; bufsize = 256; buf = (char *) mymalloc(bufsize, "(buildunitstr)"); *buf = '\0'; /* factor */ vbufprintf(&buf, &bufsize, num_format.format, theunit->factor); /* numerator */ for (ptr = theunit->numerator; *ptr; ptr++) { if (ptr > theunit->numerator && **ptr && !strcmp(*ptr, *(ptr - 1))) counter++; else { if (counter > 1) vbufprintf(&buf, &bufsize, "%s%d", powerstring, counter); if (**ptr) vbufprintf(&buf, &bufsize, " %s", *ptr); counter = 1; } } if (counter > 1) vbufprintf(&buf, &bufsize, "%s%d", powerstring, counter); counter = 1; printedslash = 0; /* denominator */ for (ptr = theunit->denominator; *ptr; ptr++) { if (ptr > theunit->denominator && **ptr && !strcmp(*ptr, *(ptr - 1))) counter++; else { if (counter > 1) vbufprintf(&buf, &bufsize, "%s%d", powerstring, counter); if (**ptr) { if (!printedslash) vbufprintf(&buf, &bufsize, " /"); printedslash = 1; vbufprintf(&buf, &bufsize, " %s", *ptr); } counter = 1; } } if (counter > 1) vbufprintf(&buf, &bufsize, "%s%d", powerstring, counter); return buf; } /* If the given character string has only one unit name in it, then print out the rule for that unit. In any case, print out the reduced form for the unit. */ void showdefinition(char *unitstr, struct unittype *theunit) { size_t bufsize = 256; char *buf, *showstr; logputs(deftext); showstr = buildunitstr(theunit); buf = (char *) mymalloc(bufsize, "(showdefinition)"); while((unitstr = lookupunit(unitstr,1)) && strspn(unitstr,digits) != strlen(unitstr) && !strchr(unitstr,PRIMITIVECHAR)) { if (strlen(unitstr) > bufsize - 1) { bufsize = strlen(unitstr) + 1; buf = realloc(buf, bufsize); } tightbufprint(buf, unitstr); logputs(buf); if (strcmp(buf, showstr)) logputs(" = "); } if (strcmp(buf, showstr)) logputs(showstr); logputchar('\n'); free(buf); free(showstr); } void showfunction(struct functype *func) { struct unittype unit; int not_dimensionless, i; if (!func->def) { logputs(" is undefined"); return; } if (func->dimen){ /* coverity[check_return] */ parseunit(&unit,func->dimen,0,0); /* unit2num returns 0 for */ not_dimensionless = unit2num(&unit); /* dimensionless units */ } logprintf("(%s) = %s", func->param, func->def); if (func->domain_min || func->domain_max){ logputchar('\n'); for(i=strwidth(deftext);i;i--) logputchar(' '); logputs("defined for "); if (func->domain_min && func->domain_max) { logprintf(num_format.format, *func->domain_min); if (func->dimen && (not_dimensionless || unit.factor != 1)){ if (isdecimal(*func->dimen)) logputs(" *"); logprintf(" %s",func->dimen); } logputs(func->domain_min_open?" < ":" <= "); } logputs(func->param); if (func->domain_max){ logputs(func->domain_max_open?" < ":" <= "); logprintf(num_format.format, *func->domain_max); } else { logputs(func->domain_min_open?" > ":" >= "); logprintf(num_format.format, *func->domain_min); } if (func->dimen && (not_dimensionless || unit.factor != 1)){ if (isdecimal(*func->dimen)) logputs(" *"); logprintf(" %s",func->dimen); } if (!func->dimen) logputs(" (any units)"); } else if (func->dimen){ logputchar('\n'); for(i=strwidth(deftext);i;i--) logputchar(' '); if (not_dimensionless) logprintf("%s has units %s",func->param, func->dimen); else logprintf("%s is dimensionless",func->param); } logputchar('\n'); } void showtable(struct func *fun, int inverse) { int i; logprintf("%sinterpolated table with points\n",deftext); if (inverse){ int reverse, j; reverse = (fun->table[0].value > fun->table[fun->tablelen-1].value); for(i=0;itablelen;i++){ if (reverse) j = fun->tablelen-i-1; else j=i; if (flags.verbose>0) logputs("\t\t "); logprintf("~%s(", fun->name); logprintf(num_format.format, fun->table[j].value); if (isdecimal(fun->tableunit[0])) logputs(" *"); logprintf(" %s",fun->tableunit); logputs(") = "); logprintf(num_format.format, fun->table[j].location); logputchar('\n'); } } else { for(i=0;itablelen;i++){ if (flags.verbose>0) logputs("\t\t "); logprintf("%s(", fun->name); logprintf(num_format.format, fun->table[i].location); logputs(") = "); logprintf(num_format.format, fun->table[i].value); if (isdecimal(fun->tableunit[0])) logputs(" *"); logprintf(" %s\n",fun->tableunit); } } } void showfuncdefinition(struct func *fun, int inverse) { if (fun->table) /* It's a table */ showtable(fun, inverse); else { logprintf("%s%s%s", deftext,inverse?"~":"", fun->name); if (inverse) showfunction(&fun->inverse); else showfunction(&fun->forward); } } void showunitlistdef(struct wantalias *alias) { logprintf("%sunit list, ",deftext); tightprint(stdout,alias->definition); if (logfile) tightprint(logfile,alias->definition); logputchar('\n'); } /* Show conversion to a function. Input unit 'have' is replaced by the function inverse and completely reduced. */ int showfunc(char *havestr, struct unittype *have, struct func *fun) { int err; char *dimen; err = evalfunc(have, fun, INVERSE, NORMALERR); if (!err) err = completereduce(have); if (err) { if (err==E_BADFUNCARG){ logputs("conformability error"); if (fun->table) dimen = fun->tableunit; else if (fun->inverse.dimen) dimen = fun->inverse.dimen; else dimen = 0; if (!dimen) logputchar('\n'); else { struct unittype want; if (emptystr(dimen)) dimen = "1"; logprintf(": conversion requires dimensions of '%s'\n",dimen); if (flags.verbose==2) logprintf("\t%s = ",havestr); else if (flags.verbose==1) logputchar('\t'); showunit(have); if (flags.verbose==2) logprintf("\n\t%s = ",dimen); else if (flags.verbose==1) logprintf("\n\t"); else logputchar('\n'); /* coverity[check_return] */ parseunit(&want, dimen, 0, 0); /* coverity[check_return] */ completereduce(&want); /* dimen was already checked for */ showunit(&want); /* errors so no need to check here */ logputchar('\n'); } } else if (err==E_NOTINDOMAIN) logprintf("Value '%s' is not in the function's range\n",havestr); else if (err==E_NOINVERSE) logprintf("Inverse of the function '%s' is not defined\n",fun->name); else logputs("Function evaluation error (bad function definition)\n"); return 1; } if (flags.verbose==2) logprintf("\t%s = %s(", havestr, fun->name); else if (flags.verbose==1) logputchar('\t'); showunit(have); if (flags.verbose==2) logputchar(')'); logputchar('\n'); return 0; } /* Print the conformability error message */ void showconformabilityerr(char *havestr,struct unittype *have, char *wantstr,struct unittype *want) { logputs("conformability error\n"); if (flags.verbose==2) logprintf("\t%s = ",havestr); else if (flags.verbose==1) logputchar('\t'); showunit(have); if (flags.verbose==2) logprintf("\n\t%s = ",wantstr); else if (flags.verbose==1) logputs("\n\t"); else logputchar('\n'); showunit(want); logputchar('\n'); } /* end showconformabilityerr */ /* determine whether a unit string begins with a fraction; assume it does if it starts with an integer, '|', and another integer */ int isfract(const char *unitstr) { char *enddouble=0, *endlong=0; while (isdigit(*unitstr)) unitstr++; if (*unitstr++ == '|') { (void)strtod(unitstr, &enddouble); (void)strtol(unitstr, &endlong, 10); if (enddouble == endlong) return 1; } return 0; } int checksigdigits(char *arg) { int errors, ival; char *nonum; errors = 0; if (!strcmp(arg, "max")) num_format.precision = MAXPRECISION; else { ival = (int) strtol(arg, &nonum, 10); if (!emptystr(nonum)) { fprintf(stderr, "%s: invalid significant digits (%s)--integer value or 'max' required\n", progname, arg); errors++; } else if (ival <= 0) { fprintf(stderr, "%s: number of significant digits must be positive\n", progname); errors++; } else if (strchr("EeGg", num_format.type) && ival > MAXPRECISION) { fprintf(stderr, "%s: too many significant digits (%d) for '%c' format--using maximum value (%d)\n", progname, ival, num_format.type, MAXPRECISION); num_format.precision = MAXPRECISION; } else num_format.precision = ival; } if (errors) return -1; else return 0; } /* Set output number format specification from flags, width, precision, and type; here, "precision" is the same as for printf(3). */ int setnumformat() { int len; if (num_format.format) free(num_format.format); if (num_format.width > 0) len = snprintf(NULL, 0, "%%%s%d.%d%c", num_format.flags, num_format.width, num_format.precision, num_format.type); else len = snprintf(NULL, 0, "%%%s.%d%c", num_format.flags, num_format.precision, num_format.type); num_format.format = (char *) mymalloc(len + 1, "(setnumformat)"); if (num_format.width > 0) sprintf(num_format.format, "%%%s%d.%d%c", num_format.flags, num_format.width, num_format.precision, num_format.type); else sprintf(num_format.format, "%%%s.%d%c", num_format.flags, num_format.precision, num_format.type); return 0; } /* parse and validate the output number format specification and extract its type and precision into the num_format structure. Returns nonzero for invalid format. */ int parsenumformat() { static char *format_types = NULL; static char *format_flags = "+-# 0'"; static char badflag; char *two = "0x1p+1"; char *valid="ABCDEFGHIJKLMNOPQRSTUVWXYXabcdefghijklmnopqrstuvwxyx.01234567890"; char *dotptr, *lptr, *nonum, *p0, *p; char testbuf[80]; int errors, ndx; if (format_types == NULL){ format_types = (char *) mymalloc(strlen(BASE_FORMATS)+4, "(parsenumformat)"); strcpy(format_types,BASE_FORMATS); /* check for support of type 'F' (MS VS 2012 didn't have it) */ sprintf(testbuf, "%.1F", 1.2); if (strlen(testbuf) == 3 && testbuf[0] == '1' && testbuf[2] == '2') strcat(format_types,"F"); /* check for support of hexadecimal floating point */ sprintf(testbuf, "%.0a", 2.0); if (!strcmp(testbuf,two)) strcat(format_types, "aA"); /* check for support of digit-grouping (') flag */ sprintf(testbuf, "%'.0f", 1234.0); if (strlen(testbuf) > 2 && testbuf[0] == '1' && testbuf[2] == '2') badflag = '\0'; /* supported */ else badflag = '\''; /* not supported */ } errors = 0; p = num_format.format; if (*p != '%') { fprintf(stderr, "%s: number format specification must start with '%%'\n", progname); errors++; } else if (strrchr(num_format.format, '%') != num_format.format) { fprintf(stderr, "%s: only one '%%' allowed in number format specification\n", progname); errors++; p++; } else p++; dotptr = strchr(num_format.format, '.'); if (dotptr && strrchr(num_format.format, '.') != dotptr) { fprintf(stderr, "%s: only one '.' allowed in number format specification\n", progname); errors++; } p0 = p = num_format.format + 1; /* skip over flags */ while (*p && strchr(format_flags, *p)) { if (*p == badflag) { /* only if digit-grouping flag (') not supported */ fprintf(stderr, "%s: digit-grouping flag (') not supported\n", progname); errors++; } p++; } /* save any flags */ if (num_format.flags != NULL) free(num_format.flags); num_format.flags = dupnstr(p0, p - p0, "(parsenumformat)"); /* check for type length modifiers, which aren't allowed */ if ((lptr = strstr(num_format.format, "hh")) || (lptr = strstr(num_format.format, "ll"))) { fprintf(stderr, "%s: type length modifier (%.2s) not supported\n", progname, lptr); errors++; } else if ((lptr = strpbrk(num_format.format, "hjLltz"))) { fprintf(stderr, "%s: type length modifier (%c) not supported\n", progname, lptr[0]); errors++; } /* check for other invalid characters */ ndx = strspn(p, valid); if (ndx < strlen(p)) { fprintf(stderr, "%s: invalid character (%c) in width, precision, or type\n", progname, p[ndx]); errors++; } if (errors) { /* results of any other checks are likely to be misleading */ fprintf(stderr, "%s: invalid number format specification (%s)\n", progname, num_format.format); fprintf(stderr, "%s: valid specification is %%[flags][width][.precision]type\n", progname); return -1; } /* get width and precision if specified; check precision */ num_format.width = (int) strtol(p, &nonum, 10); if (*nonum == '.'){ if (isdigit(nonum[1])) num_format.precision = (int) strtol(nonum+1, &nonum, 10); else { num_format.precision = 0; nonum++; } } else /* precision not given--use printf() default */ num_format.precision = 6; /* check for valid format type */ if (emptystr(nonum)) { fprintf(stderr, "%s: missing format type\n", progname); errors++; } else { if (strchr(format_types, *nonum)) { if (nonum[1]) { fprintf(stderr, "%s: invalid character(s) (%s) after format type\n", progname, nonum + 1); errors++; } else num_format.type = *nonum; } else { fprintf(stderr, "%s: invalid format type (%c)--valid types are [%s]\n", progname, *nonum, format_types); errors++; } } if (num_format.precision == 0 && (num_format.type == 'G' || num_format.type == 'g')) num_format.precision = 1; if (errors) { fprintf(stderr, "%s: invalid number format specification (%s)\n", progname, num_format.format); fprintf(stderr, "%s: valid specification is %%[flags][width][.precision]type\n", progname); return -1; } else return 0; } /* round a number to the lesser of the displayed precision or the remaining significant digits; indicate in hasnondigits if a number will contain any character other than the digits 0-9 in the current display format. */ double round_output(double value, int sigdigits, int *hasnondigits) { int buflen; char *buf; double rounded; double mult_factor, rdigits; int fmt_digits; /* decimal significant digits in format */ if (!isfinite(value)){ if (hasnondigits) *hasnondigits = 1; return value; } fmt_digits = num_format.precision; switch (num_format.type) { case 'A': case 'a': sigdigits = (int) round(sigdigits * log2(10) / 4); fmt_digits++; break; case 'E': case 'e': fmt_digits++; break; case 'F': case 'f': if (fabs(value) > 0) fmt_digits += (int) ceil(log10(fabs(value))); break; } if (sigdigits < fmt_digits) rdigits = sigdigits; else rdigits = fmt_digits; /* place all significant digits to the right of the radix */ if (value != 0) rdigits -= ceil(log10(fabs(value))); /* then handle like rounding to specified decimal places */ mult_factor = pow(10.0, rdigits); rounded = round(value * mult_factor) / mult_factor; /* allow for sign (1), radix (1), exponent (5), E or E formats (1), NUL */ buflen = num_format.precision + 9; if (num_format.width > buflen) buflen = num_format.width; if (strchr("Ff", num_format.type)) { int len=num_format.precision+2; if (fabs(value) > 1.0) len += (int) floor(log10(fabs(value))) + 1; if (len > buflen) buflen = len; } /* allocate space for thousands separators with digit-grouping (') flag */ /* assume worst case--that all groups are two digits */ if (strchr(num_format.format, '\'') && strchr("FfGg", num_format.type)) buflen = buflen*3/2; buf = (char *) mymalloc(buflen, "(round_output)"); sprintf(buf, num_format.format, value); if (hasnondigits){ if (strspn(buf, "1234567890") != strlen(buf)) *hasnondigits = 1; else *hasnondigits = 0; } free(buf); return rounded; } /* Determine significant digits in remainder relative to an original value which is assumed to have full double precision. Returns the number of binary or decimal digits depending on the value of base, which must be 2 or 10. */ int getsigdigits(double original, double remainder, int base) { int sigdigits; double maxdigits; double (*logfunc)(double); if (base == 2) { maxdigits = DBL_MANT_DIG; logfunc = log2; } else { maxdigits = DBL_MANT_DIG * log10(2.0); logfunc = log10; } if (original == 0) return (int) floor(maxdigits); else if (remainder == 0) return 0; sigdigits = (int) floor(maxdigits - logfunc(fabs(original/remainder))); if (sigdigits < 0) sigdigits = 0; return sigdigits; } /* Rounds a double to the specified number of binary or decimal digits. The base argument must be 2 or 10. */ double round_digits(double value, int digits, int base) { double mult_factor; double (*logfunc)(double); if (digits == 0) return 0.0; if (base == 2) logfunc = log2; else logfunc = log10; if (value != 0) digits -= (int) ceil(logfunc(fabs(value))); mult_factor = pow((double) base, digits); return round(value*mult_factor)/mult_factor; } /* Returns true if the value will display as equal to the reference and if hasnondigits is non-null then return true if the displayed output contains any character in "0123456789". */ int displays_as(double reference, double value, int *hasnondigits) { int buflen; char *buf; double rounded; if (!isfinite(value)){ if (hasnondigits) *hasnondigits = 1; return 0; } /* allow for sign (1), radix (1), exponent (5), E or E formats (1), NUL */ buflen = num_format.precision + 9; if (num_format.width > buflen) buflen = num_format.width; if (strchr("Ff", num_format.type)) { int len=num_format.precision+2; if (fabs(value) > 1.0) len += (int) floor(log10(fabs(value))) + 1; if (len > buflen) buflen = len; } /* allocate space for thousands separators with digit-grouping (') flag */ /* assume worst case--that all groups are two digits */ if (strchr(num_format.format, '\'') && strchr("FfGg", num_format.type)) buflen = buflen*3/2; buf = (char *) mymalloc(buflen, "(round_to_displayed)"); sprintf(buf, num_format.format, value); if (hasnondigits){ if (strspn(buf, "1234567890") != strlen(buf)) *hasnondigits = 1; else *hasnondigits = 0; } rounded = strtod(buf, NULL); free(buf); return rounded==reference; } /* Print the unit in 'unitstr' along with any necessary punctuation. The 'value' is the multiplier for the unit. If printnum is set to PRINTNUM then this value is printed, or set it to NOPRINTNUM to prevent the value from being printed. */ #define PRINTNUM 1 #define NOPRINTNUM 0 void showunitname(double value, char *unitstr, int printnum) { int hasnondigits; /* flag to indicate nondigits in displayed value */ int is_one; /* Does the value display as 1? */ is_one = displays_as(1, value, &hasnondigits); if (printnum && !(is_one && isdecimal(*unitstr))) logprintf(num_format.format, value); if (strpbrk(unitstr, "+-")) /* show sums and differences of units */ logprintf(" (%s)", unitstr); /* in parens */ /* fractional unit 1|x and multiplier is all digits and not one-- */ /* no space or asterisk or numerator (3|8 in instead of 3 * 1|8 in) */ else if (printnum && !flags.showfactor && startswith(unitstr,"1|") && isfract(unitstr) && !is_one && !hasnondigits) logputs(unitstr+1); /* multiplier is unity and unit begins with a number--no space or */ /* asterisk (multiplier was not shown, and the space was already output)*/ else if (is_one && isdecimal(*unitstr)) logputs(unitstr); /* unitstr begins with a non-fraction number and multiplier was */ /* shown--prefix a spaced asterisk */ else if (isdecimal(unitstr[0])) logprintf(" * %s", unitstr); else logprintf(" %s", unitstr); } /* Show the conversion factors or print the conformability error message */ int showanswer(char *havestr,struct unittype *have, char *wantstr,struct unittype *want) { struct unittype invhave; int doingrec; /* reciprocal conversion? */ char *right = NULL, *left = NULL; doingrec=0; if (compareunits(have, want, ignore_dimless)) { char **src,**dest; invhave.factor=1/have->factor; for(src=have->numerator,dest=invhave.denominator;*src;src++,dest++) *dest=*src; *dest=0; for(src=have->denominator,dest=invhave.numerator;*src;src++,dest++) *dest=*src; *dest=0; if (flags.strictconvert || compareunits(&invhave, want, ignore_dimless)){ showconformabilityerr(havestr, have, wantstr, want); return -1; } if (flags.verbose>0) logputchar('\t'); logputs("reciprocal conversion\n"); have=&invhave; doingrec=1; } if (flags.verbose==2) { if (!doingrec) left=right=""; else if (strchr(havestr,'/')) { left="1 / ("; right=")"; } else { left="1 / "; right=""; } } /* Print the first line of output. */ if (flags.verbose==2) logprintf("\t%s%s%s = ",left,havestr,right); else if (flags.verbose==1) logputs("\t* "); if (flags.verbose==2) showunitname(have->factor / want->factor, wantstr, PRINTNUM); else logprintf(num_format.format, have->factor / want->factor); /* Print the second line of output. */ if (!flags.oneline){ if (flags.verbose==2) logprintf("\n\t%s%s%s = (1 / ",left,havestr,right); else if (flags.verbose==1) logputs("\n\t/ "); else logputchar('\n'); logprintf(num_format.format, want->factor / have->factor); if (flags.verbose==2) { logputchar(')'); showunitname(0,wantstr, NOPRINTNUM); } } logputchar('\n'); return 0; } /* Checks that the function definition has a valid inverse Prints a message to stdout if function has bad definition or invalid inverse. */ #define SIGN(x) ( (x) > 0.0 ? 1 : \ ( (x) < 0.0 ? (-1) : \ 0 )) void checkfunc(struct func *infunc, int verbose) { struct unittype theunit, saveunit; struct prefixlist *prefix; int err, i; double direction; if (infunc->skip_error_check){ if (verbose) printf("skipped function '%s'\n", infunc->name); return; } if (verbose) printf("doing function '%s'\n", infunc->name); if ((prefix=plookup(infunc->name)) && strlen(prefix->name)==strlen(infunc->name)) printf("Warning: '%s' defined as prefix and function\n",infunc->name); if (infunc->table){ /* Check for valid unit for the table */ if (parseunit(&theunit, infunc->tableunit, 0, 0) || completereduce(&theunit)) printf("Table '%s' has invalid units '%s'\n", infunc->name, infunc->tableunit); freeunit(&theunit); /* Check for monotonicity which is needed for unique inverses */ if (infunc->tablelen<=1){ printf("Table '%s' has only one data point\n", infunc->name); return; } direction = SIGN(infunc->table[1].value - infunc->table[0].value); for(i=2;itablelen;i++) if (SIGN(infunc->table[i].value-infunc->table[i-1].value) != direction){ printf("Table '%s' lacks unique inverse around entry " ERRNUMFMT "\n", infunc->name, infunc->table[i].location); return; } return; } if (infunc->forward.dimen){ if (parseunit(&theunit, infunc->forward.dimen, 0, 0) || completereduce(&theunit)){ printf("Function '%s' has invalid units '%s'\n", infunc->name, infunc->forward.dimen); freeunit(&theunit); return; } } else initializeunit(&theunit); if (infunc->forward.domain_max && infunc->forward.domain_min) theunit.factor *= (*infunc->forward.domain_max+*infunc->forward.domain_min)/2; else if (infunc->forward.domain_max) theunit.factor = theunit.factor * *infunc->forward.domain_max - 1; else if (infunc->forward.domain_min) theunit.factor = theunit.factor * *infunc->forward.domain_min + 1; else theunit.factor *= 7; /* Arbitrary choice where we evaluate inverse */ if (infunc->forward.dimen){ unitcopy(&saveunit, &theunit); err = evalfunc(&theunit, infunc, FUNCTION, ALLERR); if (err) { printf("Error in definition %s(%s) as '%s':\n", infunc->name, infunc->forward.param, infunc->forward.def); printf(" %s\n",errormsg[err]); freeunit(&theunit); freeunit(&saveunit); return; } } else { # define MAXPOWERTOCHECK 4 struct unittype resultunit, arbunit; char unittext[9]; double factor; int errors[MAXPOWERTOCHECK], errcount=0; char *indent; strcpy(unittext,"(kg K)^ "); factor = theunit.factor; initializeunit(&saveunit); initializeunit(&resultunit); for(i=0;iname, infunc->forward.param, infunc->forward.def); printf(" appears to require a dimensionless argument, 'units' keyword not given\n"); indent = " "; } else if (errcount==MAXPOWERTOCHECK) { printf("Error or missing 'units' keyword in definion %s(%s) as '%s'\n", infunc->name, infunc->forward.param, infunc->forward.def); indent=" "; } else if (errcount){ printf("Warning: function '%s(%s)' defined as '%s'\n", infunc->name, infunc->forward.param, infunc->forward.def); printf(" failed for some test inputs:\n"); indent = " "; } for(i=0;iname); printf(num_format.format, factor); printf("%s): %s\n", unittext, errormsg[errors[i]]); } } if (completereduce(&theunit)){ printf("Definition %s(%s) as '%s' is irreducible\n", infunc->name, infunc->forward.param, infunc->forward.def); freeunit(&theunit); freeunit(&saveunit); return; } if (!(infunc->inverse.def)){ printf("Warning: no inverse for function '%s'\n", infunc->name); freeunit(&theunit); freeunit(&saveunit); return; } err = evalfunc(&theunit, infunc, INVERSE, ALLERR); if (err){ printf("Error in inverse ~%s(%s) as '%s':\n", infunc->name,infunc->inverse.param, infunc->inverse.def); printf(" %s\n",errormsg[err]); freeunit(&theunit); freeunit(&saveunit); return; } divunit(&theunit, &saveunit); if (unit2num(&theunit) || fabs(theunit.factor-1)>1e-12) printf("Inverse is not the inverse for function '%s'\n", infunc->name); freeunit(&theunit); } struct namedef { char *name; char *def; }; #define CONFORMABLE 1 #define TEXTMATCH 2 void addtolist(struct unittype *have, char *searchstring, char *rname, char *name, char *def, struct namedef **list, int *listsize, int *maxnamelen, int *count, int searchtype) { struct unittype want; int len = 0; int keepit = 0; if (!name) return; if (searchtype==CONFORMABLE){ initializeunit(&want); if (!parseunit(&want, name,0,0) && !completereduce(&want)) keepit = !compareunits(have,&want,ignore_dimless); } else if (searchtype == TEXTMATCH) { keepit = (strstr(rname,searchstring) != NULL); } if (keepit){ if (*count==*listsize){ *listsize += 100; *list = (struct namedef *) realloc(*list,*listsize*sizeof(struct namedef)); if (!*list){ fprintf(stderr, "%s: memory allocation error (addtolist)\n", progname); exit(EXIT_FAILURE); } } (*list)[*count].name = rname; if (strchr(def, PRIMITIVECHAR)) (*list)[*count].def = ""; else (*list)[*count].def = def; (*count)++; len = strwidth(name); if (len>*maxnamelen) *maxnamelen = len; } if (searchtype == CONFORMABLE) freeunit(&want); } int compnd(const void *a, const void *b) { return strcmp(((struct namedef *)a)->name, ((struct namedef *)b)->name); } int screensize() { int lines = 20; /* arbitrary but probably safe value */ #if defined (_WIN32) && defined (_MSC_VER) CONSOLE_SCREEN_BUFFER_INFO csbi; if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) lines = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; #endif #ifdef HAVE_IOCTL struct winsize ws; int fd; fd = open("/dev/tty", O_RDWR); if (fd>=0 && ioctl(fd, TIOCGWINSZ, &ws)==0) lines = ws.ws_row; #endif return lines; } /* determines whether the output will fit on the screen, and opens a pager if it won't */ FILE * get_output_fp(int lines) { FILE *fp = NULL; if (isatty(fileno(stdout)) && screensize() < lines) { if ((fp = popen(pager, "w")) == NULL) { fprintf(stderr, "%s: can't run pager '%s--'", progname, pager); perror((char*) NULL); } } if (!fp) fp = stdout; return fp; } int countlines(char *msg) { int nlines = 0; char *p; for (p = msg; *p; p++) if (*p == '\n') nlines++; return nlines; } /* If have is non-NULL then search through all units and print the ones which are conformable with have. Otherwise search through all the units for ones whose names contain the second argument as a substring. */ void tryallunits(struct unittype *have, char *searchstring) { struct unitlist *uptr; struct namedef *list; int listsize, maxnamelen, count; struct func *funcptr; struct wantalias *aliasptr; int i, j, searchtype; FILE *outfile; char *seploc, *firstunit; list = (struct namedef *) mymalloc( 100 * sizeof(struct namedef), "(tryallunits)"); listsize = 100; maxnamelen = 0; count = 0; if (have) searchtype = CONFORMABLE; else { if (!searchstring) searchstring=""; searchtype = TEXTMATCH; } for(i=0;inext) addtolist(have, searchstring, uptr->name, uptr->name, uptr->value, &list, &listsize, &maxnamelen, &count, searchtype); for(i=0;inext){ if (funcptr->table) addtolist(have, searchstring, funcptr->name, funcptr->tableunit, "", &list, &listsize, &maxnamelen, &count, searchtype); else addtolist(have, searchstring, funcptr->name, funcptr->inverse.dimen, "", &list, &listsize, &maxnamelen, &count, searchtype); } for(aliasptr=firstalias;aliasptr;aliasptr=aliasptr->next){ firstunit = dupstr(aliasptr->definition, "(tryallunits)");/* coverity[var_assigned] */ seploc = strchr(firstunit,UNITSEPCHAR); /* Alias definitions allowed in */ *seploc = 0; /* database contain UNITSEPCHAR */ addtolist(have, searchstring, aliasptr->name, firstunit, aliasptr->definition, &list, &listsize, &maxnamelen, &count, searchtype); free(firstunit); } qsort(list, count, sizeof(struct namedef), compnd); if (count==0) puts("No matching units found."); #ifdef SIGPIPE signal(SIGPIPE, SIG_IGN); #endif /* see if we need a pager */ outfile = get_output_fp(count); for(i=0;i 0 || flags.interactive) { for(j=strwidth(list[i].name);j<=maxnamelen;j++) putc(' ',outfile); tightprint(outfile,list[i].def); } fputc('\n',outfile); } if (outfile != stdout) pclose(outfile); #ifdef SIGPIPE signal(SIGPIPE, SIG_DFL); #endif } /* If quiet is false then prompt user with the query. Fetch one line of input and return it in *buffer. The bufsize argument is a dummy argument if we are using readline. The readline version frees buffer if it is non-null. The other version keeps the same buffer and grows it as needed. If no data is read, then this function exits the program. */ void getuser_noreadline(char **buffer, int *bufsize, const char *query) { #ifdef SUPPORT_UTF8 int valid = 0; while(!valid){ fputs(query, stdout); if (!fgetslong(buffer, bufsize, stdin,0)){ if (!flags.quiet) putchar('\n'); exit(EXIT_SUCCESS); } valid = strwidth(*buffer)>=0; if (!valid) printf("Error: %s\n",invalid_utf8); } #else fputs(query, stdout); if (!fgetslong(buffer, bufsize, stdin,0)){ if (!flags.quiet) putchar('\n'); exit(EXIT_SUCCESS); } #endif } #ifndef READLINE # define getuser getuser_noreadline #else /* we DO have readline */ void getuser_readline(char **buffer, int *bufsize, const char *query) { #ifdef SUPPORT_UTF8 int valid = 0; while (!valid){ if (*buffer) free(*buffer); *buffer = readline(query); if (*buffer) replacectrlchars(*buffer); if (!*buffer || strwidth(*buffer)>=0) valid=1; else printf("Error: %s\n",invalid_utf8); } #else if (*buffer) free(*buffer); *buffer = readline(query); if (*buffer) replacectrlchars(*buffer); #endif if (nonempty(*buffer)) add_history(*buffer); if (!*buffer){ if (!flags.quiet) putchar('\n'); exit(EXIT_SUCCESS); } } void getuser(char **buffer, int *bufsize, const char *query) { if (flags.readline) getuser_readline(buffer,bufsize,query); else getuser_noreadline(buffer,bufsize,query); } /* Unit name completion for readline. Complete function names or alias names or builtin functions. Complete to the end of a prefix or complete to the end of a unit. If the text includes a full prefix plus part of a unit and if the prefix is longer than one character then complete that compound. Don't complete a prefix fragment into prefix plus anything. */ #define CU_ALIAS 0 #define CU_BUILTIN 1 #define CU_FUNC 2 #define CU_PREFIX 3 #define CU_UNITS 4 #define CU_DONE 5 char * completeunits(char *text, int state) { static int uhash, fhash, phash, checktype; static struct prefixlist *curprefix, *unitprefix; static struct unitlist *curunit; static struct func *curfunc; static struct wantalias *curalias; static char **curbuiltin; char *output = 0; #ifndef NO_SUPPRESS_APPEND rl_completion_suppress_append = 1; #endif if (!state){ /* state == 0 means this is the first call, so initialize */ checktype = 0; /* start at first type */ fhash = uhash = phash = 0; unitprefix=0; /* search for unit continuations starting with this prefix */ curfunc=ftab[fhash]; curunit=utab[uhash]; curprefix=ptab[phash]; curbuiltin = builtins; curalias = firstalias; } while (checktype != CU_DONE){ if (checktype == CU_ALIAS){ while(curalias){ if (startswith(curalias->name,text)) output = dupstr(curalias->name, "(completeunits)"); curalias = curalias->next; if (output) return output; } checktype++; } if (checktype == CU_BUILTIN){ while(*curbuiltin){ if (startswith(*curbuiltin,text)) output = dupstr(*curbuiltin, "(completeunits)"); curbuiltin++; if (output) return output; } checktype++; } while (checktype == CU_FUNC){ while (!curfunc && fhashname,text)) output = dupstr(curfunc->name, "(completeunits)"); curfunc = curfunc->next; if (output) return output; } } while (checktype == CU_PREFIX){ while (!curprefix && phashname,text)) output = dupstr(curprefix->name, "(completeunits)"); curprefix = curprefix->next; if (output) return output; } } while (checktype == CU_UNITS){ while (!curunit && uhashname)>1){ uhash = 0; curunit = utab[uhash]; } if (!curunit) { checktype++; break; } if (unitprefix){ if (startswith(curunit->name, text+unitprefix->len)){ output = (char *)mymalloc(1+strlen(curunit->name)+unitprefix->len, "(completeunits)"); strcpy(output, unitprefix->name); strcat(output, curunit->name); } } else if (startswith(curunit->name,text)) output = dupstr(curunit->name, "(completeunits)"); curunit=curunit->next; if (output) return output; } } return 0; } #endif /* READLINE */ /* see if current directory contains an executable file */ int checkcwd (char *file) { FILE *fp; char *p; fp = openfile(file, "r"); if (fp){ fclose(fp); return 1; } #ifdef _WIN32 else if (!((p = strrchr(file, '.')) && isexe(p))) { char *pathname; pathname = mymalloc(strlen(file) + strlen(EXE_EXT) + 1, "(checkcwd)"); strcpy(pathname, file); strcat(pathname, EXE_EXT); fp = openfile(pathname, "r"); free(pathname); if (fp) { fclose(fp); return 1; } } #endif return 0; } /* return the last component of a pathname, and remove a .exe extension if one exists. */ char * getprogramname(char *path) { size_t proglen; char *p; path = pathend(path); /* get rid of filename extensions in Windows */ proglen = strlen(path); if ((p = strrchr(path, '.')) && isexe(p)) proglen -= 4; return dupnstr(path, proglen, "(getprogramname)"); } /* Find the directory that contains the invoked executable. */ char * getprogdir(char *progname, char **fullprogname) { char *progdir = NULL; char *p; #if defined (_WIN32) && defined (_MSC_VER) char buf[FILENAME_MAX + 1]; /* get the full pathname of the current executable and be done with it */ /* TODO: is there way to do this with gcc? */ if (GetModuleFileName(NULL, buf, FILENAME_MAX + 1)) progdir = dupstr(buf, "(getprogdir)"); #endif /* If path name is absolute or includes more than one component use it */ if (!progdir && (isfullpath(progname) || hasdirsep(progname))) progdir = dupstr(progname, "(getprogdir)"); /* command.com and cmd.exe under Windows always run a program that's in the current directory whether or not the current directory is in PATH, so we need to check the current directory. This could return a false positive if units is run from a Unix-like command interpreter under Windows if the current directory is not in PATH but contains 'units' or 'units.exe' */ #if defined (_WIN32) && !defined (_MSC_VER) if (!progdir && checkcwd(progname)) progdir = dupstr(progname, "(getprogdir)"); #endif /* search PATH to find the executable */ if (!progdir) { char *env; env = getenv("PATH"); if (env) { /* search PATH */ char *direc, *direc_end, *pathname; int len; FILE *fp; pathname = mymalloc(strlen(env)+strlen(progname)+strlen(EXE_EXT)+2, "(getprogdir)"); direc = env; while (direc) { direc_end = strchr(direc,PATHSEP); if (!direc_end) len = strlen(direc); else len = direc_end-direc; strncpy(pathname, direc, len); if (len>0) pathname[len++]=DIRSEP; strcpy(pathname+len, progname); fp = openfile(pathname, "r"); if (fp){ progdir = dupstr(pathname, "(getprogdir)"); break; } #ifdef _WIN32 /* executable may or may not have '.exe' suffix, so we need to look for both */ if (!((p = strrchr(pathname, '.')) && isexe(p))) { strcat(pathname, EXE_EXT); fp = openfile(pathname, "r"); if (fp){ progdir = dupstr(pathname, "(getprogdir)"); break; } } #endif direc = direc_end; if (direc) direc++; } free(pathname); if (fp) fclose(fp); } } if (!progdir) { fprintf(stderr, "%s: cannot find program directory\n", progname); exit(EXIT_FAILURE); } *fullprogname = dupstr(progdir, "(getprogdir)"); /* used by printversion() */ p = pathend(progdir); *p = '\0'; return progdir; } /* find a possible data directory relative to a 'bin' directory that contains the executable */ char * getdatadir() { int progdirlen; char *p; if (isfullpath(DATADIR)) return DATADIR; if (!progdir || emptystr(DATADIR)) return NULL; progdirlen = strlen(progdir); datadir = (char *) mymalloc(progdirlen + strlen(DATADIR) + 2, "(getdatadir)"); strcpy(datadir, progdir); if (isdirsep(progdir[progdirlen - 1])) datadir[progdirlen - 1] = '\0'; /* so pathend() can work */ p = pathend(datadir); if ((strlen(p) == 3) && (tolower(p[0]) == 'b') \ && (tolower(p[1]) == 'i') && (tolower(p[2]) == 'n')) { p = DATADIR; while (*p == '.') /* ignore "./", "../" */ p++; if (isdirsep(*p)) p++; strcpy(pathend(datadir), p); return datadir; } else return NULL; } void showfilecheck(int errnum, char *filename) { if (errnum==ENOENT) printf(" Checking %s\n", filename); else printf(" Checking %s: %s\n", filename, strerror(errnum)); } /* On Windows, find the locale map If print is set to ERRMSG then display error message if the file is not valid. If print is set to SHOWFILES then display files that are checked (when the filename is not a fully specified path). If print is set to NOERRMSG then do not display anything. Returns filename of valid local map file or NULL if no file was found. */ #ifdef _WIN32 char * findlocalemap(int print) { FILE *map = NULL; char *filename = NULL; char *file; /* Try the environment variable UNITSLOCALEMAP, then the #defined value LOCALEMAP, then the directory containing the units executable, then the directory given by datadir, and finally the directory containing the units data file. */ /* check the environment variable UNITSLOCALEMAP */ file = getenv("UNITSLOCALEMAP"); if (nonempty(file)) { map = openfile(file,"rt"); if (!map) { if (print == ERRMSG) { fprintf(stderr, "%s: cannot open locale map '%s'\n specified in UNITSLOCALEMAP environment variable. ", progname, file); perror((char *) NULL); } return NULL; } else filename = dupstr(file, "(findlocalemap)"); } /* check the #defined value LOCALEMAP */ if (!map) { file = LOCALEMAP; map = openfile(file,"rt"); if (map) filename = dupstr(file, "(findlocalemap)"); } if (!map && !progdir) { if (print == ERRMSG) { fprintf(stderr, "%s: cannot find locale map--program directory not set\n", progname); exit(EXIT_FAILURE); } else return NULL; } /* check the directory with the units executable */ if (!map) { filename = (char *) mymalloc(strlen(progdir) + strlen(file) + 2, "(findlocalemap)"); strcpy(filename, progdir); strcat(filename, file); map = openfile(filename,"rt"); if (print==SHOWFILES && !map) showfilecheck(errno, filename); } /* check data directory */ if (!map && datadir) { if (filename) free(filename); filename = (char *) mymalloc(strlen(datadir) + strlen(file) + 3, "(findlocalemap)"); strcpy(filename, datadir); strcat(filename, DIRSEPSTR); strcat(filename, file); map = openfile(filename, "rt"); if (print==SHOWFILES && !map) showfilecheck(errno, filename); } /* check the directory with the units data file */ if (!map && unitsfiles[0]) { char *lastfilename = NULL; if (filename) { if (datadir) lastfilename = dupstr(filename, "(findlocalemap)"); free(filename); } filename = (char *) mymalloc(strlen(unitsfiles[0]) + strlen(file) + 2, "(findlocalemap)"); strcpy(filename, unitsfiles[0]); strcpy(pathend(filename), file); /* don't bother if we've just checked for it */ if (lastfilename && strcmp(filename, lastfilename)) { map = openfile(filename,"rt"); if (print==SHOWFILES && !map) showfilecheck(errno, filename); } } if (map) { fclose(map); return filename; } else { if (filename) free(filename); return NULL; } } #endif /* Find the units database file. If print is set to ERRMSG then display error message if the file is not valid. If print is set to SHOWFILES then display files that are checked (when the filename is not a fully specified path). If print is set to NOERRMSG then do not display anything. Returns filename of valid database file or NULL if no file was found. */ char * findunitsfile(int print) { FILE *testfile=0; char *file; file = getenv("UNITSFILE"); if (nonempty(file)) { testfile = openfile(file, "rt"); if (!testfile) { if (print==ERRMSG) { fprintf(stderr, "%s: cannot open units file '%s' in environment variable UNITSFILE. ", progname, file); perror((char *) NULL); } return NULL; } } if (!testfile && isfullpath(UNITSFILE)){ file = UNITSFILE; testfile = openfile(file, "rt"); if (!testfile) { if (print==ERRMSG) { fprintf(stderr, "%s: cannot open units data file '%s'. ", progname, UNITSFILE); perror((char *) NULL); } return NULL; } } if (!testfile && !progdir) { if (print==ERRMSG) { fprintf(stderr, "%s: cannot open units file '%s' and cannot find program directory.\n", progname, UNITSFILE); perror((char *) NULL); } return NULL; } if (!testfile) { /* check the directory containing the units executable */ file = (char *) mymalloc(strlen(progdir)+strlen(UNITSFILE)+1, "(findunitsfile)"); strcpy(file, progdir); strcat(file, UNITSFILE); testfile = openfile(file, "rt"); if (print==SHOWFILES && !testfile) showfilecheck(errno, file); if (!testfile) free(file); } /* check data directory */ if (!testfile && datadir) { file = (char *) mymalloc(strlen(datadir) + strlen(UNITSFILE) + 2, "(findunitsfile)"); strcpy(file, datadir); strcat(file, DIRSEPSTR); strcat(file, UNITSFILE); testfile = openfile(file, "rt"); if (print==SHOWFILES && !testfile) showfilecheck(errno, file); if (!testfile) free(file); } if (!testfile) { if (print==ERRMSG) fprintf(stderr,"%s: cannot find units file '%s'\n", progname, UNITSFILE); return NULL; } else { fclose(testfile); return file; } } /* Find the user's home directory. Unlike *nix, Windows doesn't usually set HOME, so we check several other places as well. */ char * findhome(char **errmsg) { struct stat statbuf; int allocated = 0; char *homedir; char notfound[] = "Specified home directory '%s' does not exist"; char notadir[] = "Specified home directory '%s' is not a directory"; /* Under UNIX just check HOME. Under Windows, if HOME is not set then check HOMEDRIVE:HOMEPATH and finally USERPROFILE */ homedir = getenv("HOME"); #ifdef _WIN32 if (!nonempty(homedir)) { /* try a few other places */ /* try HOMEDRIVE and HOMEPATH */ char *homedrive, *homepath; if ((homedrive = getenv("HOMEDRIVE")) && *homedrive && (homepath = getenv("HOMEPATH")) && *homepath) { homedir = mymalloc(strlen(homedrive)+strlen(homepath)+1,"(personalfile)"); allocated = 1; strcpy(homedir, homedrive); strcat(homedir, homepath); } else /* finally, try USERPROFILE */ homedir = getenv("USERPROFILE"); } #endif /* If a home directory is specified, see if it exists and is a directory. If not set error message text. */ if (nonempty(homedir)) { if (stat(homedir, &statbuf) != 0) { *errmsg = malloc(strlen(notfound)+strlen(homedir)); sprintf(*errmsg, notfound, homedir); } else if (!(statbuf.st_mode & S_IFDIR)) { *errmsg = malloc(strlen(notadir)+strlen(homedir)); sprintf(*errmsg, notadir, homedir); } if (!allocated) homedir = dupstr(homedir, "(findhome)"); return homedir; } else { *errmsg = "no home directory"; return NULL; } } /* Find a personal file. First checks the specified environment variable (envname) for the filename to use. If this is unset then search user's home directory for basename. If there is no home directory, returns NULL. Otherwise if the file exists then returns its name in newly allocated space and sets *exists to 1. If the file does not exist then sets *exist to zero and: With checkonly == 0, prints error message and returns NULL With checkonly != 0, returns filename (does not print error message) */ char * personalfile(const char *envname, const char *basename, int checkonly, int *exists) { FILE *testfile; char *filename=NULL; *exists = 0; /* First check the specified environment variable for a file name */ if (envname) filename = getenv(envname); if (nonempty(filename)){ testfile = openfile(filename, "rt"); if (testfile){ fclose(testfile); *exists = 1; return filename; } if (checkonly) return filename; else { fprintf(stderr, "%s: cannot open file '%s' specified in %s environment variable: ", progname, filename, envname); perror((char *) NULL); return NULL; } } /* Environment variable not set: look in home directory */ else if (nonempty(homedir)) { filename = mymalloc(strlen(homedir)+strlen(basename)+2, "(personalfile)"); strcpy(filename,homedir); if (strcmp(homedir, "/") && strcmp(homedir, "\\")) strcat(filename,DIRSEPSTR); strcat(filename,basename); testfile = openfile(filename, "rt"); if (testfile){ fclose(testfile); *exists = 1; return filename; } if (checkonly) return filename; else { if (errno==EACCES || errno==EISDIR) { fprintf(stderr,"%s: cannot open file '%s': ",progname,filename); perror(NULL); } free(filename); return NULL; } } else return NULL; } /* print usage message */ void usage() { int nlines; char *unitsfile; char *msg = "\nUsage: %s [options] ['from-unit' 'to-unit']\n\n\ Options:\n\ -h, --help show this help and exit\n\ -c, --check check that all units reduce to primitive units\n\ --check-verbose like --check, but lists units as they are checked\n\ --verbose-check so you can find units that cause endless loops\n\ -d, --digits show output to specified number of digits (default: %d)\n\ -e, --exponential exponential format output\n\ -f, --file specify a units data file (-f '' loads default file)\n" #ifdef READLINE "\ -H, --history specify readline history file (-H '' disables history)\n" #endif "\ -L, --log specify a file to log conversions\n\ -l, --locale specify a desired locale\n\ -m, --minus make - into a subtraction operator (default)\n\ --oldstar use old '*' precedence, higher than '/'\n\ --newstar use new '*' precedence, equal to '/'\n\ -n, --nolists disable conversion to unit lists\n\ -S, --show-factor show non-unity factor before 1|x in multi-unit output\n\ --conformable in non-interactive mode, show all conformable units\n\ -o, --output-format specify printf numeric output format (default: %%.%d%c)\n\ -p, --product make '-' into a product operator\n\ -q, --quiet suppress prompting\n\ --silent same as --quiet\n\ -s, --strict suppress reciprocal unit conversion (e.g. Hz<->s)\n\ -v, --verbose show slightly more verbose output\n\ --compact suppress printing of tab, '*', and '/' character\n\ -1, --one-line suppress the second line of output\n\ -t, --terse terse output (--strict --compact --quiet --one-line)\n\ -r, --round round last element of unit list output to an integer\n\ -U, --unitsfile show units data filename and exit\n\ -u, --units specify a CGS units system or natural units system:\n\ gauss[ian],esu,emu,hlu,natural,natural-gauss,\n\ hartree,planck,planck-red,si\n\ -V, --version show version, data filenames (with -t: version only)\n\ -I, --info show version, files, and program properties\n"; FILE *fp = NULL; unitsfile = findunitsfile(NOERRMSG); nlines = countlines(msg); /* see if we need a pager */ fp = get_output_fp(nlines + 4); fprintf(fp, msg, progname, DEFAULTPRECISION, DEFAULTPRECISION, DEFAULTTYPE); if (!unitsfile) fprintf(fp, "Units data file '%s' not found.\n\n", UNITSFILE); else fprintf(fp, "\nTo learn about the available units look in '%s'\n\n", unitsfile); fputs("Report bugs to adrianm@gnu.org.\n\n", fp); if (fp != stdout) pclose(fp); } /* Print message about how to get help */ void helpmsg() { fprintf(stderr,"\nTry '%s --help' for more information.\n",progname); exit(EXIT_FAILURE); } /* show units version, and optionally, additional information */ void printversion() { int exists; char *u_unitsfile = NULL; /* units data file specified in UNITSFILE */ char *m_unitsfile; /* personal units data file from HOME_UNITS_ENV */ char *p_unitsfile; /* personal units data file */ #ifdef READLINE FILE *histfile; #endif #ifdef _WIN32 char *localemap; void remaplocale(char *); #endif if (flags.verbose == 0) { printf("GNU Units version %s\n", VERSION); return; } #ifdef _WIN32 printf("GNU Units version %s\n%s, %s%s, locale %s", VERSION, RVERSTR, UTF8VERSTR, utf8mode ? "" : " (disabled)", mylocale); localemap = findlocalemap(0); /* save error message for later */ if (localemap) { remaplocale(localemap); printf(" (%s)", mylocale); } putchar('\n'); # ifdef HAVE_MKS_TOOLKIT puts("With MKS Toolkit"); # endif if (! utf8mode) { printf("To enable UTF-8: "); if (! getenv(WINDOWS_TERMINAL)) printf("run in Windows Terminal and "); printf("set code page to 65001\n"); } #else printf("GNU Units version %s\n%s, %s%s, locale %s\n", VERSION, RVERSTR, UTF8VERSTR, utf8mode ? "" : " (disabled)", mylocale); #endif if (flags.verbose == 2) { if (!fullprogname) getprogdir(progname, &fullprogname); if (fullprogname) printf("\n%s program is %s\n", progname, fullprogname); } /* units data file */ putchar('\n'); if (isfullpath(UNITSFILE)) printf("Default units data file is '%s'\n", UNITSFILE); else printf("Default units data file is '%s';\n %s will search for this file\n", UNITSFILE, progname); if (flags.verbose < 2) printf("Default personal units file: %s\n", homeunitsfile); if (flags.verbose == 2){ u_unitsfile = getenv("UNITSFILE"); if (u_unitsfile) printf("Environment variable UNITSFILE set to '%s'\n", u_unitsfile); else puts("Environment variable UNITSFILE not set"); unitsfiles[0] = findunitsfile(SHOWFILES); if (unitsfiles[0]) { /* We searched for the file in program and data dirs */ if (!isfullpath(UNITSFILE) && !nonempty(u_unitsfile)) printf("Found data file '%s'\n", unitsfiles[0]); else printf("Units data file is '%s'\n", unitsfiles[0]); } else { if (errno && (nonempty(u_unitsfile) || isfullpath(UNITSFILE))) printf("*** Units data file invalid: %s ***\n",strerror(errno)); else puts("*** Units data file not found ***"); } if (homedir_error) printf("\n%s\n", homedir_error); else printf("\nHome directory is '%s'\n", homedir); } /* personal units data file: environment */ if (flags.verbose == 2){ m_unitsfile = getenv(HOME_UNITS_ENV); putchar('\n'); if (m_unitsfile) { printf("Environment variable %s set to '%s'\n", HOME_UNITS_ENV,m_unitsfile); } else printf("Environment variable %s not set\n", HOME_UNITS_ENV); p_unitsfile = personalfile(HOME_UNITS_ENV, homeunitsfile, 1, &exists); if (p_unitsfile) { printf("Personal units data file is '%s'\n", p_unitsfile); if (!exists){ if (homedir_error && !nonempty(m_unitsfile)) printf(" (File invalid: %s)\n", homedir_error); else if (errno==ENOENT && !nonempty(m_unitsfile)) puts(" (File does not exist)"); else printf(" (File invalid: %s)\n",strerror(errno)); } } else puts("Personal units data file not found: no home directory"); } #ifdef READLINE if (flags.verbose == 2) { historyfile = personalfile(NULL,HISTORY_FILE,1,&exists); if (historyfile){ printf("\nDefault readline history file is '%s'\n", historyfile); histfile = openfile(historyfile,"r+"); if (!histfile) printf(" (File invalid: %s)\n", homedir_error ? homedir_error : strerror(errno)); else fclose(histfile); } else puts("\nReadline history file unusable: no home directory"); } #endif #ifdef _WIN32 /* locale map */ if (flags.verbose == 2) { putchar('\n'); localemap = getenv("UNITSLOCALEMAP"); if (localemap) printf("Environment variable UNITSLOCALEMAP set to '%s'\n", localemap); else puts("Environment variable UNITSLOCALEMAP not set"); if (isfullpath(LOCALEMAP)) printf("Default locale map is '%s'\n", LOCALEMAP); else printf("Default locale map is '%s';\n %s will search for this file\n", LOCALEMAP, progname); localemap = findlocalemap(SHOWFILES); if (localemap && !isfullpath(LOCALEMAP)) printf("Found locale map '%s'\n", localemap); else if (localemap) printf("Locale map is '%s'\n", localemap); else puts("*** Locale map not found ***"); } #endif printf("\n%s\n\n", LICENSE); } void showunitsfile() { char *unitsfile; unitsfile = findunitsfile(NOERRMSG); if (unitsfile) printf("%s\n", unitsfile); else puts("Units data file not found"); } char *shortoptions = "VIUu:vqechSstf:o:d:mnpr1l:L:8" #ifdef READLINE "H:" #endif ; struct option longoptions[] = { {"check", no_argument, &flags.unitcheck, 1}, {"check-verbose", no_argument, &flags.unitcheck, 2}, {"compact", no_argument, &flags.verbose, 0}, {"digits", required_argument, 0, 'd'}, {"exponential", no_argument, 0, 'e'}, {"file", required_argument, 0, 'f'}, {"help", no_argument, 0, 'h'}, #ifdef READLINE {"history", required_argument, 0, 'H'}, #endif {"info", no_argument, 0, 'I'}, {"locale", required_argument, 0, 'l'}, {"log", required_argument, 0, 'L'}, {"minus", no_argument, &parserflags.minusminus, 1}, {"newstar", no_argument, &parserflags.oldstar, 0}, {"nolists", no_argument, 0, 'n'}, {"oldstar", no_argument, &parserflags.oldstar, 1}, {"one-line", no_argument, &flags.oneline, 1}, {"output-format", required_argument, 0, 'o'}, {"product", no_argument, &parserflags.minusminus, 0}, {"quiet", no_argument, &flags.quiet, 1}, {"round",no_argument, 0, 'r'}, {"show-factor", no_argument, 0, 'S'}, {"conformable", no_argument, &flags.showconformable, 1 }, {"silent", no_argument, &flags.quiet, 1}, {"strict",no_argument,&flags.strictconvert, 1}, {"terse",no_argument, 0, 't'}, {"unitsfile", no_argument, 0, 'U'}, {"units", required_argument, 0, 'u'}, {"verbose", no_argument, &flags.verbose, 2}, {"verbose-check", no_argument, &flags.unitcheck, 2}, {"version", no_argument, 0, 'V'}, {0,0,0,0} }; /* Process the args. Returns 1 if interactive mode is desired, and 0 for command line operation. If units appear on the command line they are returned in the from and to parameters. */ int processargs(int argc, char **argv, char **from, char **to) { extern char *optarg; extern int optind; int optchar, optindex; int ind; int doprintversion=0; char *unitsys=0, *digitsstr, *temp; digitsstr = NULL; while ( -1 != (optchar = getopt_long(argc, argv,shortoptions,longoptions, &optindex ))) { switch (optchar) { case 'm': parserflags.minusminus = 1; break; case 'p': parserflags.minusminus = 0; break; case 't': flags.oneline = 1; flags.quiet = 1; flags.strictconvert = 1; flags.verbose = 0; break; /* numeric output format */ case 'd': digitsstr = optarg; num_format.format = NULL; break; case 'e': num_format.type = 'e'; num_format.format = NULL; break; case 'o': num_format.format = dupstr(optarg, "(processargs)"); digitsstr = NULL; break; case 'c': flags.unitcheck = 1; break; case 'f': for(ind=0;unitsfiles[ind];ind++); if (ind==MAXFILES){ fprintf(stderr, "At most %d -f specifications are allowed\n", MAXFILES); exit(EXIT_FAILURE); } if (optarg && *optarg) unitsfiles[ind] = optarg; else { unitsfiles[ind] = findunitsfile(ERRMSG); if (!unitsfiles[ind]) exit(EXIT_FAILURE); } unitsfiles[ind+1] = 0; break; case 'L': logfilename = optarg; break; case 'l': mylocale = optarg; break; case 'n': flags.unitlists = 0; break; case 'q': flags.quiet = 1; break; case 'r': flags.round = 1; break; case 'S': flags.showfactor = 1; break; case 's': flags.strictconvert = 1; break; case 'v': flags.verbose = 2; break; case '1': flags.oneline = 1; break; case 'I': flags.verbose = 2; /* fall through */ case 'V': doprintversion = 1; break; case 'U': showunitsfile(); exit(EXIT_SUCCESS); break; case 'u': unitsys = optarg; for(ind=0;unitsys[ind];ind++) unitsys[ind] = tolower(unitsys[ind]); break; case 'h': usage(); exit(EXIT_SUCCESS); #ifdef READLINE case 'H': if (emptystr(optarg)) historyfile=NULL; else historyfile = optarg; break; #endif case 0: break; /* This is reached if a long option is processed with no return value set. */ case '?': /* Invalid option or missing argument returns '?' */ default: helpmsg(); /* helpmsg() exits with error */ } } if (digitsstr && checksigdigits(digitsstr) < 0) exit(EXIT_FAILURE); temp = strchr(mylocale,'.'); if (temp) *temp = '\0'; if (doprintversion){ printversion(); exit(EXIT_SUCCESS); } /* command-line option overwrites environment */ if (unitsys) setenv("UNITS_SYSTEM", unitsys, 1); if (flags.unitcheck) { if (optind != argc){ fprintf(stderr, "Too many arguments (arguments are not allowed with -c).\n"); helpmsg(); /* helpmsg() exits with error */ } } else { if (optind == argc - 2) { if (flags.showconformable) { fprintf(stderr,"Too many arguments (only one unit expression allowed with '--conformable').\n"); helpmsg(); /* helpmsg() exits with error */ } flags.quiet=1; *from = argv[optind]; *to = dupstr(argv[optind+1], "(processargs)"); /* This string may get rewritten later */ return 0; /* and we might call free() on it */ } if (optind == argc - 1) { flags.quiet=1; *from = argv[optind]; *to=0; return 0; } if (optind < argc - 2) { fprintf(stderr,"Too many arguments (maybe you need quotes).\n"); helpmsg(); /* helpmsg() exits with error */ } } return 1; } /* Show a pointer under the input to indicate a problem. Prints 'position' spaces and then the pointer. If 'position' is negative, nothing is printed. */ void showpointer(int position) { if (position >= 0){ while (position--) putchar(' '); puts(POINTER); } } /* end showpointer */ /* Process the string 'unitstr' as a unit, placing the processed data in the unit structure 'theunit'. Returns 0 on success and 1 on failure. If an error occurs an error message is printed to stdout. A pointer ('^') will be printed if an error is detected, and promptlen should be set to the printing width of the prompt string, or set it to NOPOINT to supress printing of the pointer. */ int processunit(struct unittype *theunit, char *unitstr, int promptlen) { char *errmsg; int errloc,err; char savechar; if (flags.unitlists && strchr(unitstr, UNITSEPCHAR)){ puts("Unit list not allowed"); return 1; } if ((err=parseunit(theunit, unitstr, &errmsg, &errloc))){ if (promptlen >= 0){ if (err!=E_UNKNOWNUNIT || !irreducible){ if (errloc>0) { savechar = unitstr[errloc]; unitstr[errloc] = 0; showpointer(promptlen+strwidth(unitstr)-1); unitstr[errloc] = savechar; } else showpointer(promptlen); } } else printf("Error in '%s': ", unitstr); fputs(errmsg,stdout); if (err==E_UNKNOWNUNIT && irreducible) printf(" '%s'", irreducible); putchar('\n'); return 1; } if ((err=completereduce(theunit))){ fputs(errormsg[err],stdout); if (err==E_UNKNOWNUNIT) printf(" '%s'", irreducible); putchar('\n'); return 1; } return 0; } /* Checks for a new unit defined on the prompt with the form _ = */ int definevariable(char *def, int promptlen) { int dummy, err; struct unittype unit; struct unitlist *uptr; int needfree=0; char *logstr, *reduced, *oldvalue = NULL; char *value = strchr(def,'='); if (!value) return 0; logstr = dupstr(def, "(definevariable)"); *value++=0; if (processunit(&unit, value, promptlen + (value-def))) { free(logstr); return 1; } if (lastchar(def)==':'){ char **entry; int spaceneeded, numeratorspace; int counter; lastchar(def)=0; needfree=1; spaceneeded = 30; /* Space for leading number and a division sign */ for(entry=unit.numerator;*entry;entry++) if (*entry!=NULLUNIT) spaceneeded+=1+strlen(*entry); numeratorspace = spaceneeded; for(entry=unit.denominator;*entry;entry++) if (*entry!=NULLUNIT) spaceneeded+=1+strlen(*entry); reduced = (char *)mymalloc(spaceneeded,"(definevariable)"); snprintf(reduced,spaceneeded, "%.*g ",DBL_DECIMAL_DIG,unit.factor); for(entry=unit.numerator;*entry;entry++){ if (*entry!=NULLUNIT){ strcat(reduced, *entry); for(counter=1;entry[counter] && !strcmp(entry[counter],*entry);counter++); if (counter>1){ strcat(reduced,powerstring); snprintf(reduced+strlen(reduced),spaceneeded-strlen(reduced),"%d",counter); } entry+=counter-1; strcat(reduced," "); } } if (numeratorspace1){ strcat(reduced,powerstring); snprintf(reduced+strlen(reduced),spaceneeded-strlen(reduced),"%d",counter); } entry+=counter-1; strcat(reduced," "); } } value=reduced; removespaces(def); } else { removespaces(def); /* see if this is a re-assignment */ if ((uptr=ulookup(def))) /* save the current value so it can be restored if the re-assignment fails */ oldvalue = dupstr(uptr->value, "(definevariable)"); } removespaces(value); err = *def!='_' || newunit(def,value, &dummy, 0, 0, NULL, 1, 1); if (err) printf("Invalid variable name: %s\n", def); /* restore the current value if the assignment is invalid */ else if (! needfree && processunit(&unit, def, NOPOINT)) { if (oldvalue && (uptr = ulookup(def))){ free(uptr->value); uptr->value = dupstr(oldvalue, "(definevariable)"); } err++; } if (! err && logfile) fprintf(logfile, "Var: %s\n", logstr); free(logstr); if (oldvalue) free(oldvalue); if (needfree) free(reduced); return 1; } /* Checks the input parameter unitstr (a list of units separated by UNITSEPCHAR) for errors. All units must be parseable and conformable to each other. Returns 0 on success and 1 on failure. If an error is found then print an error message on stdout. A pointer ('^') will be printed to mark the error. The promptlen parameter should be set to the printing width of the prompt string so that the pointer is correctly aligned. To suppress the printing of the pointer set promptlen to NOPOINT. To suppress printing of error messages entirely set promptlen to NOERRMSG. */ int checkunitlist(char *unitstr, int promptlen) { struct unittype unit[2], one; char *firstunitstr,*nextunitstr; int unitidx = 0; int printerror = promptlen != NOERRMSG; initializeunit(&one); firstunitstr = unitstr; initializeunit(unit); initializeunit(unit+1); while (unitstr) { if ((nextunitstr = strchr(unitstr, UNITSEPCHAR)) != 0) *nextunitstr = '\0'; if (!unitstr[strspn(unitstr, " ")]) { /* unitstr is blank */ if (!nextunitstr) { /* terminal UNITSEPCHAR indicates repetition */ freeunit(unit); /* of last unit and is permitted */ return 0; } else { /* internal blank units are not allowed */ if (printerror){ showpointer(promptlen); puts("Error: blank unit not allowed"); } freeunit(unit); return 1; } } /* processunit() prints error messages; avoid it to supress them */ if ((printerror && processunit(unit+unitidx,unitstr,promptlen)) || (!printerror && (parseunit(unit+unitidx, unitstr,0,0) || completereduce(unit+unitidx) || compareunits(unit+unitidx,&one, ignore_primitive)))){ if (printerror) printf("Error in unit list entry: %s\n",unitstr); freeunit(unit); freeunit(unit+1); return 1; } if (unitidx == 0) unitidx = 1; else { if (compareunits(unit, unit+1, ignore_dimless)){ if (printerror){ int wasverbose = flags.verbose; FILE *savelog = logfile; logfile=0; flags.verbose = 2; /* always use verbose form to be unambiguous */ /* coverity[returned_null] */ *(strchr(firstunitstr, UNITSEPCHAR)) = '\0'; removespaces(firstunitstr); removespaces(unitstr); showpointer(promptlen); showconformabilityerr(firstunitstr, unit, unitstr, unit+1); flags.verbose = wasverbose; logfile = savelog; } freeunit(unit); freeunit(unit+1); return 1; } freeunit(unit+1); } if (nextunitstr) { if (promptlen >= 0) promptlen += strwidth(unitstr)+1; *(nextunitstr++) = UNITSEPCHAR; } unitstr = nextunitstr; } freeunit(unit); return 0; } /* end checkunitlist */ /* Call either processunit or checkunitlist, depending on whether the string 'unitstr' contains a separator character. Returns 0 on success and 1 on failure. If an error occurs an error message is printed to stdout. A pointer will be printed if an error is detected, and promptlen should be set to the printing width of the prompt string, or set it to NOPOINT to supress printing of the pointer. */ int processwant(struct unittype *theunit, char *unitstr, int promptlen) { if (flags.unitlists && strchr(unitstr, UNITSEPCHAR)) return checkunitlist(unitstr, promptlen); else return processunit(theunit, unitstr, promptlen); } void checkallaliases(int verbose) { struct wantalias *aliasptr; for(aliasptr = firstalias; aliasptr; aliasptr=aliasptr->next){ if (verbose) printf("doing unit list '%s'\n", aliasptr->name); if (checkunitlist(aliasptr->definition,NOERRMSG)) printf("Unit list '%s' contains errors\n", aliasptr->name); if (ulookup(aliasptr->name)) printf("Unit list '%s' hides a unit definition.\n", aliasptr->name); if (fnlookup(aliasptr->name)) printf("Unit list '%s' hides a function definition.\n", aliasptr->name); } } /* Check that all units and prefixes are reducible to primitive units and that function definitions are valid and have correct inverses. A message is printed for every unit that does not reduce to primitive units. */ void checkunits(int verbosecheck) { struct unittype have,second,one; struct unitlist *uptr; struct prefixlist *pptr; struct func *funcptr; char *prefixbuf, *testunit; int i, reduce_err; char *err; initializeunit(&one); /* Check all functions for valid definition and correct inverse */ for(i=0;inext) checkfunc(funcptr, verbosecheck); checkallaliases(verbosecheck); /* Now check all units for validity */ for(i=0;inext){ if (verbosecheck) printf("doing '%s'\n",uptr->name); if (strchr(uptr->value, PRIMITIVECHAR)) continue; else if (fnlookup(uptr->name)) printf("Unit '%s' hidden by function '%s'\n", uptr->name, uptr->name); else if (parseunit(&have, uptr->value,&err,0)) printf("'%s' defined as '%s': %s\n",uptr->name, uptr->value,err); else if ((reduce_err=completereduce(&have))){ printf("'%s' defined as '%s' irreducible: %s",uptr->name, uptr->value,errormsg[reduce_err]); if (reduce_err==E_UNKNOWNUNIT && irreducible) printf(" '%s'", irreducible); putchar('\n'); } else { parserflags.minusminus = !parserflags.minusminus; /* coverity[check_return] */ parseunit(&second, uptr->name, 0, 0); /* coverity[check_return] */ completereduce(&second); /* Can't fail because it worked above */ if (compareunits(&have, &second, ignore_nothing)){ printf("'%s': replace '-' with '+-' for subtraction or '*' to multiply\n", uptr->name); } freeunit(&second); parserflags.minusminus=!parserflags.minusminus; } freeunit(&have); } /* Check prefixes */ testunit="meter"; for(i=0;inext){ if (verbosecheck) printf("doing '%s-'\n",pptr->name); prefixbuf = mymalloc(strlen(pptr->name) + strlen(testunit) + 1, "(checkunits)"); strcpy(prefixbuf,pptr->name); strcat(prefixbuf,testunit); if (parseunit(&have, prefixbuf,0,0) || completereduce(&have) || compareunits(&have,&one,ignore_primitive)) printf("'%s-' defined as '%s' irreducible\n",pptr->name, pptr->value); else { int plevel; /* check for bad '/' character in prefix */ char *ch; plevel = 0; for(ch=pptr->value;*ch;ch++){ if (*ch==')') plevel--; else if (*ch=='(') plevel++; else if (plevel==0 && *ch=='/'){ printf( "'%s-' defined as '%s' contains a bad '/'. (Add parentheses.)\n", pptr->name, pptr->value); break; } } } freeunit(&have); free(prefixbuf); } } /* Converts the input value 'havestr' (which is already parsed into the unit structure 'have') into a sum of the UNITSEPCHAR-separated units listed in 'wantstr'. You must call checkunitlist first to ensure 'wantstr' is error-free. Prints the results (or an error message) on stdout. Returns 0 on success and 1 on failure. */ int showunitlist(char *havestr, struct unittype *have, char *wantstr) { struct unittype want, lastwant; char *lastunitstr, *nextunitstr, *lastwantstr=0; double remainder; /* portion of have->factor remaining */ double round_dir; /* direction of rounding */ double value; /* value (rounded to integer with 'r' option) */ int firstunit = 1; /* first unit in a multi-unit string */ int value_shown = 0; /* has a value been shown? */ int sigdigits; char val_sign; initializeunit(&want); remainder = fabs(have->factor); val_sign = have->factor < 0 ? '-' : '+'; lastunitstr = 0; nextunitstr = 0; round_dir = 0; if (flags.round) { /* disable unit repetition with terminal UNITSEPCHAR when rounding */ if (lastchar(wantstr) == UNITSEPCHAR) lastchar(wantstr) = 0; if ((lastwantstr = strrchr(wantstr, UNITSEPCHAR))) lastwantstr++; } while (wantstr) { if ((nextunitstr = strchr(wantstr, UNITSEPCHAR))) *(nextunitstr++) = '\0'; removespaces(wantstr); /* if wantstr ends in UNITSEPCHAR, repeat last unit--to give integer and fractional parts (3 oz + 0.371241 oz rather than 3.371241 oz) */ if (emptystr(wantstr)) /* coverity[alias_transfer] */ wantstr = lastunitstr; if (processunit(&want, wantstr, NOPOINT)) { freeunit(&want); return 1; } if (firstunit){ /* checkunitlist() ensures conformability within 'wantstr', so we just need to check the first unit to see if it conforms to 'have' */ if (compareunits(have, &want, ignore_dimless)) { showconformabilityerr(havestr, have, wantstr, &want); freeunit(&want); return 1; } /* round to nearest integral multiple of last unit */ if (flags.round) { value = remainder; if (nonempty(lastwantstr)) { /* more than one unit */ removespaces(lastwantstr); initializeunit(&lastwant); if (processunit(&lastwant, lastwantstr, NOPOINT)) { freeunit(&lastwant); return 1; } remainder = round(remainder / lastwant.factor) * lastwant.factor; } else /* first unit is last unit */ remainder = round(remainder / want.factor) * want.factor; round_dir = remainder - value; } if (flags.verbose == 2) { removespaces(havestr); logprintf("\t%s = ", havestr); } else if (flags.verbose == 1) logputchar('\t'); } /* end if first unit */ if (0==(sigdigits = getsigdigits(have->factor, remainder, 10))) break; /* nothing left */ /* Remove sub-precision junk accumulating in the remainder. Rounding is base 2 to ensure that we keep all valid bits. */ remainder = round_digits(remainder, getsigdigits(have->factor,remainder,2),2); if (nextunitstr) remainder = want.factor * modf(remainder / want.factor, &value); else value = remainder / want.factor; /* The remainder represents less than one of the current want unit. But with display rounding it may round up to 1, leading to an output like "4 feet + 12 inch". Check for this case and if the remainder indeed rounds up to 1 then add that remainder into the current unit and set the remainder to zero. */ if (nextunitstr){ double rounded_next = round_digits(remainder/want.factor, getsigdigits(have->factor, remainder / want.factor, 10), 10); if (displays_as(1,rounded_next, NULL)){ value++; remainder = 0; /* Remainder is zero */ } } /* Round the value to significant digits to prevent display of bogus sub-precision decimal digits */ value = round_digits(value,sigdigits,10); /* This ensures that testing value against zero will work below at the last unit, which is the only case where value is not integer */ if (!nextunitstr && displays_as(0, value, NULL)) value=0; if (!flags.verbose){ if (!firstunit) logputchar(UNITSEPCHAR); logprintf(num_format.format,value); value_shown=1; } else { /* verbose case */ if (value != 0) { if (value_shown) /* have already displayed a number so need a '+' */ logprintf(" %c ",val_sign); else if (val_sign=='-') logputs("-"); showunitname(value, wantstr, PRINTNUM); if (sigdigits <= floor(log10(value))+1) /* Used all sig digits */ logprintf(" (at %d-digit precision limit)", DBL_DIG); value_shown=1; } } freeunit(&want); lastunitstr = wantstr; wantstr = nextunitstr; firstunit = 0; } /* if the final unit value was rounded print indication */ if (!value_shown) { /* provide output if every value rounded to zero */ logputs("0 "); if (isdecimal(*lastunitstr)) logputs("* "); logputs(lastunitstr); } if (round_dir != 0) { if (flags.verbose){ if (round_dir > 0) logprintf(" (rounded up to nearest %s) ", lastunitstr); else logprintf(" (rounded down to nearest %s) ", lastunitstr); } else logprintf("%c%c", UNITSEPCHAR, round_dir > 0 ?'-':'+'); } logputchar('\n'); return 0; } /* end showunitlist */ #if defined (_WIN32) && defined (HAVE_MKS_TOOLKIT) int ismksmore(char *pager) { static int mksmore = -1; if (mksmore >= 0) return mksmore; /* Tries to determine whether the MKS Toolkit version of more(1) or less(1) will run. In older versions of the Toolkit, neither accepted '+', insisting on the POSIX-compliant '+g'. */ if (strstr(pager, "more") || strstr(pager, "less")) { char *mypager, *mkspager, *mksroot, *p; char pathbuf[FILENAME_MAX + 1]; struct _stat mybuf, mksbuf; mypager = NULL; mkspager = NULL; mksmore = 0; if (strlen(pager) > FILENAME_MAX) { fprintf(stderr, "%s: cannot invoke pager--value '%s' in PAGER too long\n", progname, pager); return 0; /* TODO: this really isn't the right value */ } else if (!isfullpath(pager)) { mypager = (char *) mymalloc(strlen(pager) + strlen(EXE_EXT) + 1, "(ishelpquery)"); strcpy(mypager, pager); if (!((p = strrchr(mypager, '.')) && isexe(p))) strcat(mypager, EXE_EXT); _searchenv(mypager, "PATH", pathbuf); } else strcpy(pathbuf, pager); mksroot = getenv("ROOTDIR"); if (mksroot) { char * mksprog; if (strstr(pager, "more")) mksprog = "more.exe"; else mksprog = "less.exe"; mkspager = (char *) mymalloc(strlen(mksroot) + strlen("/mksnt/") + strlen(mksprog) + 1, "(ishelpquery)"); strcpy(mkspager, mksroot); strcat(mkspager, "\\mksnt\\"); strcat(mkspager, mksprog); } if (*pathbuf && mksroot) { if (_stat(mkspager, &mksbuf)) { fprintf(stderr, "%s: cannot stat file '%s'. ", progname, mkspager); perror((char *) NULL); return 0; } if (_stat(pathbuf, &mybuf)) { fprintf(stderr, "%s: cannot stat file '%s'. ", progname, pathbuf); perror((char *) NULL); return 0; } /* if we had inodes, this would be simple ... but if it walks like a duck and swims like a duck and quacks like a duck ... */ if (mybuf.st_size == mksbuf.st_size && mybuf.st_ctime == mksbuf.st_ctime && mybuf.st_mtime == mksbuf.st_mtime && mybuf.st_atime == mksbuf.st_atime && mybuf.st_mode == mksbuf.st_mode) mksmore = 1; } if (mypager) free(mypager); if (mkspager) free(mkspager); } return mksmore; } #endif /* Checks to see if the input string contains HELPCOMMAND possibly followed by a unit name on which help is sought. If not, then return 0. Otherwise invoke the pager on units file at the line where the specified unit is defined. Then return 1. */ int ishelpquery(char *str, struct unittype *have) { struct unitlist *unit; struct func *function; struct wantalias *alias; struct prefixlist *prefix; char commandbuf[1000]; /* Hopefully this is enough overkill as no bounds */ int unitline; /* checking is performed. */ char *file; char **exitptr; char *commandstr; /* command string varies with OS */ if (have && !strcmp(str, UNITMATCH)){ tryallunits(have,0); return 1; } for(exitptr=exit_commands;*exitptr;exitptr++) if (!strcmp(str, *exitptr)) exit(EXIT_SUCCESS); if (startswith(str, SEARCHCOMMAND)){ str+=strlen(SEARCHCOMMAND); if (!emptystr(str) && *str != ' ') return 0; removespaces(str); if (emptystr(str)){ printf("\n\ Type 'search text' to see a list of all unit names \n\ containing 'text' as a substring\n\n"); return 1; } tryallunits(0,str); return 1; } if (startswith(str, HELPCOMMAND)){ str+=strlen(HELPCOMMAND); if (!emptystr(str) && *str != ' ') return 0; removespaces(str); if (emptystr(str)){ int nlines; char *unitsfile; char *msg = "\n\ %s converts between different measuring systems and %s6 inches\n\ acts as a units-aware calculator. At the '%s' %scm\n\ prompt, type in the units you want to convert from or * 15.24\n\ an expression to evaluate. At the '%s' prompt, / 0.065\n\ enter the units to convert to or press return to see\n\ the reduced form or definition. %stempF(75)\n\ %stempC\n\ The first example shows that 6 inches is about 15 cm 23.889\n\ or (1/0.065) cm. The second example shows how to\n\ convert 75 degrees Fahrenheit to Celsius. The third %sbu^(1/3)\n\ example converts the cube root of a bushel to a list %sft;in\n\ of semicolon-separated units. 1 ft + 0.9 in\n\ \n\ To quit from %s type 'quit' or 'exit'. %s2 btu + 450 ft lbf\n\ %s(kg^2/s)/(day lb/m^2)\n\ At the '%s' prompt type '%s' to get a * 1.0660684e+08\n\ list of conformable units. At either prompt you / 9.3802611e-09\n\ type 'help myunit' to browse the units database\n\ and read the comments relating to myunit or see %s6 tbsp sugar\n\ other units related to myunit. Typing 'search %sg\n\ text' will show units whose names contain 'text'. * 75\n\ / 0.013333333\n\n\ Many command-line options can be set interactively by typing\n\ 'set