[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[lmi] fesetround() requirements and guarantees [Was: master a91cbc67: Ma
From: |
Greg Chicares |
Subject: |
[lmi] fesetround() requirements and guarantees [Was: master a91cbc67: Make two comparisons work even for x87] |
Date: |
Thu, 12 May 2022 09:06:42 +0000 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.8.0 |
On 5/11/22 15:30, Vadim Zeitlin wrote:
> On Wed, 11 May 2022 10:52:42 -0400 (EDT) Greg Chicares
> <gchicares@sbcglobal.net> wrote:
[...]
> GC> commit a91cbc67d7479e4b51a268748b9d1dabe2b66806
[...]
> IMHO these checks would be more readable if we had a materially_less() or
> its moral equivalent under some other name ("substantially_less" perhaps?).
>
> GC> @@ -557,7 +557,12 @@ double Irc7702A::MaxNonMecPremium
> GC> {
> GC> if(TestPeriodDur < TestPeriodLen)
> GC> {
> GC> - LMI_ASSERT(CumPmts <= CumSevenPP);
> GC> + // Weird condition--see:
> GC> + //
> https://lists.nongnu.org/archive/html/lmi/2022-05/msg00006.html
> GC> + LMI_ASSERT
> GC> + ( CumPmts <= CumSevenPP
> GC> + || materially_equal(CumSevenPP, CumPmts)
> GC> + );
>
> And having such function would also allow to put this URL in a single
> place instead of duplicating it wherever it's applicable.
True; however, instead of comparing floating-point values more carefully,
the real solution is to compare integral values. That's easier said than
done: here, for example, 'CumPmts' must be integral cents because it
represents actual payments, but 'CumSevenPP' can represent an irrational
number. I've postponed the currency-ization of tax-related code because
it's challenging, and because the existing implementation really needs
a thoroughgoing rewrite. I hope to get to that later in the year; until
then, I hesitate to beautify these ugly workarounds, because they should
soon be removed.
But there is one thing I've been tempted to beautify: this block...
// Do not save and restore prior rounding direction, because lmi
// generally expects rounding to nearest everywhere.
std::fesetround(FE_TONEAREST);
...preceding every call to std::nearbyint(). Probably that ought to be
factored into a function that could be called instead. But first let me
ask a couple of questions:
- Should the return code be checked? That is, can fesetround() ever
realistically fail when it's called with one of its predefined macro
arguments? I tend to think that checking it is useless: if it fails,
we can't do anything about the failure; and if it fails because some
variety of floating-point hardware lacks rounding control, then it
would presumably round to nearest.
- How often should this be called? C++20 [cfenv.syn] specifies that the
floating-point environment has "thread storage duration" and that
child threads inherit the calling thread's environment, so shouldn't
it be sufficient to set it OAOO, at program startup? C++20 doesn't
seem to require that the compiler library restore the original state
when a library function changes it, AFAICT; can they really have
left that as a QOI issue?
- Given that 'long double' calculations on x86_64 depend on the x87
state, and 'double' on the SSE state, I'm somewhat surprised that the
standard implies that there's exactly one floating-point environment.
When setting the rounding direction, should we set both? or is it
reasonable to hope that any reasonable compiler would do that for us?