[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