postgresql-unit
postgresql-unit copied to clipboard
Fractional units
This is an idea to allow fractional dimension units that are powers of 1/2 or 1/4. We use the same amount of storage and just shift all the unit definitions to the left two bits and use those two bits as the binary fractions .5 and .25.
For example we can represent fracture toughness this way...
unit_databases=# select '1.0 psi * in^.5'::unit;
unit
--------------------------------
1098.84349410875 kg/m^0.50*s^2
(1 row)
unit_databases=# select '1.0 ksi * in^.5'::unit;
unit
--------------------------------
1098843.49410875 kg/m^0.50*s^2
(1 row)
unit_databases=# select '1.0 ksi * in^.52'::unit;
ERROR: unit exponent is not allowed "^.52". Fractional part must be be one of: .0, .25, .5, .75.
LINE 1: select '1.0 ksi * in^.52'::unit;
Add predicate function to test if a unit is compatible with a string representation of the unit.
This allows you to add constrains to unit columns.
unit_databases=# create table a (temp unit check(unit_compatible(temp,'degC')));
CREATE TABLE
unit_databases=# insert into a values ('12 degF'::unit);
INSERT 0 1
unit_databases=# insert into a values ('12 degC'::unit);
INSERT 0 1
unit_databases=# insert into a values ('12 degK'::unit);
INSERT 0 1
unit_databases=# insert into a values ('12 m'::unit);
ERROR: new row for relation "a" violates check constraint "a_temp_check"
DETAIL: Failing row contains (12 m).
Hi, when I implemented the module, I was looking at fractional units, and iirc the outcome was that the practical relevance was low. But maybe I was wrong - which units do use them? The Wikipedia article https://en.wikipedia.org/wiki/Fracture_toughness doesn't even talk about the unit which appears as heading in the materials table.
Plane-strain fracture toughness (K_ic) has the SI units MPa m^.5. Its definition and measurement are given in ASTM E399.
Added a predicate function that, given a text parameter, will tell you if that is parseable unit.
unit_databases=# select unit_valid('MPa m^0.5');
unit_valid
------------
t
(1 row)
unit_databases=# select unit_valid('abcdefghijklmnop');
unit_valid
------------
f
(1 row)
unit_databases=# select unit_valid('MPa m^1.2');
unit_valid
------------
f
(1 row)
Also added a function that prints out the value of UnitShifted as a double array...
unit_databases=# select unit_send_array('1 MPa m^0.5'::unit);
unit_send_array
-------------------------------
{1000000,-0.5,1,-2,0,0,0,0,0}
(1 row)
TBH I need some time to think about this. Parts of me says "wtf physics doesn't like these", parts says "yeah people do use them". Then there's also the issue with breaking the on-disk format for people who have actually stored data in "unit" columns. I was actually pondering to halve the bit width of exponents to have room for more basic units (like € or $), this change would best be done with this one in parallel.
A few more ideas that could be useful: add base unit for pixel and cycle. I changed the unit definitions for angle and solid angles to be defined in terms of the new cycle base unit.
With these, it's possible to do things like this ...
unit_database=# select '72 pixel/in'::unit^2 @@ 'pixel^2/mm^2';
?column?
------------------
8.03521607043214
(1 row)
unit_database=# select '1 sr'::unit @@ 'degree^2';
?column?
--------------------
3282.8063500117437
(1 row)
unit_database=# select ('1 Hz'::unit * '.2 seconds'::unit) @@ 'radian';
?column?
--------------------
1.2566370614359172
(1 row)
unit_database=# select '24 bits/pixel'::unit @@ 'MB/(1e6 pixel)';
?column?
----------
3
(1 row)