summaryrefslogtreecommitdiffstats
path: root/usr.bin
diff options
context:
space:
mode:
authordwmalone <dwmalone@FreeBSD.org>2008-08-16 16:27:41 +0000
committerdwmalone <dwmalone@FreeBSD.org>2008-08-16 16:27:41 +0000
commit0d283f41de78a4d50b4f1e8c376fb3beff51234d (patch)
tree9b55a8af84521593b5152c7d580467904e865b4d /usr.bin
parent396faad5a15f348b13bcbb696fe3dda7640e7bd5 (diff)
downloadFreeBSD-src-0d283f41de78a4d50b4f1e8c376fb3beff51234d.zip
FreeBSD-src-0d283f41de78a4d50b4f1e8c376fb3beff51234d.tar.gz
Add limited support for units that are related by affine rather
than linear relations. We can now convert degC to degF. 586 units, 56 prefixes You have: 24 degC You want: degF 75.2 You have: degC You want: K (-> x*1 +273.15) (<- y*1 -273.15)
Diffstat (limited to 'usr.bin')
-rw-r--r--usr.bin/units/units.c75
-rw-r--r--usr.bin/units/units.lib10
2 files changed, 63 insertions, 22 deletions
diff --git a/usr.bin/units/units.c b/usr.bin/units/units.c
index 9ca5cda..e700c94 100644
--- a/usr.bin/units/units.c
+++ b/usr.bin/units/units.c
@@ -53,6 +53,8 @@ struct unittype {
char *numerator[MAXSUBUNITS];
char *denominator[MAXSUBUNITS];
double factor;
+ double offset;
+ int quantity;
};
struct {
@@ -78,7 +80,7 @@ void initializeunit(struct unittype * theunit);
int addsubunit(char *product[], char *toadd);
void showunit(struct unittype * theunit);
void zeroerror(void);
-int addunit(struct unittype * theunit, char *toadd, int flip);
+int addunit(struct unittype *theunit, char *toadd, int flip, int quantity);
int compare(const void *item1, const void *item2);
void sortunit(struct unittype * theunit);
void cancelunit(struct unittype * theunit);
@@ -207,8 +209,10 @@ readunits(const char *userfile)
void
initializeunit(struct unittype * theunit)
{
- theunit->factor = 1.0;
theunit->numerator[0] = theunit->denominator[0] = NULL;
+ theunit->factor = 1.0;
+ theunit->offset = 0.0;
+ theunit->quantity = 0;
}
@@ -237,6 +241,8 @@ showunit(struct unittype * theunit)
int counter = 1;
printf("\t%.8g", theunit->factor);
+ if (theunit->offset)
+ printf("&%.8g", theunit->offset);
for (ptr = theunit->numerator; *ptr; ptr++) {
if (ptr > theunit->numerator && **ptr &&
!strcmp(*ptr, *(ptr - 1)))
@@ -284,16 +290,17 @@ zeroerror(void)
/*
Adds the specified string to the unit.
Flip is 0 for adding normally, 1 for adding reciprocal.
+ Quantity is 1 if this is a quantity to be converted rather than a pure unit.
Returns 0 for successful addition, nonzero on error.
*/
int
-addunit(struct unittype * theunit, char *toadd, int flip)
+addunit(struct unittype * theunit, char *toadd, int flip, int quantity)
{
char *scratch, *savescr;
char *item;
- char *divider, *slash;
+ char *divider, *slash, *offset;
int doingtop;
if (!strlen(toadd))
@@ -313,7 +320,17 @@ addunit(struct unittype * theunit, char *toadd, int flip)
item = strtok(scratch, " *\t\n/");
while (item) {
if (strchr("0123456789.", *item)) { /* item is a number */
- double num;
+ double num, offsetnum;
+
+ if (quantity)
+ theunit->quantity = 1;
+
+ offset = strchr(item, '&');
+ if (offset) {
+ *offset = 0;
+ offsetnum = atof(offset+1);
+ } else
+ offsetnum = 0.0;
divider = strchr(item, '|');
if (divider) {
@@ -323,19 +340,25 @@ addunit(struct unittype * theunit, char *toadd, int flip)
zeroerror();
return 1;
}
- if (doingtop ^ flip)
+ if (doingtop ^ flip) {
theunit->factor *= num;
- else
+ theunit->offset *= num;
+ } else {
theunit->factor /= num;
+ theunit->offset /= num;
+ }
num = atof(divider + 1);
if (!num) {
zeroerror();
return 1;
}
- if (doingtop ^ flip)
+ if (doingtop ^ flip) {
theunit->factor /= num;
- else
+ theunit->offset /= num;
+ } else {
theunit->factor *= num;
+ theunit->offset *= num;
+ }
}
else {
num = atof(item);
@@ -343,12 +366,16 @@ addunit(struct unittype * theunit, char *toadd, int flip)
zeroerror();
return 1;
}
- if (doingtop ^ flip)
+ if (doingtop ^ flip) {
theunit->factor *= num;
- else
+ theunit->offset *= num;
+ } else {
theunit->factor /= num;
-
+ theunit->offset /= num;
+ }
}
+ if (doingtop ^ flip)
+ theunit->offset += offsetnum;
}
else { /* item is not a number */
int repeat = 1;
@@ -534,7 +561,7 @@ reduceproduct(struct unittype * theunit, int flip)
free(*product);
*product = NULLUNIT;
}
- if (addunit(theunit, toadd, flip))
+ if (addunit(theunit, toadd, flip, 0))
return ERROR;
}
}
@@ -613,6 +640,20 @@ showanswer(struct unittype * have, struct unittype * want)
showunit(have);
showunit(want);
}
+ else if (have->offset != want->offset) {
+ if (want->quantity)
+ printf("WARNING: conversion of non-proportional quantities.\n");
+ printf("\t");
+ if (have->quantity)
+ printf("%.8g\n",
+ (have->factor + have->offset-want->offset)/want->factor);
+ else
+ printf(" (-> x*%.8g %+.8g)\n\t (<- y*%.8g %+.8g)\n",
+ have->factor / want->factor,
+ (have->offset-want->offset)/want->factor,
+ want->factor / have->factor,
+ (want->offset - have->offset)/have->factor);
+ }
else
printf("\t* %.8g\n\t/ %.8g\n", have->factor / want->factor,
want->factor / have->factor);
@@ -666,10 +707,10 @@ main(int argc, char **argv)
strlcpy(havestr, argv[optind], sizeof(havestr));
strlcpy(wantstr, argv[optind + 1], sizeof(wantstr));
initializeunit(&have);
- addunit(&have, havestr, 0);
+ addunit(&have, havestr, 0, 1);
completereduce(&have);
initializeunit(&want);
- addunit(&want, wantstr, 0);
+ addunit(&want, wantstr, 0, 1);
completereduce(&want);
showanswer(&have, &want);
}
@@ -687,7 +728,7 @@ main(int argc, char **argv)
putchar('\n');
exit(0);
}
- } while (addunit(&have, havestr, 0) ||
+ } while (addunit(&have, havestr, 0, 1) ||
completereduce(&have));
do {
initializeunit(&want);
@@ -698,7 +739,7 @@ main(int argc, char **argv)
putchar('\n');
exit(0);
}
- } while (addunit(&want, wantstr, 0) ||
+ } while (addunit(&want, wantstr, 0, 1) ||
completereduce(&want));
showanswer(&have, &want);
}
diff --git a/usr.bin/units/units.lib b/usr.bin/units/units.lib
index d7c0796..67127bc 100644
--- a/usr.bin/units/units.lib
+++ b/usr.bin/units/units.lib
@@ -671,14 +671,14 @@ Xunit 1.00206e-13 m
k 1.38047e-16 erg/degC
-degC K
+degC 1&+273.15 K
kelvin K
brewster 1e-12 m2/newton
-degF 5|9 degC
-degreesrankine degF
+degF 5|9&255.37222222222222222222 K
+degreesrankine 5|9 K
degrankine degreesrankine
-degreerankine degF
-degreaumur 10|8 degC
+degreerankine degreesrankine
+degreaumur 10|8&+273.15 K
drachm 60 grain
poncelet 100 kg m g / sec
denier .05|450 gram / m
OpenPOWER on IntegriCloud