Skip to content

pre-srfi/numeric-quantities

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

16 Commits
 
 
 
 
 
 
 
 

Repository files navigation

SRFI 2xx: Numeric Quantities

Numeric quantities

Abstract

This SRFI describes numeric procedures and constructors for quantities, which are numbers that have an associated unit. The specified procedures are similar to Scheme’s numerical procedures, but allow for dimensional analysis during type-checking. The ability to create new quantities, procedures to convert quantities to different types, and libraries for standardized or common quantities are also provided.

Issues

  • Currently conversions are 1-directional (towards base unit), need a way to make them bidirectional
  • The included imperial/US units were selected based on present-day usage. Historical units or units specific to a commodity (alcohol, oil, soybean etc.) are excluded. Have I forgotten any? Are there other special unit systems that would be useful to include?
  • Should shannon and bit be compatible?

Rationale

Numeric quantities are ubiquitous in scientific software, and in any software that interacts with the outside world. However, the numerical towers of most programming languages (including Scheme) have no concept of units, and programmers instead must use simple numbers to represent quantities, sometimes with code comments to indicate the intended unit. This can lead to a class of errors where procedures expect numeric arguments that represent a quantitity with a certain unit, but instead receive numbers that represent a different unit.

With the introducton of SRFI 253: Data (Type-)Checking, Scheme can now check the validity of procedure arguments, ensuring that they match a given predicate. This is one of the prerequisites towards eliminating unit conversion errors. The other prerequisite is the existence of numeric types for quantities: that is the goal of this SRFI.

This SRFI provides an extensive set of commonly-used units, encompassing both standard SI units and specialized systems of measurement. While it is possible to define custom units, it is expected that the provided units will meet the needs of the vast majority of programs. This SRFI can only guarantee dimensional correctness for operations that use the provided units exclusively.

Implementation of this SRFI does not require modification of the existing Scheme numeric tower or type system. Quantity arithmetic is performed using special procedures that are similar to the arithmetic procedures provided by R7RS-small. wHaving separate arithmetic procedures for quantities provides a greater degree of safety.

Some programming languages provide quantity types in the base language, or more commonly, as an external library. The following implementations were referenced during the creation of this SRFI:

Specification

Quantity checking should be implemented using SRFI 145 assumptions or SRFI 253 type checking forms, so that debug mode behavior remains consistent.

Quantities

(make-quantity num unit)

Return a quantity object for a given number and unit. An error is signalled if the number argument is infinite or NaN.

(quantity? object)

Return #t if object is a quantity, #f otherwise.

(quantity-number quantity)

Return the number component of a quantity, a Scheme number.

(quantity-unit quantity)

Return the unit component of a quantity, a unit record.

(quantity=? quantity quantity2 . rest)

Return #t if all the supplied quantities are equal, when the quantities are converted to a common unit. Otherwise, returns #f. An error shall be signalled if any of the supplied arguments is not a quantity.

(strict-quantity=? quantity quantity2 . rest)

Return #t if all the supplied quantities are equal, and the units of the quantities are all the same. Otherwise, returns #f. An error shall be signalled if any of the supplied arguments is not a quantity.

Strict equality does not consider the name, abbreviation, or other auxillary properties of the unit. For example, kilometer and an alias for kilometer would be strictly equal, but kilometer and meter would not.

(quantity-predicate unit)

Returns a predicate procedure that accepts one argument of any type, and returns #t if the received argument is a quantity with unit compatible with that of the supplied unit argument. Otherwise, the predicate procedure must return #f.

(strict-quantity-predicate unit)

Returns a predicate procedure that accepts one argument of any type, and returns #t if the received argument is a quantity with a unit that is the same as that of the supplied unit argument. Otherwise, the predicate procedure must return #f.

(convert-quantity quantity new-unit)

Returns a quantity with unit new-unit, that is equivalent to the supplied quantity argument. If the unit of the quantity argument and new-unit are the same, the quantity argument is returned. If the quantity argument cannot be converted to new-unit, an error shall be signalled.

(quantity->string quantity)

Converts any quantity value to a formatted string. This procedure must use the unabbreviated form of unit names. This procedure should represent the number using a unit prefix, but the unit prefix must also be unabbreviated.

(quantity->string (qn* (make-quantity 1000 meter)
                       (qn* (make-quantity 1 second)
                            (make-quantity 1 second))))
;; => "1000 kilometers / second^2"
(quantity->short-string quantity)

Converts any quantity value to a formatted string. This procedure should use the abbreviated form of unit names. This procedure may represent the quantity using an abbreviated unit prefix.

