From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 28503 invoked from network); 10 Mar 2003 08:55:56 -0000 Received: from sunsite.dk (130.225.247.90) by ns1.primenet.com.au with SMTP; 10 Mar 2003 08:55:56 -0000 Received: (qmail 19808 invoked by alias); 10 Mar 2003 08:55:50 -0000 Mailing-List: contact zsh-workers-help@sunsite.dk; run by ezmlm Precedence: bulk X-No-Archive: yes X-Seq: 18330 Received: (qmail 19799 invoked from network); 10 Mar 2003 08:55:50 -0000 Received: from localhost (HELO sunsite.dk) (127.0.0.1) by localhost with SMTP; 10 Mar 2003 08:55:50 -0000 X-MessageWall-Score: 0 (sunsite.dk) Received: from [212.125.75.4] by sunsite.dk (MessageWall 1.0.8) with SMTP; 10 Mar 2003 8:55:49 -0000 Received: (qmail 32208 invoked from network); 10 Mar 2003 08:54:23 -0000 Received: from iris.logica.co.uk (158.234.9.163) by server-3.tower-1.messagelabs.com with SMTP; 10 Mar 2003 08:54:23 -0000 Received: from finches.logica.co.uk ([158.234.142.11]) by iris.logica.co.uk (8.9.3/8.9.3/Debian 8.9.3-21) with ESMTP id IAA18272; Mon, 10 Mar 2003 08:54:22 GMT X-Authentication-Warning: iris.logica.co.uk: Host [158.234.142.11] claimed to be finches.logica.co.uk Received: from finches.logica.co.uk (localhost [127.0.0.1]) by finches.logica.co.uk (8.11.6/8.11.6/SuSE Linux 0.5) with ESMTP id h2A8wK801558; Mon, 10 Mar 2003 09:58:20 +0100 X-VirusChecked: Checked cc: Zsh hackers list In-reply-to: <20030224184502.A9922@pcchazelas.free.fr> From: Oliver Kiddle References: <20030224184502.A9922@pcchazelas.free.fr> To: Stephane CHAZELAS Subject: Re: LC_NUMERIC=fr_FR and floating point arithmetics Date: Mon, 10 Mar 2003 09:58:20 +0100 Message-ID: <1556.1047286700@finches.logica.co.uk> On 24 Feb, Stephane CHAZELAS wrote: > $ LC_NUMERIC=fr_FR ksh93 -c 'float a=1; echo $(( a / 3 ))' > 0,333333333333 > $ LC_NUMERIC=fr_FR zsh -c 'float a=1; echo $(( a / 3 ))' > 0,33333333333333331. > > zsh seems to assume that "." is the decimal separator which is > not correct in a french locale. > > I agree this is confusing. A ksh93 script such as > echo $(( 1. / 3 )) > > won't work under french locale. > (must be echo $(( 1, / 3 )) ) Which is worse in my opinion. $(( 1.1 )) really ought to be interpreted as a 1 point 1 regardless of locale - it is otherwise impossible to use decimals in portable shell scripts. If we didn't have backward and ksh compatibility to consider, I would be inclined to say that $a for floats and $(( ... )) should always use the C locale and anyone wanting locale specific output could use printf (see below) (implementing this is easy; just save the LC_NUMERIC locale in convfloat()). But keeping locale handling in output means that scalar parameters can't be reused in a calculation. And making math evaluation accept either `.' or whatever the locale dictates is not easy when you consider that a comma in math evaluation is used as a separator: (( a=1, 3.4 )) Also, because we allow this: % a='3 + 4' % echo $(( a )) 7 you can't just interpret the comma in a parameter expansion. So I can't think of any solution except limiting math evaluation to the C locale. So what can we do? I did a grep for mon_decimal_point in /usr/share/i18n/locales to see if any other characters are used as decimal separators. It indicates that Portugal use `$' as their decimal separator. Seems weird. Apart from that it is , or . for the rest of the world except Burkina Faso who apparently use something outside the normal ASCII range. Currently, a bug prevents locale handling for printf (on at least some platforms). The bug causing this is in math.c where it does: prev_locale = setlocale(LC_NUMERIC, NULL); setlocale(LC_NUMERIC, "POSIX"); The second setlocale call clobbers prev_locale - we have to use dupstring(). The patch fixes this. Oliver diff -ur zsh-latest/Src/math.c localeprob2/Src/math.c --- zsh-latest/Src/math.c 2002-12-19 10:58:19.000000000 +0000 +++ localeprob2/Src/math.c 2003-03-09 01:13:18.000000000 +0000 @@ -399,12 +399,12 @@ /* it's a float */ yyval.type = MN_FLOAT; #ifdef USE_LOCALE - prev_locale = setlocale(LC_NUMERIC, NULL); + prev_locale = dupstring(setlocale(LC_NUMERIC, NULL)); setlocale(LC_NUMERIC, "POSIX"); #endif yyval.u.d = strtod(ptr, &nptr); #ifdef USE_LOCALE - setlocale(LC_NUMERIC, prev_locale); + if (prev_locale) setlocale(LC_NUMERIC, prev_locale); #endif if (ptr == nptr || *nptr == '.') { zerr("bad floating point constant", NULL, 0);