diff --git a/defined_units.h b/defined_units.h index 0a88d99..6d6e147 100644 --- a/defined_units.h +++ b/defined_units.h @@ -13,27 +13,30 @@ const char *base_units[N_UNITS] = { "mol", "cd", "B", + "cycle", + "pixel", }; +/* Compromise: Allow the rational exponents but don't use more storage: 1, n/2, n/4 */ const struct derived_unit_t si_derived_units[] = { /* https://en.wikipedia.org/wiki/International_System_of_Units#Derived_units */ /* The second is part of this table so we can easily detect its usage for printing it using the hh:mm:ss syntax */ - { "s", { 0, 0, 1, 0, 0, 0, 0, 0,} }, /* second time s */ - { "Hz", { 0, 0, -1, 0, 0, 0, 0, 0,} }, /* hertz frequency s^-1 */ - { "N", { 1, 1, -2, 0, 0, 0, 0, 0,} }, /* newton force, weight kg·m·s^-2 */ - { "Pa", { -1, 1, -2, 0, 0, 0, 0, 0,} }, /* pascal pressure, stress N/m^2 kg·m^-1·s^-2 */ - { "J", { 2, 1, -2, 0, 0, 0, 0, 0,} }, /* joule energy, work, heat N·m kg·m^2·s^-2 */ - { "W", { 2, 1, -3, 0, 0, 0, 0, 0,} }, /* watt power, radiant flux J/s kg·m^2·s^-3 */ - { "C", { 0, 0, 1, 1, 0, 0, 0, 0,} }, /* coulomb electric charge s·A */ - { "V", { 2, 1, -3, -1, 0, 0, 0, 0,} }, /* volt voltage W/A kg·m^2·s^-3·A^-1 */ - { "F", { -2, -1, 4, 2, 0, 0, 0, 0,} }, /* farad electric capacitance C/V kg^-1·m^-2·s^4·A^2 */ - { "Ω", { 2, 1, -3, -2, 0, 0, 0, 0,} }, /* ohm electric resistance, impedance V/A kg·m^2·s^-3·A^-2 */ - { "S", { -2, -1, 3, 2, 0, 0, 0, 0,} }, /* siemens electrical conductance A/V kg^-1·m^-2·s^3·A^2 */ - { "Wb", { 2, 1, -2, -1, 0, 0, 0, 0,} }, /* weber magnetic flux V·s kg·m^2·s^-2·A^-1 */ - { "T", { 0, 1, -2, -1, 0, 0, 0, 0,} }, /* tesla magnetic flux density Wb/m^2 kg·s^-2·A^-1 */ - { "H", { 2, 1, -2, -2, 0, 0, 0, 0,} }, /* henry inductance Wb/A kg·m^2·s^-2·A^-2 */ - { "lx", { -2, 0, 0, 0, 0, 0, 1, 0,} }, /* lux illuminance lm/m^2 m^-2·cd */ - { "Gy", { 2, 0, -2, 0, 0, 0, 0, 0,} }, /* gray absorbed dose (of ionizing radiation) J/kg m^2·s^-2 */ - { "kat", { 0, 0, -1, 0, 0, 1, 0, 0,} }, /* katal catalytic activity mol·s^-1 */ + { "s", { 0*ONES_DIGIT, 0*ONES_DIGIT, 1*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT}, }, /* second time s */ + { "Hz", { 0*ONES_DIGIT, 0*ONES_DIGIT, -1*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 1*ONES_DIGIT, 0*ONES_DIGIT}, }, /* hertz frequency s^-1 */ + { "N", { 1*ONES_DIGIT, 1*ONES_DIGIT, -2*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT}, }, /* newton force, weight kg·m·s^-2 */ + { "Pa", {-1*ONES_DIGIT, 1*ONES_DIGIT, -2*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT}, }, /* pascal pressure, stress N/m^2 kg·m^-1·s^-2 */ + { "J", { 2*ONES_DIGIT, 1*ONES_DIGIT, -2*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT}, }, /* joule energy, work, heat N·m kg·m^2·s^-2 */ + { "W", { 2*ONES_DIGIT, 1*ONES_DIGIT, -3*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT}, }, /* watt power, radiant flux J/s kg·m^2·s^-3 */ + { "C", { 0*ONES_DIGIT, 0*ONES_DIGIT, 1*ONES_DIGIT, 1*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT}, }, /* coulomb electric charge s·A */ + { "V", { 2*ONES_DIGIT, 1*ONES_DIGIT, -3*ONES_DIGIT, -1*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT}, }, /* volt voltage W/A kg·m^2·s^-3·A^-1 */ + { "F", {-2*ONES_DIGIT, -1*ONES_DIGIT, 4*ONES_DIGIT, 2*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT}, }, /* farad electric capacitance C/V kg^-1·m^-2·s^4·A^2 */ + { "Ω", { 2*ONES_DIGIT, 1*ONES_DIGIT, -3*ONES_DIGIT, -2*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT}, }, /* ohm electric resistance, impedance V/A kg·m^2·s^-3·A^-2 */ + { "S", {-2*ONES_DIGIT, -1*ONES_DIGIT, 3*ONES_DIGIT, 2*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT}, }, /* siemens electrical conductance A/V kg^-1·m^-2·s^3·A^2 */ + { "Wb", { 2*ONES_DIGIT, 1*ONES_DIGIT, -2*ONES_DIGIT, -1*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT}, }, /* weber magnetic flux V·s kg·m^2·s^-2·A^-1 */ + { "T", { 0*ONES_DIGIT, 1*ONES_DIGIT, -2*ONES_DIGIT, -1*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT}, }, /* tesla magnetic flux density Wb/m^2 kg·s^-2·A^-1 */ + { "H", { 2*ONES_DIGIT, 1*ONES_DIGIT, -2*ONES_DIGIT, -2*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT}, }, /* henry inductance Wb/A kg·m^2·s^-2·A^-2 */ + { "lx", {-2*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 1*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT}, }, /* lux illuminance lm/m^2 m^-2·cd */ + { "Gy", { 2*ONES_DIGIT, 0*ONES_DIGIT, -2*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT}, }, /* gray absorbed dose (of ionizing radiation) J/kg m^2·s^-2 */ + { "kat",{ 0*ONES_DIGIT, 0*ONES_DIGIT, -1*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 1*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT}, }, /* katal catalytic activity mol·s^-1 */ { 0 } }; diff --git a/unit--7.sql.in b/unit--7.sql.in index 098e9e2..c6c77a3 100644 --- a/unit--7.sql.in +++ b/unit--7.sql.in @@ -37,8 +37,13 @@ CREATE FUNCTION unit_send(unit) AS '$libdir/unit' LANGUAGE C IMMUTABLE STRICT; +CREATE FUNCTION unit_send_array(unit) + RETURNS double precision[] + AS '$libdir/unit' + LANGUAGE C IMMUTABLE STRICT; + CREATE TYPE unit ( - internallength = 16, + internallength = 18, input = unit_in, output = unit_out, receive = unit_recv, @@ -141,6 +146,16 @@ CREATE FUNCTION byte(double precision DEFAULT 1.0) AS '$libdir/unit', 'unit_byte' LANGUAGE C IMMUTABLE STRICT; +CREATE FUNCTION cycle(double precision DEFAULT 1.0) + RETURNS unit + AS '$libdir/unit', 'unit_cycle' + LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION pixel(double precision DEFAULT 1.0) + RETURNS unit + AS '$libdir/unit', 'unit_pixel' + LANGUAGE C IMMUTABLE STRICT; + -- functions without operators CREATE FUNCTION value(unit) @@ -311,6 +326,24 @@ CREATE FUNCTION unit_at_double(unit, text) AS '$libdir/unit', 'unit_at_double' LANGUAGE C IMMUTABLE STRICT; +CREATE FUNCTION unit_compatible(unit, text) + RETURNS boolean + SET search_path = @extschema@ + AS '$libdir/unit', 'unit_compatible' + LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION unit_smallest_pow() + RETURNS double precision + SET search_path = @extschema@ + AS '$libdir/unit', 'unit_smallest_pow' + LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION unit_valid(text) + RETURNS boolean + SET search_path = @extschema@ + AS '$libdir/unit', 'unit_valid' + LANGUAGE C IMMUTABLE STRICT; + CREATE OPERATOR @@ ( leftarg = unit, rightarg = text, diff --git a/unit.c b/unit.c index 7c5c667..e0024f2 100644 --- a/unit.c +++ b/unit.c @@ -14,6 +14,7 @@ GNU General Public License for more details. #include "postgres.h" #include "fmgr.h" +#include "catalog/pg_type.h" #include "libpq/pqformat.h" /* send/recv */ #include "utils/builtins.h" /* cstring_to_text (needed on 9.5) */ #include "utils/guc.h" @@ -75,7 +76,7 @@ unit_get_definitions(void) strlcpy(unit_name->name, base_units[i], UNIT_NAME_LENGTH); unit_name->unit_shift.unit.value = 1.0; memset(unit_name->unit_shift.unit.units, 0, N_UNITS); - unit_name->unit_shift.unit.units[i] = 1; + unit_name->unit_shift.unit.units[i] = ONES_DIGIT; unit_name->unit_shift.shift = 0.0; } } @@ -209,6 +210,20 @@ static char *superscripts[] = { static void print_exponent (char **output_p, int e) { + /* Rational Exponent. Two least significant bits represent 1/2 and 1/4 .*/ + if (ONES_DIGIT > 1 && abs(e)%ONES_DIGIT) + { + /* /2 or /4 */ + *output_p += sprintf(*output_p,"^%.2f",e/((double)ONES_DIGIT)); + return; + } + + /* Integer Exponent */ + e /= ONES_DIGIT; + if(e == 1) + { + return; + } if (unit_output_superscript) { char ascii_exp[5]; int i = 0; @@ -571,6 +586,30 @@ unit_send(PG_FUNCTION_ARGS) PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); } +PG_FUNCTION_INFO_V1(unit_send_array); + +Datum +unit_send_array(PG_FUNCTION_ARGS) +{ + int i; + Unit *unit = (Unit *) PG_GETARG_POINTER(0); + Datum values[1 + N_UNITS]; + ArrayType *result; + + + /* 0 element is the value */ + values[0] = Float8GetDatum(unit->value); + + /* Rest are double values the represent the power */ + for(i = 1; i < N_UNITS + 1; ++i) + { + values[i] = Float8GetDatum((double)unit->units[i-1]/ONES_DIGIT); + } + + result = construct_array(values, 1 + N_UNITS, FLOAT8OID, 8, true, 'd'); + PG_RETURN_POINTER(result); +} + /* constructors */ PG_FUNCTION_INFO_V1 (dbl2unit); @@ -594,7 +633,7 @@ unit_meter (PG_FUNCTION_ARGS) result = (Unit *) palloc0(sizeof(Unit)); result->value = PG_GETARG_FLOAT8(0); - result->units[UNIT_m] = 1; + result->units[UNIT_m] = ONES_DIGIT; PG_RETURN_POINTER(result); } @@ -607,7 +646,7 @@ unit_kilogram (PG_FUNCTION_ARGS) result = (Unit *) palloc0(sizeof(Unit)); result->value = PG_GETARG_FLOAT8(0); - result->units[UNIT_kg] = 1; + result->units[UNIT_kg] = ONES_DIGIT; PG_RETURN_POINTER(result); } @@ -620,7 +659,7 @@ unit_second (PG_FUNCTION_ARGS) result = (Unit *) palloc0(sizeof(Unit)); result->value = PG_GETARG_FLOAT8(0); - result->units[UNIT_s] = 1; + result->units[UNIT_s] = ONES_DIGIT; PG_RETURN_POINTER(result); } @@ -633,7 +672,7 @@ unit_ampere (PG_FUNCTION_ARGS) result = (Unit *) palloc0(sizeof(Unit)); result->value = PG_GETARG_FLOAT8(0); - result->units[UNIT_A] = 1; + result->units[UNIT_A] = ONES_DIGIT; PG_RETURN_POINTER(result); } @@ -646,7 +685,7 @@ unit_kelvin (PG_FUNCTION_ARGS) result = (Unit *) palloc0(sizeof(Unit)); result->value = PG_GETARG_FLOAT8(0); - result->units[UNIT_K] = 1; + result->units[UNIT_K] = ONES_DIGIT; PG_RETURN_POINTER(result); } @@ -659,7 +698,7 @@ unit_mole (PG_FUNCTION_ARGS) result = (Unit *) palloc0(sizeof(Unit)); result->value = PG_GETARG_FLOAT8(0); - result->units[UNIT_mol] = 1; + result->units[UNIT_mol] = ONES_DIGIT; PG_RETURN_POINTER(result); } @@ -672,7 +711,7 @@ unit_candela (PG_FUNCTION_ARGS) result = (Unit *) palloc0(sizeof(Unit)); result->value = PG_GETARG_FLOAT8(0); - result->units[UNIT_cd] = 1; + result->units[UNIT_cd] = ONES_DIGIT; PG_RETURN_POINTER(result); } @@ -685,7 +724,33 @@ unit_byte (PG_FUNCTION_ARGS) result = (Unit *) palloc0(sizeof(Unit)); result->value = PG_GETARG_FLOAT8(0); - result->units[UNIT_B] = 1; + result->units[UNIT_B] = ONES_DIGIT; + PG_RETURN_POINTER(result); +} + +PG_FUNCTION_INFO_V1 (unit_cycle); + +Datum +unit_cycle (PG_FUNCTION_ARGS) +{ + Unit *result; + + result = (Unit *) palloc0(sizeof(Unit)); + result->value = PG_GETARG_FLOAT8(0); + result->units[UNIT_cycle] = ONES_DIGIT; + PG_RETURN_POINTER(result); +} + +PG_FUNCTION_INFO_V1 (unit_pixel); + +Datum +unit_pixel (PG_FUNCTION_ARGS) +{ + Unit *result; + + result = (Unit *) palloc0(sizeof(Unit)); + result->value = PG_GETARG_FLOAT8(0); + result->units[UNIT_pixel] = ONES_DIGIT; PG_RETURN_POINTER(result); } @@ -1065,6 +1130,54 @@ unit_at_double(PG_FUNCTION_ARGS) PG_RETURN_FLOAT8((a->value - bu.shift) / bu.unit.value); } + +PG_FUNCTION_INFO_V1(unit_compatible); +Datum +unit_compatible(PG_FUNCTION_ARGS) +{ + Unit *a = (Unit *) PG_GETARG_POINTER(0); + char *b = text_to_cstring(PG_GETARG_TEXT_PP(1)); + UnitShift bu; + if (unit_parse(b, &bu) > 0) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for unit: \"%s\", %s", + b, yyerrstr))); + PG_RETURN_BOOL(memcmp(a->units, bu.unit.units, N_UNITS)==0); +} + +PG_FUNCTION_INFO_V1(unit_smallest_pow); +Datum +unit_smallest_pow(PG_FUNCTION_ARGS) +{ + PG_RETURN_FLOAT8(1.0/ONES_DIGIT); +} + + +PG_FUNCTION_INFO_V1 (unit_valid); + +Datum +unit_valid (PG_FUNCTION_ARGS) +{ + char *str = text_to_cstring(PG_GETARG_TEXT_PP(0)); + UnitShift result; + bool parse_error_p; + + PG_TRY(); + { + parse_error_p = unit_parse(str, &result) <= 0; + } + PG_CATCH(); + { + parse_error_p = false; + FlushErrorState(); + } + PG_END_TRY(); + + PG_RETURN_BOOL(parse_error_p); +} + + /* comparisons */ static int diff --git a/unit.h b/unit.h index c94e34b..dbb53b1 100644 --- a/unit.h +++ b/unit.h @@ -5,16 +5,20 @@ #include /* indices */ -#define UNIT_m 0 /* meter */ -#define UNIT_kg 1 /* kilogram */ -#define UNIT_s 2 /* second */ -#define UNIT_A 3 /* ampere */ -#define UNIT_K 4 /* kelvin */ -#define UNIT_mol 5 /* mole */ -#define UNIT_cd 6 /* candela */ -#define UNIT_B 7 /* byte */ - -#define N_UNITS 8 +#define UNIT_m 0 /* meter */ +#define UNIT_kg 1 /* kilogram */ +#define UNIT_s 2 /* second */ +#define UNIT_A 3 /* ampere */ +#define UNIT_K 4 /* kelvin */ +#define UNIT_mol 5 /* mole */ +#define UNIT_cd 6 /* candela */ +#define UNIT_B 7 /* byte */ +#define UNIT_cycle 8 /* cycle */ +#define UNIT_pixel 9 /* pixel */ + +#define N_UNITS 10 + +#define ONES_DIGIT (1<<2) /* defined units */ diff --git a/unit_units.data b/unit_units.data index 3581505..2f3f1c1 100644 --- a/unit_units.data +++ b/unit_units.data @@ -13,9 +13,9 @@ mol 1 mol \N mol \N mole 1 mol \N mol \N K 1 K \N K \N kelvin 1 K \N K \N -radian 1 \N 1 \N -sr 1 \N 1 \N -steradian 1 \N sr \N +radian 0.15915494309189535 cycle \N 1 \N +sr 0.025330295910584444 cycle^2 \N 1 \N +steradian 0.025330295910584444 cycle^2 \N sr \N B 1 B \N B \N byte 1 B \N B \N bit 0.125 B \N 1|8 B \N @@ -168,19 +168,19 @@ henry 1 m^2*kg/s^2*A^2 \N V s / A \N H 1 m^2*kg/s^2*A^2 \N henry \N tesla 1 kg/s^2*A \N Wb/m^2 \N T 1 kg/s^2*A \N tesla \N -hertz 1 s^-1 \N /s \N -Hz 1 s^-1 \N hertz \N +hertz 1 cycle*s^-1 \N /s \N +Hz 1 cycle*s^-1 \N hertz \N LENGTH 1 m \N meter \N AREA 1 m^2 \N LENGTH^2 \N VOLUME 1 m^3 \N LENGTH^3 \N MASS 1 kg \N kilogram \N AMOUNT 1 mol \N mole \N -ANGLE 1 \N radian \N -SOLID_ANGLE 1 \N steradian \N +ANGLE 0.15915494309189535 cycle \N radian \N +SOLID_ANGLE 0.025330295910584444 cycle^2 \N steradian \N FORCE 1 m*kg/s^2 \N newton \N PRESSURE 1 kg/m*s^2 \N FORCE / AREA \N STRESS 1 kg/m*s^2 \N FORCE / AREA \N -FREQUENCY 1 s^-1 \N hertz \N +FREQUENCY 1 cycle*s^-1 \N hertz \N DENSITY 1 kg/m^3 \N MASS / VOLUME \N LINEAR_DENSITY 1 kg/m \N MASS / LENGTH \N CURRENT 1 A \N ampere \N @@ -274,7 +274,7 @@ decimalhour 8640 s \N 1|10 day \N decimalminute 86.4000000000000057 s \N 1|100 decimalhour \N decimalsecond 0.864000000000000101 s \N 1|100 decimalminute \N beat 86.4000000000000057 s \N decimalminute \N -pulsatance 1 s^-1 \N radian / sec \N +pulsatance 0.15915494309189535 cycle*s^-1 \N radian / sec \N centrad 0.0100000000000000002 \N 0.01 radian \N percent 0.0100000000000000002 \N 0.01 \N % 0.0100000000000000002 \N percent \N @@ -2287,41 +2287,41 @@ solarirradiance 1361.16369462234866 kg/s^3 \N solarluminosity / (4 pi sundist^2) solarconstant 1361.16369462234866 kg/s^3 \N solarirradiance \N TSI 1361.16369462234866 kg/s^3 \N solarirradiance \N cron 31556925974678.4023 s \N 1e6 years \N -circle 6.28318530717958623 \N 2 pi radian \N -degree 0.0174532925199432955 \N 1|360 circle \N -deg 0.0174532925199432955 \N degree \N -arcdeg 0.0174532925199432955 \N degree \N -arcmin 0.00029088820866572158 \N 1|60 degree \N -arcminute 0.00029088820866572158 \N arcmin \N -' 0.00029088820866572158 \N arcmin \N -arcsec 4.84813681109535984e-06 \N 1|60 arcmin \N -arcsecond 4.84813681109535984e-06 \N arcsec \N -" 4.84813681109535984e-06 \N arcsec \N -'' 4.84813681109535984e-06 \N " \N -rightangle 1.57079632679489656 \N 90 degrees \N -quadrant 1.57079632679489656 \N 1|4 circle \N -quintant 1.25663706143591725 \N 1|5 circle \N -sextant 1.04719755119659763 \N 1|6 circle \N -sign 0.523598775598298816 \N 1|12 circle \N -turn 6.28318530717958623 \N circle \N -revolution 6.28318530717958623 \N turn \N -rev 6.28318530717958623 \N turn \N -gon 0.015707963267948967 \N 1|100 rightangle \N -grade 0.015707963267948967 \N gon \N -centesimalminute 0.000157079632679489682 \N 1|100 grade \N -centesimalsecond 1.57079632679489688e-06 \N 1|100 centesimalminute \N -milangle 0.000981747704246810435 \N 1|6400 circle \N -pointangle 0.19634954084936207 \N 1|32 circle \N -mas 4.84813681109536025e-09 \N milliarcsec \N -seclongitude 7.27220521664303951e-05 \N circle (seconds/day) \N -sphere 12.5663706143591725 \N 4 pi sr \N -squaredegree 0.000304617419786708569 \N 1|180^2 pi^2 sr \N -squareminute 8.46159499407523867e-08 \N 1|60^2 squaredegree \N -squaresecond 2.35044305390978853e-11 \N 1|60^2 squareminute \N -squarearcmin 8.46159499407523867e-08 \N squareminute \N -squarearcsec 2.35044305390978853e-11 \N squaresecond \N -sphericalrightangle 1.57079632679489656 \N 0.5 pi sr \N -octant 1.57079632679489656 \N 0.5 pi sr \N +circle 1 cycle \N 2 pi radian \N +degree 0.002777777777777778 cycle \N 1|360 circle \N +deg 0.002777777777777778 cycle \N degree \N +arcdeg 0.002777777777777778 cycle \N degree \N +arcmin 4.62962962962963e-05 cycle \N 1|60 degree \N +arcminute 4.62962962962963e-05 cycle \N arcmin \N +' 4.62962962962963e-05 cycle \N arcmin \N +arcsec 7.71604938271605e-07 cycle \N 1|60 arcmin \N +arcsecond 7.71604938271605e-07 cycle \N arcsec \N +" 7.71604938271605e-07 cycle \N arcsec \N +'' 7.71604938271605e-07 cycle \N " \N +rightangle 0.25 cycle \N 90 degrees \N +quadrant 0.25 cycle \N 1|4 circle \N +quintant 0.25 cycle \N 1|5 circle \N +sextant 0.16666666666666666 cycle \N 1|6 circle \N +sign 0.08333333333333333 cycle \N 1|12 circle \N +turn 1 cycle \N circle \N +revolution 1 cycle \N turn \N +rev 1 cycle \N turn \N +gon 0.0025 cycle \N 1|100 rightangle \N +grade 0.0025 cycle \N gon \N +centesimalminute 2.5e-5 cycle \N 1|100 grade \N +centesimalsecond 2.5e-7 cycle \N 1|100 centesimalminute \N +milangle 0.00015625 cycle \N 1|6400 circle \N +pointangle 0.03125 cycle \N 1|32 circle \N +mas 7.71604938271605e-10 cycle \N milliarcsec \N +seclongitude 1.1574074074074072e-05 cycle \N circle (seconds/day) \N +sphere 0.3183098861837907 cycle^2 \N 4 pi sr \N +squaredegree 7.71604938271605e-06 cycle^2 \N 1|180^2 pi^2 sr \N +squareminute 2.143347050754458e-09 cycle^2 \N 1|60^2 squaredegree \N +squaresecond 5.953741807651273e-13 cycle^2 \N 1|60^2 squareminute \N +squarearcmin 2.143347050754458e-09 cycle^2 \N squareminute \N +squarearcsec 5.953741807651273e-13 cycle^2 \N squaresecond \N +sphericalrightangle 0.039788735772973836 cycle^2 \N 0.5 pi sr \N +octant 0.039788735772973836 cycle^2 \N 0.5 pi sr \N gasconstant 8.3144598635874285 m^2*kg/s^2*K*mol \N k N_A \N R 8.3144598635874285 m^2*kg/s^2*K*mol \N gasconstant \N molarvolume 0.0224139621193082256 m^3 \N mol R stdtemp / atm \N @@ -2431,8 +2431,8 @@ majorsecond 1.125 \N musicalfifth^2 / octave \N pythagoreanthird 1.265625 \N majorsecond musicalfifth^2 / octave \N syntoniccomma 1.01249999999999996 \N pythagoreanthird / majorthird \N denier 1.11111111111111096e-07 kg/m \N 1|9 tex \N -rpm 0.104719755119659766 s^-1 \N rev/min \N -rps 6.28318530717958623 s^-1 \N rev/sec \N +rpm 0.104719755119659766 cycle*s^-1 \N rev/min \N +rps 1 cycle*s^-1 \N rev/sec \N mbh 293.071070172222278 m^2*kg/s^3 \N 1e3 btu/hour \N hd 0.2384809423920001 m^3 \N hogshead \N RADIATION_DOSE 1 m^2/s^2 \N gray \N diff --git a/unitparse.l b/unitparse.l index bb31953..21e2434 100644 --- a/unitparse.l +++ b/unitparse.l @@ -52,7 +52,7 @@ ALNUM [a-zA-Z$%'"_0-9]|{UTF8} DOUBLE_R [0-9]*\.?[0-9]+([eE][\-+]?[0-9]+)? TIME_R [0-9]+:[0-9]+:[0-9]+(\.[0-9]+)? UNIT_R {ALPHA}{ALNUM}* -EXP_R \^[\-+]?[0-9]+ +EXP_R \^[\-+]?[0-9]*\.?[0-9]+ SUPER_PLUS \xe2\x81\xba SUPER_MINUS \xe2\x81\xbb @@ -294,12 +294,11 @@ SUPER_9 \xe2\x81\xb9 } /* nothing found, error out */ + SPI_finish(); ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("unit \"%s\" is not known", yytext))); - found: - SPI_finish(); /* store computed unit in hash table */ @@ -311,7 +310,15 @@ found: } {EXP_R} { - yyunitlval.EXPONENT = atoi(yytext+1); + yyunitlval.EXPONENT = atof(yytext+1); + /* check if fractional portion of exponent is .0 .25 .5 .75 */ + if (fmod(ONES_DIGIT*fabs(yyunitlval.EXPONENT),1.0) > 1e-12) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("unit exponent is not allowed \"%s\". Fractional part must be a power of 2 and at least %f. ", yytext, 1.0/ONES_DIGIT))); + return ERR; + } return EXPONENT; } diff --git a/unitparse.tab.c b/unitparse.tab.c index fcbffab..2057a41 100644 --- a/unitparse.tab.c +++ b/unitparse.tab.c @@ -154,18 +154,18 @@ union YYUNITSTYPE UnitShift simple_expr; /* DOUBLE */ double DOUBLE; - /* number */ - double number; /* EXPONENT */ - int EXPONENT; + double EXPONENT; /* SUPER_SIGN */ - int SUPER_SIGN; + double SUPER_SIGN; /* SUPER */ - int SUPER; + double SUPER; + /* number */ + double number; /* exponent */ - int exponent; + double exponent; /* super */ - int super; + double super; #line 170 "unitparse.tab.c" /* yacc.c:355 */ }; @@ -1313,10 +1313,10 @@ yyparse (void) #line 67 "unitparse.y" /* yacc.c:1646 */ { int i; - if ((*(int*)(&yyvsp[0])) != 1) { - (*(UnitShift*)(&yyval)).unit.value = pow((*(UnitShift*)(&yyvsp[-1])).unit.value, (*(int*)(&yyvsp[0]))); + if ((*(double*)(&yyvsp[0])) != 1) { + (*(UnitShift*)(&yyval)).unit.value = pow((*(UnitShift*)(&yyvsp[-1])).unit.value, (*(double*)(&yyvsp[0]))); for (i = 0; i < N_UNITS; i++) - (*(UnitShift*)(&yyval)).unit.units[i] = (*(UnitShift*)(&yyvsp[-1])).unit.units[i] * (*(int*)(&yyvsp[0])); + (*(UnitShift*)(&yyval)).unit.units[i] = (*(UnitShift*)(&yyvsp[-1])).unit.units[i] * (*(double*)(&yyvsp[0])); } else { (*(UnitShift*)(&yyval)) = (*(UnitShift*)(&yyvsp[-1])); } @@ -1411,13 +1411,13 @@ yyparse (void) case 19: #line 127 "unitparse.y" /* yacc.c:1646 */ - { (*(int*)(&yyval)) = (*(int*)(&yyvsp[-1])) * (*(int*)(&yyvsp[0])); } + { (*(double*)(&yyval)) = (*(double*)(&yyvsp[-1])) * (*(double*)(&yyvsp[0])); } #line 1416 "unitparse.tab.c" /* yacc.c:1646 */ break; case 22: #line 133 "unitparse.y" /* yacc.c:1646 */ - { (*(int*)(&yyval)) = 10 * (*(int*)(&yyvsp[-1])) + (*(int*)(&yyvsp[0])); } + { (*(double*)(&yyval)) = 10 * (*(double*)(&yyvsp[-1])) + (*(double*)(&yyvsp[0])); } #line 1422 "unitparse.tab.c" /* yacc.c:1646 */ break; diff --git a/unitparse.tab.h b/unitparse.tab.h index 43aa009..0e76d86 100644 --- a/unitparse.tab.h +++ b/unitparse.tab.h @@ -79,18 +79,18 @@ union YYUNITSTYPE UnitShift simple_expr; /* DOUBLE */ double DOUBLE; - /* number */ - double number; /* EXPONENT */ - int EXPONENT; + double EXPONENT; /* SUPER_SIGN */ - int SUPER_SIGN; + double SUPER_SIGN; /* SUPER */ - int SUPER; + double SUPER; + /* number */ + double number; /* exponent */ - int exponent; + double exponent; /* super */ - int super; + double super; #line 95 "unitparse.tab.h" /* yacc.c:1909 */ }; diff --git a/unitparse.y b/unitparse.y index b646ae4..5321922 100644 --- a/unitparse.y +++ b/unitparse.y @@ -32,11 +32,11 @@ static UnitShift *unit_parse_result; /* parsing result gets stored here */ %define api.value.type union %token DOUBLE %token UNIT_SHIFT -%token EXPONENT SUPER_SIGN SUPER +%token EXPONENT SUPER_SIGN SUPER %token ERR %type input expr simple_expr %type number -%type exponent super +%type exponent super %left '+' '-' %left '/'