(quantity->short-string (qn* (make-quantity 1000 meter)
                             (qn* (make-quantity 1 second)
                                  (make-quantity 1 second))))
;; => "1 km / s^2"

Units

(make-unit name abbreviation dimension base-unit converter)

Return an object representing a unit. The name argument is a string containing the uncapitalized full name of the unit. The abbreviation argument is a string containing the abbreviation of the unit, without punctuation. The base unit argument is the unit from which the specified unit is derived.

The dimension argument is a list of dimension objects that represent the base quantities of what the unit measures. See the Dimensions section for details.

The converter argument is a procedure that accepts a single argument, a Scheme number. It must convert its numeric argument into the equivalent number of the base unit. If a number argument is invalid or out of range for the specified unit, the procedure is permitted to signal an error, in which case quantity conversions and arithmetic operations will also signal an error.

The accessor functions unit-name, unit-abbreviation, unit-dimension, unit-base-unit, unit-converter shall be made available by the SRFI library.

;; 1 foo = 500 meters
(define foo (make-unit "foo" "f" (unit-dimension meter) meter
                       (lambda (x) (* x 500))))
(quantity->full-string (quantity-convert (make-quantity 3 foo) kilometer))
;; => "1.5 kilometer"
(unit? object)

Return #t if object is a unit, #f otherwise.

(unit=? unit1 unit2 . rest)

Return #t if all the supplied unit arguments are the same, #f otherwise. If any of the supplied arguments is not a unit, an error shall be signalled.

(units-compatible? unit1 unit2 . rest)

Return #t if all the supplied unit arguments can be converted to a common unit. Otherwise, return #f. If any of the supplied arguments is not a unit, an error shall be signalled.

Units that can be converted to one another using dimensional analysis are not necessarily compatible. For example, both hertz and becquerel are both derived from seconds, but since hertz has the dimension frequency and becquerel has the dimension activity they are not compatible. Units are considered compatible if they are mathematically convertible, and their list of dimensions are equal, order notwithstanding.

(unit* unit1 unit2 . rest)

Create a derived unit by multiplying the provided unit arguments. The name, abbreviation, dimension, and other unit fields are automatically generated.

If a change to the derived unit’s auxillary information (name, abbreviation, etc.) is required, use the derived unit as the base-unit argument of the make-unit procedure.

(define newton-meter (unit* newton meter))
(define foobar (make-unit "foobar" "fb" (unit-dimension newton-meter)
                          newton-meter
                          (lambda (x) x)))
(unit/ unit1 unit2 . rest)

Create a derived unit by dividing the provided unit arguments. The name, abbreviation, dimension, and other unit fields are automatically populated.

(define meters-per-second-squared (unit/ meter (unit* second second)))
unitless

A predefined unit that represents unitless constants. Can be used as a base unit.

ratio

A predefined unit that represents ratios between two quantities. Can be used as a base unit.

angle

A predefined unit that represents angles. Can be used as a base unit.

Dimensions

(make-dimension symbol inverse?)

Returns a new dimension record. The symbol argument is the symbol that represents the dimension, such as 'length. The inverse? argument is a boolean that indicates whether or not the dimension is a reciprocal. The accessor procedures dimension-symbol and dimension-inverse? shall be made available by the SRFI library.

(dimension=? dim1 dim2 . rest)

Returns #t if the provided dimension arguments are equal, #f otherwise. Dimensions are equal if their symbol and inverse? fields are equal by the eq? comparator. An error is signalled if any of the supplied arguments are not dimensions.

dimensionless

A dimension to represent dimensionless quantities.

count

A dimension to represent a count of something.

Math procedures

(qn+ quantity quantity2 . rest)

Add two or more quantities with compatible units, and return a new quantity. The unit of the returned quantity must be compatible with those of all of the provided arguments, but no further requirements regarding the unit conversion are specified. An error is signalled if the units of any argument are incompatible.

Quantities shall be converted to the common unit before addition occurs. For example, adding 10 degrees Celsius to 10 Kelvin does not result in 20 Kelvin. Instead, the 10 degrees Celsius is converted to 283.15 Kelvin, then that quantity is added to the 10 Kelvin quantity.

(qn- quantity quantity2 . rest)

Subtract two or more quantities with compatible units, and return a new quantity. The unit of the returned quantity must be compatible with those of all of the provided arguments, but no further requirements regarding the unit conversion are specified. An error is signalled if the units of any argument are incompatible.

(qn* quantity quantity2 . rest)

Multiply two or more quantities, creating a quantity with a derived unit, that is based on the units of its arguments.

(qn/ quantity quantity2 . rest)

