Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
GNU Units (gnu.org)
421 points by tosh on Jan 6, 2021 | hide | past | favorite | 203 comments


My first exposure to GNU Units was when I read the story about emails failing if they were to be sent more than 500 miles.

I’m sure it’s popped up here before but here’s a link for those who haven’t come across it: https://www.ibiblio.org/harris/500milemail.html


Same here back in the early aughts, but it took me a while to really dig in and discover that units also handles times too.

e.g. units "sec $(echo $SECONDS)" "day;hr;min;sec"


Useless use of echo there.


It's very important to watch out for useless uses of echo/cat. What is cat, a few megabytes now? Fine for those of us on modern hardware, but you never know what PDP-11 user is going to copy paste your comment into their terminal.


Not unless you’re also trying to demonstrate the magic of fork.


Extraneously strenuous use of "useless" when using "redundant" would have done...unless useless has another usage.

EDIT: The commenter echoed, duckly.


I use a construct like this to ensure that the value ends with a newline.


$() chomps the newline though...


noted, thanks


First time user. Failed on me.

    You have: 25 C
    You want: K
    conformability error
        25 A s
        1 K

    You have: 1 cup flour
    Unknown unit 'flour'
I think I'll stick with Google.


Well, flour isn't a unit...


It's relevant information if you're converting to mass, which was probably the intention. Google will return the correct result for "mass 1 cup flour", by comparison.


There is no correct way to turn "1 cup flour" into a mass. For one thing, you can fit more into the same volume by compressing. But more importantly, the material is ambiguous. There are many different kinds of flour with varying physical properties.


Neither is cup...



Last time this showed up on here, a poster claimed to be the consultant who did the upgrade and caused the problem.


Same here... And I think it was quoted here a week or so ago again. Great story.


Fun story, but the numbers don't add up for me:

Wouldn't the signal have to do a full round trip within the timeout of 3 ms, meaning it could not go beyond 580 / 2 = 290 miles?

Additionally, the connection from A to B is usually not a straight line, and at that time fiber lines were much less widespread. All these factors combines make it unlikely that even 200 miles could be reached...


The FAQ [1] addresses both of these questions. See numbers 8 and 15, respectively.

[1]: https://www.ibiblio.org/harris/500milemail-faq.html


Thanks for that link.

> Well, to start with, it can't be three milliseconds, because that would only be for the outgoing packet to arrive at its destination. You have to get a response, too, before the timeout will be aborted. Shouldn't it be six milliseconds?

> Of course. This is one of the details I skipped in the story. It seemed irrelevant, and boring, so I left it out.

I don't understand, so it was in fact 6 ms?


I remember chatting with Trey about this as it happened in real time.

I love that every time this link gets posted to HN someone says it looks like a hoax.


I never claimed it was a hoax, I just didn't agree with the math, that's all. No reason to get upset.


I love that every time someone says something is a hoax a person who was there shows up to correct the record :)


I wanna see that happen for The Loch Ness monster!


This is addressed in the FAQ[1].

> That three millisecond time doesn't make sense as the timeout for a connect() call.

> Yes, I know. And it wasn't the timeout, actually. In the story, I make it sound like it took all of ten minutes from being made aware of the 500-mile email limit and determining a 3 ms light-speed issue. In fact, this took several hours, and quite a bit of detective work. The point is, eventually I came up with that figure, ran units, and gagged on my latte. (I'm fairly certain it was a different latte from the one I started with.) So what, in particular, is your question about the 3 ms figure?

[1] https://www.ibiblio.org/harris/500milemail-faq.html


A simple example I used recently in order to guesstimate how much energy is needed to heat 300liters of water by 5K:

  You have: 5K * 300kg * water_specificheat
  You want: kWh
  * 1.7433333
really easy to use.

How much power could you obtain with a small water turbine if you had 10m of head and 1l/s ? Easy !

  You have: 10m * 1kg/s * gravity
  You want: W
  * 98.0665


Thanks, I did not know that units is able to work with constants. I always used Insect[0] for this.

0: https://github.com/sharkdp/insect


I do these kind of calculations all of the time and never realize units had this level of functionality. Wow, thanks Faaak!


I kept reading this as “water specific cheat” and was really confused.


~ units

586 units, 56 prefixes

You have: 50m * 1kg/s * gravity

unknown unit 'gravity'

how did you get gravity?


  $ units
  Currency exchange rates from FloatRates (USD base) on 2020-12-21
  3677 units, 109 prefixes, 114 nonlinear units
  
  You have: 10m * 1kg/s * gravity
  You want: W
          * 98.0665
          / 0.010197162
  You have:
You lack some units and prefixes.


How do you get the other units/prefixes?

EDIT: Figured it out, just had to brew install gnu-units


I’ve always wondered why units(1) isn’t a library. I’d love to have access to abstract “united quantities” and “united measurements” in my HLL of choice, rather than needing to switch to a special-purpose tool (units, Frink) or a statistical-analysis language like R just to get them.

Sometimes I need to bust out stoichiometry-like unit-balancing in the middle of my code, and I want type enforcement that I’m getting the right units in the output! Sometimes I want to do a series of floating-point calculations, and I need to put error-bars on the result, and it’d be great if those were tracked for me in the form of a measurement ADT that tracked sig-figs. Etc.

My only guess for why there’s no libunits, is that it’d be a obtrusive black-box of operational non-guarantees if it was implemented in C, given that what Units does — if naively implemented — would be heavy on arbitrary memory allocations, and basically necessitate garbage collection.

It’d make much more sense for a libunits to exist as a C++-ish “template library” that takes an allocator as an argument; but that doesn’t really help anyone who wants to use any language other than C++ (as the template parameters can’t be exposed in the C wrapper code that other languages FFI to.)

