unofficial mirror of guix-patches@gnu.org 
 help / color / mirror / code / Atom feed
From: "Ludovic Courtès" <ludo@gnu.org>
To: Maxime Devos <maximedevos@telenet.be>
Cc: 49659@debbugs.gnu.org
Subject: [bug#49659] [PATCH core-updates] gnu: guile: Fix failing tests on i686-linux.
Date: Tue, 20 Jul 2021 22:51:59 +0200	[thread overview]
Message-ID: <87fsw8k8sw.fsf_-_@gnu.org> (raw)
In-Reply-To: <ca331c5fb87a4d0697c5282e5452e0e0eaae6424.camel@telenet.be> (Maxime Devos's message of "Tue, 20 Jul 2021 18:55:52 +0200")

Maxime Devos <maximedevos@telenet.be> skribis:

> Ludovic Courtès schreef op di 20-07-2021 om 15:55 [+0200]:

[...]

>>   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 ‘supported’ cross-target.

Yes, makes sense.

>>      ?  (I wonder why armhf-linux doesn’t 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==8 (64 bits).
>
> (I'm ignoring MMX, SSE and the like.)
>
> I don't know any architectures beside x86 which have excess precision.
> "-fexcess-precision=standard" 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 ‘supported’ targets in Guix.

Alright.

I’d still err on the side of making the change only for target-x86-32?,
because that’s the only case where we know it’s needed.

>>   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.

OK.

>>   3. Do we have a clear explanation of why ‘-fexcess-precision=fast’
>>      (the default) would lead to failures in ‘numbers.test’?
>
> 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 
>   scm_i_inexact_floor_remainder
> (There are tests testing whether the results agree.)
>
> "-fexcess-precision=standard" 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.

Makes sense.  Seems to me that this should simply be implemented
differently to avoid the inconsistency in the first place (or one could
ignore IA32 altogether…).

> I dunno if 'floor' is broken.  Let me explain why this output is possible for 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 stack memory.
>   (doesn't apply here I think because SCM values discard the excess precision)
>
>   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 rounding
> choices may be different from those made for printf("%f", floor(x/y)).
>
> So this inconsistency (x/y=91.00... > 90.00 = floor(x/y))  doesn't really
> surprise me.  A more concrete scenario: suppose the CPU is configured to round
> 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 ‘rounding upwards’ mode, in ‘rounding downwards’ it might
>       have been slightly less than 91 as in (2))
>      Denote this approximation as F2.
>
> Then [floor(x/y)=] floor(F1)=floor(90.999...)=90.0,
> and  [x/y=] F2=91.0, thus we seemingly have x/y >= 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=%f, floor(x/y)=%f",x/y,floor(x/y)) will output "x/y=91.0 floor(x/y)=90.0".

I’m no expert but that makes sense to me.

Could you send an updated patch?

If you think of a way to fix the issue in Guile itself, we can also do
that.  :-)

Thanks for the investigation & explanation!

Ludo’.




  reply	other threads:[~2021-07-20 20:53 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-07-20 11:27 [bug#49659] [PATCH core-updates] gnu: guile: Fix failing tests on i686-linux Maxime Devos
2021-07-20 13:55 ` Ludovic Courtès
2021-07-20 16:55   ` Maxime Devos
2021-07-20 20:51     ` Ludovic Courtès [this message]
2021-07-20 18:22   ` Efraim Flashner
2021-07-20 21:34 ` [bug#49659] [PATCH v2\ core-updates v2] " Maxime Devos
2021-07-21 13:49   ` bug#49659: [PATCH core-updates] " Ludovic Courtès
2021-07-21 14:50     ` [bug#49659] " Mathieu Othacehe
2021-07-23  9:07       ` Ludovic Courtès
2021-07-23  9:27         ` Maxime Devos
2021-07-25 23:52         ` Thiago Jung Bauermann via Guix-patches via

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://guix.gnu.org/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87fsw8k8sw.fsf_-_@gnu.org \
    --to=ludo@gnu.org \
    --cc=49659@debbugs.gnu.org \
    --cc=maximedevos@telenet.be \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/guix.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).