Divide two or more quantities, creating a quantity with a derived unit that is based on the units of its arguments.

The following procedures shall be made available, and provide quantity-specific equivalents to the corresponding R7RS-small procedures. The corresponding R7RS-small procedure can be determined by removing the qn- prefix from the identifier.

qn< qn<= qn=> qn> qn>= qn-abs
qn-ceiling qn-even? qn-exact qn-exact-integer-sqrt qn-expt qn-floor
qn-floor-quotient qn-floor-remainder qn-floor/ qn-inexact
qn-max qn-min qn-modulo qn-negative? qn-numerator qn-odd? qn-positive?
qn-quotient qn-rationalize qn-remainder qn-round qn-square qn-truncate
qn-truncate-quotient qn-truncate-remainder qn-truncate/ qn-zero?

ISQ dimensions

The following dimensions shall be provided in the (srfi 2xx isq) library:

length
mass
time
current
temperature
amount-of-substance
luminous-intensity

Radiation dimensions

The following dimensions shall be provided in the (srfi 2xx radiation) library:

activity
absorbed-dose
equivalent-dose

SI units

The following units shall be provided in the (srfi 2xx si) library:

ampere
becquerel
candela
celsius
coulomb
farad
gram
gray
henry
hertz
joule
katal
kelvin
lumen
lux
meter
mole
newton
ohm
pascal
radian
second
siemens
sievert
steradian
tesla
volt
watt
weber

Each of the following prefixes shall be applied to each of the above units to create prefixed units:

quetta
ronna
yotta
zetta
exa
peta
tera
giga
mega
kilo
hecto
deca
deci
centi
milli
micro
nano
pico
femto
atto
zepto
yocto
ronto
quecto

These units should be implemented as defined by the latest BIPM SI brochure.

Metric units

The following units shall be provided in the (srfi 2xx metric) library:

minute
hour
day
arcminute
arcsecond
astronomical-unit
atmosphere
bar
bel
decibel
carat
dalton
degree
electronvolt
fermi
hectare
jansky
liter
millimeter-of-mercury
neper
parsec
tonne
torr

These units should be implemented as defined by the latest BIPM SI brochure and/or the latest revisions of NIST Special Publication 881 and 330.

Information units

The following units shall be provided in the (srfi 2xx information) library:

bit
trit
nibble
byte
dit

Each of the SI unit prefixes greater than or equal to kilo- shall be applied to each of the above units.

Each of the following prefixes shall also be applied to each of the (unprefixed) units above:

yobi
zebi
exbi
pebi
tebi
gibi
mebi
kibi

The following units shall also be provided:

ban
deciban
shannon
nat
hartley

The following dimensions shall be provided:

data
entropy

These units and dimensions should be implemented as defined by the latest revision of IEC 80000-13.

Imperial units

The following units shall be provided in the (srfi 2xx imperial) library:

acre
bushel
cable
chain
cup
dram
fathom
fluid-ounce
foot
furlong
gallon
grain
hand
hundredweight
inch
knot
link
long-ton
mile
nautical-mile
paris-point
pennyweight
pint
quart
rod
slug
stone
tablespoon
teaspoon
thou
troy-ounce
troy-pound
yard

These units should be implemented as defined by the latest version of the British Weights and Measures Act.

US customary units

The following units shall be provided in the (srfi 2xx us-customary) library:

acre
bushel
cable
chain
cup
dram
farenheit
fathom
fluid-ounce
foot
furlong
gallon
grain
hand
hundredweight
inch
inch-of-mercury
knot
link
long-ton
mile
nautical-mile
pennyweight
pint
quart
rankine
rod
short-ton
slug
tablespoon
teaspoon
thou
troy-ounce
troy-pound
yard

These units should be implemented as defined by the latest revision of NIST Handbook 44.

Centimeter-gram-second (CGS) units

The following units shall be provided in the (srfi 2xx cgs) library:

barye
biot
calorie
darcy
debye
dyne
emu
erg
franklin
gal
gauss
gilbert
kayser
kilocalorie
lambert
langley
line
maxwell
oersted
phot
poise
rad
rem
roentgen
stilb
stokes

These units should be implemented as defined by the latest revisions of NIST Special Publication 881 and 330.

Typographical units

The following units shall be provided in the (srfi 2xx typographic) library:

big-point
cicero
didot-point
pica
point
scaled-point
twip

These units should be implemented as defined by the latest stable release of the TeX Live typesetting system.

Implementation

A compliant sample implementation written in R7RS-small is provided. It depends on SRFI 253.

About

Numbers with units

Resources

Stars

Watchers

Forks

Languages