[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [lmi] rint() vs. nearbyint()
From: |
Greg Chicares |
Subject: |
Re: [lmi] rint() vs. nearbyint() |
Date: |
Wed, 3 Feb 2021 22:01:27 +0000 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.4.0 |
On 2/3/21 1:04 AM, Vadim Zeitlin wrote:
> On Wed, 3 Feb 2021 00:02:28 +0000 Greg Chicares <gchicares@sbcglobal.net>
> wrote:
>
> GC> Vadim--C99 (N1256, which is probably good enough for this purpose) says:
> GC>
> GC> | F.9.6.4 The rint functions
> GC> | The rint functions differ from the nearbyint functions only in that
> they do raise the
> GC> | "inexact" floating-point exception if the result differs in value from
> the argument.
> GC>
> GC> Does this mean anything in practice--i.e., do library implementations
> GC> really differ? If so, is rint() implemented in terms of nearbyint(),
> GC> or vice versa?
>
> In theory, the answer depends on the implementors choice. And in a rare
> show of unity between the practice and the theory, in practice it does
> actually differ between the implementations.
Systemic postmodernism, rolling back the Enlightenment. The world
could just have embraced IEEE754 and done everything in silicon.
> GC> Here's why I ask. I really do want to call one of them with an infinite
> GC> argument. If either is faster, faster is preferable; and here I'm
> GC> interested in establishing a general principle, so I don't care if I'm
> GC> only saving a single machine cycle, as long as the savings is positive
> GC> or at least nonnegative.
(IOW, we always write "++j" here:
for(int j = 0; j < max_val; ++j)
and not "j++", because it's a rule of thumb that's sometimes beneficial
and never harmful; likewise, I'm trying to choose either nearbyint() or
rint() as the default tool that I can choose without thinking about it.)
> GC> But wait--I can just check the glibc sources myself:
> GC>
> GC>
> https://github.com/bminor/glibc/blob/be9b0b9a012780a403a266c90878efffb9a5f3ca/sysdeps/ieee754/dbl-64/s_rint.c
> GC>
> https://github.com/bminor/glibc/blob/be9b0b9a012780a403a266c90878efffb9a5f3ca/sysdeps/ieee754/dbl-64/s_nearbyint.c
> GC>
> GC> and it looks like my guess was wrong: nearbyint() is implemented as
> GC> a copy of the rint() code, surrounded by additional code to save and
> GC> restore fenv_t.
>
> Sorry, but I don't think this shows anything. You're probably looking at
> the generic code but it's (almost?) never used, AFAIK all normal platforms
> have the built-in versions of these functions. Unfortunately I don't know
> where are those defined (I couldn't find them quickly in gcc sources,
> although they definitely must be there somewhere)
Thanks for pointing that out.
> and I've confirmed that this is the code which actually gets used when you
> call these functions, i.e. rint() is just a frndint in disguise, while
> nearbyint() contains a few more instructions.
>
> GC> Of course, some other standard library may do differently, but this
> GC> is good enough for me: rint() is terser, and is likely to be faster.
>
> So this conclusion is still correct for the standard library we use, but
> not necessarily for the other ones.
Well, it's still terser for all standard libraries; and if that's
the only universal truth that can be established, it's good enough.