From 3111804c06112dfade510909dc4cd3860fb9da55 Mon Sep 17 00:00:00 2001 From: Matthias Schmidt Date: Thu, 4 Dec 2008 15:10:23 +0100 Subject: [PATCH] Update units(1) to allow conversion between degC and degF This patch (in modified form from FreeBSD) rested for some time on my disk, so I'll throw it in. It allows conversion between Celsius and Fahrenheit: You have: 20 degC You want: degF 68 Reminded-by: corecode@ --- usr.bin/units/units.1 | 9 +++-- usr.bin/units/units.c | 77 +++++++++++++++++++++++++++++++---------- usr.bin/units/units.lib | 13 ++++--- 3 files changed, 71 insertions(+), 28 deletions(-) diff --git a/usr.bin/units/units.1 b/usr.bin/units/units.1 index 491d1656d4..8232e99f9c 100644 --- a/usr.bin/units/units.1 +++ b/usr.bin/units/units.1 @@ -1,6 +1,6 @@ .\" $FreeBSD: src/usr.bin/units/units.1,v 1.18 2005/02/13 22:25:25 ru Exp $ .\" $DragonFly: src/usr.bin/units/units.1,v 1.4 2008/08/12 09:28:22 matthias Exp $ -.Dd August 12, 2008 +.Dd December 4, 2008 .Dt UNITS 1 .Os .Sh NAME @@ -37,8 +37,7 @@ The .Nm program can only handle multiplicative scale changes. -It cannot convert Celsius -to Fahrenheit, for example. +Experimental support is available to convert Celsius to Fahrenheit. It works interactively by prompting the user for input: .Bd -literal @@ -61,6 +60,10 @@ the user for input: You want: cm * 1.27 / 0.78740157 + + You have: 20 degC + You want: degF + 68 .Ed .Pp Powers of units can be specified using the '^' character as shown in diff --git a/usr.bin/units/units.c b/usr.bin/units/units.c index a05e224c4c..0f3fb9a79f 100644 --- a/usr.bin/units/units.c +++ b/usr.bin/units/units.c @@ -14,7 +14,7 @@ * I would appreciate (though I do not require) receiving a copy of any * improvements you might make to this program. * - * $FreeBSD: src/usr.bin/units/units.c,v 1.6.2.2 2001/03/04 09:22:35 kris Exp $ + * $FreeBSD: src/usr.bin/units/units.c,v 1.11 2008/08/16 16:27:41 dwmalone Exp $ * $DragonFly: src/usr.bin/units/units.c,v 1.4 2006/08/13 19:19:44 swildner Exp $ */ @@ -51,6 +51,8 @@ struct unittype { char *numerator[MAXSUBUNITS]; char *denominator[MAXSUBUNITS]; double factor; + double offset; + int quantity; }; struct { @@ -72,7 +74,7 @@ int prefixcount; static int addsubunit(char *[], char *); -static int addunit(struct unittype *, char *, int); +static int addunit(struct unittype *, char *, int, int); static void cancelunit(struct unittype *); static int compare(const void *, const void *); static int compareproducts(char **, char **); @@ -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 8e247fbb9d..47e2616540 100644 --- a/usr.bin/units/units.lib +++ b/usr.bin/units/units.lib @@ -1,5 +1,4 @@ -/ $FreeBSD: src/usr.bin/units/units.lib,v 1.18 2008/08/07 05:35:01 edwin Exp $ -/ $DragonFly: src/usr.bin/units/units.lib,v 1.4 2008/08/12 09:28:22 matthias Exp $ +/ $FreeBSD: src/usr.bin/units/units.lib,v 1.19 2008/08/16 16:27:41 dwmalone Exp $ / primitive units @@ -672,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 -- 2.41.0