(Before someone asks, you could get a limited kind of united-quantities — ones that can only represent “realistic” units — with a static per-qty bitfield representing the compiled-in units. But this wouldn’t really let you represent arbitrary unexpected “unit polynomial” qtys, e.g. m^5s^-3. This might seem fine, but sometimes intermediate quantities in formulae look like that, even though they work out to something sensible when everything is multiplied out.)

Even if there couldn’t be a single units library implementation, it’d at least make sense for there to be 1. a canonical libunits-data release (sort of like tzdata), that individual library impls could pull in; and 2. a high-level API spec or reference-impl of what a libunits library for a given language-runtime would look like (sort of like how every HLL has copied JodaTime’s datetime design.)


I've seen a few before, and a quick search yielded a bunch for me, right off the bat. By no means exhaustive:

Julia: https://github.com/PainterQubits/Unitful.jl

Python: https://pint.readthedocs.io/en/0.6/

C++: https://github.com/nholthaus/units

etc.

And yes, it has always struck me as strange that date/time/calendar utilities are standard as canonical functionality shipped with language distributions, but units are not.



The source isn't that big, I just downloaded 2.21 source and it is one directory with about ~45 files, and the majority of bytes are for /doc/dvi binaries, only 5 c files and a post Yacc'd tab file for parsing the units definitions file. Surprisingly simple now that I look at it.

Heck... I was going ask you to write it, but now I'm thinking this could be a fun weekend project.

I can see one function in that library:

    bool convert(const char *from, const char *to, double input, double *output);
No need to make it more complex for starters. If you want to make an .hxx Boost-like class around it, that's outta my league!

EDIT: markdown help

EDIT: added a status return instead of val return to check for conversion correctness (bool is newer C)


> (...how the heck do I make a literal asterisk in HN markdown?)

Spaces on both sides: const char * from

But also you are supposed to mark up code by indenting with four spaces, and then everything will be treated as verbatim text:

    const char *from


There are heaps of libraries for all languages because it is a fairly fun and straight forward project. I personally created this one because I was frustrated with how slow and clunky the existing javascript libraries were:

https://github.com/GhostWrench/pqm

Also, I open sourced just the unit database (in JSON format) for anyone interested in making their own version:

https://github.com/GhostWrench/unitdb


Commenting on my own thread because the window to edit has passed. What is up with the haters today? I share a useful open-source library with everyone that I spent a ton of time working on only to get crapped on by the know-it-all crew? Did you even click the link and read the github readme? This library is tested against NIST data! It also has 100% test coverage and support for corner cases like non-linear unit conversions like temperature. How does anyone enjoy participating in this community?


HN has a huge number of users, most of whom don't comment on any given topic. So I think it's best to not care too much what the handful of individuals who interact with you happen to think.

I went to search through dang's comment history to see whether he's posted any statistics to make that "huge number of users" more precise, but instead I found this comment which explains it better than any statistics: https://news.ycombinator.com/item?id=18523361


> straight forward project.

Assuming this is straightforward is as wrong as with calendars / time Systems.


What makes you say that? I suppose you could add as much complexity as you want with differentiating units from different standards and adding uncertainty in the unit definitions and on and on. But for 99% percent of users, just conversion factors and basic arithmetic operations are all that is needed. What application do you have in mind where this would fall short? In 15 years as an engineer I have not run into one.


What day is it?

Be conservative in what you send, be liberal in what you accept.

leap years, leap seconds, julian dates, pre-gregorian dates, years beyond 9999, yyyy-mm-dd vs d/m/y vs month day year vs ..., zero padding, 12 hour vs 24 hour, 32 bit time stamps, DOS time accurate to every two seconds, why does excel need the date time in a specific format, I dual boot between Windows10 and Linux and every-time I boot up Windows10 the first thing I need to do is adjust the date time, pico-second granularity, time zones, daylight savings time, ...

Today is Stability (4), Flint (Tijaax * Etznab)

It's a good day to: Spend time in reflection and introspection.


What are you talking about? The topic is unit conversion, not datetime libraries.


Don't disagree that datetime libraries that are used to control computer networking are immensely complex. Never said they weren't. However:

1) That is not what we are talking about

2) Sometimes you just need a stopwatch, timing applications _can_ be simple


There's also uom for Rust https://github.com/iliekturtles/uom which also provides types for type level operations


You means something like this? http://www.dmitry-kazakov.de/ada/units.htm


Very much so! But I don’t think I can link Ada libraries into my Ruby or Elixir codebase :)


> I don’t think I can link Ada libraries into my Ruby or Elixir codebase

Ruby has (among others, I’m certain): https://github.com/olbrich/ruby-units


Keeping track of units was one of the first ever uses of C++ templates (one of the Bjarne books IIRC mentions it existing prior to the STL), but was apparently reinvented multiple times later.


Looks cool. If the poster is affiliated with the project, some suggestions:

1. I don't know what I am looking at with the examples. I think that this is an interactive session with the program, but this is not clear. 2. It is also unclear how to start the program as the executable name is not specified. This and the former point could be addressed by including one of those gifs of an interactive session that are popular in GitHub readmes these days. Sure, they are a bit gimmicky, but still useful. 3. It is not clearly stated if this is an executable program or a library. I believe it is the former, but this is nowhere in the introduction. 4. Probably this is included with a number of package managers. If that is the case, instructions for installing via a package manager would be helpful, especially since the name is not particularly unique.


No please don't use a gif. That's a terrible way to present information and leads to accessibility issues in documentation where it has no business. Instead, just show a shell prompt and the command needed to launch the program.


So long as those with disabilities are also accounted for, using gifs are a great way to demonstrate usage. I always appreciate running across them when I hit a readme.


I see how they're useful, but I'm still not fond of them because:

(1) Often, the speed is wrong. Either they play too fast to follow along or they play too slowly and time is wasted waiting for it to show me the part I care about (or loop back around).

It's hard to get the speed just right. And AFAIK browsers don't offer controls to adjust the speed, and even if they did, it would be tedious.

