Skip to content

Commit

Permalink
Add limited support for units that are related by affine rather
Browse files Browse the repository at this point in the history
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)
  • Loading branch information
dwmalone committed Aug 16, 2008
1 parent f70f5c2 commit 9c95bc1
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 22 deletions.
75 changes: 58 additions & 17 deletions usr.bin/units/units.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ struct unittype {
char *numerator[MAXSUBUNITS];
char *denominator[MAXSUBUNITS];
double factor;
double offset;
int quantity;
};

struct {
Expand All @@ -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);
Expand Down Expand Up @@ -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;
}


Expand Down Expand Up @@ -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)))
Expand Down Expand Up @@ -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))
Expand All @@ -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) {
Expand All @@ -323,32 +340,42 @@ 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);
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;
}
}
if (doingtop ^ flip)
theunit->offset += offsetnum;
}
else { /* item is not a number */
int repeat = 1;
Expand Down Expand Up @@ -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;
}
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}
Expand All @@ -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);
Expand All @@ -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);
}
Expand Down
10 changes: 5 additions & 5 deletions usr.bin/units/units.lib
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 9c95bc1

Please sign in to comment.