help-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: scientific notation in Bash


From: Tapani Tarvainen
Subject: Re: scientific notation in Bash
Date: Wed, 16 Mar 2022 08:52:13 +0200

On Tue, Mar 15, 2022 at 02:16:29PM +0100, Ante Bilandzic (abilandzic@gmail.com) 
wrote:

> > $ printf "%.0f\n" 4.4e9
> > 4400000000
> >
> > So instead of Var=44e1 you could do
> >
> > printf -v Var "%.0f" 44e1
> >
> 
> Thanks!
> 
> This works but only as a workaround, because it's clearly impractical and
> inefficient to have such a conversion explicitly written for each integer
> variable, whether or not it contains the integer written in sci. notation.

Without actually measuring, I wouldn't be at all sure it would be more
inefficient than doing an extra test to determine if the conversion is
necessary. I am pretty sure, however, that the difference would be
insignificant for more or less all practical purposes. If you have
some special application where it really matters, do experiment,
although I suspect bash would not be the right tool in that case.

> 1/ Trying to force each external utility with its own specific formatting
> to return an integer in the normal notation which Bash can swallow;
> 2/ For each variable I expect to be an integer and whose content is
> obtained from external utility, I can implement in Bash an additional
> check, something like [[ $Var =~ [eE] ]], and if true, apply the conversion
> via printf as you suggested.

Unless you really control the external utility's output to the extent
that you trust it can't return invalid data (and I don't think you
ever should), you should do proper input validation anyway, letting
through only good data. For example, instead of just looking for [eE],
maybe do something like this:

shopt -s extglob

case "$1" in
  ?(-)[1-9]*([0-9])) Var=$1;;
  ?(-)+([0-9])?(.*([0-9]))?([eE]?([+-])+([0-9]))) printf -v Var "%.0f" "$1";;
  *) echo invalid number "$1" >&2; exit 1;;
esac

Although as noted I doubt if the first case for plain integers
is really useful.

> The potential danger here is that if external
> utility mistakingly returns the floating-point, Bash will still see it as
> an integer:
> 
> $ Var=4.1234e1
> $ printf -v Var "%.0f" $Var
> $ echo $Var
> 41

What would you want to happen in that case?

Testing whether a number in scientific notation is actually an integer
is not entirely trivial. Perhaps you could do the conversion like
this:

shopt -s extglob
printf -v Var "%.18f" $Var
Var=${Var%%?(.*(0))}

That leaves the decimals in place unless they're all zeroes:

$ shopt -s extglob
$ Var=4.1234e1
$ printf -v Var "%.18f" $Var
$ Var=${Var%%?(.*(0))}
$ echo $Var
41.234000000000000000

$ Var=4.12e3
$ printf -v Var "%.18f" $Var
$ Var=${Var%%?(.*(0))}
$ echo $Var
4120


After that you could test for the presence of the decimal point.

Note, that will still fail in some corner cases.
For example, Var=1e-100 will return as zero.

-- 
Tapani Tarvainen



reply via email to

[Prev in Thread] Current Thread [Next in Thread]