(2) Personally I find animations (especially rapid or looping ones) quite distracting when trying to read the rest of the page. My eye just keeps moving to the thing that's trying to grab my attention.

I usually try to work around that by scrolling so that the animation is out of view. So, I'll live, but it's not a good user experience. And again, (some?) browsers seem to offer no help, like a setting to always enable animation controls (play/pause/etc.) or to loop only once.


Out of curiosity, what makes gifs better than static text for you?


I dislike them, but I see one benefit: they increase effective screen real estate by leveraging time as an additional dimension.

I guess they also allow you to passively view a sequence of stuff instead of having to actively scroll to move through the sequence. Maybe that feels easier to some people.


There's a link to the documentation [0] right on the page. The documentation is very clear.

People should read their package manager's documentation for help using their package manager.

[0] https://www.gnu.org/software/units/manual/units.html


I agree with you, but package names aren't predictable. I find that an example of installing a package is helpful even for users familiar with use of package managers as it gives context and helps readability. Whenever I see `sudo apt-get somethingsomething` I immediately know that somethingsomething is the package name.


Application developers typically do not decide package names (unless they provide their own package repository), distribution maintainers do. Package names may change over time, and might be different for different distributions (or even between different versions of the same distribution), even if they use the same package format.

Of course, application developers may decide anyway to keep track of package names for their N favourite distributions and display them on their website. But to me it comes across as a waste of useful space.


It's an old GNU tool. The package name will be "units" everywhere.


On Homebrew, at least, it's `gnu-units`.

If you try to install just `units`, brew is smart enough to suggest it, however.


This is a GNU implementation of an old UNIX tool. It’s older than Linux, let alone package managers. There’s also BSD and other implementations available (the BSD version comes pre-installed on macOS).

This isn’t some new tool that is uncommon in UNIX systems, it’s something that a lot of OSs ship with their base install and have done for several decades.

The reason why that matters is because documentation was very different back then. People relied on ‘man’ pages and physical binders with printed instructions. READMEs did exist but they were plain text (not even markdown) and that was generally just there to explain how to compile the source (the compilation would create man pages)


> the BSD version comes pre-installed on macOS

