Received: (at 49659) by debbugs.gnu.org; 20 Jul 2021 16:56:10 +0000
From debbugs-submit-bounces@debbugs.gnu.org Tue Jul 20 12:56:10 2021
Received: from localhost ([127.0.0.1]:35219 helo=debbugs.gnu.org)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from )
id 1m5t2P-0002zw-UI
for submit@debbugs.gnu.org; Tue, 20 Jul 2021 12:56:10 -0400
Received: from andre.telenet-ops.be ([195.130.132.53]:59904)
by debbugs.gnu.org with esmtp (Exim 4.84_2)
(envelope-from ) id 1m5t2M-0002zm-6n
for 49659@debbugs.gnu.org; Tue, 20 Jul 2021 12:56:09 -0400
Received: from ptr-bvsjgyjmffd7q9timvx.18120a2.ip6.access.telenet.be
([IPv6:2a02:1811:8c09:9d00:aaf1:9810:a0b8:a55d])
by andre.telenet-ops.be with bizsmtp
id XUw42500K0mfAB401Uw4gl; Tue, 20 Jul 2021 18:56:04 +0200
Message-ID:
Subject: Re: bug#49659: [PATCH core-updates] gnu: guile: Fix failing tests
on i686-linux.
From: Maxime Devos
To: Ludovic =?ISO-8859-1?Q?Court=E8s?=
Date: Tue, 20 Jul 2021 18:55:52 +0200
In-Reply-To: <871r7tks2i.fsf@gnu.org>
References: <20210720112712.25905-1-maximedevos@telenet.be>
<871r7tks2i.fsf@gnu.org>
Content-Type: multipart/signed; micalg="pgp-sha512";
protocol="application/pgp-signature"; boundary="=-FPoAg0/iGbMpsN6KuKTy"
User-Agent: Evolution 3.34.2
MIME-Version: 1.0
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=telenet.be; s=r21;
t=1626800164; bh=rbHL3mQHMPSX1w8DWb4NOGYHclsXlcAyXvVJAJ4H8eM=;
h=Subject:From:To:Cc:Date:In-Reply-To:References;
b=hu7ZWMR9+k6zKtkDVTXiRCYT3bBzX622krfz1vmbHjUwnzdUY54rLI2FCyHCr2R2b
Ja26xmdEGwG5zl0f22F30xd5nXM0VFswYLrXuSsh9RZuqpcLvM47kZ+Mnisab9zD9C
tGJM2t1PQr8sFwZSVYEiV5eNAclnfE8q1ze/FWw2jVWLzMtWwVWRlDQVhSau5NErCS
aRYj71dMpfN7TIHh+H/szBUnqE/6Jg7fOP0Cf30b1dREEMCRD8fWXN61lhJFF6hIMT
ELZ+iB2q9ixq84EG7IM8CY1yWBkK5BMdgQcI9grrnsvWHbcLIWXpqbSZNileKLXrgq
NUu8N0EGFDCUQ==
X-Spam-Score: -0.7 (/)
X-Debbugs-Envelope-To: 49659
Cc: 49659@debbugs.gnu.org
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.7 (-)
--=-FPoAg0/iGbMpsN6KuKTy
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
Ludovic Court=C3=A8s schreef op di 20-07-2021 om 15:55 [+0200]:
> Hi!
>=20
> Maxime Devos skribis:
>=20
> > i586-gnu might have the same issue.
>=20
> Please add a =E2=80=9CFixes =E2=80=A6=E2=80=9D line.
I didn't find the bug report.
> > (substitute-keyword-arguments (package-arguments guile-2.2)
> > ((#:configure-flags flags ''())
> > - (let ((flags `(cons "--enable-mini-gmp" ,flags)))
> > + ;; -fexcess-precision=3Dstandard is required when compiling fo=
r
> > + ;; i686-linux, otherwise "numbers.test" will fail.
> > + (let ((flags `(cons* "CFLAGS=3D-g -O2 -fexcess-precision=3Dsta=
ndard"
> > + "--enable-mini-gmp" ,flags)))
>=20
> Yay! Questions:
>=20
> 1. Should we make it conditional on
> (or (string-prefix? "i686-" %host-type)
> (string-prefix? "i586-" %host-type))
Rather, (target-x86-32?). target-x86-32? also recognises "i486-linux-gnu"
even though that's not a =E2=80=98supported=E2=80=99 cross-target.
> ? (I wonder why armhf-linux doesn=E2=80=99t have the same problem.)
AFAIK floats & doubles on arm don't have excess precision.
Floating-point numbers are either 32-bit or 64-bit,
unlike in x86, where the floating-point registers are 80-bit
but (sizeof) double=3D=3D8 (64 bits).
(I'm ignoring MMX, SSE and the like.)
I don't know any architectures beside x86 which have excess precision.
"-fexcess-precision=3Dstandard" should be harmless on architectures
that don't have excess precision.
I'd make it unconditional, but conditional on x86-target? should work
for all =E2=80=98supported=E2=80=99 targets in Guix.
> 2. Is there any downside to compiling all of libguile with this flag?
I searched with "git grep -F double" and "git grep -F float".
Floating-point arithmetic doen't seem to be used much outside numbers.c.
There's vm-engine.c, but the results of the calculations are written
to some (stack?) memory (not a register), so the excess precision
would be thrown away anyway, so I don't expect a slow-down.
No code appears to be relying on excess precision.
> 3. Do we have a clear explanation of why =E2=80=98-fexcess-precision=3D=
fast=E2=80=99
> (the default) would lead to failures in =E2=80=98numbers.test=E2=80=
=99?
The problem I think is that the rounding choices made in
scm_i_inexact_floor_divide
must be consistent with those made in
scm_i_inexact_floor_quotient
and=20
scm_i_inexact_floor_remainder
(There are tests testing whether the results agree.)
"-fexcess-precision=3Dstandard" reduces the degrees of freedom GCC has
in choosing when to round, so it is more likely the rounding choices
coincide? It's only an untested hypothesis though.
FWIW, I think this line:
/* in scm_i_inexact_floor_remainder */
return scm_i_from_double (x - y * floor (x / y));
should be (for less fragility in case GCC changes its optimisations and
register allocation / spilling)
/* in scm_i_inexact_floor_remainder */
return scm_i_from_double (x - y * (double) floor (x / y));
even then, there's no guarantee the rounding choices for x/y
are the same in scm_i_inexact_floor_divide, scm_i_inexact_floor_remainder
and scm_i_inexact_floor_quotient.
> I looked at the GCC manual (info "(gcc) Optimize Options") and at links
> you provided earlier on IRC, but I can=E2=80=99t really explain how this =
would
> lead those tests to fail: ;.
> I added a =E2=80=98printf=E2=80=99 call in =E2=80=98scm_i_inexact_floor_d=
ivide=E2=80=99, which is where
> it all happens:
>=20
> --8<---------------cut here---------------start------------->8---
> static void
> scm_i_inexact_floor_divide (double x, double y, SCM *qp, SCM *rp)
> {
> if (SCM_UNLIKELY (y =3D=3D 0))
> scm_num_overflow (s_scm_floor_divide); /* or return a NaN? */
> else
> {
> double q =3D floor (x / y);
> double r =3D x - q * y;
> printf ("%s x=3D%f y=3D%f x/y=3D%f floor(x/y)=3D%f q=3D%f r=3D%f\n"=
, __func__,
> x, y, x/y, floor (x/y), q, r);
> *qp =3D scm_i_from_double (q);
> *rp =3D scm_i_from_double (r);
> }
> }
> --8<---------------cut here---------------end--------------->8---
>=20
> I get this:
>=20
> --8<---------------cut here---------------start------------->8---
> scheme@(guile-user)> (euclidean/ 130. (exact->inexact 10/7))
> scm_i_inexact_floor_divide x=3D130.000000 y=3D1.428571 x/y=3D91.000000 fl=
oor(x/y)=3D90.000000 q=3D90.000000 r=3D1.428571
> $1 =3D 90.0
> $2 =3D 1.4285714285714257
> --8<---------------cut here---------------end--------------->8---
>=20
> So it=E2=80=99s really =E2=80=98floor=E2=80=99 that=E2=80=99s messing up =
somehow.
>=20
I dunno if 'floor' is broken. Let me explain why this output is possible f=
or a
well-implemented 'floor':
I want to note that printf("%f", floor(x/y))
can display 16 different strings:
GCC can choose to round 'x' and/or 'y' by moving it from a register to st=
ack memory.
(doesn't apply here I think because SCM values discard the excess precisi=
on)
GCC can choose to round the result of x/y (same reasons)
GCC can choose to round the result of floor(x/y) (same reasons)
Likewise, printf("%f", x/y) can display 8 different strings, and the roundi=
ng
choices may be different from those made for printf("%f", floor(x/y)).
So this inconsistency (x/y=3D91.00... > 90.00 =3D floor(x/y)) doesn't real=
ly
surprise me. A more concrete scenario: suppose the CPU is configured to ro=
und
upwards, and 'floor' is a mapping between extended-precision floating-point=
numbers.
Let 'x' and 'y' be two floating-point numbers, such that:
(1) the mathematical value of 'x/y' is slightly less than 91
(2) 'x/y' when calculated in extended precision is slightly less than 91.
Denote this approximation as F1.
(3) 'x/y' when calculated in double precision is 91 (or slightly larger)
(due to the =E2=80=98rounding upwards=E2=80=99 mode, in =E2=80=98round=
ing downwards=E2=80=99 it might
have been slightly less than 91 as in (2))
Denote this approximation as F2.
Then [floor(x/y)=3D] floor(F1)=3Dfloor(90.999...)=3D90.0,
and [x/y=3D] F2=3D91.0, thus we seemingly have x/y >=3D 1 + floor(x/y),
even though that's mathematically nonsense.
Thus, by choosing when to round (in-)appropriately, it is possible (on x86)
that printf("x/y=3D%f, floor(x/y)=3D%f",x/y,floor(x/y)) will output "x/y=3D=
91.0 floor(x/y)=3D90.0".
(Please tell if I made an error somewhere.)
Greetings,
Maxime
--=-FPoAg0/iGbMpsN6KuKTy
Content-Type: application/pgp-signature; name="signature.asc"
Content-Description: This is a digitally signed message part
Content-Transfer-Encoding: 7bit
-----BEGIN PGP SIGNATURE-----
iI0EABYKADUWIQTB8z7iDFKP233XAR9J4+4iGRcl7gUCYPcAGBccbWF4aW1lZGV2
b3NAdGVsZW5ldC5iZQAKCRBJ4+4iGRcl7hKyAQDJ5XlQC2mQ7FYEHe5CSJkDoEru
yljUJ9ZQ9NoE8PgYMAEAyRzRhrXT5MyPD6NUUNrwVAvAy1twRHMZpQ2S8EbVMQQ=
=PqZC
-----END PGP SIGNATURE-----
--=-FPoAg0/iGbMpsN6KuKTy--