[LLVMbugs] [Bug 20537] duration_cast has rounding bug converting long double seconds to long long nanoseconds

bugzilla-daemon at llvm.org bugzilla-daemon at llvm.org
Tue Aug 5 09:18:14 PDT 2014


http://llvm.org/bugs/show_bug.cgi?id=20537

Marshall Clow (home) <mclow.lists at gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
         Resolution|---                         |INVALID

--- Comment #3 from Marshall Clow (home) <mclow.lists at gmail.com> ---
(In reply to comment #0)
> Converting from floating-point seconds to nanoseconds, there is a
> demonstrable rounding bug.  It looks like converting from floating-point
> seconds to integral nanoseconds uses division by 1e-9 instead of
> multiplication by 1e9 which causes rounding error when the floating-point
> storage is long double.

I believe that you've misdiagnosed what's going on here.
There is no division going on in your example.

If you have access to the C++11 standard, get a copy of section 20.11.5.7/2 and
let's step through it.

    typedef std::chrono::duration<long double> T;
    T x = 1.31_s;    
    x += 20_ms;

//  Let CF be ratio_divide<Period, typename ToDuration::period>
    typedef std::ratio_divide<T::period, nanoseconds::period>::type CF;
    std::cout << typeid(CF).name() << "\n";  // std::ratio<1000000000l, 1l>

//  and CR be common_type<typename ToDuration::rep, Rep, intmax_t>::type
    typedef std::common_type<nanoseconds::rep, T::rep, intmax_t>::type CR;
    std::cout << typeid(CR).name() << "\n";  // long double

//  Looking at [time.duration.cast]/2, this falls under the second bullet
    auto res = static_cast<CR>(x.count() * static_cast<CR>(CF::num));
//  this prints '1329999999.9999999999'
    std::cout << std::fixed << std::setprecision(10) << res << std::endl;
//  this prints '1329999999'
    std::cout << static_cast<long long>(res) << std::endl;

//  this prints '1329999999 vs 1330000000 from 1.3300000000'
    std::cout << duration_cast<nanoseconds>(x).count() << " from " << x.count()
<< "\n";

I think that the problem here is that your "1.33" is not really "1.33", but
rather "1.329999999xxxxx", so that when it gets multiplied and converted to an
integral type, you get 1329999999.

In any case, I'm pretty sure that it's not a bug in libc++. Please re-open if
you disagree.

-- 
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20140805/449b3791/attachment.html>


More information about the llvm-bugs mailing list