As discussed elsewhere in the thread (https://news.ycombinator.com/item?id=25659223), it looks like macOS uses an early version of GNU Units.


Ahh yes, before it adopted GPL. I should have spotted that because it’s very typical of Apple hehe


Maybe a shell script showing the inputs more explicitly would help?

    echo -e '500 miles\nkm' | gnu-units-executable-name
But I'm pretty sure from reading the post that units prompts you first for 'you have' (units and/or measurement to convert) and then prompts you for 'you want' (units to convert to).


I recommend the "-1" (also called "--one-line") flag for bc.

It takes away the extra (to me) reciprocal conversion factors. (Note: it's the number one, not a lowercase "L".)

Without:

    $ units 
    Currency exchange rates from FloatRates (USD base) on 2019-05-31 
    3460 units, 109 prefixes, 109 nonlinear units
    
    You have: inch
    You want: cm
     * 2.54
     / 0.39370079
    You have: 
With:

    $ units -1
    Currency exchange rates from FloatRates (USD base) on 2019-05-31 
    3460 units, 109 prefixes, 109 nonlinear units
    
    You have: inch
    You want: cm
     * 2.54
    You have: 
To me the reciprocals are just clutter. If I want a reciprocal, I will just type the two parts of my query in the opposite order. I'd even say they're confusing because you have to look at them understand why there are two numbers.

(Also on the subject of flags, I'd like one that suppresses the first two lines of output but not the prompts like "You have:".)


Did you paste that printout from a recent run of units? If so, the currency rates are pretty useless. You can configure the system to update them daily (or however you like) with something like this:

  $ cat /etc/systemd/system/units-currency-update.service
  [Unit]
  Description=Update units(1) currency rates
  
  [Service]
  Type=oneshot
  Nice=19
  
  ExecStart=/usr/bin/units_cur
  
  
  
  $ cat /etc/systemd/system/units-currency-update.timer
  [Unit]
  Description=Update units(1) currency rates
  
  [Timer]
  OnCalendar=daily
  AccuracySec=3h
  RandomizedDelaySec=3h
  Persistent=true
  
  [Install]
  WantedBy=timers.target
  
  
  # systemctl daemon-reload
  # systemctl enable units-currency-update.timer


Or just something like

  0 0 * * * nice -n 19 /usr/bin/units_cur
for *BSD crontabs or both HN users (besides me) who prefer systemd-free distros of GNU


Corrections (b/c too late to edit):

(1) The flag isn't for bc, of course; it's for units. I'm always running the wrong one, so no surprise I mixed them up again.

(2) Should read "look at them to understand" near the end.


I started using this tool some years ago after I found out the CO₂ cost of a Google search. I don't need a web query when I search "40000lb in tonnes" when reading an American news article, for example.

  units 40000lb tonnes
   * 18.143695
It even includes currencies. "sudo units_cur" will update the exchange rate data file, if you need that.

  units 50GBP USD
   * 68.143948


> "sudo units_cur" will update the exchange rate data file, if you need that.

Oh good tip that. I noticed the package on Ubuntu 20.04 came with currency conversion from 2019. Not very useful without updating it.


> It even includes currencies. "sudo units_cur" will update the exchange rate data file, if you need that.

Doesn't work for XDR. Of course, who needs XDR? I sure don't. But you can get the XDR exchange rate with this command:

curl -d '__EVENTTARGET=lbnTSV' https://www.imf.org/external/np/fin/data/rms_sdrv.aspx

Maybe someone should integrate that into units_cur.


> Like many similar programs, it can handle multiplicative scale changes. It can also handle nonlinear conversions such as Fahrenheit to Celsius

how is

  C = (5/9)(F-32)
not linear?


In certain contexts (such as linear algebra), linear refers to the fact that the mapping must cross the origin.

This follows from the constraint that for a linear map f, f(a + b) = f(a) + f(b), which is not true for the farenheit-celsius example.

EDIT: See https://en.wikipedia.org/wiki/Linear_function#As_a_linear_ma...


Also: a linear function plus a constant is said to be affine!

Reference: https://mathworld.wolfram.com/AffineFunction.html


I just learned something. Is it correct to call both of the first order? Or is that term really only to be used for the underlying polynomials?


I think of nth order as mostly just applying to approximations. But I guess first order would be ok here.


If f is linear, then f(a)=f(a+0)=f(a)+f(0). So f(0)=0.


It’s linear in terms of its order but it’s not a linear transformation, which must satisfy:

    f(c*(a+b)) = c*f(a) + c*f(b)
Where c is a scalar. A and b are abstract objects. Examples include vectors, real numbers, and functions themselves.


Linear does not mean "graph is a line". It means "graph is a line through origin" (in the 2d case).

Somewhat counterintuitive, but that's how it's defined.


The Wikipedia article someone else posted already seems to disagree: https://en.wikipedia.org/wiki/Linear_function. This confuses me.


The article actually agrees.

> In mathematics, the term linear function refers to two distinct but related notions (...) [proceeds to specify them using incomprehensible math words]

GNU Units documentation uses the second notion, common with linear algebra (and thus arguably more common in any computing) - the notion that calls y=ax a linear function, and y=ax+b an affine function.


So, rather than calling it non-linear, which is clearly somewhat confusing, perhaps it would be more clear to state that it handles affine functions like F to C...?


Agreed. Why they wasting our time pointing out it’s “non-linear” when this statement is only true for some definitions of linear? Just pick a non-ambiguous word, or add an asterisk and footnote.


Perhaps. That's what I myself did when adding handling for affine unit conversions in a project I worked on.


It's affine. It's not linear because the offset means superposition doesn't hold.


It's even in the documentation to Units:

> But Fahrenheit to Celsius is linear, you insist. Not so. A transformation T is linear if T(x+y)=T(x)+T(y) and this fails for T(x)=ax+b . This transformation is affine, but not linear.

https://www.gnu.org/software/units/manual/html_node/Overview...


Frim jxy's 6th edition man page:

"Units only does multiplicative scale changes. Thus it can convert Kelvin to Rankine, but not Centigrade to Fahrenheit."


Because 0°C is not 0°F


As I understood it: C to K would be linear since they are always offset by the same amount, but 0°C is not 0°K. C to F is not linear since they are not offset by the same amount.


That's not how it works. The definition of linear used in this context requires f(a+b) = f(a) + f(b) which is not the case with the C to K translation which is f(x) = x + 273.15 Only functions in the form y=mx+0 meet the criteria.


It seems to me C to K is affine as well. True, it's somewhat special in that the factor is exactly one, but if there's an offset it's not linear in the sense of the sentence under discussion.


How does GNU Units compare to Frink ( https://frinklang.org/ )?


Units is older, frink is a lot bigger, it's a whole programming environment.

Frink started from and extended the units defined by Units, I don't know if anything has gone in the other direction.

Later: for simpler calculations an interesting feature frink adds is the ability to do interval arithmetic. Terms can be specified as ranges that are then carried through the calculations to the result.


The author of Frink takes particular pride in doing unit maths correctly.

For example, if the conversion between two units is defined by statute to be some weird ratio, Frink will use that, and not merely the best f64 approximation of that ratio.

As indicated by a sibling comment, Frink also handles interval maths, and in general it just has a remarkable amount of features, being a fully-fledged programming language.

It's a pity it isn't open-source, the author says he doesn't want the aggravation of having to deal with pull requests and so on, and just wants to work on his software project on his own. Which, ok, that's fair: but at least Lua and SQLite don't accept contributions from outside the team, so there's a model for releasing open-source software without having to collaborate with the general public.

No question that it would increase the size of his inbox though, so I get it.


Looks like it is comparable to javax.measure (https://jcp.org/en/jsr/detail?id=363). I used an implementation of that a few years ago: https://github.com/unitsofmeasurement/uom-se

It's a complex domain, especially if you get down to having more complex units composed of other units and want to do conversions between metric and imperial. In our case we were dealing with material properties (chemical, physical, magnetic, etc.) and different countries and companies using different ways to record characteristics for materials.


GNU Units is a beautiful piece of software. I keep using it for everything. You can convert between currencies, too.

If GNU Units cannot do something, I resort to using Maxima[1].

[1] https://maxima.sourceforge.io


If Units can convert between currencies, how does it source the exchange rates? They change on sub-second time scales and bid/ask spreads make the notion of a rate somewhat uncertain.

Edit: answering my own question. There are multiple providers, some requiring API-key signup, but the answer is far from definitive: https://www.gnu.org/software/units/manual/html_node/Currency...


I've been using WolframAlpha for this sort of thing. The idea of using something fully local and open-source does have some appeal, but it's hard to compete with the convenience of Ctrl+T "wo" <Tab> <Query> <Enter>.


You mean Ctrl+T "wo" <Tab> <Query> <Enter> <Wait 15 to 60 seconds for the page with your results to load> <Get something that's a mighty pain to copy/paste from>.

This experience is why I stopped using W|A few years ago. It's awesome, but it's also a pain.


Can relate; that's definitely been an issue for me as well. Though on the plus side it's nice to be able to open multiple tabs, make small tweaks to the formula, and switch between them to compare results.

Kinda wish there was an open source browser-based WolframAlpha alternative which did more of the computation locally so everything wasn't so slow.


I used to love Wolfram Alpha but it hasn't worked for me for several years and I've been unable to find out why.

Just tested now and it does work on Android FF - yay! But not on my desktop (neither Chrome nor Edge). Doesn't work for me on Firefox nor Brave either (neither Win10 nor Kubuntu). I have randomly assigned IP from major UK provider (which provider has also changed). Doesn't work through my work VPN either.

I've taken to using Geogebra (online) when I quickly need a function plotting.


I must be dense but what do the star and the slash mean? It looks like "multiply by" and "divide by" but it appears to have results of the conversion next to the star... Do the docs explain this and I missed it?

    You have: 1 lbs
    You want: kg
     * 0.45359237
     / 2.2046226
    You have: 2 lbs
    You want: kg
     * 0.90718474
     / 1.1023113
    You have: 2.4 lbs
    You want: kg
     * 1.0886217
     / 0.91859276


It's in the manual:

https://www.gnu.org/software/units/manual/html_node/Interact...

"The second number gives the conversion in the opposite direction."

Try with 'units --verbose' and you get nicer output:

    $ units lb kg
     lb = 0.45359237 kg
     lb = (1 / 2.2046226) kg


It's just showing the inverse. It makes more sense if you don't enter a number for the first unit:

   You have: kg/day
   You want: lb/hr
 * 0.091859276
 / 10.886217


It's not about GNU.

V6 Unix (circa 1975) had it: http://man.cat-v.org/unix-6th/6/units

Your macOS have the BSD version:

    % units -v
    
      units version 1.0  Copyright (c) 1993 by Adrian Mariano
                        This program may be freely distributed
    usage: units [-f unitsfile] [-q] [-v] [from-unit to-unit]


I'm not sure of the total history, but "by Adrian Mariano" means macOS uses GNU units. Wiki says they forked a copy before the license change.


You are probably right.

The one in FreeBSD is from NetBSD: https://svnweb.freebsd.org/base/head/usr.bin/units/units.c?v...

The NetBSD version is from Adrian Mariano: http://cvsweb.netbsd.org/bsdweb.cgi/src/usr.bin/units/units....

The one in Plan9 is in yacc: http://9p.io/sources/plan9/sys/src/cmd/units.y

This GitHub repo claims to be V6: https://github.com/memnoth/unix-v6/blob/master/source/s2/uni...


It’s about Unix, and GNU’s Not happens to be the best implementation of it. Which is why macOS copies pieces of it, despite needing to use obsolete versions in order to comply with Apple’s hatred for end-user freedom.


I love being able to convert from millilightseconds to miles, and vice versa. You can figure minimum latency for a given distance or maximum distance for a given latency.


Is this a covert reference to the 500-mile e-mail?


Probably not. Knowing the speed-of-light round trip time to a network location gives you a bound on how much you can improve the performance of remote operations.

For example, I'm in Austin, querying a database hosted in Amazon's us-east-1 data center ("Northern Virginia"). Call it 1000 miles away, 2000 mile round trip.

    You have: 2000 miles
    You want: millilightseconds
            2000 miles = 10.736388 millilightseconds
If I have a query that's taking < 1ms, no optimization of how that query is executed by the database can possibly improve the overall performance.


Oh thank goodness, I can stop using Google for this. (Aside: Is anyone else annoyed that Google doesn't understand what a hectopascal is? It interprets hPa as Pa, which is obnoxious. Every time I convert to or from hPa I have to do it twice: once in hPa and then again in millibars.)


The units command has been part of Unix since the 1970s. GNU Units is a clone with many improvements and has been around since the 1980s.

You kids gotta learn your damn history!


In my defense, I've been using Unix since the early '90s (was taught Scheme and C on a DEC ULTRIX, and then got my hands on a Turbo NeXTstation). This is a rare gap in my knowledge. ;-)


I forgive you.


For Python, I've had good experience with the Pint library[1]. It's helped avoid a whole class of bugs.

1: https://pint.readthedocs.io/en/stable/


The documentation seems a bit incomplete, not what I'm used to with GNU. There seems to be no list of all units supported.

I tried converting torque "100 ft lbf" to standard ISO notation (Nm). Let's see:

  units "100 ft lbs" "Nm"
  > Unknown unit 'Nm'

  units "100 ft lbs" "nm"
  > conformability error

  units "100 ft lbs" "newton meter"
  > * 135.58
How am I supposed to know that 'newton' must be written in full (though 'ft' and 'lbs' can be abbreviated)? Searching for 'newton' in the manpage yields 0 results.


The list of all units supported is, for the GNU version, /usr/share/units/definitions.units


It should be “N m”, even standard ISO notation requires a small space between the two.


The supported units aren't listed in the man page, because they're defined in a data file. Your site might have customized that file, meaning the man page would be incomplete.


I keep using different tools to do conversions so now I can unify that all into Units and get my speed in furlongs per fortnight as the ancient prophecies foretold.

Rejoice!

(but for real this is top I’m replacing multiple other tools with Units)


I love it, everything is there!

    You have: kilometers per hour
    You want: attoparsecs per microfortnight
            * 10.889018


For what's not, you can add additional definitions.

I found myself wanting to calculate Little Boy blast yields sufficiently often that I added a hiroshimabomb unit of energy.

Similarly, various areal units such as countries and states/provinces.


How many Australian football fields in 1.3 Canada's?


Aussie Rules is a variably-specified pitch:

Australian rules football grounds, even at the highest level of the game, have no fixed dimensions. For senior football, the playing field is an oval, typically between 135–185 metres (148–202 yd) long goal-to-goal and 110–155 metres (120–170 yd) wide wing-to-wing. Grounds can vary from long and narrow to almost circular, and are not necessarily symmetrical, depending upon how and where the field was constructed. At least 5 metres (5.5 yd) of space between the boundary line and any fence is required for safety.

https://en.wikipedia.org/wiki/Australian_rules_football_play...

Canadian Football: 150 yards length overall, 65 yards width overall. 2.0144628 acres area, 0.81522418 hectares.

https://sportsknowhow.com/football/field-dimensions/canadian...

The other question is if you're looking for length or areal metrics.


That's even better than the furlongs per fortnight example, which gave me a good laugh already :)


It's a nod to the furlong-firkin-fortnight measurement system:

https://en.wikipedia.org/wiki/FFF_system


I absolutely adore this program. It works exactly like I expect, every time. Sometimes I'll just think about what a nice tool it is, even when I'm not using it.


A favourite tool, which I also found via Trey Harris's speed-of-light email post.

I've written a few quick guides and examples using GNU units:

GNU 'units' utility and energy / resource calculations

https://old.reddit.com/r/dredmorbius/comments/1x9u0f/gnu_uni...

How many Hiroshima bombs in a Ferrari, with mass-energy conversion (or how I learned to extend GNU units)

https://old.reddit.com/r/dredmorbius/comments/1yvxde/how_man...

And for assessing specifc alternative energy claims:

Boeing's Biofuel "Breakthrough" -- Less than overwhelming

https://old.reddit.com/r/dredmorbius/comments/1wo2hl/boeings...


I have been using qalc for that

How does it compare?

  $ qalc

  > furlongs per fortnight

   furlong / fortnight = 1 fur / fortnight

 > to m/s

   1 fur / fortnight = approx. 0,0001663095238 m / s

 > 17 yards + 2 feet + 5 inches

   (17 * yard) + (2 * foot) + (5 * inch) = 17 yd + 2 ft + 5 in

 > to meter

   17 yd + 2 ft + 5 in = 16,2814 m

 >


For use cases like that it is incredibly similar if you give the --verbose flag:

    $ units --verbose
    [header]
    You have: furlongs per fortnight
    You want: m/s
            furlongs per fortnight = 0.00016630952 m/s
            furlongs per fortnight = (1 / 6012.8848) m/s
    You have: 17 yards + 2 feet + 5 inches
    You want: meter
            17 yards + 2 feet + 5 inches = 16.2814 meter
            17 yards + 2 feet + 5 inches = (1 / 0.06141978) meter
Personally, I find qalc via qalculate-gtk more useful for exploratory sessions but I still use units an awful lot.


Do GNU Units handle units with implicit parameters?

For example, 1500 mAh (milliamp∗hours) could be converted to 5.55 Wh (watt∗hours), or 19.98 kJ in SI units, in the context of a 3.7-volt battery.

Naive approach fails:

  $ units "1500 milliampere*hours at 3.7 volts" "watt*hours"
  conformability error
        1.9593687e+09 kg^2 m / s^4
        3600 kg m^2 / s^2


You are multiplying mAh, volts, and atmospheres. (“at” is a unit not an operator.) You want to just multiply mAh and V like

  You have: 1500 mA hours * 3.7V
  You want: W hours
          * 5.55
          / 0.18018018


  You have: 1500 mA * hr * 3.7 V
  You want: kJ
          * 19.98
          / 0.05005005

  You have: 1500 mA * hr * 3.7 V
  You want: watt * hours
          * 5.55
          / 0.18018018


  You have: 1500 mA * hours * 3.7 V
  You want: watt * hours
          * 5.55
          / 0.18018018


Does the GNU projet make its repositories available online ?

I'd like to have a look at the code but all I found is an outdated mirror : https://github.com/ryantenney/gnu-units


Here you go:

http://savannah.gnu.org/projects/units

All official GNU software is hosted here: http://savannah.gnu.org


For comparison, the original: https://minnie.tuhs.org/cgi-bin/utree.pl?file=V7/usr/src/cmd...

(Slightly discombobulating to read some of today's lucky 10,000 treating `units` as a (GNU) novelty when it's been around for 40+ years.)



GNU Savannah is where they keep their source IIRC. https://savannah.gnu.org/projects/units

Unfortunately it looks like the upstream for this project is in... cvs


Units should be built into languages! Others have pointed to some libraries that make this possible in C++ and Rust; I'm sure it exists for other languages too. But this seems still short of what's needed: Every number in an application should be of a certain type and those types should combine on mathematical operations. Often those types already exist within the application's type model -- i.e. every class/interface is an obvious candidate. Then it would just be a matter of assigning those types to numbers. This would yield the ability to express things like Users/Client or Requests/second through simple math operations on variables and have it all type checked.


It's a lot harder to do well than it looks, mostly because unit systems were invented by humans and have a lot of aggravating edge cases and oddities. For example, most units can be converted to another unit of the same dimensionality by mulitiplication or division (such as length in inches * 2.54 == length in millimeters), but then there's temperature where you also need to add or subtract an offset.

It's almost as if humans spent thousands of years inventing units without ever once considering how difficult they might be to implement in a computer programming language.


Are there any edge cases if we just stick to SI units?

Most of the world doesn't care about the thousand-year units, and the bit that does could just convert to them on output.


Temperature, times, dates, cgs vs mks, dimensionless quantities, angles, the list goes on and on.

And that’s before you get into the technical details of how you store units and conversion factors in memory, how you handle precision when mixing large and small units, how you interact with unlimited‐precision and rational numbers, how you use or avoid the type system in your programming language, how users of your unit library define their own units…

Here’s a good write‐up of what they’re thinking about for future versions of C++: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p193.... It’s worth a read even if you don’t write in C++.

And if you bake it into your language, you’d better get it all right the first time, because you probably won’t be able to fix it later.


Ada does this well with its concept of subtypes; so you could subtype Int to your unit, and even give it valid ranges. It's then typechecked by the compiler.


F#


My hp48 calculator had unit conversions built-in. You could add units to any number and then conversions are done automatically when you do math: (1_ft + 1_in) / 20_s + 5_mi/h

if the units don't match then the operation was an error: 1_ft + 1_gal => error

As other people have mentioned I really wish spreadsheets had this built-in where units are like formats for a cell. Ii controls about how you want things displayed and will prevent you from making conversion mistakes or doing illegal operations.


Emacs has org-mode, and org-mode has tables with formulas which can invoke calc-mode. calc-mode also has units:

https://www.gnu.org/software/emacs/manual/html_node/calc/Uni...


>You have: 7 meters >You want: ft;in > 22 ft + 11.590551 in

Is there a way to get inches in ruler-based fractions instead of decimals? Imperial rulers don't give you tenths or hundredths of an inch, so I would find it much more useful if the output were "just under 22ft + 11 19/32in" or something similar.


FYI: use tab completion in the 'units' REPL to show a list of available definitions. You won't find them in the 'units' manpage, as they are defined in an external datafile (on my machine this file is /usr/share/units/definitions.units)


My go-to test for such systems is converting miles per gallon to liters per 100 km. Can anybody give it a try?

Google did it well for the longest time, then stopped at some point. Now it works again.

Just tried it on iOS and it works now. Don’t quite remember when I last tried, but I believe it’s fairly recent.


    units "30 miles per gallon" "liters per 100km"
        reciprocal conversion
        * 7.8404861
        / 0.12754311


What I particularly like is the use of the locale:

    LANG=en_GB.UTF-8 units "30 miles per gallon" "liters per 100km"
        reciprocal conversion
        * 9.4160312
        / 0.10620186

    LANG=en_US.UTF-8 units "30 miles per gallon" "liters per 100km"
        reciprocal conversion
        * 7.8404861
        / 0.12754311
(Although it is incomplete, as it only uses Imperial gallons for "gallon" for en_GB, although there are probably more English locales that use(d) the Imperial gallon than the US gallon.)


        $ units "6 l/100 km" mpg

        reciprocal conversion

        * 39.202431

        / 0.025508622


Why isn't this released as a library (as opposed to a program)?


In the README in the GNU units source code (2.21):

  203: Ideas the future (may or may not happen):
  204:
  205:  * Bundle up the units conversion stuff into a library. 
At the end of units.c, too:

  6280: /* NOTES:
  6281: 
  6282: mymalloc, growbuffer and tryallunits are the only places with print
  6283: statements that should (?) be removed to make a library.  How can
  6284: error reporting in these functions (memory allocation errors) be
  6285: handled cleanly for a library implementation?  
  6286: 
  6287: Way to report the reduced form of the two operands of a sum when
  6288: they are not conformable.
  6289: 
  6290: Way to report the required domain when getting an domain error.
  6291:
  6292: */
My prowling of the source code is probably uninformed because I'm not a C expert by any means but it seems like you could include units.h and use many of the useful functions in another program.


You might also be interested in boost::units.

It implements units using a ton of templates and "compile-time metaprogramming". [0]

The nice thing is that it has no runtime overhead as all templates are "compiled away". The disadvantage is that when you make a mistake against units, it results in a "template compiler error explosion".

[0]https://www.boost.org/doc/libs/1_65_0/doc/html/boost_units.h...


Per another thread it sounds like Frink is what you want.

https://frinklang.org/


A program is easier to use. You do not need to link to it, just run it! Do you have trouble running programs?


For the non-unix folk: I regularly use wolframalpha.com for similar things.

Example query to estimate how much electricity bitcoin miners can afford to use at current prices:

https://www.wolframalpha.com/input/?i=%28%286.25+bitcoin+%2F...


GNU units works great on windows. Install with chocolatey or directly with gnuwin. It's a bit outdated, but works for most things just fine.

https://chocolatey.org/packages/GnuWin/0.6.3


I use units all the time on macos.

I don't know how it derives/compares to the gnu version

    $ units -v
    units version 1.0  Copyright (c) 1993 by Adrian Mariano
                    This program may be freely distributed
It doesn't do temperature (which would make it more useful)


Recently I created a library for unit conversion in Julia, which is the most complete tool for unit conversion I am currently aware of

https://github.com/chakravala/UnitSystems.jl


I wish someone would make a spreadsheet that tracks units like this.


Not sure what you want in a spreadsheet, but the data is stored in text files. See https://www.gnu.org/software/units/manual/html_node/Units-Da...


Not sure what GP is thinking of, but type checking for Excel would be really nice:

ERR: A1 is USD/month, B1 is USD/user, so you cannot calculate A1+B1!


Not the unit definitions in a spreadsheet; I'd like a spreadsheet where each cell has not just a number, but a number with its unit. Formulas would be evaluated the way `units` does it. B1=3m; B2=4s; B3="=B1/B2" would give as value of B3 "0.75 m/s".


Ah, sure, that would be great. I'd say it would be useful in text based programming environments too though.


Agriculture would probably love a spreadsheet that understood units of measure and kept results as fractions.

Gotta love that a bushel of Yellow Corn is a different weight than a bushel of Oats.


All the grains are different. I had to hard code a table of those conversions for an application I worked on.


> It can also handle nonlinear conversions such as Fahrenheit to Celsius

huh?


I typically use google for most unit conversions. How much concrete do I need for my driveway? I type this at the top of Chrome: 1/4 mile * 8ft * 4in in yd^3


My favorite Google unit query: "the speed of light in ghz*in". The answer is the interesting and useful 11.8028527. Interesting because if you have not studied microwaves, you might not even know that as a unit for the speed of light, useful because it makes clear the relationship between wavelength and antenna length. Divide to cancel frequently and you have wavelength.


Grace Hopper used to give talks and hand out 11.8 inch pieces of wire, calling them nanoseconds. https://en.wikipedia.org/wiki/Grace_Hopper#Anecdotes


Thanks for sharing, I had never heard this before.


This is the same as inches per nanosecond, which is a little more intuitive for us non-antenna-designers.


IMO, a port to a browser or mobile app makes a lot of sense.


Came to say the same. Free and quality mobile apps without ads are sorely lacking.

Obviously there are some stark philosophical differences between GNU and the walled gardens of mobile devices. But users don't care about that, they just want good software.


Cool, so my phone has a 69.6 btu battery.

  % units --verbose -1 '4080mA hours * 5V' btu
  4080mA hours * 5V = 69.607689 btu


  You have: 1 kelvin
  You want: degcelsius
     * 1
     / 1
This does not seem right


It is. The unit Kelvin is equal to the degree Celsius. If you want to convert temperatures, you need to use tempK and tempC:

    You have: tempK(1)
    You want: tempC
            -272.15


Makes sense because temperatures don't have a linear conversion.

From the man page: Nonlinear units are represented using functional notation. They make possible nonlinear unit conversions such as temperature.

  You have: tempK(1)
  You want: tempC
 -272.15
Edit: seems i am not alone :D


It's right in the sense that the units are the same size. IE if something increases 10 deg K it also increases 10 deg C. But it's obvious to humans that that isn't what you where asking.

Compare:

   You have: 1 degF
   You want: degcelsius
           * 0.55555556
           / 1.8


Nitpick: There are no "deg K", because it is an absolute system it doesn't have degrees.

Notice you also don't need degrees metre, degrees watt or degrees newton, because those are absolute units they are metres, watts and newtons. It is Celsius (and Fahrenheit) which are weird because they aren't absolute but instead have this arbitrary zero point.


https://www.gnu.org/software/units/manual/units.html#Tempera...

> Conversions between temperatures are different from linear conversions between temperature increments—see the example below. The absolute temperature conversions are handled by units starting with ‘temp’, and you must use functional notation. The temperature-increment conversions are done using units starting with ‘deg’ and they do not require functional notation.


I think I'm using it incorrectly:

./units "3 km in miles" Definition: 122632.01 m^3


"in" is the abbreviation for inches, and school maths/physics class taught us that length × length × length = volume, which is exactly what you have: 3 kilometres × 1 inch × 1 mile.

My physics lessons at secondary school must have spent at least a week on SI units, base and derived units:

  Force = mass × acceleration
      N =  kg  ×    m·s¯²
  (i.e. a Newton is a kilogram-metre-per-second-squared.)

  Pressure =    force ÷ area
     Pa    =      N   ÷  m²
     Pa    = kg·m·s¯² ÷ m²
     Pa    =   m¯¹·kg·s¯²
  (So Pascals are Newtons-per-square-metre, or kilograms-per-metre-per-second-squared.)


Try: units 3km miles


My favorite units conversion is smoots per furlong...


> You have: 1|6 cup

Is that a pipe for division?


It has both / for division with the usual precedence and | for very tight-binding division, for use in fractions. So 1/6 cup parses as 1/(6 cup) but 1|6 cup parses as (1/6) cup.


Love it!


> You have: furlongs per fortnight

We need to see this ^ more often in real life!


It's a very slow velocity, though. It's best used for things like snails.


You could count it in increments of some number, like 1280... so you'd have a car speedometer which would measure your speed in x*1280 furlongs/forthnight.

(yes i'm joking, but considering all the other freedom units, and rules measuring in 1/64", it's not far from the truth)


> nonlinear conversions such as Fahrenheit to Celsius

The heck? "y = ax + b" is linear; just not homogeneous linear.

https://en.wikipedia.org/wiki/Fahrenheit#Definition_and_conv...

https://en.wikipedia.org/wiki/Homogeneous_function


It's not a linear function for what it's worth. It breaks the f(x + y) = f(x) + f(y) part of linearity.

It is a linear equation, confusingly enough.


That's linear in the sense of "linear operator" or "linear map". I've never heard "nonlinear" as the opposite of that due to to a constant offset. "Linear map" and "linear operator" are used in contexts where homogeneity is a given.

A scaling plus displacement is linear in the sense of "linear equation" because, for instance, if you scale a signal and add DC offset, there is no distortion; no new harmonics are present in the output signal.

ax + by + c is called linear because the plot of points which satisfy the equation form a straight line; there is nothing confusing about it whatsoever.

Temperature delta conversions between C and F are certainly a linear map/operator. If it gets 5°C hotter, and then 3°C hotter, making 8°C hotter, that's exactly like 9°F hotter plus 5.4°F hotter making 14.4°F hotter.

Here is a test for linearity for a real-valued one-argument function which is not confused by an offset:

     x + y      f(x) + f(y)
  f( ------ ) = -----------
       2             2
Works just fine for °C/°F.

There is another criterion for a linear map that hasn't been mentioned, though: f(ax) = af(x).


GNU units supports normal unit conversion, such as meters to feet. These conversions all obey f(ax)=af(x), that is, if you have zero meters you have zero feet. If you want to convert something that breaks that rule then you have to give a definition in the database as a general functional form or as a lookup table. And you have to use functional syntax to perform the conversion. Some examples in the database include dB, wire gauge, shoe size, grit size for sandpaper, ring size, musical intervals, and sugar concentration. I call units defined using a lookup table or general functional form "nonlinear units".

Zero degrees Fahrenheit is of course not equal to 0 K, but conversion of absolute temperature is not presented as the best example of this class of unit conversion. It's highlighted because everybody asks about it. Temperature conversion was for years, before I figured out a way to support it elegantly, the most requested missing feature. Yes, it's a little strange to call affine transformations "nonlinear" but there is no special "affine unit" feature in the program.


Speaking of K, Celsius to K is also "nonlinear" math: you add or subtract a constant, around 272-something.


Well one way or another it's not a linear function, so calling it a non-linear conversion is technically not incorrect.

That said I completely agree that it makes way more sense to just call it a linear conversion and to pick an example that's truly nonlinear. Not that there are that many non-linear units, but something like decibel or beaufort might work.


Insistence that "linear function" is defined one way is not supported by facts:

https://en.wikipedia.org/wiki/Linear_function

A "linear function" refers to a "linear map" only in certain contexts.

The word "affine" can be used for a mapping that fails to meet the definition of a linear map operator due to offsets. That is much better than "nonlinear".




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: