Article View: comp.unix.shell
Article #4147Re: ksh->bash and floating point arithmetic
From: Chris F.A. Johnson
Date: Mon, 08 Dec 2003 18:22
Date: Mon, 08 Dec 2003 18:22
101 lines
3913 bytes
3913 bytes
On Mon, 08 Dec 2003 at 14:25 GMT, Tristan Miller wrote:
> Greetings.
>
> I have a set of KornShell (ksh93) scripts, some fairly large, which I
> wish to convert to GNU bash scripts for the following reasons:
>
> a) the KornShell licence is too restrictive;
> b) there is too much inconsistency in the version of ksh provided by
> various Unix vendors;
> c) in my experience, bash tends to be easier to compile and install than
> ksh93; and
> d) if I'm going to convert ksh93 code into anything, converting it into
> bash will probably require the least number of changes.
>
> The reason the scripts were written in ksh93 to begin with is its
> support for floating-point arithmetic.
>
> Up until now I have been replacing the ksh93-specific arithmetic
> operators with calls to bash functions which invoke bc. This seems to
> work as expected, but apart from rewriting everything in, say, Perl, is
> there a better or more efficient way of getting floating-point
> arithmetic?
I find that awk is considerably faster than bc; this may be
implementation dependent. I use this function:
calc() { awk "BEGIN {print $*}"; }
Floating point arithmetic can be implemented as shell functions
which do not call any external comands; for example, this
multiplication function is faster than calling awk:
fpmul() {
places=
tot=1
shift=0
qm=
neg=
for fpn
do
case $fpn in
-*) [ "$neg" = '-' ] && neg= || neg='-'
fpn=${fpn#-}
;;
esac
case $fpn in
.*) int=
dec=${fpn#?}
tot=$(( $tot * $dec ))
places=$places$dec
;;
*.*) dec=${fpn#*.}
int=${fpn%.*}
places=$places$dec
tot=$(( $tot * $int$dec ))
;;
*) tot=$(( $tot * $fpn ));;
esac
done
while [ ${#qm} -lt ${#places} ]
do
qm=$qm'?'
done
while [ ${#qm} -gt ${#tot} ]
do
tot=0$tot
done
int=${tot%$qm}
dec=${tot#$int}
_FPMUL=$neg$int${dec:+.$dec}
[ ${SILENT_FUNCS:-0} = 1 ] || echo "${_FPMUL}"
}
Note that in bash, as in most shells, using command substitution
to return a value is slow since it forks a new process (ksh93 is
an exception).
By setting a variable inside the function and referencing it in
the calling code, a new process is avoided.
This:
SILENT_FUNCS=1 fpmul 3.14159265 12.352
product=$_FPMUL
is considerably faster than:
product=`fpmul 3.14159265 12.352`
I don't know whether shell functions would be faster than awk when
it comes to parsing mixed calculations (e.g. "3.456 * (4 + 1.414)").
--
Chris F.A. Johnson http://cfaj.freeshell.org
===================================================================
My code (if any) in this post is copyright 2003, Chris F.A. Johnson
and may be copied under the terms of the GNU General Public License
Technical Details
Message-ID:
<br2fgh$28dbor$1@ID-210011.news.uni-berlin.de>Path:
arc1-ca.pugleaf.net!archiver1.google.com!news2.google.com!fu-berlin.de!uni-berlin.de!cpe0030ab04dde2-cm023459906638.cpe.net.cable.rogers.COM!not-for-mailReferences:
<2726696.9viUAlbAWN@ID-187157.news.dfncis.de>Show Full Headers
Complete Article Headers
X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 109f73,c9a9cf8582f4663a X-Google-Attributes: gid109f73,public X-Google-Thread: 1012a6,c9a9cf8582f4663a X-Google-Attributes: gid1012a6,public X-Google-ArrivalTime: 2003-12-08 10:22:11 PST Path: arc1-ca.pugleaf.net!archiver1.google.com!news2.google.com!fu-berlin.de!uni-berlin.de!cpe0030ab04dde2-cm023459906638.cpe.net.cable.rogers.COM!not-for-mail From: "Chris F.A. Johnson" <c.fa.johnson@rogers.com> Newsgroups: comp.unix.shell,gnu.utils.help Subject: Re: ksh->bash and floating point arithmetic Date: 8 Dec 2003 18:22:10 GMT Lines: 101 Message-ID: <br2fgh$28dbor$1@ID-210011.news.uni-berlin.de> References: <2726696.9viUAlbAWN@ID-187157.news.dfncis.de> NNTP-Posting-Host: cpe0030ab04dde2-cm023459906638.cpe.net.cable.rogers.com (24.156.50.72) X-Trace: news.uni-berlin.de 1070907730 75935515 24.156.50.72 ([210011]) User-Agent: slrn/0.9.7.4 (Linux)