From unknown Sat Jun 14 03:53:32 2025 X-Loop: help-debbugs@gnu.org Subject: bug#51276: Problems with format and scaling floats Resent-From: Timothy Sample Original-Sender: "Debbugs-submit" Resent-CC: bug-guile@gnu.org Resent-Date: Mon, 18 Oct 2021 21:24:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: report 51276 X-GNU-PR-Package: guile X-GNU-PR-Keywords: To: 51276@debbugs.gnu.org X-Debbugs-Original-To: bug-guile@gnu.org Received: via spool by submit@debbugs.gnu.org id=B.163459218310081 (code B ref -1); Mon, 18 Oct 2021 21:24:02 +0000 Received: (at submit) by debbugs.gnu.org; 18 Oct 2021 21:23:03 +0000 Received: from localhost ([127.0.0.1]:48763 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mca63-0002cW-CL for submit@debbugs.gnu.org; Mon, 18 Oct 2021 17:23:03 -0400 Received: from lists.gnu.org ([209.51.188.17]:39456) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mca60-0002bw-EQ for submit@debbugs.gnu.org; Mon, 18 Oct 2021 17:23:01 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:46864) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mca60-0001b4-3J for bug-guile@gnu.org; Mon, 18 Oct 2021 17:23:00 -0400 Received: from wout4-smtp.messagingengine.com ([64.147.123.20]:38207) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mca5u-0007Em-LH for bug-guile@gnu.org; Mon, 18 Oct 2021 17:22:59 -0400 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.west.internal (Postfix) with ESMTP id 5A1023201C4E for ; Mon, 18 Oct 2021 17:22:51 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute3.internal (MEProxy); Mon, 18 Oct 2021 17:22:51 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=content-type:date:from:message-id :mime-version:subject:to:x-me-proxy:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm1; bh=KRQBpzgttjWhskqonYd3NIs9j+uSR YP1/R6tQ0voHQI=; b=LrFG4nBsVPk96A7v3u+lj+bzCpmmpxWPXHVTvBRyAnqB5 64JOQKpXPlGZ95Ai6D+BW0dUKbI52fgwjJBc+24kGES7UM4cMQwwEIaLJ7r9RzJH GF3zMoMXV39LSSfhC8PBsa+M+sCQRQbhEXT67UodlRA+lWx5WOTobf1gIF8ReuLu b5Z5qUnxu6cWQe1iOEzH63RKq6RCe/0Y5yobktYv7kR+naD0H+kNeNK/bsKASeyx 0NParmbLteUVUicgCGJiorpERkTi4m3cvcQNUHnULWTgH+GQjJnTQNhGemPkBoLF kPJwGOptabL50qGc7/wWTDWs/Y0xX5dOjs15Oqo4A== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvtddrvddvtddgudehiecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfgh necuuegrihhlohhuthemuceftddtnecunecujfgurhephffvufffkfgfgggtsehmtderre dtreejnecuhfhrohhmpefvihhmohhthhihucfurghmphhlvgcuoehsrghmphhlvghtsehn ghihrhhordgtohhmqeenucggtffrrghtthgvrhhnpedvleelvdeiffffudefhfffhfekke fggfeftddugefhudegtdeklefggeffledvtdenucevlhhushhtvghrufhiiigvpedtnecu rfgrrhgrmhepmhgrihhlfhhrohhmpehsrghmphhlvghtsehnghihrhhordgtohhm X-ME-Proxy: Received: by mail.messagingengine.com (Postfix) with ESMTPA for ; Mon, 18 Oct 2021 17:22:50 -0400 (EDT) From: Timothy Sample Date: Mon, 18 Oct 2021 17:22:49 -0400 Message-ID: <87tuhejady.fsf@ngyro.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.2 (gnu/linux) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Received-SPF: pass client-ip=64.147.123.20; envelope-from=samplet@ngyro.com; helo=wout4-smtp.messagingengine.com X-Spam_score_int: -23 X-Spam_score: -2.4 X-Spam_bar: -- X-Spam_report: (-2.4 / 5.0 requ) BAYES_00=-1.9, DKIM_INVALID=0.1, DKIM_SIGNED=0.1, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Spam-Score: -1.6 (-) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -2.6 (--) --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Hi Guilers, It turns out there=E2=80=99s a little blunder in =E2=80=98format=E2=80=99 (= from =E2=80=98ice-9=E2=80=99). Look at what happens when using the SCALE argument to format a fixed-point float (this is Guile from the Git repo at the time of writing): GNU Guile 3.0.7.6-22120 Copyright (C) 1995-2021 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. scheme@(guile-user)> (format #t "~,,3f~%" 0.00123) 0.23 $3 =3D #t scheme@(guile-user)> (format #t "~,,1f~%" 0.00123) ice-9/boot-9.scm:1685:16: In procedure raise-exception: Value out of range 0 to 400: -1 Entering a new prompt. Type `,bt' for a backtrace or `,q' to continue. The first example gives the wrong result. Scaling 0.00123 by 3 should yield 1.23, not 0.23. For the second example, instead of 0.0123, we get an error! What=E2=80=99s going on here? Well, our =E2=80=98format=E2=80=99 code comes from SLIB and was written in = 1998, so it=E2=80=99s not easy to explain. There=E2=80=99s so much mutation even a C programmer = would blush! ;) The issue happens in the =E2=80=98format:parse-float=E2=80=99 p= rocedure (which is defined inside of =E2=80=98format=E2=80=99). It normalizes the s= tring representation of a number, and applies the scale argument when needed. It does this by keeping a string of digits and the location of the decimal point. Another thing it keeps track of the leading zeros in a variable called =E2=80=98left-zeros=E2=80=99. Here=E2=80=99s the code that= does the final shifting and places the decimal point: (if (> left-zeros 0) (if (<=3D left-zeros shift) ; shift always > 0 here (format:fn-shiftleft shift) ; shift out 0s (begin (format:fn-shiftleft left-zeros) (set! format:fn-dot (- shift left-zeros)))) (set! format:fn-dot (+ format:fn-dot shift))) The issue is that the cases in the inner =E2=80=98if=E2=80=99 form are reve= rsed. That is, if there are MORE leading zeros than we need to shift, we can just shift. Otherwise (if there are FEWER leading zeros), we need to shift out the zeros and then move the decimal point (=E2=80=98format:fn-dot=E2=80= =99). AFAICS, this bug was in the original SLIB implementation (1998) and has not been fixed since then. It=E2=80=99s been in Guile since 1999. Anyway, that=E2=80=99s more than anyone cares to know.... Here=E2=80=99s a= patch with tests! :) --=-=-= Content-Type: text/x-patch Content-Disposition: inline; filename=0001-ice-9-format-Fix-scaling-floats-with-leading-zeros.patch >From c31d1f5d44343da1201ea1be86bc6b2ac8af6c8d Mon Sep 17 00:00:00 2001 From: Timothy Sample Date: Mon, 18 Oct 2021 17:07:41 -0400 Subject: [PATCH] ice-9 format: Fix scaling floats with leading zeros --- module/ice-9/format.scm | 4 ++-- test-suite/tests/format.test | 10 ++++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/module/ice-9/format.scm b/module/ice-9/format.scm index 48d9c0c84..ee7cba910 100644 --- a/module/ice-9/format.scm +++ b/module/ice-9/format.scm @@ -1359,10 +1359,10 @@ (else (if (> left-zeros 0) (if (<= left-zeros shift) ; shift always > 0 here - (format:fn-shiftleft shift) ; shift out 0s (begin (format:fn-shiftleft left-zeros) - (set! format:fn-dot (- shift left-zeros)))) + (set! format:fn-dot (- shift left-zeros))) + (format:fn-shiftleft shift)) ; shift out 0s (set! format:fn-dot (+ format:fn-dot shift)))))))) (let ((negexp ; expon format m.nnnEee diff --git a/test-suite/tests/format.test b/test-suite/tests/format.test index b9aa7a854..d5111f1c6 100644 --- a/test-suite/tests/format.test +++ b/test-suite/tests/format.test @@ -2,7 +2,7 @@ ;;;; Matthias Koeppe --- June 2001 ;;;; ;;;; Copyright (C) 2001, 2003, 2004, 2006, 2010, 2011, 2012, -;;;; 2014, 2017 Free Software Foundation, Inc. +;;;; 2014, 2017, 2021 Free Software Foundation, Inc. ;;;; ;;;; This library is free software; you can redistribute it and/or ;;;; modify it under the terms of the GNU Lesser General Public @@ -121,7 +121,13 @@ ;; in guile prior to 1.6.9 and 1.8.1, leading zeros were incorrectly ;; stripped, moving the decimal point and giving "25.0" here (pass-if "string 02.5" - (string=? "2.5" (format #f "~f" "02.5")))) + (string=? "2.5" (format #f "~f" "02.5"))) + + (pass-if "scale with few leading zeros" + (string=? "1.23" (format #f "~,,3f" "0.00123"))) + + (pass-if "scale with many leading zeros" + (string=? "0.0123" (format #f "~,,1f" "0.00123")))) ;;; ;;; ~h -- 2.33.0 --=-=-=-- From unknown Sat Jun 14 03:53:32 2025 X-Loop: help-debbugs@gnu.org Subject: bug#51276: Problems with format and scaling floats Resent-From: lloda Original-Sender: "Debbugs-submit" Resent-CC: bug-guile@gnu.org Resent-Date: Tue, 19 Oct 2021 01:03:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 51276 X-GNU-PR-Package: guile X-GNU-PR-Keywords: To: Timothy Sample Cc: 51276@debbugs.gnu.org Received: via spool by 51276-submit@debbugs.gnu.org id=B51276.16346053565942 (code B ref 51276); Tue, 19 Oct 2021 01:03:01 +0000 Received: (at 51276) by debbugs.gnu.org; 19 Oct 2021 01:02:36 +0000 Received: from localhost ([127.0.0.1]:48903 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mcdWV-0001XX-Tz for submit@debbugs.gnu.org; Mon, 18 Oct 2021 21:02:36 -0400 Received: from mta-14-3.privateemail.com ([198.54.127.110]:53563) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mcdWR-0001R8-Pe for 51276@debbugs.gnu.org; Mon, 18 Oct 2021 21:02:34 -0400 Received: from mta-14.privateemail.com (localhost [127.0.0.1]) by mta-14.privateemail.com (Postfix) with ESMTP id C70C718000A3; Mon, 18 Oct 2021 21:02:25 -0400 (EDT) Received: from [192.168.1.105] (unknown [10.20.151.206]) by mta-14.privateemail.com (Postfix) with ESMTPA id 08F78180009E; Mon, 18 Oct 2021 21:02:24 -0400 (EDT) Content-Type: text/plain; charset=utf-8 Mime-Version: 1.0 (Mac OS X Mail 13.4 \(3608.120.23.2.7\)) From: lloda In-Reply-To: <87tuhejady.fsf@ngyro.com> Date: Tue, 19 Oct 2021 03:02:22 +0200 Content-Transfer-Encoding: quoted-printable Message-Id: References: <87tuhejady.fsf@ngyro.com> X-Mailer: Apple Mail (2.3608.120.23.2.7) X-Virus-Scanned: ClamAV using ClamSMTP X-Spam-Score: -0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Thank you very much, patch applied! Now that you've dived into (ice-9 format), what about this one: (format #t "~,,2f~%" 0.01) =3D> 1.0 (format #t "~,,3f~%" 0.01) ; !! =3D> 010.0 (format #t "~,,3f~%" 0.001) =3D> 1.0 (format #t "~,,4f~%" 0.001) ; !! =3D> 0010.0 (format #t "~,,4f~%" 0.0001) =3D> 1.0 (format #t "~,,5f~%" 0.0001) ; ok somehow... =3D> 10.0 regards > On 18 Oct 2021, at 23:22, Timothy Sample wrote: >=20 > Hi Guilers, >=20 > It turns out there=E2=80=99s a little blunder in =E2=80=98format=E2=80=99= (from =E2=80=98ice-9=E2=80=99). Look > at what happens when using the SCALE argument to format a fixed-point > float (this is Guile from the Git repo at the time of writing): >=20 > GNU Guile 3.0.7.6-22120 > Copyright (C) 1995-2021 Free Software Foundation, Inc. >=20 > Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show = w'. > This program is free software, and you are welcome to redistribute = it > under certain conditions; type `,show c' for details. >=20 > Enter `,help' for help. > scheme@(guile-user)> (format #t "~,,3f~%" 0.00123) > 0.23 > $3 =3D #t > scheme@(guile-user)> (format #t "~,,1f~%" 0.00123) > ice-9/boot-9.scm:1685:16: In procedure raise-exception: > Value out of range 0 to 400: -1 >=20 > Entering a new prompt. Type `,bt' for a backtrace or `,q' to = continue. >=20 > The first example gives the wrong result. Scaling 0.00123 by 3 should > yield 1.23, not 0.23. For the second example, instead of 0.0123, we = get > an error! What=E2=80=99s going on here? >=20 > Well, our =E2=80=98format=E2=80=99 code comes from SLIB and was = written in 1998, so it=E2=80=99s > not easy to explain. There=E2=80=99s so much mutation even a C = programmer would > blush! ;) The issue happens in the =E2=80=98format:parse-float=E2=80=99= procedure > (which is defined inside of =E2=80=98format=E2=80=99). It normalizes = the string > representation of a number, and applies the scale argument when = needed. > It does this by keeping a string of digits and the location of the > decimal point. Another thing it keeps track of the leading zeros in a > variable called =E2=80=98left-zeros=E2=80=99. Here=E2=80=99s the code = that does the final > shifting and places the decimal point: >=20 > (if (> left-zeros 0) > (if (<=3D left-zeros shift) ; shift always > 0 here > (format:fn-shiftleft shift) ; shift out 0s > (begin > (format:fn-shiftleft left-zeros) > (set! format:fn-dot (- shift left-zeros)))) > (set! format:fn-dot (+ format:fn-dot shift))) >=20 > The issue is that the cases in the inner =E2=80=98if=E2=80=99 form are = reversed. That > is, if there are MORE leading zeros than we need to shift, we can just > shift. Otherwise (if there are FEWER leading zeros), we need to shift > out the zeros and then move the decimal point (=E2=80=98format:fn-dot=E2= =80=99). >=20 > AFAICS, this bug was in the original SLIB implementation (1998) and = has > not been fixed since then. It=E2=80=99s been in Guile since 1999. >=20 > Anyway, that=E2=80=99s more than anyone cares to know.... Here=E2=80=99= s a patch with > tests! :) >=20 > =46rom c31d1f5d44343da1201ea1be86bc6b2ac8af6c8d Mon Sep 17 00:00:00 = 2001 > From: Timothy Sample > Date: Mon, 18 Oct 2021 17:07:41 -0400 > Subject: [PATCH] ice-9 format: Fix scaling floats with leading zeros >=20 > --- > module/ice-9/format.scm | 4 ++-- > test-suite/tests/format.test | 10 ++++++++-- > 2 files changed, 10 insertions(+), 4 deletions(-) >=20 > diff --git a/module/ice-9/format.scm b/module/ice-9/format.scm > index 48d9c0c84..ee7cba910 100644 > --- a/module/ice-9/format.scm > +++ b/module/ice-9/format.scm > @@ -1359,10 +1359,10 @@ > (else > (if (> left-zeros 0) > (if (<=3D left-zeros shift) ; shift always = > 0 here > - (format:fn-shiftleft shift) ; shift = out 0s > (begin > (format:fn-shiftleft left-zeros) > - (set! format:fn-dot (- shift = left-zeros)))) > + (set! format:fn-dot (- shift = left-zeros))) > + (format:fn-shiftleft shift)) ; shift = out 0s > (set! format:fn-dot (+ format:fn-dot = shift)))))))) >=20 > (let ((negexp ; expon format m.nnnEee > diff --git a/test-suite/tests/format.test = b/test-suite/tests/format.test > index b9aa7a854..d5111f1c6 100644 > --- a/test-suite/tests/format.test > +++ b/test-suite/tests/format.test > @@ -2,7 +2,7 @@ > ;;;; Matthias Koeppe --- June = 2001 > ;;;; > ;;;; Copyright (C) 2001, 2003, 2004, 2006, 2010, 2011, 2012, > -;;;; 2014, 2017 Free Software Foundation, Inc. > +;;;; 2014, 2017, 2021 Free Software Foundation, Inc. > ;;;; > ;;;; This library is free software; you can redistribute it and/or > ;;;; modify it under the terms of the GNU Lesser General Public > @@ -121,7 +121,13 @@ > ;; in guile prior to 1.6.9 and 1.8.1, leading zeros were incorrectly > ;; stripped, moving the decimal point and giving "25.0" here > (pass-if "string 02.5" > - (string=3D? "2.5" (format #f "~f" "02.5")))) > + (string=3D? "2.5" (format #f "~f" "02.5"))) > + > + (pass-if "scale with few leading zeros" > + (string=3D? "1.23" (format #f "~,,3f" "0.00123"))) > + > + (pass-if "scale with many leading zeros" > + (string=3D? "0.0123" (format #f "~,,1f" "0.00123")))) >=20 > ;;; > ;;; ~h > --=20 > 2.33.0 >=20 From unknown Sat Jun 14 03:53:32 2025 X-Loop: help-debbugs@gnu.org Subject: bug#51276: Problems with format and scaling floats Resent-From: Bengt Richter Original-Sender: "Debbugs-submit" Resent-CC: bug-guile@gnu.org Resent-Date: Tue, 19 Oct 2021 08:44:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 51276 X-GNU-PR-Package: guile X-GNU-PR-Keywords: To: Timothy Sample Cc: 51276@debbugs.gnu.org Reply-To: Bengt Richter Received: via spool by 51276-submit@debbugs.gnu.org id=B51276.163463298710844 (code B ref 51276); Tue, 19 Oct 2021 08:44:02 +0000 Received: (at 51276) by debbugs.gnu.org; 19 Oct 2021 08:43:07 +0000 Received: from localhost ([127.0.0.1]:49369 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mckiB-0002oq-GP for submit@debbugs.gnu.org; Tue, 19 Oct 2021 04:43:07 -0400 Received: from imta-35.everyone.net ([216.200.145.35]:60104 helo=imta-38.everyone.net) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mcki7-0002oX-6a for 51276@debbugs.gnu.org; Tue, 19 Oct 2021 04:43:06 -0400 Received: from pps.filterd (m0004961.ppops.net [127.0.0.1]) by imta-38.everyone.net (8.16.0.43/8.16.0.43) with SMTP id 19J8gHFi021769; Tue, 19 Oct 2021 01:43:01 -0700 X-Eon-Originating-Account: vcvb2okAtsKTSb1vohNFSKl1CkBaOAnUGYKnjtkqgKA X-Eon-Dm: m0116953.ppops.net Received: by m0116953.mta.everyone.net (EON-AUTHRELAY2 - 53b92b76) id m0116953.615b1d6e.1e9871; Tue, 19 Oct 2021 01:43:00 -0700 X-Eon-Sig: AQMHrIJhboUU7HAV4gIAAAAC,7deaa4179e74c43289fc9f3733a515cb X-Eip: di0jzi7bKTOwjG-D0BYV-E2onsHCNT29_ojitNsaH6Y Date: Tue, 19 Oct 2021 10:42:49 +0200 From: Bengt Richter Message-ID: <20211019084249.GA2281@LionPure> References: <87tuhejady.fsf@ngyro.com> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: 8bit In-Reply-To: <87tuhejady.fsf@ngyro.com> User-Agent: Mutt/1.10.1 (2018-07-13) X-Proofpoint-ORIG-GUID: M5vCLD4X9qfOUqC6S-TQU-z15W3yvqQI X-Proofpoint-GUID: M5vCLD4X9qfOUqC6S-TQU-z15W3yvqQI X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.425, 18.0.790 definitions=2021-10-18_07:2021-10-18, 2021-10-18 signatures=0 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 impostorscore=0 lowpriorityscore=0 priorityscore=1501 phishscore=0 adultscore=0 mlxlogscore=999 clxscore=1034 malwarescore=0 spamscore=0 bulkscore=0 suspectscore=0 mlxscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2109230001 definitions=main-2110190053 X-Spam-Score: 0.2 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -0.8 (/) Nice catch :) On +2021-10-18 17:22:49 -0400, Timothy Sample wrote: > Hi Guilers, > > It turns out there’s a little blunder in ‘format’ (from ‘ice-9’). Look > at what happens when using the SCALE argument to format a fixed-point > float (this is Guile from the Git repo at the time of writing): > > GNU Guile 3.0.7.6-22120 > Copyright (C) 1995-2021 Free Software Foundation, Inc. > > Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. > This program is free software, and you are welcome to redistribute it > under certain conditions; type `,show c' for details. > > Enter `,help' for help. > scheme@(guile-user)> (format #t "~,,3f~%" 0.00123) > 0.23 > $3 = #t > scheme@(guile-user)> (format #t "~,,1f~%" 0.00123) > ice-9/boot-9.scm:1685:16: In procedure raise-exception: > Value out of range 0 to 400: -1 > > Entering a new prompt. Type `,bt' for a backtrace or `,q' to continue. > > The first example gives the wrong result. Scaling 0.00123 by 3 should > yield 1.23, not 0.23. For the second example, instead of 0.0123, we get > an error! What’s going on here? > > Well, our ‘format’ code comes from SLIB and was written in 1998, so it’s > not easy to explain. There’s so much mutation even a C programmer would > blush! ;) The issue happens in the ‘format:parse-float’ procedure > (which is defined inside of ‘format’). It normalizes the string > representation of a number, and applies the scale argument when needed. > It does this by keeping a string of digits and the location of the > decimal point. Another thing it keeps track of the leading zeros in a > variable called ‘left-zeros’. Here’s the code that does the final > shifting and places the decimal point: > > (if (> left-zeros 0) > (if (<= left-zeros shift) ; shift always > 0 here > (format:fn-shiftleft shift) ; shift out 0s > (begin > (format:fn-shiftleft left-zeros) > (set! format:fn-dot (- shift left-zeros)))) > (set! format:fn-dot (+ format:fn-dot shift))) > > The issue is that the cases in the inner ‘if’ form are reversed. That > is, if there are MORE leading zeros than we need to shift, we can just > shift. Otherwise (if there are FEWER leading zeros), we need to shift > out the zeros and then move the decimal point (‘format:fn-dot’). > > AFAICS, this bug was in the original SLIB implementation (1998) and has > not been fixed since then. It’s been in Guile since 1999. > > Anyway, that’s more than anyone cares to know.... Here’s a patch with > tests! :) > 1999 until now (2021), /and/ reliably reproduced all that time! :) -- Regards, Bengt Richter