Show HN: Shellmath: Floating-point arithmetic directly in bash

  • Hello, all!

    I'm proud to present shellmath, a floating-point calculator written entirely in bash.

    Shellmath does not call out to any external programs -- calculators, text manipulators, or anything else -- and achieves execution speeds competitive with GNU awk and bc.

    You can do floating-point math directly in the shell, and now you have a ready-made family of routines for doing so!

    For skeptics ;-) I've included a demo that calculates 'e'. I've also posted a few words about the methodology, runtime efficiency, and a few bells and whistles on the README and in the project wiki.

    I eagerly await your feedback!

    Be good, and have a great day!

  • > Ad astra per aspera.

    And yet reliance on Bash extensions rather than doing it in pure POSIX shell. ;)

    A quick skim suggests the biggest convenience is using local variables to make recursion easier. But it's fairly easy to implement push and pop routines to turn global variables into a stack. You could even name push "local" and keep much the same syntax. Better would be an indirect call function which saves and restores a set of global "registers" across invocations, avoiding the need for explicit pops in each function.

    Many of the pattern matching parts can be easily replaced with the canonical "fnmatch" shell implementation[1], which uses a case statement to provide in-shell fnmatch(3) emulation. If that's not powerful enough, expr supports regular expressions, though while usually a built-in it's not necessarily so. In the absence of regular expressions it's usually sufficient to use parameter expansion facilities to split strings and use simpler glob pattern matching on the components.

    Still very cool. If I get bored one day I might try refactoring to make it pure POSIX shell.

    Because Linux distributions (not to mention containers) are increasingly removing common shell utilities like bc, if this were extended to arbitrary precision arithmetic it might even be legitimately useful! For similar reasons I've implemented a base64 encoder and decoder using mostly pure POSIX shell--still depends on od(1) or dd(1) so it can do proper binary I/O, but the low-level coding is done using shell arithmetic and POSIX looping constructs.

    [1] See http://www.etalabs.net/sh_tricks.html

  • Very nice writeup!

    Related: I got a couple mails about raytracers in pure bash. It looks like they use fixed point arithmetic in bash rather than floating point, which works well:

    http://www.oilshell.org/blog/2021/01/audio-and-graphics.html...

    https://github.com/aneeshdurg/bash-raytracer

    https://www.bouledef.eu/~tleguern/articles/shell-fixedpoint/

  • > In the spirit of Bash, numerical overflow is silently ignored.

    I love that!

  • so ... anyone have a floating-point library for sed(1)?

    (this is a serious question. compare: http://sed.sourceforge.net/grabbag/tutorials/lookup_tables.t... and https://en.wikipedia.org/wiki/IBM_1620#Transferred_to_San_Jo... )

  • Why should I use `_shellmath_divide 1 $zero_factorial` over `bc 1 / $zero_factorial`?

    It's imprecise and much more clunky to write. bc exists for decades already and has arbitrary precision.

  • Well, anything’s better than multiplying the float by ten to the power of the number of decimals.

  • Hmm. Cool?

    I guess I don't expect my shell to do much, I reach for numpy or something when I want fancier math.

    Not to knock, but what's the use case? I think I prefer bc - "10/(200.7-73.6)" is easy to look at, I don't mind the extra dependency for that.

    Actually on that note what I do need to find is a proper calculator on Android, what I have found are computer algebra systems with arcane learning curves. Its surprising how bad the default calc is and nobody had made a popular good alt...