• Re: How to get mantissa of long double?

    From RadicalRabbit@theburrow.co.uk@21:1/5 to wij on Fri Oct 1 16:09:10 2021
    On Fri, 1 Oct 2021 08:37:21 -0700 (PDT)
    wij <wyniijj@gmail.com> wrote:
    // numeric_limits<long double>::digits=64.
    //
    typedef long double FType;
    FType x=numeric_limits<FType>::max();
    int iexp;
    int64_t mint;
    x=::frexpl(x,&iexp);
    x=::ldexpl(x,numeric_limits<FType>::digits);
    mint= static_cast<int64_t>(x);

    Result (mint) is a negative number, something not right!!!

    It might help if you set iexp to some value.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From wij@21:1/5 to All on Fri Oct 1 08:37:21 2021
    // numeric_limits<long double>::digits=64.
    //
    typedef long double FType;
    FType x=numeric_limits<FType>::max();
    int iexp;
    int64_t mint;
    x=::frexpl(x,&iexp);
    x=::ldexpl(x,numeric_limits<FType>::digits);
    mint= static_cast<int64_t>(x);

    Result (mint) is a negative number, something not right!!!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bonita Montero@21:1/5 to All on Fri Oct 1 19:18:43 2021
    Am 01.10.2021 um 17:37 schrieb wij:
    // numeric_limits<long double>::digits=64.
    //
    typedef long double FType;
    FType x=numeric_limits<FType>::max();
    int iexp;
    int64_t mint;
    x=::frexpl(x,&iexp);
    x=::ldexpl(x,numeric_limits<FType>::digits);
    mint= static_cast<int64_t>(x);

    Result (mint) is a negative number, something not right!!!

    Take this:

    #include <iostream>
    #include <cstdint>
    #include <limits>
    #include <utility>
    #include <iomanip>

    using namespace std;

    using mantissa_pair = pair<bool, uint64_t>;

    mantissa_pair getMantissa( double value );

    int main()
    {
    double v = numeric_limits<double>::min();
    do
    {
    mantissa_pair mp = getMantissa( v );
    cout << "value: " << v;
    if( mp.first )
    cout << " mantissa: " << hex << mp.second << endl;
    else
    cout << " invalid mantissa (Inf, S(NaN))" << endl;
    } while( (v *= 2.0) != numeric_limits<double>::infinity() );
    }

    static_assert(numeric_limits<double>::is_iec559, "must be standard fp");

    mantissa_pair getMantissa( double value )
    {
    union
    {
    uint64_t binary;
    double value;
    } u;
    u.value = value;
    unsigned exponent = (unsigned)(u.binary >> 52) & 0x7FF;
    if( exponent == 0 )
    return pair<bool, uint64_t>( true, u.binary & 0xFFFFFFFFFFFFFu |
    0x10000000000000u );
    if( exponent == 0x7FF )
    return pair<bool, uint64_t>( false, 0 );
    return pair<bool, uint64_t>( true, u.binary & 0xFFFFFFFFFFFFFu | 0x10000000000000u );
    }

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to RadicalRabbit@theburrow.co.uk on Fri Oct 1 14:05:35 2021
    On 10/1/21 12:09 PM, RadicalRabbit@theburrow.co.uk wrote:
    On Fri, 1 Oct 2021 08:37:21 -0700 (PDT)
    wij <wyniijj@gmail.com> wrote:
    // numeric_limits<long double>::digits=64.
    //
    typedef long double FType;
    FType x=numeric_limits<FType>::max();
    int iexp;
    int64_t mint;
    x=::frexpl(x,&iexp);
    x=::ldexpl(x,numeric_limits<FType>::digits);
    mint= static_cast<int64_t>(x);

    Result (mint) is a negative number, something not right!!!

    I can't duplicate this problem: I get mint:9223372036854775807.

    It might help if you set iexp to some value.

    frexpl() is from the part of the C++ standard library that is copied
    from the C standard library.

    Section 7.12.6.7p1 of the C standard says:
    long double frexpl(long double value, int *p);

    The following paragraph says:
    The frexp functions break a floating-point number into a normalized fraction and an integer exponent. They store the integer in the int object pointed to by p .

    So iexp should be set. When I ran the code, it got set to a value of
    16384. That's not the problem.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bonita Montero@21:1/5 to All on Fri Oct 1 19:20:54 2021
    Am 01.10.2021 um 19:18 schrieb Bonita Montero:
    Am 01.10.2021 um 17:37 schrieb wij:
    // numeric_limits<long double>::digits=64.
    //
    typedef long double FType;
    FType x=numeric_limits<FType>::max();
    int iexp;
    int64_t mint;
    x=::frexpl(x,&iexp);
    x=::ldexpl(x,numeric_limits<FType>::digits);
    mint= static_cast<int64_t>(x);

    Result (mint) is a negative number, something not right!!!

    Take this:

    #include <iostream>
    #include <cstdint>
    #include <limits>
    #include <utility>
    #include <iomanip>

    using namespace std;

    using mantissa_pair = pair<bool, uint64_t>;

    mantissa_pair getMantissa( double value );

    int main()
    {
        double v = numeric_limits<double>::min();
        do
        {
            mantissa_pair mp = getMantissa( v );
            cout << "value: " << v;
            if( mp.first )
                cout << " mantissa: " << hex << mp.second << endl;
            else
                cout << " invalid mantissa (Inf, S(NaN))" << endl;
        } while( (v *= 2.0) != numeric_limits<double>::infinity() );
    }

    static_assert(numeric_limits<double>::is_iec559, "must be standard fp");

    mantissa_pair getMantissa( double value )
    {
        union
        {
            uint64_t binary;
            double value;
        } u;
        u.value = value;
        unsigned exponent = (unsigned)(u.binary >> 52) & 0x7FF;
        if( exponent == 0 )
            return pair<bool, uint64_t>( true, u.binary & 0xFFFFFFFFFFFFFu
    | 0x10000000000000u );

    Should be:
    return pair<bool, uint64_t>( true, u.binary & 0xFFFFFFFFFFFFFu );


        if( exponent == 0x7FF )
            return pair<bool, uint64_t>( false, 0 );
        return pair<bool, uint64_t>( true, u.binary & 0xFFFFFFFFFFFFFu | 0x10000000000000u );
    }

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bonita Montero@21:1/5 to All on Fri Oct 1 19:25:01 2021
    mantissa_pair getMantissa( double value )
    {
         union
         {
             uint64_t binary;
             double value;
         } u;
         u.value = value;
         unsigned exponent = (unsigned)(u.binary >> 52) & 0x7FF;
         if( exponent == 0 )
             return pair<bool, uint64_t>( true, u.binary &
    0xFFFFFFFFFFFFFu | 0x10000000000000u );

    Should be:
              return pair<bool, uint64_t>( true, u.binary & 0xFFFFFFFFFFFFFu );


         if( exponent == 0x7FF )
             return pair<bool, uint64_t>( false, 0 );
         return pair<bool, uint64_t>( true, u.binary & 0xFFFFFFFFFFFFFu | >> 0x10000000000000u );
    }

    Now with maximum efficiency:

    mantissa_pair getMantissa( double value )
    {
    union
    {
    uint64_t binary;
    double value;
    } u;
    u.value = value;
    unsigned exponent = (unsigned)(u.binary >> 52) & 0x7FF;
    if( exponent == 0x7FF )
    return pair<bool, uint64_t>( false, 0 );
    uint64_t hiBit = (uint64_t)(exponent != 0) << 52;
    return pair<bool, uint64_t>( true, u.binary & 0xFFFFFFFFFFFFFu | hiBit );
    }

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bonita Montero@21:1/5 to All on Fri Oct 1 19:53:39 2021
    Am 01.10.2021 um 19:25 schrieb Bonita Montero:

    mantissa_pair getMantissa( double value )
    {
        union
        {
            uint64_t binary;
            double value;
        } u;
        u.value = value;
        unsigned exponent = (unsigned)(u.binary >> 52) & 0x7FF;
        if( exponent == 0x7FF )
            return pair<bool, uint64_t>( false, 0 );
        uint64_t hiBit = (uint64_t)(exponent != 0) << 52;
        return pair<bool, uint64_t>( true, u.binary & 0xFFFFFFFFFFFFFu | hiBit );
    }

    Oh, I think this would be the best solution for 0x7ff-exponents:

    mantissa_pair getMantissa( double value )
    {
    union
    {
    uint64_t binary;
    double value;
    } u;
    u.value = value;
    unsigned exponent = (unsigned)(u.binary >> 52) & 0x7FF;
    uint64_t mantissa = u.binary & 0xFFFFFFFFFFFFFu;
    if( exponent == 0x7FF )
    return pair<bool, uint64_t>( false, mantissa );
    uint64_t hiBit = (uint64_t)(exponent != 0) << 52;
    return pair<bool, uint64_t>( true, mantissa | hiBit );
    }

    Return the mantisssa also with false in .first for Inf and (S)NaN.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to Bonita Montero on Fri Oct 1 19:09:36 2021
    On 01/10/2021 18:18, Bonita Montero wrote:
    Am 01.10.2021 um 17:37 schrieb wij:
    // numeric_limits<long double>::digits=64.
    //
    typedef long double FType;
    FType x=numeric_limits<FType>::max();
    int iexp;
    int64_t mint;
    x=::frexpl(x,&iexp);
    x=::ldexpl(x,numeric_limits<FType>::digits);
    mint= static_cast<int64_t>(x);

    Result (mint) is a negative number, something not right!!!

    Take this:

    #include <iostream>
    #include <cstdint>
    #include <limits>
    #include <utility>
    #include <iomanip>

    using namespace std;

    using mantissa_pair = pair<bool, uint64_t>;

    mantissa_pair getMantissa( double value );

    What happened to *long* double?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bonita Montero@21:1/5 to All on Fri Oct 1 20:16:43 2021
    Am 01.10.2021 um 20:09 schrieb Bart:
    On 01/10/2021 18:18, Bonita Montero wrote:
    Am 01.10.2021 um 17:37 schrieb wij:
    // numeric_limits<long double>::digits=64.
    //
    typedef long double FType;
    FType x=numeric_limits<FType>::max();
    int iexp;
    int64_t mint;
    x=::frexpl(x,&iexp);
    x=::ldexpl(x,numeric_limits<FType>::digits);
    mint= static_cast<int64_t>(x);

    Result (mint) is a negative number, something not right!!!

    Take this:

    #include <iostream>
    #include <cstdint>
    #include <limits>
    #include <utility>
    #include <iomanip>

    using namespace std;

    using mantissa_pair = pair<bool, uint64_t>;

    mantissa_pair getMantissa( double value );

    What happened to *long* double?

    Is idiocracy.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Branimir Maksimovic@21:1/5 to wij on Fri Oct 1 18:53:38 2021
    On 2021-10-01, wij <wyniijj@gmail.com> wrote:
    // numeric_limits<long double>::digits=64.
    //
    typedef long double FType;
    FType x=numeric_limits<FType>::max();
    int iexp;
    int64_t mint;
    x=::frexpl(x,&iexp);
    x=::ldexpl(x,numeric_limits<FType>::digits);
    mint= static_cast<int64_t>(x);

    Result (mint) is a negative number, something not right!!!
    long double max = cumeric_limits<long double>::max();
    long mantissa = max; // impicit conversion

    --

    7-77-777
    Evil Sinner!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to Branimir Maksimovic on Fri Oct 1 20:19:39 2021
    On 10/1/21 2:53 PM, Branimir Maksimovic wrote:
    ...
    long double max = cumeric_limits<long double>::max();
    long mantissa = max; // impicit conversion
    "A prvalue of a floating-point type can be converted to a prvalue of an
    integer type. The conversion truncates; that is, the fractional part is discarded. The behavior is undefined if the truncated value cannot be represented in the destination type." (7.3.10p1).

    While it's not required to be the case, on most implementations std::numeric_limits<long double>::max() is WAY too large to be
    represented by a long, so the behavior of such code is undefined. The
    minimum value of LDBL_MAX (set by the C standard, inherited by the C++ standard) is 1e37, which would require long to have at least 123 bits in
    order for that conversion to have defined behavior.
    And even when it has defined behavior, I can't imagine how you would
    reach the conclusion that this conversion should be the value of the
    mantissa.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From wij@21:1/5 to james...@alumni.caltech.edu on Fri Oct 1 17:23:10 2021
    On Saturday, 2 October 2021 at 02:05:56 UTC+8, james...@alumni.caltech.edu wrote:
    On 10/1/21 12:09 PM, Radica...@theburrow.co.uk wrote:
    On Fri, 1 Oct 2021 08:37:21 -0700 (PDT)
    wij <wyn...@gmail.com> wrote:
    // numeric_limits<long double>::digits=64.
    //
    typedef long double FType;
    FType x=numeric_limits<FType>::max();
    int iexp;
    int64_t mint;
    x=::frexpl(x,&iexp);
    x=::ldexpl(x,numeric_limits<FType>::digits);
    mint= static_cast<int64_t>(x);

    Result (mint) is a negative number, something not right!!!
    I can't duplicate this problem: I get mint:9223372036854775807.
    It might help if you set iexp to some value.
    frexpl() is from the part of the C++ standard library that is copied
    from the C standard library.

    Section 7.12.6.7p1 of the C standard says:
    long double frexpl(long double value, int *p);

    The following paragraph says:
    The frexp functions break a floating-point number into a normalized fraction and an integer exponent. They store the integer in the int object pointed to by p .

    So iexp should be set. When I ran the code, it got set to a value of
    16384. That's not the problem.

    // ----- file t.cpp -----
    #include <math.h>
    #include <limits>
    #include <iostream>

    using namespace std;
    #define ENDL endl

    template<typename T>
    int64_t get_mant(T x) {
    int iexp;
    x=frexp(x,&iexp);
    x=ldexp(x,numeric_limits<T>::digits);
    return static_cast<int64_t>(x);
    };

    int main()
    {
    cout << dec << get_mant(numeric_limits<float>::max()) << ", "
    << hex << get_mant(numeric_limits<float>::max()) << ENDL;
    cout << dec << get_mant(numeric_limits<double>::max()) << ", "
    << hex << get_mant(numeric_limits<double>::max()) << ENDL;
    cout << dec << get_mant(numeric_limits<long double>::max()) << ", "
    << hex << get_mant(numeric_limits<long double>::max()) << ENDL;
    return 0;
    };
    // end file t.cpp -----

    $ g++ t.cpp
    ]$ ./a.out
    16777215, ffffff
    9007199254740991, 1fffffffffffff
    -9223372036854775808, 8000000000000000

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Branimir Maksimovic@21:1/5 to James Kuyper on Sat Oct 2 02:16:14 2021
    On 2021-10-02, James Kuyper <jameskuyper@alumni.caltech.edu> wrote:
    On 10/1/21 2:53 PM, Branimir Maksimovic wrote:
    ...
    long double max = cumeric_limits<long double>::max();
    long mantissa = max; // impicit conversion
    "A prvalue of a floating-point type can be converted to a prvalue of an integer type. The conversion truncates; that is, the fractional part is discarded. The behavior is undefined if the truncated value cannot be represented in the destination type." (7.3.10p1).

    While it's not required to be the case, on most implementations std::numeric_limits<long double>::max() is WAY too large to be
    represented by a long, so the behavior of such code is undefined. The
    minimum value of LDBL_MAX (set by the C standard, inherited by the C++ standard) is 1e37, which would require long to have at least 123 bits in order for that conversion to have defined behavior.
    And even when it has defined behavior, I can't imagine how you would
    reach the conclusion that this conversion should be the value of the mantissa.
    It is not undefined as long is larger then mantissa part.
    ok correct is long long :P

    --

    7-77-777
    Evil Sinner!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to Branimir Maksimovic on Sat Oct 2 01:28:45 2021
    On 10/1/21 10:16 PM, Branimir Maksimovic wrote:
    On 2021-10-02, James Kuyper <jameskuyper@alumni.caltech.edu> wrote:
    On 10/1/21 2:53 PM, Branimir Maksimovic wrote:
    ...
    long double max = cumeric_limits<long double>::max();
    long mantissa = max; // impicit conversion
    "A prvalue of a floating-point type can be converted to a prvalue of an
    integer type. The conversion truncates; that is, the fractional part is
    discarded. The behavior is undefined if the truncated value cannot be
    represented in the destination type." (7.3.10p1).

    While it's not required to be the case, on most implementations
    std::numeric_limits<long double>::max() is WAY too large to be
    represented by a long, so the behavior of such code is undefined. The
    minimum value of LDBL_MAX (set by the C standard, inherited by the C++
    standard) is 1e37, which would require long to have at least 123 bits in
    order for that conversion to have defined behavior.
    And even when it has defined behavior, I can't imagine how you would
    reach the conclusion that this conversion should be the value of the
    mantissa.
    It is not undefined as long is larger then mantissa part.

    No, the relevant issue isn't the size of the mantissa. As stated above
    in my quote from the standard, it's whether "the truncated value cannot
    be represented in the destination type". std::numeric_limits<long double>::max() doesn't have a fractional part, so the truncated value is
    the same as the actual value. On my system, for instance, that value is 1.18973e+4932.

    ok correct is long long :P

    On my system, changing it to long long doesn't make any different - the
    maximum value representable by long long is still 9223372036854775807,
    the same as the maximum value for long; it's still far too small to
    represent 1.18973e+4932, so the behavior of the conversion is undefined.
    The actual behavior on my system appears to be saturating at LLONG_MAX
    == 9223372036854775807. If I change the second line to

    long long mantissa = 0.75*max;

    0.75*max is 8.92299e+4931, which should certainly not have the same
    mantissa as max itself, but the value loaded into "mantissa" is still 9223372036854775807.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to Branimir Maksimovic on Sat Oct 2 01:56:04 2021
    I accidentally sent this message first to Branimir by e-mail, and he
    responded in kind.

    On 10/2/21 1:31 AM, Branimir Maksimovic wrote:

    On 02.10.2021., at 07:27, James Kuyper <jameskuyper@alumni.caltech.edu> wrote:

    On 10/1/21 10:16 PM, Branimir Maksimovic wrote:
    ...
    ok correct is long long :P
    On my system, changing it to long long doesn't make any different - the
    maximum value representable by long long is still 9223372036854775807,
    the same as the maximum value for long; it's still far too small to
    represent 1.18973e+4932, so the behavior of the conversion is undefined.
    The actual behavior on my system appears to be saturating at LLONG_MAX
    == 9223372036854775807. If I change the second line to

    long long mantissa = 0.75*max;

    0.75*max is 8.92299e+4931, which should certainly not have the same
    mantissa as max itself, but the value loaded into "mantissa" is still
    9223372036854775807.
    Problem is that neither long double nor long is defined how small
    or large can be…
    so it can fit or not…
    The C++ standard cross-references the C standard for such purposes, and
    the C standard imposes strict limits on how small those things can be: LLONG_MAX is required to be at least 9223372036854775807, and LDBL_MAX
    is supposed to be at least 1e37.
    You are right, however, about there being no limits on how large they
    can be. It is therefore permissible for an implementation to have
    LLONG_MAX >= LDBL_MAX, but do you know of any such implementation?
    In any event, the relevant issue is not the limits imposed on those
    values by the standard, but the actual values of LLONG_MAX and LDBL_MAX
    for the particular implementation you're using, and it's perfectly
    feasible to determine those values from <climits>, <cfloat>, or std::numeric_limits<>::max. What are those values on the implementation
    you're using?
    but question is how to extract mantissa which was answer :P

    No, that is not the answer. If max did have a value small enough to make
    the conversion to long long have defined behavior, the result of that conversion would be the truncated value itself (7.3.10p1), NOT the
    mantissa of the truncated value. What makes you think otherwise?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bonita Montero@21:1/5 to All on Sat Oct 2 12:09:06 2021
    Am 01.10.2021 um 17:37 schrieb wij:
    // numeric_limits<long double>::digits=64.
    //
    typedef long double FType;
    FType x=numeric_limits<FType>::max();
    int iexp;
    int64_t mint;
    x=::frexpl(x,&iexp);
    x=::ldexpl(x,numeric_limits<FType>::digits);
    mint= static_cast<int64_t>(x);

    Result (mint) is a negative number, something not right!!!


    Here, exactly 100 lines with a very convenient double to double
    parts and double parts to double conversion:

    #pragma once
    #include <limits>
    #include <cstdint>
    #include <cassert>

    struct dbl_parts
    {
    static_assert(std::numeric_limits<double>::is_iec559, "must be standard fp");
    dbl_parts( double d );
    dbl_parts &operator =( double d );
    dbl_parts() = default;
    operator double();
    bool getSign();
    std::uint16_t getBiasedExponent();
    std::int16_t getExponent();
    std::uint64_t getMantissa();
    void setSign( bool sign );
    void setBiasedExponent( uint16_t exp );
    void setExponent( int16_t exp );
    void setMantissa( uint64_t mantissa );
    private:
    union
    {
    double value;
    std::uint64_t binary;
    };
    };

    inline
    dbl_parts::dbl_parts( double d ) :
    value( d )
    {
    }

    inline
    dbl_parts &dbl_parts::operator =( double d )
    {
    value = d;
    return *this;
    }

    inline
    dbl_parts::operator double()
    {
    return value;
    }

    inline
    bool dbl_parts::getSign()
    {
    return (int64_t)binary < 0;
    }

    inline
    std::uint16_t dbl_parts::getBiasedExponent()
    {
    return (std::uint16_t)(binary >> 52) & 0x7FF;
    }

    inline
    int16_t dbl_parts::getExponent()
    {
    return (int16_t)getBiasedExponent() - 0x3FF;
    }

    inline
    std::uint64_t dbl_parts::getMantissa()
    {
    std::uint16_t bExp = getBiasedExponent();
    std::uint64_t hiBit = (uint64_t)(bExp && bExp != 0x7FF) << 52;
    return binary & 0xFFFFFFFFFFFFFu | hiBit;
    }

    inline
    void dbl_parts::setSign( bool sign )
    {
    binary = binary & 0x7FFFFFFFFFFFFFFFu | (std::uint64_t)sign << 63;
    }

    inline
    void dbl_parts::setBiasedExponent( std::uint16_t exp )
    {
    assert(exp <= 0x7FF);
    binary = binary & 0x800FFFFFFFFFFFFFu | (std::uint64_t)exp << 52;
    }

    inline
    void dbl_parts::setExponent( std::int16_t exp )
    {
    assert(exp >= -0x3FF && exp <= 400);
    setBiasedExponent( (uint16_t)(exp - 0x3FF) );
    }

    inline
    void dbl_parts::setMantissa( std::uint64_t mantissa )
    {
    assert((getBiasedExponent() == 0 || getBiasedExponent() == 0x7FF) && !(mantissa & -0x10000000000000));
    assert(getBiasedExponent() != 0 && getBiasedExponent() != 0x7FF || mantissa <= 0x1FFFFFFFFFFFFFu);
    binary = binary & 0xFFF0000000000000u | mantissa & 0xFFFFFFFFFFFFFu;
    }

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Branimir Maksimovic@21:1/5 to James Kuyper on Sat Oct 2 10:59:04 2021
    On 2021-10-02, James Kuyper <jameskuyper@alumni.caltech.edu> wrote:
    I accidentally sent this message first to Branimir by e-mail, and he

    No, that is not the answer. If max did have a value small enough to make
    the conversion to long long have defined behavior, the result of that conversion would be the truncated value itself (7.3.10p1), NOT the
    mantissa of the truncated value. What makes you think otherwise?
    Because mantissa is whole part of floating point number?

    --

    7-77-777
    Evil Sinner!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Manfred@21:1/5 to wij on Sat Oct 2 18:58:59 2021
    On 10/2/2021 2:23 AM, wij wrote:
    On Saturday, 2 October 2021 at 02:05:56 UTC+8, james...@alumni.caltech.edu wrote:
    On 10/1/21 12:09 PM, Radica...@theburrow.co.uk wrote:
    On Fri, 1 Oct 2021 08:37:21 -0700 (PDT)
    wij <wyn...@gmail.com> wrote:
    // numeric_limits<long double>::digits=64.
    //
    typedef long double FType;
    FType x=numeric_limits<FType>::max();
    int iexp;
    int64_t mint;
    x=::frexpl(x,&iexp);
    x=::ldexpl(x,numeric_limits<FType>::digits);
    mint= static_cast<int64_t>(x);

    Result (mint) is a negative number, something not right!!!
    I can't duplicate this problem: I get mint:9223372036854775807.
    <snip>

    // ----- file t.cpp -----
    #include <math.h>
    #include <limits>
    #include <iostream>

    using namespace std;
    #define ENDL endl

    template<typename T>
    int64_t get_mant(T x) {
    int iexp;
    x=frexp(x,&iexp);
    x=ldexp(x,numeric_limits<T>::digits);
    return static_cast<int64_t>(x);
    };

    int main()
    {
    cout << dec << get_mant(numeric_limits<float>::max()) << ", "
    << hex << get_mant(numeric_limits<float>::max()) << ENDL;
    cout << dec << get_mant(numeric_limits<double>::max()) << ", "
    << hex << get_mant(numeric_limits<double>::max()) << ENDL;
    cout << dec << get_mant(numeric_limits<long double>::max()) << ", "
    << hex << get_mant(numeric_limits<long double>::max()) << ENDL;
    return 0;
    };
    // end file t.cpp -----

    $ g++ t.cpp
    ]$ ./a.out
    16777215, ffffff
    9007199254740991, 1fffffffffffff
    -9223372036854775808, 8000000000000000


    There are two problems:

    1)
    The templated function uses 'frexp' and 'ldexp', which take both double arguments (not *long* double), hence UB occurs at those calls for the
    'long double' type whenever this type is actually larger than 'double'.

    2)
    On my Linux box numeric_limits<*long* double>::digits is 64 (numeric_limits<double>::digits is 53), so the static_cast<int64_t>(x)
    yields UB again.

    =========
    #include <cmath>
    #include <limits>
    #include <iostream>

    using namespace std;
    #define ENDL endl

    uint64_t get_mantf(float x)
    {
    int iexp;
    x=frexp(x,&iexp);
    x=ldexp(x,numeric_limits<float>::digits);
    return static_cast<uint64_t>(x);
    };

    uint64_t get_mant(double x)
    {
    int iexp;
    x=frexp(x,&iexp);
    x=ldexp(x,numeric_limits<double>::digits);
    return static_cast<uint64_t>(x);
    };

    uint64_t get_mantl(long double x)
    {
    int iexp;
    x=frexp(x,&iexp);
    x=ldexp(x,numeric_limits<long double>::digits);
    return static_cast<uint64_t>(x);
    };

    int main()
    {
    cout << dec << numeric_limits<float>::digits << ", " << get_mantf(numeric_limits<float>::max()) << ", "
    << hex << get_mantf(numeric_limits<float>::max()) << ENDL;
    cout << dec << numeric_limits<double>::digits << ", " << get_mant(numeric_limits<double>::max()) << ", "
    << hex << get_mant(numeric_limits<double>::max()) << ENDL;
    cout << dec << numeric_limits<long double>::digits << ", " << get_mantl(numeric_limits<long double>::max()) << ", "
    << hex << get_mantl(numeric_limits<long double>::max()) << ENDL;
    return 0;
    }
    ===================
    $ c++ -std=c++11 -O2 -Wall mant.cc && ./a.out
    24, 16777215, ffffff
    53, 9007199254740991, 1fffffffffffff
    64, 18446744073709551615, ffffffffffffffff

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Manfred@21:1/5 to Manfred on Sat Oct 2 19:21:28 2021
    On 10/2/2021 6:58 PM, Manfred wrote:
    On 10/2/2021 2:23 AM, wij wrote:
    On Saturday, 2 October 2021 at 02:05:56 UTC+8,
    james...@alumni.caltech.edu wrote:
    On 10/1/21 12:09 PM, Radica...@theburrow.co.uk wrote:
    On Fri, 1 Oct 2021 08:37:21 -0700 (PDT)
    wij <wyn...@gmail.com> wrote:
    // numeric_limits<long double>::digits=64.
    //
    typedef long double FType;
    FType x=numeric_limits<FType>::max();
    int iexp;
    int64_t mint;
    x=::frexpl(x,&iexp);
    x=::ldexpl(x,numeric_limits<FType>::digits);
    mint= static_cast<int64_t>(x);

    Result (mint) is a negative number, something not right!!!
    I can't duplicate this problem: I get mint:9223372036854775807.
    <snip>

    // ----- file t.cpp -----
    #include <math.h>
    #include <limits>
    #include <iostream>

    using namespace std;
    #define ENDL endl

    template<typename T>
    int64_t get_mant(T x) {
      int iexp;
      x=frexp(x,&iexp);
      x=ldexp(x,numeric_limits<T>::digits);
      return static_cast<int64_t>(x);
    };

    int main()
    {
      cout << dec << get_mant(numeric_limits<float>::max()) << ", "
           << hex << get_mant(numeric_limits<float>::max()) << ENDL;
      cout << dec << get_mant(numeric_limits<double>::max()) << ", "
           << hex << get_mant(numeric_limits<double>::max()) << ENDL;
      cout << dec << get_mant(numeric_limits<long double>::max()) << ", "
           << hex << get_mant(numeric_limits<long double>::max()) << ENDL; >>   return 0;
    };
    // end file t.cpp -----

    $ g++ t.cpp
    ]$ ./a.out
    16777215, ffffff
    9007199254740991, 1fffffffffffff
    -9223372036854775808, 8000000000000000


    There are two problems:

    1)
    The templated function uses 'frexp' and 'ldexp', which take both double arguments (not *long* double), hence UB occurs at those calls for the
    'long double' type whenever this type is actually larger than 'double'.

    2)
    On my Linux box numeric_limits<*long* double>::digits is 64 (numeric_limits<double>::digits is 53), so the static_cast<int64_t>(x)
    yields UB again.

    =========
    #include <cmath>
    #include <limits>
    #include <iostream>

    using namespace std;
    #define ENDL endl

    uint64_t get_mantf(float x)
    {
      int iexp;
      x=frexp(x,&iexp);
      x=ldexp(x,numeric_limits<float>::digits);
      return static_cast<uint64_t>(x);
    };

    uint64_t get_mant(double x)
    {
      int iexp;
      x=frexp(x,&iexp);
      x=ldexp(x,numeric_limits<double>::digits);
      return static_cast<uint64_t>(x);
    };

    uint64_t get_mantl(long double x)
    {
      int iexp;
      x=frexp(x,&iexp);
      x=ldexp(x,numeric_limits<long double>::digits);
      return static_cast<uint64_t>(x);
    };

    int main()
    {
      cout << dec << numeric_limits<float>::digits << ", " << get_mantf(numeric_limits<float>::max()) << ", "
        << hex << get_mantf(numeric_limits<float>::max()) << ENDL;
      cout << dec << numeric_limits<double>::digits << ", " << get_mant(numeric_limits<double>::max()) << ", "
        << hex << get_mant(numeric_limits<double>::max()) << ENDL;
      cout << dec << numeric_limits<long double>::digits << ", " << get_mantl(numeric_limits<long double>::max()) << ", "
        << hex << get_mantl(numeric_limits<long double>::max()) << ENDL;
      return 0;
    }
    ===================
    $ c++ -std=c++11 -O2 -Wall mant.cc && ./a.out
    24, 16777215, ffffff
    53, 9007199254740991, 1fffffffffffff
    64, 18446744073709551615, ffffffffffffffff

    Sorry, that should have been:

    =====
    uint64_t get_mantf(float x)
    {
    int iexp;
    x=frexpf(x,&iexp);
    x=ldexpf(x,numeric_limits<float>::digits);
    return static_cast<uint64_t>(x);
    };

    uint64_t get_mant(double x)
    {
    int iexp;
    x=frexp(x,&iexp);
    x=ldexp(x,numeric_limits<double>::digits);
    return static_cast<uint64_t>(x);
    };

    uint64_t get_mantl(long double x)
    {
    int iexp;
    x=frexpl(x,&iexp);
    x=ldexpl(x,numeric_limits<long double>::digits);
    return static_cast<uint64_t>(x);
    };
    =====

    However, the three distinct functions with frexp and ldexp in all three
    still work on my box (I'm guessing gcc is still able to compile the
    correct implementation in in this case), but the template doesn't.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Alf P. Steinbach@21:1/5 to wij on Sat Oct 2 21:00:41 2021
    On 1 Oct 2021 17:37, wij wrote:
    // numeric_limits<long double>::digits=64.
    //
    typedef long double FType;
    FType x=numeric_limits<FType>::max();
    int iexp;
    int64_t mint;
    x=::frexpl(x,&iexp);
    x=::ldexpl(x,numeric_limits<FType>::digits);
    mint= static_cast<int64_t>(x);

    Result (mint) is a negative number, something not right!!!

    Apparently you're trying to obtain the bits of the mantissa of a `long
    double` number, represented as an `int64_t` value.

    A `long double` is in practice either IEEE 754 64-bit, or IEEE 754
    80-bit. In Windows that choice depends on the compiler. With Visual C++
    (and hence probably also Intel) it's 64-bit, same as type `double`,
    while with MinGW g++ (and hence probably also clang) it 80-bit,
    originally the x86-family's math coprocessor's extended format. For
    80-bit IEEE 754 the mantissa part is 64 bits.

    With 64-bits mantissa there is a high chance of setting the sign bit of
    an `int64_t` to 1, resulting in a negative value. I believe that that
    will only /not/ happen for a denormal value, but, I'm tired and might be
    wrong about that. Anyway, instead use unsigned types for bit handling.
    For example, in this case, use `uint64_t`.

    However, instead of the shenanigans with `frexpl` and `ldexpl` I'd just
    use `memcpy`.

    Due to the silliness in gcc regarding the standard's "strict aliasing"
    rule, I'd not use a reinterpretation pointer cast.


    - Alf

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to All on Sat Oct 2 14:57:33 2021
    T24gMTAvMi8yMSA2OjU5IEFNLCBCcmFuaW1pciBNYWtzaW1vdmljIHdyb3RlOg0KPiBPbiAy MDIxLTEwLTAyLCBKYW1lcyBLdXlwZXIgPGphbWVza3V5cGVyQGFsdW1uaS5jYWx0ZWNoLmVk dT4gd3JvdGU6DQo+PiBJIGFjY2lkZW50YWxseSBzZW50IHRoaXMgbWVzc2FnZSBmaXJzdCB0 byBCcmFuaW1pciBieSBlLW1haWwsIGFuZCBoZQ0KPj4NCj4+IE5vLCB0aGF0IGlzIG5vdCB0 aGUgYW5zd2VyLiBJZiBtYXggZGlkIGhhdmUgYSB2YWx1ZSBzbWFsbCBlbm91Z2ggdG8gbWFr ZQ0KPj4gdGhlIGNvbnZlcnNpb24gdG8gbG9uZyBsb25nIGhhdmUgZGVmaW5lZCBiZWhhdmlv ciwgdGhlIHJlc3VsdCBvZiB0aGF0DQo+PiBjb252ZXJzaW9uIHdvdWxkIGJlIHRoZSB0cnVu Y2F0ZWQgdmFsdWUgaXRzZWxmICg3LjMuMTBwMSksIE5PVCB0aGUNCj4+IG1hbnRpc3NhIG9m IHRoZSB0cnVuY2F0ZWQgdmFsdWUuIFdoYXQgbWFrZXMgeW91IHRoaW5rIG90aGVyd2lzZT8N Cj4gQmVjYXVzZSBtYW50aXNzYSBpcyB3aG9sZSBwYXJ0IG9mIGZsb2F0aW5nIHBvaW50IG51 bWJlcj8NCg0KV2VsbCwgYXQgbGVhc3QgSSdtIGNsZWFyIG5vdyBhYm91dCB3aGF0IHlvdXIg Y29uZnVzaW9uIGlzLiBJJ2xsIGdpdmUgeW91DQphbiBhbnN3ZXIgaW4gdHdvIHBhcnRzOg0K MS4gVGhlIG1hbnRpc3NhIG9mIGEgZmxvYXRpbmcgcG9pbnQgbnVtYmVyIChhbHNvIGNhbGxl ZCB0aGUgc2lnbmlmaWNhbmQsDQp3aGljaCBpcyB0aGUgdGVybSB1c2VkIGluIHRoZSBDIHN0 YW5kYXJkIGluIHRleHQgdGhhdCBpcyBpbmNvcnBvcmF0ZWQgYnkNCnJlZmVyZW5jZSBpbnRv IHRoZSBDKysgc3RhbmRhcmQpIGlzIHNvbWV0aGluZyBxdWl0ZSBkaWZmZXJlbnQgZnJvbSB0 aGUNCndob2xlIHBhcnQgb2YgdGhhdCBudW1iZXIuIFNlZQ0KPGh0dHBzOi8vZW4ubS53aWtp cGVkaWEub3JnL3dpa2kvU2lnbmlmaWNhbmQ+IGZvciBkZXRhaWxzLg0KDQoyLiBXaGVuIGEg ZmxvYXRpbmcgcG9pbnQgbnVtYmVyIGlzIGdyZWF0ZXIgdGhhbiBMTE9OR19NQVgrMS4wLCB0 aGUgY29kZQ0KeW91IHByb3ZpZGVkIGhhcyB1bmRlZmluZWQgYmVoYXZpb3IuIFRoYXQgbWFr ZXMgc2Vuc2UsIHNpbmNlIGEgbG9uZyBsb25nDQpvYmplY3QgY2Fubm90IHJlcHJlc2VudCB0 aGUgd2hvbGUgcGFydCBvZiBzdWNoIGEgbnVtYmVyLiBUaGUgYWN0dWFsDQpiZWhhdmlvciBj YW4gdmFyeSBmcm9tIG9uZSBpbXBsZW1lbnRhdGlvbiB0byBhbm90aGVyLCBidXQgb24gbXkg c3lzdGVtLA0KaXQgZG9lcyBOT1QgY29udGFpbiB0aGUgbWFudGlzc2EsIGVpdGhlci4NCg0K Q29uc2lkZXIgdGhlIGZvbGxvd2luZyBwcm9ncmFtOg0KDQojaW5jbHVkZSA8aW9zdHJlYW0+ DQoNCmludCBtYWluKHZvaWQpDQp7DQogICAgdHlwZWRlZiBsb25nIGRvdWJsZSBGVHlwZTsN CiAgICBGVHlwZSBtYXg9IHN0ZDo6bnVtZXJpY19saW1pdHM8RlR5cGU+OjptYXgoKTsNCiAg ICBGVHlwZSBsYXJnZSA9IDB4QS5CQ0RFRjAxMjM0NTY3ODlwKzE2MzgwTDsNCiAgICBGVHlw ZSBtaWRkbGluZyA9IDB4QUJDREVGMDEuMjM0NTY3ODlwMEw7DQogICAgbG9uZyBsb25nIG1h eGxsID0gbWF4Ow0KICAgIGxvbmcgbG9uZyBsYXJnZWxsID0gbGFyZ2U7DQogICAgbG9uZyBs b25nIG1pZGRsaW5nbGwgPSBtaWRkbGluZzsNCg0KICAgIHN0ZDo6Y291dCA8PCBzdGQ6OmZp eGVkIDw8ICJtYXg6ICIgPDwgbWF4IDw8IHN0ZDo6ZW5kbDsNCiAgICBzdGQ6OmNvdXQgPDwg ImxhcmdlOiAiIDw8IGxhcmdlIDw8IHN0ZDo6ZW5kbDsNCiAgICBzdGQ6OmNvdXQgPDwgIm1p ZGRsaW5nOiAiIDw8IG1pZGRsaW5nIDw8IHN0ZDo6ZW5kbDsNCg0KICAgIHN0ZDo6Y291dCA8 PCAibWF4bGw6ICIgPDwgbWF4bGwgPDwgc3RkOjplbmRsOw0KICAgIHN0ZDo6Y291dCA8PCAi bGFyZ2VsbDogIiA8PCBsYXJnZWxsIDw8IHN0ZDo6ZW5kbDsNCiAgICBzdGQ6OmNvdXQgPDwg Im1pZGRsaW5nbGw6ICIgPDwgbWlkZGxpbmdsbCA8PCBzdGQ6OmVuZGw7DQoNCiAgICBzdGQ6 OmNvdXQgPDwgc3RkOjpoZXhmbG9hdCA8PCBzdGQ6OnNob3diYXNlIDw8IHN0ZDo6c2hvd3Bv aW50IDw8DQogICAgICAgIHN0ZDo6aGV4IDw8ICJtYXg6ICIgPDwgbWF4IDw8IHN0ZDo6ZW5k bDsNCiAgICBzdGQ6OmNvdXQgPDwgImxhcmdlOiAiIDw8IGxhcmdlIDw8IHN0ZDo6ZW5kbDsN CiAgICBzdGQ6OmNvdXQgPDwgIm1pZGRsaW5nOiAiIDw8IG1pZGRsaW5nIDw8IHN0ZDo6ZW5k bDsNCg0KICAgIHN0ZDo6Y291dCA8PCAibWF4bGw6ICIgPDwgbWF4bGwgPDwgc3RkOjplbmRs Ow0KICAgIHN0ZDo6Y291dCA8PCAibGFyZ2VsbDogIiA8PCBsYXJnZWxsIDw8IHN0ZDo6ZW5k bDsNCiAgICBzdGQ6OmNvdXQgPDwgIm1pZGRsaW5nbGw6ICIgPDwgbWlkZGxpbmdsbCA8PCBz dGQ6OmVuZGw7DQp9DQoNClRoZSBvdXRwdXQgZnJvbSB0aGF0IHByb2dyYW0gb24gbXkgc3lz dGVtIGlzOg0KDQptYXg6DQoxMTg5NzMxNDk1MzU3MjMxNzY1MDIxMjYzODUzMDMwOTcwMjA1 MTY5MDYzMzIyMjk0NjI0MjAwNDQwMzIzNzMzODkxNzM3MDA1NTIyOTcwNzIyNjE2NDEwMjkw MzM2NTI4ODgyODUzNTQ1Njk3ODA3NDk1NTc3MzE0NDI3NDQzMTUzNjcwMjg4NDM0MTk4MTI1 NTczODUzNzQzNjc4NjczNTkzMjAwNzA2OTczMjYzMjAxOTE1OTE4MjgyOTYxNTI0MzY1NTI5 NTEwNjQ2NzkxMDg2NjE0MzExNzkwNjMyMTY5Nzc4ODM4ODk2MTM0Nzg2NTYwNjAwMzk5MTQ4 NzUzNDMzMjExNDU0OTExMTYwMDg4Njc5ODQ1MTU0ODY2NTEyODUyMzQwMTQ5NzczMDM3NjAw MDA5MTI1NDc5MzkzOTY2MjIzMTUxMzgzNjIyNDE3ODM4NTQyNzQzOTE3ODM4MTM4NzE3ODA1 ODg5NDg3NTQwNTc1MTY4MjI2MzQ3NjU5MjM1NTc2OTc0ODA1MTEzNzI1NjQ5MDIwODg0ODU1 MjIyNDk0NzkxMzk5Mzc3NTg1MDI2MDExNzczNTQ5MTgwMDk5Nzk2MjI2MDI2ODU5NTA4NTU4 ODgzNjA4MTU5ODQ2OTAwMjM1NjQ1MTMyMzQ2NTk0NDc2Mzg0OTM5ODU5Mjc2NDU2Mjg0NTc5 NjYxNzcyOTMwNDA3ODA2NjA5MjI5MTAyNzE1MDQ2MDg1Mzg4MDg3OTU5MzI3NzgxNjIyOTg2 ODI3NTQ3ODMwNzY4MDgwMDQwMTUwNjk0OTQyMzAzNDExNzI4OTU3Nzc3MTAwMzM1NzE0MDEw NTU5Nzc1MjQyMTI0MDU3MzQ3MDA3Mzg2MjUxNjYwMTEwODI4Mzc5MTE5NjIzMDA4NDY5Mjc3 MjAwOTY1MTUzNTAwMjA4NDc0NDcwNzkyNDQzODQ4NTQ1OTEyODg2NzIzMDAwNjE5MDg1MTI2 NDcyMTExOTUxMzYxNDY3NTI3NjMzNTE5NTYyOTI3NTk3OTU3MjUwMjc4MDAyOTgwNzk1OTA0 MTkzMTM5NjAzMDIxNDcwOTk3MDM1Mjc2NDY3NDQ1NTMwOTIyMDIyNjc5NjU2MjgwOTkxNDk4 MjMyMDgzMzI5NjQxMjQxMDM4NTA5MjM5MTg0NzM0Nzg2MTIxOTIxNjk3MjEwNTQzNDg0Mjg3 MDQ4MzUzNDA4MTEzMDQyNTczMDAyMjE2NDIxMzQ4OTE3MzQ3MTc0MjM0ODAwNzE0ODgwNzUx MDAyMDY0MzkwNTE3MjM0MjQ3NjU2MDA0NzIxNzY4MDk2NDg2MTA3OTk0OTQzNDE1NzAzNDc2 MzIwNjQzNTU4NjI0MjA3NDQzNTA0NDI0MzgwNTY2MTM2MDE3NjA4ODM3NDc4MTY1Mzg5MDI3 ODA5NTc2OTc1OTc3Mjg2ODYwMDcxNDg3MDI4Mjg3OTU1NTY3MTQxNDA0NjMyNjE1ODMyNjIz NjAyNzYyODk2MzE2MTczOTc4NDg0MjU0NDg2ODYwNjA5OTQ4MjcwODY3OTY4MDQ4MDc4NzAy NTExODU4OTMwODM4NTQ2NTg0MjIzMDQwOTA4ODA1OTk2Mjk0NTk0NTg2MjAxOTAzNzY2MDQ4 NDQ2NzkwOTI2MDAyMjI1NDEwNTMwNzc1OTAxMDY1NzYwNjcxMzQ3MjAwMTI1ODQ2NDA2OTU3 MDMwMjU3MTM4OTYwOTgzNzU3OTk4OTI2OTU0NTUzMDUyMzY4NTYwNzU4NjgzMTc5MjIzMTEz NjM5NTE5NDY4ODUwODgwNzcxODcyMTA0NzA1MjAzOTU3NTg3NDgwMDEzMTQzMTMxNDQ0MjU0 OTQzOTE5OTQwMTc1NzUzMTY5MzM5MzkyMzY2ODgxODU2MTg5MTI5OTMxNzI5MTA0MjUyOTIx MjM2ODM1MTU5OTIyMzIyMDUwOTk4MDAxNjc3MTAyNzg0MDM1MzYwMTQwODI5Mjk2Mzk4MTE1 MTIyODc3NzY4MTM1NzA2MDQ1Nzg5MzQzNTM1NDUxNjk2NTM5NTYxMjU0MDQ4ODQ2NDQ3MTY5 Nzg2ODkzMjExNjcxMDg3MjI5MDg4MDgyNzc4MzUwNTE4MjI4ODU3NjQ2MDYyMjE4NzM5NzAy ODUxNjU1MDgzNzIwOTkyMzQ5NDgzMzM0NDM1MjI4OTg0NzUxMjMyNzUzNzI2NjM2MDY2MjEz OTAyMjgxMjY0NzA2MjM0MDc1MzUyMDcxNzI0MDU4NjY1MDc5NTE4MjE3MzAzNDYzNzgyNjMx MzUzMzkzNzA2Nzc0OTAxOTUwMTk3ODQxNjkwNDQxODI0NzM4MDYzMTYyODI4NTg2ODU3NzQx NDMyNTgxMTY1MzY0MDQwMjE4NDAyNzI0OTEzMzkzMzIwOTQ5MjE5NDk4NDIyNDQyNzMwNDI3 MDE5ODczMDQ0NTM2NjIwMzUwMjYyMzg2OTU3ODA0NjgyMDAzNjAxNDQ3MjkxOTk3MTIzMDk1 NTMwMDU3MjA2MTQxODY2OTc0ODUyODQ2ODU2MTg2NTE0ODMyNzE1OTc0NDgxMjAzMTIxOTQ2 NzUxNjg2Mzc5MzQzMDk2MTg5NjE1MTA3MzMwMDY1NTUyNDIxNDg1MTk1MjAxNzYyODU4NTk1 MDkxMDUxODM5NDcyNTAyODYzODcxNjMyNDk0MTY3NjEzODA0OTk2MzE5NzkxNDQxODcwMjU0 MzAyNzA2NzU4NDk1MTkyMDA4ODM3OTE1MTY5NDAxNTgxNzQwMDQ2NzExNDc3ODc3MjAxNDU5 NjQ0NDYxMTc1MjA0MDU5NDUzNTA0NzY0NzIxODA3OTc1NzYxMTExNzIwODQ2MjczNjM5Mjc5 NjAwMzM5NjcwNDcwMDM3NjEzMzc0NTA5NTUzMTg0MTUwMDczNzk2NDEyNjA1MDQ3OTIzMjUx NjYxMzU0ODQxMjkxODg0MjExMzQwODIzMDE1NDczMzA0NzU0MDY3MDcyODE4NzYzNTAzNjE3 MzMyOTA4MDA1OTUxODk2MzI1MjA3MDcxNjczOTA0NTQ3Nzc3MTI5NjgyMjY1MjA2MjI1NjUx NDM5OTE5Mzc2ODA0NDAwMjkyMzgwOTAzMTEyNDM3OTEyNjE0Nzc2MjU1OTY0Njk0MjIxOTgx Mzc1MTQ2OTY3MDc5NDQ2ODcwMzU4MDA0MzkyNTA3NjU5NDUxNjE4Mzc5ODExODU5MzkyMDQ5 NTQ0MDM2MTE0OTE1MzEwNzgyMjUxMDcyNjkxNDg2OTc5ODA5MjQwOTQ2NzcyMTQyNzI3MDEy NDA0Mzc3MTg3NDA5MjE2NzU2NjEzNjM0OTM4OTAwNDUxMjMyMzUxNjY4MTQ2MDg5MzIyNDAw Njk3OTkzMTc2MDE3ODA1MzM4MTkxODQ5OTgxOTMzMDA4NDEwOTg1OTkzOTM4NzYwMjkyNjAx MzkwOTExNDE0NTI2MDAzNzIwMjg0ODcyMTMyNDExOTU1NDI0MjgyMTAxODMxMjA0MjE2MTA0 NDY3NDA0NjIxNjM1MzM2OTAwNTgzNjY0NjA2NTkxMTU2Mjk4NzY0NzQ1NTI1MDY4MTQ1MDAz OTMyOTQxNDA0MTMxNDk1NDAwNjc3NjAyOTUxMDA1OTYyMjUzMDIyODIzMDAzNjMxNDczODI0 NjgxMDU5NjQ4NDQyNDQxMzI0ODY0NTczMTM3NDM3NTk1MDk2NDE2MTY4MDQ4MDI0MTI5MzUx ODc2MjA0NjY4MTM1NjM2ODc3NTMyODE0Njc1NTM4Nzk4ODcxNzcxODM2NTEyODkzOTQ3MTk1 MzM1MDYxODg1MDAzMjY3NjA3MzU0Mzg4NjczMzY4MDAyMDc0Mzg3ODQ5NjU3MDE0NTc2MDkw MzQ5ODU3NTcxMjQzMDQ1MTAyMDM4NzMwNDk0ODU0MjU2NzAyNDc5MzM5MzIyODA5MTEwNTI2 MDQxNTM4NTI4OTk0ODQ5MjAzOTkxMDkxOTQ2MTI5OTEyNDkxNjMzMjg5OTE3OTk4MDk0Mzgw MzM3ODc5NTIyMDkzMTMxNDY2OTQ2MTQ5NzA1OTM5NjY0MTUyMzc1OTQ5Mjg1ODkwOTYwNDg5 OTE2MTIxOTQ0OTg5OTg2Mzg0ODM3MDIyNDg2NjcyMjQ5MTQ4OTI0Njc4NDEwMjA2MTgzMzY0 NjI3NDE2OTY5NTc2MzA3NjMyNDgwMjM1NTg3OTc1MjQ1MjUzNzM3MDM1NDMzODgyOTYwODYy NzUzNDI3NzQwMDE2MzMzNDM0MDU1MDgzNTM3MDQ4NTA3Mzc0NTQ0ODE5NzU0NzIyMjI4OTc1 MjgxMDgzMDIwODk4NjgyNjMzMDIwMjg1MjU5OTIzMDg0MTY4MDU0NTM5Njg3OTExNDE4Mjk3 NjI5OTg4OTY0NTc2NDgyNzY1Mjg3NTA0NTYyODU0OTI0MjY1MTY1MjE3NzUwNzk5NTE2MjU5 NjY5MjI5MTE0OTc3Nzg4OTYyMzU2NjcwOTU2NjI3MTM4NDgyMDE4MTkxMzQ4MzIxNjg3OTk1 ODYzNjUyNjM3NjIwOTc4Mjg1MDcwMDk5MzM3Mjk0Mzk2Nzg0NjM5ODc5MDI0OTE0NTE0MjIy NzQyNTI3MDA2MzYzOTQyMzI3OTk4NDgzOTc2NzM5OTg3MTU0NDE4NTU0MjAxNTYyMjQ0MTU0 OTI2NjUzMDE0NTE1NTA0Njg1NDg5MjU4NjIwMjc2MDg1NzYxODM3MTI5NzYzMzU4NzYxMjE1 MzgyNTY1MTI5NjMzNTM4MTQxNjYzOTQ5NTE2NTU2MDAwMjY0MTU5MTg2NTU0ODUwMDU3MDUy NjExNDMxOTUyOTE5OTE4ODA3OTU0NTIyMzk0NjQ5NjI3NjM1NjMwMTc4NTgwODk2NjkyMjI2 NDA2MjM1MzgyODk4NTM1ODY3NTk1OTkwNjQ3MDA4Mzg1Njg3MTIzODEwMzI5NTkxOTI2NDk0 ODQ2MjUwNzY4OTkyMjU4NDE5MzA1NDgwNzYzNjIwMjE1MDg5MDIyMTQ5MjIwNTI4MDY5ODQy MDE4MzUwODQwNTg2OTM4NDkzODE1NDk4OTA5NDQ1NDYxOTc3ODkzMDI5MTEzNTc2NTE2Nzc1 NDA2MjMyMjc4Mjk4MzE0MDMzNDczMjc2NjAzOTUyMjMxNjAzNDIyODI0NzE3NTI4MTgxODE4 ODQ0MzA0ODgwOTIxMzIxOTMzNTUwODY5ODczMzk1ODYxMjc2MDczNjcwODY2NjUyMzc1NTU1 Njc1ODAzMTcxNDkwMTA4NDc3MzIwMDk2NDI0MzE4NzgwMDcwMDA4Nzk3MzQ2MDMyOTA2Mjc4 OTQzNTUzNzQzNTY0NDQ4ODUxOTA3MTkxNjE2NDU1MTQxMTU1NzYxOTM5Mzk5NjkwNzY3NDE1 MTU2NDAyODI2NTQzNjY0MDI2NzYwMDk1MDg3NTIzOTQ1NTA3MzQxNTU2MTM1ODY3OTMzMDY2 MDMxNzQ0NzIwOTI0NDQ2NTEzNTMyMzY2NjQ3NjQ5NzM1NDAwODUxOTY3MDQwNzcxMTAzNjQw NTM4MTUwMDczNDg2ODkxNzk4MzY0MDQ5NTcwNjA2MTg5NTM1MDA1MDg5ODQwOTEzODI2ODY5 NTM1MDkwMDY2NzgzMzI0NDcyNTc4NzEyMTk2NjA0NDE1Mjg0OTI0ODQwMDQxODUwOTMyODEx OTA4OTYzNjM0MTc1NzM5ODk3MTY2NTk2MDAwNzU5NDg3ODAwNjE5MTY0MDk0ODU0MzM4NzU4 NTIwNjU3MTE2NTQxMDcyMjYwOTk2Mjg4MTUwMTIzMTQ0Mzc3OTQ0MDA4NzQ5MzAxOTQ0NzQ0 MzMwNzg0Mzg4OTk1NzAxODQyNzEwMDA0ODA4MzA1MDEyMTc3MTIzNTYwNjIyODk1MDc2MjY5 MDQyODU2ODAwMDQ3NzE4ODkzMTU4MDg5MzU4NTE1NTkzODYzMTc2NjUyOTQ4MDg5MDMxMjY3 NzQ3MDI5NjYyNTQ1MTEwODYxNTQ4OTU4Mzk1MDg3Nzk2NzU1NDY0MTM3OTQ0ODk1OTYwNTI3 OTc1MjA5ODc0ODEzODM5NzYyNTc4NTkyMTA1NzU2Mjg0NDAxNzU5MzQ5MzI0MTYyMTQ4MzM5 NTY1MzUwMTg5MTk2ODExMzg5MDkxODQzNzk1NzM0NzAzMjY5NDA2MzQyODkwMDg3ODA1ODQ2 OTQwMzUyNDUzNDc5Mzk4MDgwNjc0MjczMjM2Mjk3ODg3MTAwODY3MTc1ODAyNTMxNTYxMzAy MzU2MDY0ODc4NzA5MjU5ODY1Mjg4NDE2MzUwOTcyNTI5NTM3MDkxMTE0MzE3MjA0ODg3NzQ3 NDA1NTM5MDU0MDA5NDI1Mzc1NDI0MTE5MzE3OTQ0MTc1MTM3MDY0Njg5NjQzODYxNTE3NzE4 ODQ5ODY3MDEwMzQxNTMyNTQyMzg1OTExMDg5NjI0NzEwODg1Mzg1ODA4Njg4ODM3Nzc3MjU4 NjQ4NTY0MTQ1OTM0MjYyMTIxMDg2NjQ3NTg4NDg5MjYwMDMxNzYyMzQ1OTYwNzY5NTA4ODQ5 MTQ5NjYyNDQ0MTU2NjA0NDE5NTUyMDg2ODExOTg5NzcwMjQwLjAwMDAwMA0KbGFyZ2U6DQo3 OTg0NDE5NTAxMzE5ODQxNzA2MjgwMzA0NjA2NjY4MTAzMzM1NTczNDgyNzUxOTAyNjU1NzYw Nzg5ODQwOTQxODY4MDkzMTQ1OTU4NDE1NzM1MzI1OTkwMzM2MDY4ODI3MzMyNDIyMTQ1MDMx ODQ1MTU2NDYxMTQ3NTc4NTQ4MDkyODUyMjE5OTYzNTYyMjgyODk1NTQzNzY2MzUwMTkzNDQ3 NTM5MjA3NzY3MDI3NjA2NjkxODc5NDA4MTc1MTQ1MzEzMTcwODYxNDAzODM1MTA3MzMxMTI1 MDg2NDk2NjQ2MjM2MzMxMzk1MjgwNTA3NzcxMTAwNzQ2MTgwMDU2MTc1MDk1ODAxNDY4MzMz MDUwNjA5MjQzMjQyNDY3NTQzNDIzOTA4MTk4MDMyOTQ5NzU0ODkyNDQyOTQ2OTA0NTcxODE2 MTU5MTYzODA4NDY3ODcyMjAzMTAxMDA5OTU5OTQzMDM5NDU3Nzc5MTM0NTAxNzg1NzA1ODE5 ODE2ODYxOTg0OTgxOTM5MDc3ODI1NDcxNzMyNzM2OTgyNzkzODUzOTI4NzAwNjcxMjI1MTY0 MDEzODA2NjEzMDk0MjkxOTQzNzc1NzEyODg2NzU1MTA1OTIxMjEzNjI5MzMxMjg2OTAyMTY5 Mzc1NTExNjQ3MjM5MDMwMzM5Njc3MzIyODgxOTQ2MzMzMDQ4MDY5NzQ0NDMwNzc1MDYwNzk3 NjQ1MDYxNDAzNDgxMDQwOTMyMTMxNzYwODgyNDA1Njk3NjM1MzI0MzMwMzEzMDk2MjgxMjA3 NTgwNTEyOTk4NDcxOTA5MDY1MzEyODI3MzU1NjA3NDA5ODE1MDQzNTE2NDUyNjI0MDU5ODgw MjQwMjI5MTU3NjkwMTUxNTUyOTE1MzczNzMwMzk0NTI3NTcyODc3MTQyMjQ0MTMyNzE5MjU3 MjI5NjUxMDkxOTY0MTI5NjAyMzM0NTAxMDg5OTc1NTYyMDUzNTQ0MzExMDczNzg1MTgzNDE2 NDI5ODcyOTE2MDQwOTA3NTI0MjY5MzkwMjcyNjQyMTMwMTk0NDAxNDUxMjQ0OTA2NjE0Nzc3 MjY3NDczMTg5MTQ1NzQ4ODE0Njk5NjE1MTgxMzQ1MTUxMDg4ODA4NTcyNDUyNDAxODU1NzI3 MTgxMzk4MjY2MzMwODMxNTM0MDU0NjI4MDY0NDU2NTI4ODg0MTM0MTA2MzgxODg3MzM3MzQ1 MTUzMzYwODk0NjE2OTAxODg3Njk5NDEyOTYwMDAzMTAyMzc5MDg0NzI4NzE1MzQ5MjQwMjI2 MDU3ODE1NTMxMzc3NTgxNTAyMzM3ODkyNjAzNTg1MzI5MDcxNDU4ODIwMzYxNjE2NjAxMjY5 NDU2NjE3MTE4Mzk3MzU0MjE3MTE4MjUxNzgxNzc3NjA5NTc4MTgwMDk2MDU5Mjg2NzcxNzc2 MDAyMDYzNTM2MDg0ODc0NDc4NjcwMDAwMDc2NjEzMzQzODQxMjc3ODMwNDIwMTIyOTQ1NjI1 OTM1Mjg2ODQ3MjU4MTA4ODQ2MTc3Mzc2MDkyNTQxNjkxNDk2MjY3NTcyOTU2Nzk3MDY2NzU2 NDAyNTM2NzQzMDUxMzc3MjQwMDc1NzY0MzAzNjIxNDYzNTExOTU0ODE2MTg3NTAxNTI0MDA5 NTQzMTMwNTM5OTc4NjY0NjQ2Njk3OTk0MjYwOTY1ODc0NTY4MzE2NDIxNjI5ODc0MTQ3MjQ4 OTYxMDAyNjIxNjQ1Mzk3NjM2NjAzNjIzODIwOTI1NzM5NjE3ODMxMzQ1MDE3NzIyODI5MDgw OTgyOTA1OTMyODk2MzAxNTI4NzY3NzAzMDA0MTc3NDQ5NzM0NTg1NTY0NzAxNDI2ODg3NjY0 NjQ2NzE1NzUxMzA0MDkwMDM3ODgzMDM3MTI0MjI2Mjk5NDY2NTI3NzI3NDc5ODk0MTI1NzA0 NTI3MTk1NjMwNDkwNjE3ODEyMzU4MTYwMDEwNjc3NTIyNTE4NTE1MTk4MjcwOTY2ODQ5NDEz NjYyNDIzMDc4ODA4NTc0NTk5OTI4NTk5ODg5OTUyNDIzNTg4NzY2OTkwNzM0OTYyMDQ5NDYx ODkwMTIxMTYwOTQ2MzY3MjYwMDc3NTEwMjQ1NjI1MDEwNzA4Njg2MTYxNTgwMDM1MzA2NTg0 NTU4NTczNDExNjI1MjY0MzkxNjU0OTIxNDA1MTc2MDk5NTAwOTY2MTk0MTI3MzI5MDc5NDQ4 OTYwNTczOTAxOTYyNzAwNTcxNzcyNDI3MjgxNTYzMzk2Mzg1NDA4Njc2MTA5MjQxMDU4NTc0 MTI1NTY0NDQ1NzkxMDc3NzY4MTY4ODk2NzQ2MzEzNjY0MTM2Nzc4MzMwNDcxNjEzNzk4ODQ1 MzIxNjQxOTg5OTMyNzY3NzI4OTY0MjU0OTUwODMwMDA1MDU1NTU0NDk1MDQzNjE3ODA3NzI2 MzUwOTk5NTA2NzcyODAxOTUyNDUwMTczMDAzNTIyNTY1OTE3ODY1MzU0NDU2NDkzNzY2MDE4 Mjk0ODgxOTYzODI4OTgxNzU5MTIwMzQ3ODcwMTU0Mjg5MjM1OTI3ODQ1ODAyNzYxMTMzNjk2 NjY5MDMxNjczNTgyNTM2MzM1MzA0NDE2MTEwOTc2NTM1OTY5NzU0NjEyNDgwNjE2NjIzMzkz NjU0ODg0NzMxMTk2MDA4Mjk1MjM1MDA0NTkyMDM2MTk0NTY5NjQ2MDMxMjkwMTg5ODg5MzEx OTQzMjgyODg4MTM2NDcxMDE3MDE2MzI4Mzk1MTI4NTg5Mjk4Njk0NzgzOTQ4MDQyOTY2OTgz OTQyNjA5NTQ4MDk2OTI0MTcyMzQ0MDYyMDUzNzExMDY4OTM0OTYyMzY5Njc3ODk5OTE1NjU1 MDU3MzU1ODYyMzYzODQ2Nzc5NTA4MDk4NDI5NTMyMTc5MzE1ODQ3NDkyNjA3Njk5NTk3MDE0 Mzg3ODI0Nzg1NzE1MDEzMzQ1MzkzODU2NDA0Mzk4ODAzOTY3OTMzNzI0OTMyMTMwMTY2Mjc3 NDUzNTc4MTE5MzA0NzkwMjkwMjM1NDEwOTU3Njk0NTUxNDI0ODgyOTY5NjY4NzkwNzI5MzY0 MjUxNzM3ODU4MjM0MjM0OTE3ODQ4MzE4OTYxOTQ1NTYwMzEzODY3NjY2MzQ0MDgzODc5ODI2 MjIzMzc3MjQ0ODAxMzUwMDcyOTk5MTQ0NDY4NzcxNTI1MzA3ODAzNDI5MjgwOTcwODY5ODc1 MTQ2MzMyODM5MjQ4NTY0MzcyNjMxNDQ3NjgzODM4NTkxNzExMTE5ODgwMTQzMDUzNTA5MzUz NzQ4MTY1MDI3MDIzMzMyNTEwOTM5MjM3NTc3MzI0NjI3OTIzNTUzMDc3ODk5MDUxNzQ3MTkw OTk0ODg3NTk3MzMzOTM0Mzg2OTg2ODk2MzQyMzAzNjE0MDMwODQyNTg1MzMzOTcyNjUxMjAx Mjc1Njg5NjExNzQxMTEzMjcyOTczMjA3ODIyNjA0ODg3MzA4OTMyMTY3MDA0NTM5Nzg4Mzc3 MTcxMzc2MjI3NjkwODQ0MDYxNjc1NjYxNTI3NTk2MjMxODE3MDYwMjg5NzYzNzUxNjQ2NDYw OTQ0NzUxNDY2NDczNjkyODE1NzU5NzI1MjI4NTM1NDk1NTI1NDE3MjA5MjMwMDc2NjU5NDg2 NDM2NDYwMTEyODI3MzY4NzMzMDk1MjY0Mjg5NjM0MDc4OTgzNTI0NjQ0ODExNjU4NDc2NjQ1 MTUxMjEwOTIxOTgyMzYzMjk1NTU5OTcwMjQwODkxODE3NzY3ODIyNzMxMzMwMDgzNDc2ODM4 NDkwNDg1NTMzOTA4MDA2NjQ3MTI5ODAzNDA0NzU5OTYyNjA0ODAwNzI3MjA1NjU3MTU4ODc4 MzEyMDc0ODM5NTU4MDc4MzI3Njc5Mzk4ODMzOTI0MjU1NDYzODU1MzY3MTYwNzc0MzI2MzA4 OTgyMTQ4OTk0ODQyODExMDc1MTEwNzM3OTIxNzU0MTM4MjkwNjgxMzgxNzUzNzM5NTU3ODc5 NDIyNjQ0NjQ5ODU5ODM3NzQ5Njk3ODM2MDQ1NjI2Mzc4ODUxODA4NzEwMTY1NTE4NjgyMzEy NDIyNTQ2MjUyODk0ODY5MzA3OTQyMDIzOTE0MTM0NTQxMzQ0NjAzOTA4NTE4MjI5NzIyODgw MjgzNjc5OTQ5MjQzNDc4NDAxNDg3OTM3OTEzNjE5MTgyODI4OTE2NjU4NjY4Nzk2NTg0OTE3 OTY5MzQ0NzY5Mjc2NDE0OTM0MTI5Mjg5NTg2NDkyNDAxMzA4MjU2NTIyMjkxMTU3MTE0OTE4 MTc3Njc0NTAxMDYwNjI3ODk2MTU1NDEzMjA0MDA3MjEwOTg4ODk4NTIwODU4OTgyNTkyNTQx NjI3MzUzMDc3OTMwNDY0OTA1MjYzODgwMjYzMTYyOTUyODA4OTQ3OTg5MjcwNzY2MjUxNzI5 NTIwMzM2MzE4MTYxOTM1MTA4NDAyODc2OTEyNjg5MjcyOTQwOTgwNTgxOTIzMDgzNzIyMTI0 ODYyNzU5MzUwMTg5MTY1NzkxNjQ5NjQ5NTE0MDEyOTc4MDUwMDMyOTEyNzAwNDA2NjAzMDI3 MDY3NjA5MjI2NzQ2MjA3NTc4NDQ5Mzc3MzcxODk4NzQ3MzU4MzMwNDg2MTE4NzY1ODcwNjIw ODQzOTgwNjUxODQ0OTc5OTIyNTQyNTA5MjMxNzA0ODIwMDUzNzk3MDc3NzgwMjUxNzg0NDQ2 MTQwNDAyMDY5MjQ1OTczMjA2Mjc0NjYyNDM1OTcwMDM3OTAzOTU1MDkwMjIzMTAwNTU1NjU5 NTkxNzM1OTk5NzQ4MTQ5NTc0ODY4MzIxMjE3NDc4MTI4OTgxMTA0Njg0NzI3NTc3MTEzNDQ5 MzUxNDE1ODE2MTk3NjgxNzkwMjcyNzczMDA3NDUwMjYxNzg1NDg2OTA4NDIwMjczODkwMjI1 NzM0MTM0ODY3MTkwODY0MjQzNzY1NDk5OTU1MzE4NjI5NTM0OTUyNjI4MTA3NDM4NDQ5Njc1 MTg5MTI3NDU3ODg0MTA4ODU0MTczMjAwNzM2NjczNDYzOTkzNzIxNDQ3MjkxNzI4MDQzMTYy NjU0NzQzOTM0NjE5MjUyMDYzNzAwMTYzMzI4Mzc0OTMzNDYyOTg3MTQyMzE1OTkzNDg2OTkw Mjg3MDk3Mjg4NjI5ODg2NjQ0NTI4MzAyOTAzNjE2NDY1NDU0NzU3OTMyNDg2MTc1MTIzMTAw ODEzNzIzNjg3OTk3NzIwNTQzNTAyMzEzMTczNzE2ODY0NTI2NzI5OTYwMDk5ODE1NTEwNTc0 MDAwODA0MjU1MjIzOTY0NDY0ODcyMjkzNTYyNjIzMDM5MTc5MzgyMjk2NjQ3ODk4NjkyMDgz NjMyMzgxMzYzOTcwNjg4OTM0NDA4MDcyMjM0NjQ0NTE0MTc5MjYzMDIzMzk0NDU4ODA1MzU4 NzUxOTU3MDIyODc2ODQ2MTUyMDY0MzM3MTAyOTI5NjM1OTQ3OTEzOTIxODcxNjc1MDAyNDY3 ODU4MDg3OTIxNTgzODAwMzk1OTA1NjMxODc4MDA2NjgzMjE5MTkwNTQ3MDA3Nzg5OTMyMjM2 NjQxMjcwMDUwMzk1NjI4Nzk5MzE5NjM3NzU2NDQxNzQ0MTQyMzQyNDIzNzE4OTcwNTM0MTc1 MDA5NTYxODYwMzIyMDg1MDY1NjQ4Mjc4MjQ1MzA5MDk0MzIxNDQzNzg2NjEzMjYzMTM2MTc1 Nzc2NjE4OTQyMzMxMjU0MTI4NzU3MTM5NTczOTI1OTQyMzcyNTAyNzI5MDA0Nzk1MjMzOTk5 MjUyMDAzODE3NTMyNzA0NTc4NjI1NzM4MzE0NTMzODI2OTMyMTk2ODI1MTA3NzM5OTk3OTg0 MzYwNTk0MDUzOTcxMDkzNDAwOTYwOTk4NTE0NDA0NzA1NDMzMTU4NDI2NTExOTQzMTM1ODA3 MjY2OTAyNDY5NDgzMDkxNzMwMzcwNzAxMDI0MjI2OTc5Mjg4NjU1NDM1OTM1OTM5ODAxNjYw NzU3ODEyMjAwNjQ1ODQ3NDgxMzU5NDk1Mjg4MDMzMjIwNDM3NjM3OTg1MjgxMjg3OTMxNTI4 ODM2NDc0ODcxMDgxOTI4NTQwMTI0NTM5ODg4MjE1NjU4MTc2MTE0NjU0NzQ5MzM4OTE0ODEx NDA3NjgwNjIyNjg4MzQ4Mzg4MzMzMjY2NzM1NTU4MDgyMzczNTcxODQwNTE0Njg5ODkxMTcx MjY5Nzg1MDIxNDE0MDQ4NTIxOTE4MDQzMDE1NDI2MDc2NDY5NDYxMzA5Nzc0MTA4MDk5Njcy Nzg0NzY2OTg0NjAxODEyMjI0NjUyNTkwNTYzODYyNDY5ODIyNjc1NTg1Mjg5ODc4OTQ0NTc4 Njg0MTAzODUxMDEwMDY0MjIwOTkyODcwNjQ0ODMxODk1OTg2MzEzODkyNTA2MDQwMTc3NzM4 MjkxNzQzOTI0MjExNjA5MzA2MjY4ODU3NjY0Njk4NjI2NjU5NzA5Njg1NzU5NzgxMjI5Mzg4 OTUxOTExNTMyODAyODY3MjAuMDAwMDAwDQptaWRkbGluZzogMjg4MjQwMDAwMS4xMzc3NzgN Cm1heGxsOiA5MjIzMzcyMDM2ODU0Nzc1ODA3DQpsYXJnZWxsOiA5MjIzMzcyMDM2ODU0Nzc1 ODA3DQptaWRkbGluZ2xsOiAyODgyNDAwMDAxDQptYXg6IDB4Zi5mZmZmZmZmZmZmZmZmZmZw KzE2MzgwDQpsYXJnZTogMHhhLmJjZGVmMDEyMzQ1Njc4OXArMTYzODANCm1pZGRsaW5nOiAw eGEuYmNkZWYwMTIzNDU2Nzg5cCsyOA0KbWF4bGw6IDB4N2ZmZmZmZmZmZmZmZmZmZg0KbGFy Z2VsbDogMHg3ZmZmZmZmZmZmZmZmZmZmDQptaWRkbGluZ2xsOiAweGFiY2RlZjAxDQoNCkkn bGwgdXNlIGhleGFkZWNpbWFsIG5vdGF0aW9uIGluIHRoZSBmb2xsb3dpbmcgY29tbWVudHM6 DQoNClRoZSB3aG9sZSBwYXJ0IG9mICJtYXgiIGhhcyB0aGUgc2FtZSB2YWx1ZSBhcyAibWF4 IiBpdHNlbGYuIFRoZSBzYW1lIGlzDQp0cnVlIG9mICJsYXJnZSIuIFRoZSB3aG9sZSBwYXJ0 IG9mIG1pZGRsaW5nIGlzIDB4QUJDREVGMDEuIFRoZQ0KZnJhY3Rpb25hbCBwYXJ0IG9mIG1p ZGRsaW5nIGlzIDB4MC4yMzQ1Njc4OS4NCg0KVGhlIG1hbnRpc3NhcyBhcmUgYXMgZm9sbG93 czoNCm1heDogMHhmZmZmZmZmZmZmZmZmZmZmDQpsYXJnZTogMHhhYmNkZWYwMTIzNDU2Nzg5 DQptaWRkbGluZzogMHhhYmNkZWYwMTIzNDU2Nzg5DQoNClRoZSB2YWx1ZXMgc3RvcmVkIGlu ICJtYXhsbCIgYW5kICJsYXJnZWxsIiBkbyBub3QgbWF0Y2ggZWl0aGVyIHRoZSB3aG9sZQ0K cGFydCBvciB0aGUgbWFudGlzc2Egb2YgdGhlIGNvcnJlc3BvbmRpbmcgZmxvYXRpbmcgcG9p bnQgbnVtYmVyLiBCZWNhdXNlDQoibWlkZGxpbmciIGlzIHRoZSBvbmx5IG9uZSBvZiB0aGUg dGhyZWUgbG9uZyBkb3VibGUgdmFsdWVzIHRoYXQgaXMNCnNtYWxsZXIgdGhhbiBMTE9OR19N QVgsIHRoZSB2YWx1ZSBzdG9yZWQgaW4gbWlkZGxpbmdsbCBpcyB0aGUgd2hvbGUgcGFydA0K b2YgIm1pZGRsaW5nIiwgYXMgaXQgc2hvdWxkIGJlLCBidXQgaXMgcXVpdGUgZGlmZmVyZW50 IGZyb20gdGhlIG1hbnRpc3NhDQpvZiAibWlkZGxpbmciLg0K

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to Alf P. Steinbach on Sat Oct 2 15:12:05 2021
    On 10/2/21 3:00 PM, Alf P. Steinbach wrote:
    On 1 Oct 2021 17:37, wij wrote:
    // numeric_limits<long double>::digits=64.
    //
    typedef long double FType;
    FType x=numeric_limits<FType>::max();
    int iexp;
    int64_t mint;
    x=::frexpl(x,&iexp);
    x=::ldexpl(x,numeric_limits<FType>::digits);
    mint= static_cast<int64_t>(x);>>
    Result (mint) is a negative number, something not right!!!

    Apparently you're trying to obtain the bits of the mantissa of a `long double` number, represented as an `int64_t` value.

    A `long double` is in practice either IEEE 754 64-bit, or IEEE 754
    80-bit. In Windows that choice depends on the compiler. With Visual C++
    (and hence probably also Intel) it's 64-bit, same as type `double`,
    while with MinGW g++ (and hence probably also clang) it 80-bit,
    originally the x86-family's math coprocessor's extended format. For
    80-bit IEEE 754 the mantissa part is 64 bits.

    With 64-bits mantissa there is a high chance of setting the sign bit of
    an `int64_t` to 1, resulting in a negative value. I believe that that
    will only /not/ happen for a denormal value, but, I'm tired and might be wrong about that. Anyway, instead use unsigned types for bit handling.
    For example, in this case, use `uint64_t`.

    It would be safer and more portable to use FType; there's no portable
    guarantee that any integer type is large enough to hold the mantissa,
    but FType is.

    However, instead of the shenanigans with `frexpl` and `ldexpl` I'd just
    use `memcpy`.

    The advantage of the code as written is that (if you change mint to have
    FType) it will give the correct result even if your assumption about
    IEEE 754 is false; that's not the case with memcpy().

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to Branimir Maksimovic on Sat Oct 2 15:37:40 2021
    On 10/2/21 2:59 PM, Branimir Maksimovic wrote:


    On 02.10.2021., at 20:51, James Kuyper
    <jameskuyper@alumni.caltech.edu
    <mailto:jameskuyper@alumni.caltech.edu>> wrote:

    int main(void)
    {
       typedef long double FType;
       FType max= std::numeric_limits<FType>::max();
       FType large = 0xA.BCDEF0123456789p+16380L;
       FType middling = 0xABCDEF01.23456789p0L;
       long long maxll = max;
       long long largell = large;
       long long middlingll = middling;

       std::cout << std::fixed << "max: " << max << std::endl;
       std::cout << "large: " << large << std::endl;
       std::cout << "middling: " << middling << std::endl;

       std::cout << "maxll: " << maxll << std::endl;
       std::cout << "largell: " << largell << std::endl;
       std::cout << "middlingll: " << middlingll << std::endl;

       std::cout << std::hexfloat << std::showbase << std::showpoint <<
           std::hex << "max: " << max << std::endl;
       std::cout << "large: " << large << std::endl;
       std::cout << "middling: " << middling << std::endl;

       std::cout << "maxll: " << maxll << std::endl;
       std::cout << "largell: " << largell << std::endl;
       std::cout << "middlingll: " << middlingll << std::endl;
    }
    mantissa.cpp:7:18: warning: magnitude of floating-point constant too
    large for type 'long double'; maximum is 1.7976931348623157E+308 [-Wliteral-range]
    Sorry your program is not correct..

    The value of "large" was chosen to be almost as large as "max" on my
    machine. It's apparently larger than LDBL_MAX on your system. A more
    portable initializer would be

        FType large = 0x0.ABCDEF0123456789p0L * max;

    Depending upon the value of LDBL_EPSILON on the target implementation,
    that definition might result in the mantissa of "large" having fewer significant digits than it has on mine, but that's not particularly
    important.

    This is output on my system:
    bmaxa@Branimirs-Air projects % ./a.out
    max: 1797693134862315708145274237317043567980705675258449965989174768031572607800285387605895586327668781715404589535143824642343213268894641827684675467035375169860499105765512820762454900903893289440758685084551339423045832369032229481658085593321233482747
    97826204144723168738177180919299881250404026184124858368.000000
    large: inf
    middling: 2882400001.137778
    maxll: 9223372036854775807
    largell: 9223372036854775807
    middlingll: 2882400001
    max: 0x1.fffffffffffffp+1023
    large: inf
    middling: 0x1.579bde02468adp+31
    maxll: 0x7fffffffffffffff
    largell: 0x7fffffffffffffff
    middlingll: 0xabcdef01

    Greetings, Branimir.

    With that change, the value of "large" on my machine changes to 0xa.bcdef0123456788p+16380, with a corresponding (HUGE) change to the
    less significant digits of the decimal output, and the mantissa is
    therefore 0xabcdef0123456788.
    You'll get much different values for "max" and "large" on your system,
    since LDBL_MAX is much smaller, but the qualitative comments I made
    about those values should still be accurate. There's no guarantees,
    since the behavior is undefined, but I would expect that the values of
    "maxll" and "largell" will be unchanged.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Alf P. Steinbach@21:1/5 to James Kuyper on Sat Oct 2 21:23:23 2021
    On 2 Oct 2021 21:12, James Kuyper wrote:
    On 10/2/21 3:00 PM, Alf P. Steinbach wrote:
    On 1 Oct 2021 17:37, wij wrote:
    // numeric_limits<long double>::digits=64.
    //
    typedef long double FType;
    FType x=numeric_limits<FType>::max();
    int iexp;
    int64_t mint;
    x=::frexpl(x,&iexp);
    x=::ldexpl(x,numeric_limits<FType>::digits);
    mint= static_cast<int64_t>(x);>>
    Result (mint) is a negative number, something not right!!!

    Apparently you're trying to obtain the bits of the mantissa of a `long
    double` number, represented as an `int64_t` value.

    A `long double` is in practice either IEEE 754 64-bit, or IEEE 754
    80-bit. In Windows that choice depends on the compiler. With Visual C++
    (and hence probably also Intel) it's 64-bit, same as type `double`,
    while with MinGW g++ (and hence probably also clang) it 80-bit,
    originally the x86-family's math coprocessor's extended format. For
    80-bit IEEE 754 the mantissa part is 64 bits.

    With 64-bits mantissa there is a high chance of setting the sign bit of
    an `int64_t` to 1, resulting in a negative value. I believe that that
    will only /not/ happen for a denormal value, but, I'm tired and might be
    wrong about that. Anyway, instead use unsigned types for bit handling.
    For example, in this case, use `uint64_t`.

    It would be safer and more portable to use FType; there's no portable guarantee that any integer type is large enough to hold the mantissa,
    but FType is.

    I believe you intended to write `uintptr_t`, not `FType`.

    If so, agreed.

    It's late in the day for me, sorry.


    However, instead of the shenanigans with `frexpl` and `ldexpl` I'd just
    use `memcpy`.

    The advantage of the code as written is that (if you change mint to have FType) it will give the correct result even if your assumption about
    IEEE 754 is false; that's not the case with memcpy().

    Uhm, I'd rather assert IEEE 754 representation
    (numeric_limits::is_iec559). Dealing with the bits of just about any representation seems to me a hopelessly daunting task. :-o


    - Alf

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Alf P. Steinbach@21:1/5 to Alf P. Steinbach on Sat Oct 2 21:27:18 2021
    On 2 Oct 2021 21:23, Alf P. Steinbach wrote:
    On 2 Oct 2021 21:12, James Kuyper wrote:
    On 10/2/21 3:00 PM, Alf P. Steinbach wrote:
    On 1 Oct 2021 17:37, wij wrote:
    // numeric_limits<long double>::digits=64.
    //
    typedef long double FType;
    FType x=numeric_limits<FType>::max();
    int iexp;
    int64_t mint;
    x=::frexpl(x,&iexp);
    x=::ldexpl(x,numeric_limits<FType>::digits);
    mint= static_cast<int64_t>(x);>>
    Result (mint) is a negative number, something not right!!!

    Apparently you're trying to obtain the bits of the mantissa of a `long
    double` number, represented as an `int64_t` value.

    A `long double` is in practice either IEEE 754 64-bit, or IEEE 754
    80-bit. In Windows that choice depends on the compiler. With Visual C++
    (and hence probably also Intel) it's 64-bit, same as type `double`,
    while with MinGW g++ (and hence probably also clang) it 80-bit,
    originally the x86-family's math coprocessor's extended format. For
    80-bit IEEE 754 the mantissa part is 64 bits.

    With 64-bits mantissa there is a high chance of setting the sign bit of
    an `int64_t` to 1, resulting in a negative value. I believe that that
    will only /not/ happen for a denormal value, but, I'm tired and might be >>> wrong about that. Anyway, instead use  unsigned types for bit handling. >>> For example, in this case, use `uint64_t`.

    It would be safer and more portable to use FType; there's no portable
    guarantee that any integer type is large enough to hold the mantissa,
    but FType is.

    I believe you intended to write `uintptr_t`, not `FType`.

    If so, agreed.

    It's late in the day for me, sorry.

    It's /very/ late.

    There AFAIK is no suitable type name for the integer type with
    sufficient bits to represent the mantissa, or generally >N bits.

    Unfortunately the standard library doesn't provide a mapping from number
    of bits as a value, to integer type with that many bits. It can be done,
    on the assumption that all types in `<stdint.h>` are present. And
    perhaps one can then define a name like `FType` in terms of that mapping.


    However, instead of the shenanigans with `frexpl` and `ldexpl` I'd just
    use `memcpy`.

    The advantage of the code as written is that (if you change mint to have
    FType) it will give the correct result even if your assumption about
    IEEE 754 is false; that's not the case with memcpy().

    Uhm, I'd rather assert IEEE 754 representation
    (numeric_limits::is_iec559). Dealing with the bits of just about any representation seems to me a hopelessly daunting task. :-o


    - Alf


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Manfred@21:1/5 to Alf P. Steinbach on Sat Oct 2 23:19:50 2021
    On 10/2/2021 9:27 PM, Alf P. Steinbach wrote:
    On 2 Oct 2021 21:23, Alf P. Steinbach wrote:
    On 2 Oct 2021 21:12, James Kuyper wrote:
    On 10/2/21 3:00 PM, Alf P. Steinbach wrote:
    On 1 Oct 2021 17:37, wij wrote:
    // numeric_limits<long double>::digits=64.
    //
    typedef long double FType;
    FType x=numeric_limits<FType>::max();
    int iexp;
    int64_t mint;
    x=::frexpl(x,&iexp);
    x=::ldexpl(x,numeric_limits<FType>::digits);
    mint= static_cast<int64_t>(x);>>
    Result (mint) is a negative number, something not right!!!

    Apparently you're trying to obtain the bits of the mantissa of a `long >>>> double` number, represented as an `int64_t` value.

    A `long double` is in practice either IEEE 754 64-bit, or IEEE 754
    80-bit. In Windows that choice depends on the compiler. With Visual C++ >>>> (and hence probably also Intel) it's 64-bit, same as type `double`,
    while with MinGW g++ (and hence probably also clang) it 80-bit,
    originally the x86-family's math coprocessor's extended format. For
    80-bit IEEE 754 the mantissa part is 64 bits.

    With 64-bits mantissa there is a high chance of setting the sign bit of >>>> an `int64_t` to 1, resulting in a negative value. I believe that that
    will only /not/ happen for a denormal value, but, I'm tired and
    might be
    wrong about that. Anyway, instead use  unsigned types for bit handling. >>>> For example, in this case, use `uint64_t`.

    It would be safer and more portable to use FType; there's no portable
    guarantee that any integer type is large enough to hold the mantissa,
    but FType is.

    I believe you intended to write `uintptr_t`, not `FType`.

    If so, agreed.

    It's late in the day for me, sorry.

    It's /very/ late.

    There AFAIK is no suitable type name for the integer type with
    sufficient bits to represent the mantissa, or generally >N bits.

    He meant the FType that is in the original post. I.e. the same floating
    point type of the number to be analyzed.


    Unfortunately the standard library doesn't provide a mapping from number
    of bits as a value, to integer type with that many bits. It can be done,
    on the assumption that all types in `<stdint.h>` are present. And
    perhaps one can then define a name like `FType` in terms of that mapping.


    However, instead of the shenanigans with `frexpl` and `ldexpl` I'd just >>>> use `memcpy`.

    The advantage of the code as written is that (if you change mint to have >>> FType) it will give the correct result even if your assumption about
    IEEE 754 is false; that's not the case with memcpy().

    Uhm, I'd rather assert IEEE 754 representation
    (numeric_limits::is_iec559). Dealing with the bits of just about any
    representation seems to me a hopelessly daunting task. :-o


    - Alf


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Branimir Maksimovic@21:1/5 to James Kuyper on Sun Oct 3 00:47:53 2021
    On 2021-10-02, James Kuyper <jameskuyper@alumni.caltech.edu> wrote:
    On 10/2/21 2:59 PM, Branimir Maksimovic wrote:


    On 02.10.2021., at 20:51, James Kuyper
    <jameskuyper@alumni.caltech.edu
    <mailto:jameskuyper@alumni.caltech.edu>> wrote:

    int main(void)
    {
       typedef long double FType;
       FType max= std::numeric_limits<FType>::max();
       FType large = 0xA.BCDEF0123456789p+16380L;
       FType middling = 0xABCDEF01.23456789p0L;
       long long maxll = max;
       long long largell = large;
       long long middlingll = middling;

       std::cout << std::fixed << "max: " << max << std::endl;
       std::cout << "large: " << large << std::endl;
       std::cout << "middling: " << middling << std::endl;

       std::cout << "maxll: " << maxll << std::endl;
       std::cout << "largell: " << largell << std::endl;
       std::cout << "middlingll: " << middlingll << std::endl;

       std::cout << std::hexfloat << std::showbase << std::showpoint <<
           std::hex << "max: " << max << std::endl;
       std::cout << "large: " << large << std::endl;
       std::cout << "middling: " << middling << std::endl;

       std::cout << "maxll: " << maxll << std::endl;
       std::cout << "largell: " << largell << std::endl;
       std::cout << "middlingll: " << middlingll << std::endl;
    }
    mantissa.cpp:7:18: warning: magnitude of floating-point constant too
    large for type 'long double'; maximum is 1.7976931348623157E+308
    [-Wliteral-range]
    Sorry your program is not correct..

    The value of "large" was chosen to be almost as large as "max" on my
    machine. It's apparently larger than LDBL_MAX on your system. A more
    portable initializer would be

        FType large = 0x0.ABCDEF0123456789p0L * max;

    Depending upon the value of LDBL_EPSILON on the target implementation,
    that definition might result in the mantissa of "large" having fewer significant digits than it has on mine, but that's not particularly important.

    Now outputs:
    bmaxa@Branimirs-Air projects % ./a.out
    max: 1797693134862315708145274237317043567980705675258449965989174768031572607800285387605895586327668781715404589535143824642343213268894641827684675467035375169860499105765512820762454900903893289440758685084551339423045832369032229481658085593321233482
    74797826204144723168738177180919299881250404026184124858368.000000
    large: 12064517228800137212661991951594735565385313509582009374226938785176317321061319451690255702134937474403640375664746260210194473312772580939243431998152628482818127377340360551330743112190498124394832005780577478728129092684856500029128222504750729
    4705767371139696722108291516984908752371556782562287095382016.000000
    middling: 2882400001.137778
    maxll: 9223372036854775807
    largell: 9223372036854775807
    middlingll: 2882400001
    max: 0x1.fffffffffffffp+1023
    large: 0x1.579bde02468acp+1023
    middling: 0x1.579bde02468adp+31
    maxll: 0x7fffffffffffffff
    largell: 0x7fffffffffffffff
    middlingll: 0xabcdef01




    --

    7-77-777
    Evil Sinner!
    to weak you should be meek, and you should brainfuck stronger https://github.com/rofl0r/chaos-pp

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Branimir Maksimovic@21:1/5 to James Kuyper on Sun Oct 3 00:45:16 2021
    On 2021-10-02, James Kuyper <jameskuyper@alumni.caltech.edu> wrote:
    On 10/2/21 3:00 PM, Alf P. Steinbach wrote:
    On 1 Oct 2021 17:37, wij wrote:
    // numeric_limits<long double>::digits=64.
    //
    typedef long double FType;
    FType x=numeric_limits<FType>::max();
    int iexp;
    int64_t mint;
    x=::frexpl(x,&iexp);
    x=::ldexpl(x,numeric_limits<FType>::digits);
    mint= static_cast<int64_t>(x);>>
    Result (mint) is a negative number, something not right!!!

    Apparently you're trying to obtain the bits of the mantissa of a `long
    double` number, represented as an `int64_t` value.

    A `long double` is in practice either IEEE 754 64-bit, or IEEE 754
    80-bit. In Windows that choice depends on the compiler. With Visual C++
    (and hence probably also Intel) it's 64-bit, same as type `double`,
    while with MinGW g++ (and hence probably also clang) it 80-bit,
    originally the x86-family's math coprocessor's extended format. For
    80-bit IEEE 754 the mantissa part is 64 bits.

    With 64-bits mantissa there is a high chance of setting the sign bit of
    an `int64_t` to 1, resulting in a negative value. I believe that that
    will only /not/ happen for a denormal value, but, I'm tired and might be
    wrong about that. Anyway, instead use unsigned types for bit handling.
    For example, in this case, use `uint64_t`.

    It would be safer and more portable to use FType; there's no portable guarantee that any integer type is large enough to hold the mantissa,
    but FType is.

    How so if FType is just typedef?


    --

    7-77-777
    Evil Sinner!
    to weak you should be meek, and you should brainfuck stronger https://github.com/rofl0r/chaos-pp

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bonita Montero@21:1/5 to All on Sun Oct 3 08:09:56 2021
    So, this should be the most elegant code:

    #pragma once
    #include <limits>
    #include <cstdint>
    #include <cassert>

    struct dbl_parts
    {
    static_assert(std::numeric_limits<double>::is_iec559, "must be standard fp");
    dbl_parts( double d );
    dbl_parts &operator =( double d );
    dbl_parts() = default;
    operator double();
    bool getSign();
    std::uint16_t getBiasedExponent();
    std::int16_t getExponent();
    std::uint64_t getMantissa();
    void setSign( bool sign );
    void setBiasedExponent( uint16_t exp );
    void setExponent( int16_t exp );
    void setMantissa( uint64_t mantissa );
    private:
    static unsigned const
    MANTISSA_BITS = 52;
    using i64 = std::int64_t;
    using ui64 = std::uint64_t;
    static ui64 const
    SIGN_MASK = (ui64)1 << 63,
    EXP_MASK = (ui64)0x7FF << MANTISSA_BITS,
    MANTISSA_MASK = ~-((i64)1 << MANTISSA_BITS),
    MANTISSA_MAX = ((ui64)1 << MANTISSA_BITS) | MANTISSA_MASK;
    using ui16 = std::uint16_t;
    using i16 = std::int16_t;
    static ui16 const
    BEXP_DENORMAL = 0,
    BEXP_BASE = 0x3FF,
    BEXP_MAX = 0x7FF;
    static i16 const
    EXP_MIN = 0 - BEXP_BASE,
    EXP_MAX = BEXP_MAX - BEXP_BASE;
    union
    {
    double value;
    ui64 binary;
    };
    };

    inline
    dbl_parts::dbl_parts( double d ) :
    value( d )
    {
    }

    inline
    dbl_parts &dbl_parts::operator =( double d )
    {
    value = d;
    return *this;
    }

    inline
    dbl_parts::operator double()
    {
    return value;
    }

    inline
    bool dbl_parts::getSign()
    {
    return (i64)binary < 0;
    }

    inline
    std::uint16_t dbl_parts::getBiasedExponent()
    {
    return (ui16)(binary >> MANTISSA_BITS) & BEXP_MAX;
    }

    inline
    int16_t dbl_parts::getExponent()
    {
    return (i16)(getBiasedExponent() - BEXP_BASE);
    }

    inline
    std::uint64_t dbl_parts::getMantissa()
    {
    ui16 bExp = getBiasedExponent();
    ui64 hiBit = (ui64)(bExp && bExp != BEXP_MAX) << MANTISSA_BITS;
    return binary & MANTISSA_MASK | hiBit;
    }

    inline
    void dbl_parts::setSign( bool sign )
    {
    binary = binary & ~SIGN_MASK | (ui64)sign << 63;
    }

    inline
    void dbl_parts::setBiasedExponent( std::uint16_t exp )
    {
    assert(exp <= BEXP_MAX);
    binary = binary & (SIGN_MASK | MANTISSA_MASK) | (ui64)exp << MANTISSA_BITS;
    }

    inline
    void dbl_parts::setExponent( std::int16_t exp )
    {
    exp += BEXP_BASE;
    setBiasedExponent( exp );
    }

    inline
    void dbl_parts::setMantissa( std::uint64_t mantissa )
    {
    #if !defined(NDEBUG)
    ui64 mantissaMax = MANTISSA_MASK | (ui64)(getBiasedExponent() != BEXP_DENORMAL && getBiasedExponent() != BEXP_MAX) << MANTISSA_BITS;
    assert(mantissa <= mantissaMax);
    #endif
    binary = binary & (SIGN_MASK | EXP_MASK) | mantissa & MANTISSA_MASK;
    }

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From wij@21:1/5 to Alf P. Steinbach on Sun Oct 3 00:35:56 2021
    On Sunday, 3 October 2021 at 03:00:58 UTC+8, Alf P. Steinbach wrote:
    On 1 Oct 2021 17:37, wij wrote:
    // numeric_limits<long double>::digits=64.
    //
    typedef long double FType;
    FType x=numeric_limits<FType>::max();
    int iexp;
    int64_t mint;
    x=::frexpl(x,&iexp);
    x=::ldexpl(x,numeric_limits<FType>::digits);
    mint= static_cast<int64_t>(x);

    Result (mint) is a negative number, something not right!!!
    Apparently you're trying to obtain the bits of the mantissa of a `long double` number, represented as an `int64_t` value.

    A `long double` is in practice either IEEE 754 64-bit, or IEEE 754
    80-bit. In Windows that choice depends on the compiler. With Visual C++
    (and hence probably also Intel) it's 64-bit, same as type `double`,
    while with MinGW g++ (and hence probably also clang) it 80-bit,
    originally the x86-family's math coprocessor's extended format. For
    80-bit IEEE 754 the mantissa part is 64 bits.

    With 64-bits mantissa there is a high chance of setting the sign bit of
    an `int64_t` to 1, resulting in a negative value. I believe that that
    will only /not/ happen for a denormal value, but, I'm tired and might be wrong about that. Anyway, instead use unsigned types for bit handling.
    For example, in this case, use `uint64_t`.

    However, instead of the shenanigans with `frexpl` and `ldexpl` I'd just
    use `memcpy`.

    Due to the silliness in gcc regarding the standard's "strict aliasing"
    rule, I'd not use a reinterpretation pointer cast.


    - Alf

    I changed int64_t to uint64_t, my problem is solved, thanks.
    (in the original post, the include file <math.h> should be <cmath>)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bonita Montero@21:1/5 to All on Sun Oct 3 12:19:30 2021
    Am 03.10.2021 um 12:15 schrieb Bart:

    Jesus. And I think this still doesn't do an actual long double!

    long double isn't supported by many compilers for x86-64.
    long double should be avoided when possible because loads
    and stores are slow with long double.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to Bonita Montero on Sun Oct 3 11:15:35 2021
    On 03/10/2021 07:09, Bonita Montero wrote:
    So, this should be the most elegant code:

    #pragma once
    #include <limits>
    #include <cstdint>
    #include <cassert>

    struct dbl_parts
    {
        static_assert(std::numeric_limits<double>::is_iec559, "must be standard fp");
        dbl_parts( double d );
        dbl_parts &operator =( double d );
        dbl_parts() = default;
        operator double();
        bool getSign();
        std::uint16_t getBiasedExponent();
        std::int16_t getExponent();
        std::uint64_t getMantissa();
        void setSign( bool sign );
        void setBiasedExponent( uint16_t exp );
        void setExponent( int16_t exp );
        void setMantissa( uint64_t mantissa );
    private:
        static unsigned const
            MANTISSA_BITS = 52;
        using i64 = std::int64_t;
        using ui64 = std::uint64_t;
        static ui64 const
            SIGN_MASK = (ui64)1 << 63,
            EXP_MASK = (ui64)0x7FF << MANTISSA_BITS,
            MANTISSA_MASK = ~-((i64)1 << MANTISSA_BITS),
            MANTISSA_MAX = ((ui64)1 << MANTISSA_BITS) | MANTISSA_MASK;
        using ui16 = std::uint16_t;
        using i16 = std::int16_t;
        static ui16 const
            BEXP_DENORMAL = 0,
            BEXP_BASE = 0x3FF,
            BEXP_MAX = 0x7FF;
        static i16 const
            EXP_MIN = 0 - BEXP_BASE,
            EXP_MAX = BEXP_MAX - BEXP_BASE;
        union
        {
            double value;
            ui64 binary;
        };
    };

    inline
    dbl_parts::dbl_parts( double d ) :
        value( d )
    {
    }

    inline
    dbl_parts &dbl_parts::operator =( double d )
    {
        value = d;
        return *this;
    }

    inline
    dbl_parts::operator double()
    {
        return value;
    }

    inline
    bool dbl_parts::getSign()
    {
        return (i64)binary < 0;
    }

    inline
    std::uint16_t dbl_parts::getBiasedExponent()
    {
        return (ui16)(binary >> MANTISSA_BITS) & BEXP_MAX;
    }

    inline
    int16_t dbl_parts::getExponent()
    {
        return (i16)(getBiasedExponent() - BEXP_BASE);
    }

    inline
    std::uint64_t dbl_parts::getMantissa()
    {
        ui16 bExp = getBiasedExponent();
        ui64 hiBit = (ui64)(bExp && bExp != BEXP_MAX) << MANTISSA_BITS;
        return binary & MANTISSA_MASK | hiBit;
    }

    inline
    void dbl_parts::setSign( bool sign )
    {
        binary = binary & ~SIGN_MASK | (ui64)sign << 63;
    }

    inline
    void dbl_parts::setBiasedExponent( std::uint16_t exp )
    {
        assert(exp <= BEXP_MAX);
        binary = binary & (SIGN_MASK | MANTISSA_MASK) | (ui64)exp << MANTISSA_BITS;
    }

    inline
    void dbl_parts::setExponent( std::int16_t exp )
    {
        exp += BEXP_BASE;
        setBiasedExponent( exp );
    }

    inline
    void dbl_parts::setMantissa( std::uint64_t mantissa )
    {
    #if !defined(NDEBUG)
        ui64 mantissaMax = MANTISSA_MASK | (ui64)(getBiasedExponent() != BEXP_DENORMAL && getBiasedExponent() != BEXP_MAX) << MANTISSA_BITS;
        assert(mantissa <= mantissaMax);
    #endif
        binary = binary & (SIGN_MASK | EXP_MASK) | mantissa & MANTISSA_MASK; }

    Jesus. And I think this still doesn't do an actual long double!

    If you know you're running on an x86/x64 device (or even an 8088 with
    8087 co-processor!), then this inline code expands a 64-bit double 'x64'
    to its constituent parts:

    fld qword [x64]
    fstp tword [a80] ; sometimes, 'tbyte'

    And for a long double 'x80' known to use 80-bit format:

    fld tword [x80]
    fstp tword [a80]

    The former works because on the x87, all loads expand to an 80-bit
    internal format with no hidden parts.

    'a80' needs to be an instance of a type like this (here assumes
    little-endian memory format, which is typical for anything with x87):

    typedef struct {
    uint64_t mantissa;
    uint16_t sign_and_exponent; // sign is top bit
    } ldformat;

    I don't know how to reliably split those last 16 bits into 15- and 1-bit
    fields using C's bitfields. (I used a different test language.)

    ASM code shown may need adapting to gcc-style assembly.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ben Bacarisse@21:1/5 to wij on Sun Oct 3 15:02:09 2021
    I've not been following the details of the thread but it seems to have
    strayed from the original question (as happens of course).

    wij <wyniijj@gmail.com> writes:

    // numeric_limits<long double>::digits=64.
    //
    typedef long double FType;
    FType x=numeric_limits<FType>::max();
    int iexp;
    int64_t mint;
    x=::frexpl(x,&iexp);
    x=::ldexpl(x,numeric_limits<FType>::digits);
    mint= static_cast<int64_t>(x);

    Result (mint) is a negative number, something not right!!!

    frexp (et. al.) return a signed result with a magnitude in the interval
    [1/2, 1). If you want the 64 most significant digits of the mantissa of
    a long double (it may have many more digits than that) then I'd go for something like this:

    uint_least64_t ms64bits(long double d)
    {
    int exp;
    return (uint_least64_t)std::scalbn(std::fabs(std::frexp(d, &exp)), 64);
    }

    If, as your code sketch suggests, you want all of them, then you are out
    of luck as far as portable code goes because there may not be an integer
    type wide enough.

    But why do you want an integer value? For most mathematical uses the
    result of std::frexp is what you really want.

    --
    Ben.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From red floyd@21:1/5 to Bonita Montero on Sun Oct 3 18:03:54 2021
    On 10/3/21 3:19 AM, Bonita Montero wrote:
    Am 03.10.2021 um 12:15 schrieb Bart:

    Jesus. And I think this still doesn't do an actual long double!

    long double isn't supported by many compilers for x86-64.
    long double should be avoided when possible because loads
    and stores are slow with long double.


    FFS, Bonita, READ THE FRICKIN' SUBJECT LINE!!!

    OP wanted to get the mantissa of long double.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From wij@21:1/5 to Ben Bacarisse on Sun Oct 3 18:46:52 2021
    On Sunday, 3 October 2021 at 22:02:25 UTC+8, Ben Bacarisse wrote:
    I've not been following the details of the thread but it seems to have strayed from the original question (as happens of course).
    wij <wyn...@gmail.com> writes:

    // numeric_limits<long double>::digits=64.
    //
    typedef long double FType;
    FType x=numeric_limits<FType>::max();
    int iexp;
    int64_t mint;
    x=::frexpl(x,&iexp);
    x=::ldexpl(x,numeric_limits<FType>::digits);
    mint= static_cast<int64_t>(x);

    Result (mint) is a negative number, something not right!!!
    frexp (et. al.) return a signed result with a magnitude in the interval
    [1/2, 1). If you want the 64 most significant digits of the mantissa of
    a long double (it may have many more digits than that) then I'd go for something like this:

    uint_least64_t ms64bits(long double d)
    {
    int exp;
    return (uint_least64_t)std::scalbn(std::fabs(std::frexp(d, &exp)), 64);
    }

    If, as your code sketch suggests, you want all of them, then you are out
    of luck as far as portable code goes because there may not be an integer
    type wide enough.

    But why do you want an integer value? For most mathematical uses the
    result of std::frexp is what you really want.

    --
    Ben.

    // --- Here is the real codes
    explicit VLFloat(long double x) try {
    typedef long double FType;
    typedef uint64_t UIntMant;
    WY_ENSURE(Limits<FType>::Bits<=CHAR_BIT*sizeof(UIntMant));
    if(Wy::isfinite(x)==false) {
    throw Errno(EINVAL);
    }
    Errno r;
    int iexp;
    if(x<0) {
    x=-x;
    m_neg=true;
    } else {
    m_neg=false;
    }
    x=Wy::frexp(x,&iexp);
    x=Wy::ldexp(x,Limits<FType>::Bits);
    m_exp=iexp-Limits<FType>::Bits;
    if((r=m_mant.set_num(MantType::itv(static_cast<UIntMant>(x))))!=Ok) {
    throw r;
    }
    if((r=_finalize())!=Ok) {
    throw r;
    }
    }
    catch(const Errno& e) {
    WY_THROW( Reply(e) );
    };
    --
    Most of the time while asking questions in comp.lang.c/c++, I need to rewrite a bit.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to Branimir Maksimovic on Sun Oct 3 23:42:25 2021
    On 10/2/21 8:47 PM, Branimir Maksimovic wrote:
    On 2021-10-02, James Kuyper <jameskuyper@alumni.caltech.edu> wrote:
    On 10/2/21 2:59 PM, Branimir Maksimovic wrote:


    On 02.10.2021., at 20:51, James Kuyper
    <jameskuyper@alumni.caltech.edu
    <mailto:jameskuyper@alumni.caltech.edu>> wrote:

    int main(void)
    {
       typedef long double FType;
       FType max= std::numeric_limits<FType>::max();
       FType large = 0xA.BCDEF0123456789p+16380L;
       FType middling = 0xABCDEF01.23456789p0L;
       long long maxll = max;
       long long largell = large;
       long long middlingll = middling;

       std::cout << std::fixed << "max: " << max << std::endl;
       std::cout << "large: " << large << std::endl;
       std::cout << "middling: " << middling << std::endl;

       std::cout << "maxll: " << maxll << std::endl;
       std::cout << "largell: " << largell << std::endl;
       std::cout << "middlingll: " << middlingll << std::endl;

       std::cout << std::hexfloat << std::showbase << std::showpoint << >>>>        std::hex << "max: " << max << std::endl;
       std::cout << "large: " << large << std::endl;
       std::cout << "middling: " << middling << std::endl;

       std::cout << "maxll: " << maxll << std::endl;
       std::cout << "largell: " << largell << std::endl;
       std::cout << "middlingll: " << middlingll << std::endl;
    }
    mantissa.cpp:7:18: warning: magnitude of floating-point constant too
    large for type 'long double'; maximum is 1.7976931348623157E+308
    [-Wliteral-range]
    Sorry your program is not correct..

    The value of "large" was chosen to be almost as large as "max" on my
    machine. It's apparently larger than LDBL_MAX on your system. A more
    portable initializer would be

        FType large = 0x0.ABCDEF0123456789p0L * max;

    Depending upon the value of LDBL_EPSILON on the target implementation,
    that definition might result in the mantissa of "large" having fewer
    significant digits than it has on mine, but that's not particularly
    important.

    Now outputs:
    bmaxa@Branimirs-Air projects % ./a.out
    max: 17976931348623157081452742373170435679807056752584499659891747680315726078002853876058955863276687817154045895351438246423432132688946418276846754670353751698604991057655128207624549009038932894407586850845513394230458323690322294816580855933212334
    8274797826204144723168738177180919299881250404026184124858368.000000
    large: 120645172288001372126619919515947355653853135095820093742269387851763173210613194516902557021349374744036403756647462602101944733127725809392434319981526284828181273773403605513307431121904981243948320057805774787281290926848565000291282225047507
    294705767371139696722108291516984908752371556782562287095382016.000000
    middling: 2882400001.137778
    maxll: 9223372036854775807
    largell: 9223372036854775807
    middlingll: 2882400001
    max: 0x1.fffffffffffffp+1023
    large: 0x1.579bde02468acp+1023
    middling: 0x1.579bde02468adp+31
    maxll: 0x7fffffffffffffff
    largell: 0x7fffffffffffffff
    middlingll: 0xabcdef01

    Your system has a different value for LDBL_MAX than mine, which is
    perfectly normal. With that difference in mind, all of those results are consistent with what I said. None of the long long values are the same
    as the mantissa of the corresponding float value, and only middlingll is
    the same as the whole part of corresponding float value.

    Do you now concede that your approach is not guaranteed to result in a
    long long value containing the mantissa?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to Branimir Maksimovic on Sun Oct 3 23:31:57 2021
    On 10/2/21 8:45 PM, Branimir Maksimovic wrote:
    On 2021-10-02, James Kuyper <jameskuyper@alumni.caltech.edu> wrote:
    On 10/2/21 3:00 PM, Alf P. Steinbach wrote:
    On 1 Oct 2021 17:37, wij wrote:
    // numeric_limits<long double>::digits=64.
    //
    typedef long double FType;
    FType x=numeric_limits<FType>::max();
    int iexp;
    int64_t mint;
    x=::frexpl(x,&iexp);
    x=::ldexpl(x,numeric_limits<FType>::digits);
    mint= static_cast<int64_t>(x);>>
    Result (mint) is a negative number, something not right!!!

    Apparently you're trying to obtain the bits of the mantissa of a `long
    double` number, represented as an `int64_t` value.

    A `long double` is in practice either IEEE 754 64-bit, or IEEE 754
    80-bit. In Windows that choice depends on the compiler. With Visual C++
    (and hence probably also Intel) it's 64-bit, same as type `double`,
    while with MinGW g++ (and hence probably also clang) it 80-bit,
    originally the x86-family's math coprocessor's extended format. For
    80-bit IEEE 754 the mantissa part is 64 bits.

    With 64-bits mantissa there is a high chance of setting the sign bit of
    an `int64_t` to 1, resulting in a negative value. I believe that that
    will only /not/ happen for a denormal value, but, I'm tired and might be >>> wrong about that. Anyway, instead use unsigned types for bit handling.
    For example, in this case, use `uint64_t`.

    It would be safer and more portable to use FType; there's no portable
    guarantee that any integer type is large enough to hold the mantissa,
    but FType is.

    How so if FType is just typedef?

    A typedef is just a synonym for a type, it has exactly the same
    characteristics as the type for which it is a synonym. What I said is
    true because FType is a synonym for long double, the same type as x
    itself. What I was asserting is that for any given floating point
    object, the mantissa or significand stored in that object has a value
    that is guaranteed to be representable in the same floating point type
    as the object itself. There's no guarantee that any integer type is big
    enough to represent it.

    I've since thought this over, and checked carefully, and that's not
    quite true - though it's true enough for most practical purposes. Let me explain.

    The C++ standard defines <cfloat>, and defines it's contents mostly by cross-referencing the C standard's definition of <float.h>. Section
    5.2.4.2.2 the C standard defines a parameterized model for floating
    point representations, that is used as a basis for describing the
    meaning of the macros defined in <float.h>, so that model is inherited
    by C++.

    I will need to refer to the following parameters of that model:
    b - base or radix of exponent representation (an integer > 1)
    e - exponent (an integer between a minimum e_min and a maximum e_max )
    p - precision (the number of base-b digits in the significand)

    Note that b, e_min, e_max, and p are constants for any specific floating
    point type.

    In terms of that model, the value of the significand of a floating point
    value x, interpreted as an integer, can be represented in the same
    floating point type by a number with exactly the same significand, and e
    = p.

    The key issue is whether such a representation is allowed, and it turns
    out that there can be floating point representations which fit the C
    standard's model, for which e_max < p, preventing some signficands from
    being representable in such a type.

    The macro LDBL_MAX (corresponding to std::numeric_limits<long
    double>::max()) is defined as expanding to the value of
    (1 - b^(-p))*b^e_max, and is required to be at least 1e37. If, for
    example, e_max == p-1 and b=2, then this means that for such a type, p
    must be at least 124.

    Every floating point format I'm familiar with has an e_max value much
    larger than p, so I think, as a practical matter, that it's safe to
    assume that signficands can be represented in the same floating point
    type, but strictly speaking, it's not guaranteed.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to Alf P. Steinbach on Sun Oct 3 23:43:13 2021
    On 10/2/21 3:23 PM, Alf P. Steinbach wrote:
    On 2 Oct 2021 21:12, James Kuyper wrote:
    ...
    It would be safer and more portable to use FType; there's no portable
    guarantee that any integer type is large enough to hold the mantissa,
    but FType is.

    I believe you intended to write `uintptr_t`, not `FType`.

    No, uintptr_t is not guaranteed to be able to hold the mantissa; nor is
    any other integer type. FType is guaranteed to be able to hold it.

    However, instead of the shenanigans with `frexpl` and `ldexpl` I'd just
    use `memcpy`.

    The advantage of the code as written is that (if you change mint to have
    FType) it will give the correct result even if your assumption about
    IEEE 754 is false; that's not the case with memcpy().

    Uhm, I'd rather assert IEEE 754 representation
    (numeric_limits::is_iec559). Dealing with the bits of just about any representation seems to me a hopelessly daunting task. :-o

    Well, that's the purpose of frexpl() and ldexpl() - they save you from
    having to worry about the bits.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Branimir Maksimovic@21:1/5 to James Kuyper on Mon Oct 4 04:35:25 2021
    On 2021-10-04, James Kuyper <jameskuyper@alumni.caltech.edu> wrote:

    Do you now concede that your approach is not guaranteed to result in a
    long long value containing the mantissa?
    of course, you convinced me.

    --

    7-77-777
    Evil Sinner!
    to weak you should be meek, and you should brainfuck stronger https://github.com/rofl0r/chaos-pp

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Branimir Maksimovic@21:1/5 to James Kuyper on Mon Oct 4 04:34:23 2021
    On 2021-10-04, James Kuyper <jameskuyper@alumni.caltech.edu> wrote:
    Note that b, e_min, e_max, and p are constants for any specific floating point type.

    In terms of that model, the value of the significand of a floating point value x, interpreted as an integer, can be represented in the same
    floating point type by a number with exactly the same significand, and e
    = p.

    The key issue is whether such a representation is allowed, and it turns
    out that there can be floating point representations which fit the C standard's model, for which e_max < p, preventing some signficands from
    being representable in such a type.

    The macro LDBL_MAX (corresponding to std::numeric_limits<long
    double>::max()) is defined as expanding to the value of
    (1 - b^(-p))*b^e_max, and is required to be at least 1e37. If, for
    example, e_max == p-1 and b=2, then this means that for such a type, p
    must be at least 124.

    Every floating point format I'm familiar with has an e_max value much
    larger than p, so I think, as a practical matter, that it's safe to
    assume that signficands can be represented in the same floating point
    type, but strictly speaking, it's not guaranteed.
    Great!!!
    So intead of int we use float type and truncate?

    --

    7-77-777
    Evil Sinner!
    to weak you should be meek, and you should brainfuck stronger ettps://github.com/rofl0r/chaos-pp

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Bonita Montero on Mon Oct 4 09:52:04 2021
    On 03/10/2021 12:19, Bonita Montero wrote:
    Am 03.10.2021 um 12:15 schrieb Bart:

    Jesus. And I think this still doesn't do an actual long double!

    long double isn't supported by many compilers for x86-64.
    long double should be avoided when possible because loads
    and stores are slow with long double.


    "long double" is supported by any C++ or C compiler, for any target,
    that tries to come close to any current standards compliance.

    What you probably mean is that on some targets, "long double" is the
    same size as "double". That's true for most 32-bit (and smaller)
    targets. Most 64-bit targets support larger "long double".

    As happens so often, there is /one/ major exception to the common
    practices used by (AFAICS) every other OS, every other processor, every
    other compiler manufacturer - on Windows, and with MSVC, "long double"
    is 64-bit.

    "long double" should not be used where "double" will do, because it can
    be a great deal slower on many platforms (the load and saves are
    irrelevant). You also have to question whether "long double" does what
    you want, on any given target. On smaller targets (or more limited
    compilers, like MSVC), it gives you no benefits in accuracy or range
    compared to "double". On some, such as x86-64 with decent tools, it
    generally gives you 80-bit types. On others - almost any other 64-bit
    system - it gives you 128-bit quad double, but it is likely to be
    implemented in software rather than hardware.

    However, it /is/ a valid type on all (reasonable) C and C++ systems, and
    it is a perfectly reasonable question to ask how to handle it. Some
    aspects can be handled in a portable manner, others require implementation-dependent details.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Juha Nieminen@21:1/5 to David Brown on Mon Oct 4 09:59:15 2021
    David Brown <david.brown@hesbynett.no> wrote:
    What you probably mean is that on some targets, "long double" is the
    same size as "double". That's true for most 32-bit (and smaller)
    targets. Most 64-bit targets support larger "long double".

    That might perhaps be true for non-x86 32-bit targets. However, in x86 architectures long double is most typically 80-bit, and has been so
    for pretty much as long as the x86 (and its x87 math coprocessor)
    has existed, ie. all the way from the 8086 (which was a 16-bit
    processor), especially if you had the 8087 FPU coprocessor.

    The reason why long double is 80-bit in x86 architectures is that
    that's the native floating point format used by the x87 FPU.
    (While you can load 32-bit floats and 64-bit doubles, internally
    the FPU uses 80-bit floating point. And you can load and store
    full 80-bit floating point values, of course.)

    However, what has happened since then is the introduction of SSE
    (and later AVX), which is much simpler to use and more efficient
    than the FPU, and is a direct replacement of the FPU (well, with
    the exception of trigonometric functions, which SSE/AVX for some
    reason do not support natively). However, SSE/AVX only supports
    64-bit floating point, not 80-bit, which is why 80-bit floating
    point has been "soft-deprecated" for like two decades now.

    You can still use 80-bit long doubles with compilers like gcc
    and clang, even when targeting the latest x86-64 CPUs. The compilers
    will generate FPU opcodes to handle them (and, most often than not,
    they will be less efficient. Also, if I understand correctly, using
    the FPU and SSE at the same time is not very efficient because they
    share logic circuitry and interfere with each other. In other words,
    the SSE unit needs to wait for the FPU logic to do its thing, which
    wastes clock cycles. I might be wrong in this, though.)

    80-bit long doubles are also considered justifiably deprecated
    because they don't really all that much precision. Sure, they
    have an 11 bits larger mantissa, and a slightly bigger range,
    but all in all that's not a huge advantage in most calculations.
    If you calculations are hitting the precision limits of double,
    chances are that they are going to hit the precision limits of
    long double as well. There's a relatively small range where
    long double beats double in practical use.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bonita Montero@21:1/5 to All on Mon Oct 4 13:50:14 2021
    Am 04.10.2021 um 09:52 schrieb David Brown:

    "long double" is supported by any C++ or C compiler, for any target,
    that tries to come close to any current standards compliance.

    Most compilers map long double to IEEE-754 double precision and not
    extended precision. Even with Intel C++ you must supply a compiler
    -switch that you have double as a extended precision.

    What you probably mean is that on some targets, "long double" is the
    same size as "double". That's true for most 32-bit (and smaller)
    targets. Most 64-bit targets support larger "long double".

    No, most don't.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to David Brown on Mon Oct 4 14:06:41 2021
    On 04/10/2021 08:52, David Brown wrote:
    On 03/10/2021 12:19, Bonita Montero wrote:
    Am 03.10.2021 um 12:15 schrieb Bart:

    Jesus. And I think this still doesn't do an actual long double!

    long double isn't supported by many compilers for x86-64.
    long double should be avoided when possible because loads
    and stores are slow with long double.


    "long double" is supported by any C++ or C compiler, for any target,
    that tries to come close to any current standards compliance.

    What you probably mean is that on some targets, "long double" is the
    same size as "double". That's true for most 32-bit (and smaller)
    targets. Most 64-bit targets support larger "long double".

    Any code running on x86 can choose to use x87 instructions for floating
    point.

    Then, even calculations involving 64-bit variables, will use 80-bit intermediate results.


    As happens so often, there is /one/ major exception to the common
    practices used by (AFAICS) every other OS, every other processor, every
    other compiler manufacturer - on Windows, and with MSVC, "long double"
    is 64-bit.


    Here's quick survey of Windows C compilers:

    Compiler sizeof(long double)

    MSCV 8 bytes
    gcc 16
    clang 8
    DMC 10
    lccwin 16
    tcc 8
    bcc 8

    So, some compilers do manage to use a wider long double type, even on
    Windows, showing that the choice is nothing do with the OS.

    And at least one 'big' compiler that is not MSVC also uses a 64-bit type
    for long double.

    You just like having a bash at Windows (it doesn't stop the use of
    float80), and at MSVC (Clang doesn't support float80 either).

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bonita Montero@21:1/5 to All on Mon Oct 4 16:12:51 2021
    Am 04.10.2021 um 15:06 schrieb Bart:

       DMC           10
       lccwin        16


    Irrelevant.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to David Brown on Mon Oct 4 14:37:45 2021
    David Brown <david.brown@hesbynett.no> writes:
    On 03/10/2021 12:19, Bonita Montero wrote:


    "long double" should not be used where "double" will do, because it can
    be a great deal slower on many platforms (the load and saves are
    irrelevant). You also have to question whether "long double" does what
    you want, on any given target. On smaller targets (or more limited >compilers, like MSVC), it gives you no benefits in accuracy or range
    compared to "double". On some, such as x86-64 with decent tools, it >generally gives you 80-bit types. On others - almost any other 64-bit
    system - it gives you 128-bit quad double, but it is likely to be
    implemented in software rather than hardware.


    ARMv8 has 128-bit floating point, in hardware.

    FWIW, it also has 512 to 2048 bit floating point, in hardware, when
    the SVE extension is implemented.

    From the ARMv8 ARM (Architecture Reference Manual):


    The architecture also supports the following floating-point data types:
    Half-precision, see Half-precision floating-point formats
    on page A1-44 for details.
    Single-precision, see Single-precision floating-point format
    on page A1-46 for details.
    Double-precision, see Double-precision floating-point format
    on page A1-47 for details.
    BFloat16, see BFloat16 floating-point format on page A1-48
    for details.

    It also supports:
    Fixed-point interpretation of words and doublewords. See
    Fixed-point format on page A1-50.
    Vectors, where a register holds multiple elements, each of
    the same data type. See Vector formats on
    page A1-41 for details.

    The Armv8 architecture provides two register files:
    A general-purpose register file.
    A SIMD&FP register file.


    In each of these, the possible register widths depend on the Execution state. In AArch64 state:
    A general-purpose register file contains thirty-two 64-bit registers:
    -- Many instructions can access these registers as 64-bit
    registers or as 32-bit registers, using only the
    bottom 32 bits.
    A SIMD&FP register file contains thirty-two 128-bit registers:
    -- The quadword integer data types only apply to the SIMD&FP
    register file.
    -- The floating-point data types only apply to the SIMD&FP
    register file.
    -- While the AArch64 vector registers support 128-bit vectors,
    the effective vector length can be 64-bits
    or 128-bits depending on the A64 instruction encoding used,
    see Instruction Mnemonics on page C1-195.

    If the SVE extension is implemented, an additional register file of 32
    512-bit to 2048-bit registers (implementation choice) is available).

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bonita Montero@21:1/5 to All on Mon Oct 4 16:53:13 2021
    Am 04.10.2021 um 16:37 schrieb Scott Lurndal:

    ARMv8 has 128-bit floating point, in hardware.
    FWIW, it also has 512 to 2048 bit floating point,
    in hardware, when the SVE extension is implemented.

    I bet that ther even isn't an implementation for 128 bit fp,
    but just a specification.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to Branimir Maksimovic on Mon Oct 4 11:30:42 2021
    On 10/4/21 12:34 AM, Branimir Maksimovic wrote:
    On 2021-10-04, James Kuyper <jameskuyper@alumni.caltech.edu> wrote:
    ...
    In terms of that model, the value of the significand of a floating point
    value x, interpreted as an integer, can be represented in the same
    floating point type by a number with exactly the same significand, and e
    = p.

    The key issue is whether such a representation is allowed, and it turns
    out that there can be floating point representations which fit the C
    standard's model, for which e_max < p, preventing some signficands from
    being representable in such a type.

    The macro LDBL_MAX (corresponding to std::numeric_limits<long
    double>::max()) is defined as expanding to the value of
    (1 - b^(-p))*b^e_max, and is required to be at least 1e37. If, for
    example, e_max == p-1 and b=2, then this means that for such a type, p
    must be at least 124.

    Every floating point format I'm familiar with has an e_max value much
    larger than p, so I think, as a practical matter, that it's safe to
    assume that signficands can be represented in the same floating point
    type, but strictly speaking, it's not guaranteed.
    Great!!!
    So intead of int we use float type and truncate?

    You're half right. If you want the mantissa (== significand), you should
    not truncate - that might lose you the parts of the significand that
    represent the fractional part of the number. The OP had it right at the
    second to last step in his original code:

    x = std::ldexp(x, numeric_limits<FType>::digits);

    At this point, x already contains the significand; there's no further
    need to convert it to an integer type - in fact, in most contexts you'd
    want it in floating point format for later steps in the processing.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Branimir Maksimovic@21:1/5 to Bonita Montero on Mon Oct 4 16:15:39 2021
    On 2021-10-04, Bonita Montero <Bonita.Montero@gmail.com> wrote:
    Am 04.10.2021 um 15:06 schrieb Bart:

       DMC           10
       lccwin        16


    Irrelevant.
    Irrelevant to whom?

    --

    7-77-777
    Evil Sinner!
    to weak you should be meek, and you should brainfuck stronger https://github.com/rofl0r/chaos-pp

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Branimir Maksimovic@21:1/5 to James Kuyper on Mon Oct 4 16:19:24 2021
    On 2021-10-04, James Kuyper <jameskuyper@alumni.caltech.edu> wrote:

    You're half right. If you want the mantissa (== significand), you should
    not truncate - that might lose you the parts of the significand that represent the fractional part of the number. The OP had it right at the second to last step in his original code:

    x = std::ldexp(x, numeric_limits<FType>::digits);

    At this point, x already contains the significand; there's no further
    need to convert it to an integer type - in fact, in most contexts you'd
    want it in floating point format for later steps in the processing.
    Thanks for explanaition.

    Greets, branimir

    --

    7-77-777
    Evil Sinner!
    to weak you should be meek, and you should brainfuck stronger https://github.com/rofl0r/chaos-pp

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Scott Lurndal on Mon Oct 4 17:08:09 2021
    scott@slp53.sl.home (Scott Lurndal) writes:
    David Brown <david.brown@hesbynett.no> writes:
    On 03/10/2021 12:19, Bonita Montero wrote:


    "long double" should not be used where "double" will do, because it can
    be a great deal slower on many platforms (the load and saves are >>irrelevant). You also have to question whether "long double" does what
    you want, on any given target. On smaller targets (or more limited >>compilers, like MSVC), it gives you no benefits in accuracy or range >>compared to "double". On some, such as x86-64 with decent tools, it >>generally gives you 80-bit types. On others - almost any other 64-bit >>system - it gives you 128-bit quad double, but it is likely to be >>implemented in software rather than hardware.


    ARMv8 has 128-bit floating point, in hardware.
    ^ registers

    It does not support 128-bit float point types.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Branimir Maksimovic@21:1/5 to Bart on Mon Oct 4 16:15:12 2021
    On 2021-10-04, Bart <bc@freeuk.com> wrote:

    Any code running on x86 can choose to use x87 instructions for floating point.

    Only in assembler...




    --

    7-77-777
    Evil Sinner!
    to weak you should be meek, and you should brainfuck stronger https://github.com/rofl0r/chaos-pp

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Bonita Montero on Mon Oct 4 20:04:18 2021
    On 04/10/2021 13:50, Bonita Montero wrote:
    Am 04.10.2021 um 09:52 schrieb David Brown:

    "long double" is supported by any C++ or C compiler, for any target,
    that tries to come close to any current standards compliance.

    Most compilers map long double to IEEE-754 double precision and not
    extended precision. Even with Intel C++ you must supply a compiler
    -switch that you have double as a extended precision.

    No, you don't.


    What you probably mean is that on some targets, "long double" is the
    same size as "double".  That's true for most 32-bit (and smaller)
    targets.  Most 64-bit targets support larger "long double".

    No, most don't.


    Yes, they do.

    Again, you are confusing "Windows" with "everything".

    MS, for reasons known only to them, seem to have decided that "long
    double" should be 64-bit in the Windows ABI (noting that there never was
    a real ABI for 32-bit Windows). So Intel's compiler /on windows/ will
    use 64-bit "long double" by default. It uses 80-bit "long double" on
    other x86-64 targets (they are actually 16 bytes in size, for alignment purposes, but 80 bits of data).

    MSVC for ARM has 64-bit "long doubles" even on 64-bit ARM, other 64-bit
    ARM targets have 128-bit (I don't know off-hand if they are IEEE quad precision). For RISC-V, even 32-bit targets have 128-bit "long double".

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to Scott Lurndal on Mon Oct 4 20:22:57 2021
    On 04/10/2021 18:08, Scott Lurndal wrote:
    scott@slp53.sl.home (Scott Lurndal) writes:
    David Brown <david.brown@hesbynett.no> writes:
    On 03/10/2021 12:19, Bonita Montero wrote:


    "long double" should not be used where "double" will do, because it can
    be a great deal slower on many platforms (the load and saves are
    irrelevant). You also have to question whether "long double" does what
    you want, on any given target. On smaller targets (or more limited
    compilers, like MSVC), it gives you no benefits in accuracy or range
    compared to "double". On some, such as x86-64 with decent tools, it
    generally gives you 80-bit types. On others - almost any other 64-bit
    system - it gives you 128-bit quad double, but it is likely to be
    implemented in software rather than hardware.


    ARMv8 has 128-bit floating point, in hardware.
    ^ registers

    It does not support 128-bit float point types.


    So it doesn't support float512 to float2048 in hardware? I thought that
    sounded far-fetched.

    But if it's just a matter of registers of 128+ bits (which can store a
    vector of smaller float types), then that's old hat with x86/x64.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bonita Montero@21:1/5 to All on Tue Oct 5 07:12:56 2021
    Am 04.10.2021 um 20:04 schrieb David Brown:

    MSVC for ARM has 64-bit "long doubles" even on 64-bit ARM, other 64-bit
    ARM targets have 128-bit (I don't know off-hand if they are IEEE quad precision). For RISC-V, even 32-bit targets have 128-bit "long double".

    There isn't any ARM-implementation with 128 bit FP.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Juha Nieminen@21:1/5 to Bart on Tue Oct 5 05:19:19 2021
    Bart <bc@freeuk.com> wrote:
    Here's quick survey of Windows C compilers:

    Compiler sizeof(long double)

    MSCV 8 bytes
    gcc 16
    clang 8
    DMC 10
    lccwin 16
    tcc 8
    bcc 8

    Note that sizeof() doesn't tell how large the floating point number is,
    only how much storage space the compiler is reserving for it. Some
    compilers may well over-reserve space for 80-bit floating point, for
    alignment reasons (the extra bytes will be unused).

    sizeof() is telling only if it gives less than 10 for long double.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Branimir Maksimovic on Tue Oct 5 09:48:38 2021
    On 04/10/2021 18:15, Branimir Maksimovic wrote:
    On 2021-10-04, Bart <bc@freeuk.com> wrote:

    Any code running on x86 can choose to use x87 instructions for floating
    point.

    Only in assembler...


    Or with a good compiler.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Bonita Montero on Tue Oct 5 09:47:59 2021
    On 05/10/2021 07:12, Bonita Montero wrote:
    Am 04.10.2021 um 20:04 schrieb David Brown:

    MSVC for ARM has 64-bit "long doubles" even on 64-bit ARM, other 64-bit
    ARM targets have 128-bit (I don't know off-hand if they are IEEE quad
    precision).  For RISC-V, even 32-bit targets have 128-bit "long double".

    There isn't any ARM-implementation with 128 bit FP.


    And you know that because ... what? Because you are confusing hardware floating point with floating point in general?

    There are very few /hardware/ implementations of quad precision floating
    point - I think perhaps Power is the only architecture that actually has
    it in practice. (Some architectures, such as SPARC and RISC-V, have
    defined them in the architecture but have no physical devices supporting
    them.)

    But /software/ implementations of quad precision floating point are not
    hard to find. And a lot of toolchains support them - just as lots of toolchains have software support for other kinds of floating point or
    integer arithmetic that are part of C or C++, but do not have hardware implementations on a given target.

    And yes, we all know that software floating point is usually a lot
    slower than hardware. People don't use 128-bit floating point for speed
    - they use it because they need the range or precision, and speed is a secondary concern.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Juha Nieminen on Tue Oct 5 10:00:40 2021
    On 05/10/2021 07:19, Juha Nieminen wrote:
    Bart <bc@freeuk.com> wrote:
    Here's quick survey of Windows C compilers:

    Compiler sizeof(long double)

    MSCV 8 bytes
    gcc 16
    clang 8
    DMC 10
    lccwin 16
    tcc 8
    bcc 8

    Note that sizeof() doesn't tell how large the floating point number is,
    only how much storage space the compiler is reserving for it. Some
    compilers may well over-reserve space for 80-bit floating point, for alignment reasons (the extra bytes will be unused).

    sizeof() is telling only if it gives less than 10 for long double.


    Yes, that is an important distinction - especially in the x86 world
    where different sizes are common. "long double" is typically 80-bit
    floating point on x86 (except MSVC and weaker tools), but for alignment purposes it is often stored in 16-byte blocks (on 64-bit) or 12-byte
    blocks (on 32-bit). On other targets (or gcc for x86 with particular
    flags), "long double" is often quad precision, almost always implemented
    in software.

    A useful value to look at is "LDBL_DIG" in <float.h>. For 32-bit IEEE
    floats, the number of digits is 6. For 64-bit, it is 15. For 80-bit,
    it is 18. For 128-bit, it is 33.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Branimir Maksimovic@21:1/5 to Bonita Montero on Tue Oct 5 10:19:04 2021
    On 2021-10-05, Bonita Montero <Bonita.Montero@gmail.com> wrote:
    Am 04.10.2021 um 20:04 schrieb David Brown:

    MSVC for ARM has 64-bit "long doubles" even on 64-bit ARM, other 64-bit
    ARM targets have 128-bit (I don't know off-hand if they are IEEE quad
    precision). For RISC-V, even 32-bit targets have 128-bit "long double".

    There isn't any ARM-implementation with 128 bit FP.

    not on Apple, as well...

    --

    7-77-777
    Evil Sinner!
    to weak you should be meek, and you should brainfuck stronger https://github.com/rofl0r/chaos-pp

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bonita Montero@21:1/5 to All on Tue Oct 5 16:47:40 2021
    Am 05.10.2021 um 07:19 schrieb Juha Nieminen:
    Bart <bc@freeuk.com> wrote:
    Here's quick survey of Windows C compilers:

    Compiler sizeof(long double)

    MSCV 8 bytes
    gcc 16
    clang 8
    DMC 10
    lccwin 16
    tcc 8
    bcc 8

    Note that sizeof() doesn't tell how large the floating point number is,
    only how much storage space the compiler is reserving for it. Some
    compilers may well over-reserve space for 80-bit floating point, for alignment reasons (the extra bytes will be unused).

    If you have a) an x86-Platform and b) sizeof(long double)
    8 then the bits stored inside the long double are 80.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bonita Montero@21:1/5 to All on Tue Oct 5 16:46:01 2021
    Am 05.10.2021 um 09:47 schrieb David Brown:

    There isn't any ARM-implementation with 128 bit FP.

    And you know that because ... what? Because you are confusing hardware floating point with floating point in general?

    There isn't even an ISA-spec. Its just an ABI.

    There are very few /hardware/ implementations of quad precision floating point - I think perhaps Power is the only architecture that actually has
    it in practice. (Some architectures, such as SPARC and RISC-V, have
    defined them in the architecture but have no physical devices supporting them.)

    https://en.wikipedia.org/wiki/Quadruple-precision_floating-point_format

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Keith Thompson@21:1/5 to David Brown on Tue Oct 5 09:04:21 2021
    David Brown <david.brown@hesbynett.no> writes:
    On 05/10/2021 07:12, Bonita Montero wrote:
    Am 04.10.2021 um 20:04 schrieb David Brown:

    MSVC for ARM has 64-bit "long doubles" even on 64-bit ARM, other 64-bit
    ARM targets have 128-bit (I don't know off-hand if they are IEEE quad
    precision).  For RISC-V, even 32-bit targets have 128-bit "long double". >>
    There isn't any ARM-implementation with 128 bit FP.

    And you know that because ... what? Because you are confusing hardware floating point with floating point in general?

    $ uname -m
    aarch64
    $ cat c.c
    #include <stdio.h>
    #include <limits.h>
    #include <float.h>

    int main(void) {
    printf("sizeof (long double) = %zu (%zu bits), LDBL_DIG = %d\n",
    sizeof (long double),
    CHAR_BIT * sizeof (long double),
    LDBL_DIG);
    }
    $ gcc c.c -o c && ./c
    sizeof (long double) = 16 (128 bits), LDBL_DIG = 33
    $

    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    Working, but not speaking, for Philips
    void Void(void) { Void(); } /* The recursive call of the void */

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bonita Montero@21:1/5 to All on Tue Oct 5 19:13:15 2021
    Am 05.10.2021 um 19:04 schrieb David Brown:
    On 05/10/2021 16:46, Bonita Montero wrote:
    Am 05.10.2021 um 09:47 schrieb David Brown:

    There isn't any ARM-implementation with 128 bit FP.

    And you know that because ... what?  Because you are confusing hardware >>> floating point with floating point in general?

    There isn't even an ISA-spec. Its just an ABI.

    And ... so what? For all your effort trying to move the goalposts,
    you are still wrong - "long double" is supported, ...

    But not on the ISA-level. So it's all up to the compiler and runtime.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bonita Montero@21:1/5 to All on Tue Oct 5 19:14:14 2021
    Am 05.10.2021 um 18:04 schrieb Keith Thompson:
    David Brown <david.brown@hesbynett.no> writes:
    On 05/10/2021 07:12, Bonita Montero wrote:
    Am 04.10.2021 um 20:04 schrieb David Brown:

    MSVC for ARM has 64-bit "long doubles" even on 64-bit ARM, other 64-bit >>>> ARM targets have 128-bit (I don't know off-hand if they are IEEE quad
    precision).  For RISC-V, even 32-bit targets have 128-bit "long double". >>>
    There isn't any ARM-implementation with 128 bit FP.

    And you know that because ... what? Because you are confusing hardware
    floating point with floating point in general?

    $ uname -m
    aarch64
    $ cat c.c
    #include <stdio.h>
    #include <limits.h>
    #include <float.h>

    int main(void) {
    printf("sizeof (long double) = %zu (%zu bits), LDBL_DIG = %d\n",
    sizeof (long double),
    CHAR_BIT * sizeof (long double),
    LDBL_DIG);
    }
    $ gcc c.c -o c && ./c
    sizeof (long double) = 16 (128 bits), LDBL_DIG = 33
    $

    That's pure software - your CPU doesn't natively support 128 bit FP.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Bonita Montero on Tue Oct 5 19:04:55 2021
    On 05/10/2021 16:46, Bonita Montero wrote:
    Am 05.10.2021 um 09:47 schrieb David Brown:

    There isn't any ARM-implementation with 128 bit FP.

    And you know that because ... what?  Because you are confusing hardware
    floating point with floating point in general?

    There isn't even an ISA-spec. Its just an ABI.

    And ... so what? For all your effort trying to move the goalposts, you
    are still wrong - "long double" is supported, and on all larger systems
    with decent compilers, it is greater range and precision than "double".
    It's that simple.


    There are very few /hardware/ implementations of quad precision floating
    point - I think perhaps Power is the only architecture that actually has
    it in practice.  (Some architectures, such as SPARC and RISC-V, have
    defined them in the architecture but have no physical devices supporting
    them.)

    https://en.wikipedia.org/wiki/Quadruple-precision_floating-point_format

    Yes, I have read that. Have you? Did you notice where it contradicted
    your claims?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to Bonita Montero on Tue Oct 5 19:21:16 2021
    On 05/10/2021 18:14, Bonita Montero wrote:
    Am 05.10.2021 um 18:04 schrieb Keith Thompson:
    David Brown <david.brown@hesbynett.no> writes:
    On 05/10/2021 07:12, Bonita Montero wrote:
    Am 04.10.2021 um 20:04 schrieb David Brown:

    MSVC for ARM has 64-bit "long doubles" even on 64-bit ARM, other
    64-bit
    ARM targets have 128-bit (I don't know off-hand if they are IEEE quad >>>>> precision).  For RISC-V, even 32-bit targets have 128-bit "long
    double".

    There isn't any ARM-implementation with 128 bit FP.

    And you know that because ... what?  Because you are confusing hardware >>> floating point with floating point in general?

         $ uname -m
         aarch64
         $ cat c.c
         #include <stdio.h>
         #include <limits.h>
         #include <float.h>

         int main(void) {
             printf("sizeof (long double) = %zu (%zu bits), LDBL_DIG = %d\n",
                    sizeof (long double),
                    CHAR_BIT * sizeof (long double),
                    LDBL_DIG);
         }
         $ gcc c.c -o c && ./c
         sizeof (long double) = 16 (128 bits), LDBL_DIG = 33
         $

    That's pure software - your CPU doesn't natively support 128 bit FP.


    Does it matter?

    Suppose there /is/ a long double type which is wider than double,
    however many bits it is, or whether it's implemented in hardware or
    software: how do you then extract its mantissa?

    I showed a non-portable way of doing when it was Intel's 80-bit type. My
    method used x87 instructions, but it's actually even simpler without it:
    just take the first 64 bits of the 80-bit little-endian representation.
    (That only works with that 80-bit format.)

    But for anything beyond 80 bits, or for something that works on any size
    of float, you will need a different approach, and possibly a uint128 type.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Branimir Maksimovic@21:1/5 to Bonita Montero on Tue Oct 5 19:34:48 2021
    On 2021-10-05, Bonita Montero <Bonita.Montero@gmail.com> wrote:
    Am 05.10.2021 um 18:04 schrieb Keith Thompson:
    David Brown <david.brown@hesbynett.no> writes:
    On 05/10/2021 07:12, Bonita Montero wrote:
    Am 04.10.2021 um 20:04 schrieb David Brown:

    MSVC for ARM has 64-bit "long doubles" even on 64-bit ARM, other 64-bit >>>>> ARM targets have 128-bit (I don't know off-hand if they are IEEE quad >>>>> precision).  For RISC-V, even 32-bit targets have 128-bit "long double". >>>>
    There isn't any ARM-implementation with 128 bit FP.

    And you know that because ... what? Because you are confusing hardware
    floating point with floating point in general?

    $ uname -m
    aarch64
    $ cat c.c
    #include <stdio.h>
    #include <limits.h>
    #include <float.h>

    int main(void) {
    printf("sizeof (long double) = %zu (%zu bits), LDBL_DIG = %d\n",
    sizeof (long double),
    CHAR_BIT * sizeof (long double),
    LDBL_DIG);
    }
    $ gcc c.c -o c && ./c
    sizeof (long double) = 16 (128 bits), LDBL_DIG = 33
    $

    That's pure software - your CPU doesn't natively support 128 bit FP.

    Exactly.

    --

    7-77-777
    Evil Sinner!
    to weak you should be meek, and you should brainfuck stronger https://github.com/rofl0r/chaos-pp

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Branimir Maksimovic@21:1/5 to Keith Thompson on Tue Oct 5 19:33:56 2021
    On 2021-10-05, Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
    David Brown <david.brown@hesbynett.no> writes:
    On 05/10/2021 07:12, Bonita Montero wrote:
    Am 04.10.2021 um 20:04 schrieb David Brown:

    MSVC for ARM has 64-bit "long doubles" even on 64-bit ARM, other 64-bit >>>> ARM targets have 128-bit (I don't know off-hand if they are IEEE quad
    precision).  For RISC-V, even 32-bit targets have 128-bit "long double". >>>
    There isn't any ARM-implementation with 128 bit FP.

    And you know that because ... what? Because you are confusing hardware
    floating point with floating point in general?

    $ uname -m
    aarch64
    $ cat c.c
    #include <stdio.h>
    #include <limits.h>
    #include <float.h>

    int main(void) {
    printf("sizeof (long double) = %zu (%zu bits), LDBL_DIG = %d\n",
    sizeof (long double),
    CHAR_BIT * sizeof (long double),
    LDBL_DIG);
    }
    $ gcc c.c -o c && ./c
    sizeof (long double) = 16 (128 bits), LDBL_DIG = 33
    $

    Apple M1:
    bmaxa@Branimirs-Air projects % gcc -O2 c.c
    bmaxa@Branimirs-Air projects % ./a.out
    sizeof (long double) = 8 (64 bits), LDBL_DIG = 15
    bmaxa@Branimirs-Air projects % uname -m
    arm64

    --

    7-77-777
    Evil Sinner!
    to weak you should be meek, and you should brainfuck stronger https://github.com/rofl0r/chaos-pp

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Bonita Montero on Wed Oct 6 08:11:55 2021
    On 06/10/2021 07:58, Bonita Montero wrote:
    Am 05.10.2021 um 20:21 schrieb Bart:
    On 05/10/2021 18:14, Bonita Montero wrote:

    That's pure software - your CPU doesn't natively support 128 bit FP.


    Does it matter?

    Yes, It's rare that you need 128 bit FP and it's even more rare that
    the speed doesn't matter.


    Until a couple of days ago, you didn't think 128-bit floating point
    existed. Now you think you know how it is used and what is important to
    users?

    There was a time when /all/ floating point, at least on "normal"
    computers, was in software. Yet people used it - including 64-bit
    doubles which were much slower than 32-bit float. Then floating point co-processors became common, and made floating point somewhat faster
    (though still slow). And people used them. There are a great many
    processors that still don't have hardware floating point, and people use software floats if they need floating point. You do so because getting
    the correct answer is more important than getting a fast answer.

    If you need the greater precision or range of quad precision floating
    point, then you use that. If it is slow, you accept that - or you pay
    the price for faster hardware.

    There does not seem to be much call for quad precision - not enough for
    many cpu manufacturers to spend the significant die space needed to
    implement it in hardware. But there is enough call for it to be
    implemented in software on many tools (gcc and clang for x86 have it as __float128, and I'd be slightly surprised if MS doesn't have some
    support through a similar extension), it is specified in a number of cpu architecture documents for future implementation, and there are many
    library implementations available.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bonita Montero@21:1/5 to All on Wed Oct 6 07:58:19 2021
    Am 05.10.2021 um 20:21 schrieb Bart:
    On 05/10/2021 18:14, Bonita Montero wrote:
    Am 05.10.2021 um 18:04 schrieb Keith Thompson:
    David Brown <david.brown@hesbynett.no> writes:
    On 05/10/2021 07:12, Bonita Montero wrote:
    Am 04.10.2021 um 20:04 schrieb David Brown:

    MSVC for ARM has 64-bit "long doubles" even on 64-bit ARM, other
    64-bit
    ARM targets have 128-bit (I don't know off-hand if they are IEEE quad >>>>>> precision).  For RISC-V, even 32-bit targets have 128-bit "long
    double".

    There isn't any ARM-implementation with 128 bit FP.

    And you know that because ... what?  Because you are confusing hardware >>>> floating point with floating point in general?

         $ uname -m
         aarch64
         $ cat c.c
         #include <stdio.h>
         #include <limits.h>
         #include <float.h>

         int main(void) {
             printf("sizeof (long double) = %zu (%zu bits), LDBL_DIG = >>> %d\n",
                    sizeof (long double),
                    CHAR_BIT * sizeof (long double),
                    LDBL_DIG);
         }
         $ gcc c.c -o c && ./c
         sizeof (long double) = 16 (128 bits), LDBL_DIG = 33
         $

    That's pure software - your CPU doesn't natively support 128 bit FP.


    Does it matter?

    Yes, It's rare that you need 128 bit FP and it's even more rare that
    the speed doesn't matter.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bonita Montero@21:1/5 to All on Wed Oct 6 10:25:21 2021
    Am 06.10.2021 um 08:11 schrieb David Brown:

    Until a couple of days ago, you didn't think 128-bit floating point
    existed. ...

    Where did I say that ?
    I only said that ARM 128 bit FP is just an ABI-issue.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to Bonita Montero on Wed Oct 6 12:12:34 2021
    On 06/10/2021 06:58, Bonita Montero wrote:
    Am 05.10.2021 um 20:21 schrieb Bart:
    On 05/10/2021 18:14, Bonita Montero wrote:
    Am 05.10.2021 um 18:04 schrieb Keith Thompson:
    David Brown <david.brown@hesbynett.no> writes:
    On 05/10/2021 07:12, Bonita Montero wrote:
    Am 04.10.2021 um 20:04 schrieb David Brown:

    MSVC for ARM has 64-bit "long doubles" even on 64-bit ARM, other >>>>>>> 64-bit
    ARM targets have 128-bit (I don't know off-hand if they are IEEE >>>>>>> quad
    precision).  For RISC-V, even 32-bit targets have 128-bit "long >>>>>>> double".

    There isn't any ARM-implementation with 128 bit FP.

    And you know that because ... what?  Because you are confusing
    hardware
    floating point with floating point in general?

         $ uname -m
         aarch64
         $ cat c.c
         #include <stdio.h>
         #include <limits.h>
         #include <float.h>

         int main(void) {
             printf("sizeof (long double) = %zu (%zu bits), LDBL_DIG = >>>> %d\n",
                    sizeof (long double),
                    CHAR_BIT * sizeof (long double),
                    LDBL_DIG);
         }
         $ gcc c.c -o c && ./c
         sizeof (long double) = 16 (128 bits), LDBL_DIG = 33
         $

    That's pure software - your CPU doesn't natively support 128 bit FP.


    Does it matter?

    Yes, It's rare that you need 128 bit FP and it's even more rare that
    the speed doesn't matter.



    You keep avoiding my point

    Suppose you HAVE 80-bit or 128-FP, and need to extract the mantissa, how
    would you do it?

    It's like someone asking how to work out the 5th root of a number, and
    you give a method for the square root. Then when pressed, you say that
    is is rare to need a 5th root!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bonita Montero@21:1/5 to All on Wed Oct 6 14:48:56 2021
    Am 06.10.2021 um 13:12 schrieb Bart:
    On 06/10/2021 06:58, Bonita Montero wrote:
    Am 05.10.2021 um 20:21 schrieb Bart:
    On 05/10/2021 18:14, Bonita Montero wrote:
    Am 05.10.2021 um 18:04 schrieb Keith Thompson:
    David Brown <david.brown@hesbynett.no> writes:
    On 05/10/2021 07:12, Bonita Montero wrote:
    Am 04.10.2021 um 20:04 schrieb David Brown:

    MSVC for ARM has 64-bit "long doubles" even on 64-bit ARM, other >>>>>>>> 64-bit
    ARM targets have 128-bit (I don't know off-hand if they are IEEE >>>>>>>> quad
    precision).  For RISC-V, even 32-bit targets have 128-bit "long >>>>>>>> double".

    There isn't any ARM-implementation with 128 bit FP.

    And you know that because ... what?  Because you are confusing
    hardware
    floating point with floating point in general?

         $ uname -m
         aarch64
         $ cat c.c
         #include <stdio.h>
         #include <limits.h>
         #include <float.h>

         int main(void) {
             printf("sizeof (long double) = %zu (%zu bits), LDBL_DIG =
    %d\n",
                    sizeof (long double),
                    CHAR_BIT * sizeof (long double),
                    LDBL_DIG);
         }
         $ gcc c.c -o c && ./c
         sizeof (long double) = 16 (128 bits), LDBL_DIG = 33
         $

    That's pure software - your CPU doesn't natively support 128 bit FP.


    Does it matter?

    Yes, It's rare that you need 128 bit FP and it's even more rare that
    the speed doesn't matter.



    You keep avoiding my point

    Suppose you HAVE 80-bit or 128-FP, and need to extract the mantissa, how would you do it?

    As the 1 high-bit is alwas included in the 64 bit mantissa of a 80 bit
    FP-value that's much easier. In contrast to smaller FP-values where the
    one bit implicity except from denormal values or values with the maximum exponent.

    union
    {
    long double value;
    struct
    {
    uint64_t mantissa;
    uint16_t exponent : 15,
    sign : 1;
    };
    }

    Just store your value into value and extract the mantissa from mantissa.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bonita Montero@21:1/5 to All on Wed Oct 6 16:53:58 2021
    Am 06.10.2021 um 16:25 schrieb Scott Lurndal:

    It seems the most popular new floating point format today is 16-bit
    floating point (bfloat16 in ARM) - important in machine learning applications.

    I think that's popular only for KI-puposes.
    Even for computer graphics that's not sufficient.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to David Brown on Wed Oct 6 14:25:20 2021
    David Brown <david.brown@hesbynett.no> writes:
    On 06/10/2021 07:58, Bonita Montero wrote:
    Am 05.10.2021 um 20:21 schrieb Bart:
    On 05/10/2021 18:14, Bonita Montero wrote:

    That's pure software - your CPU doesn't natively support 128 bit FP.


    Does it matter?

    Yes, It's rare that you need 128 bit FP and it's even more rare that
    the speed doesn't matter.


    Until a couple of days ago, you didn't think 128-bit floating point
    existed. Now you think you know how it is used and what is important to >users?

    It seems the most popular new floating point format today is 16-bit
    floating point (bfloat16 in ARM) - important in machine learning
    applications.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bonita Montero@21:1/5 to All on Wed Oct 6 19:02:34 2021
    union
    {
         long double value;
         struct
         {
             uint64_t mantissa;
             uint16_t exponent : 15,
                      sign : 1;
         };
    }


    Also, I believe bitfield allocation is implementation defined.

    The way than I did is at least portable among x86-compilers.
    On platforms where you have a differnt byte-order this won't
    work, but these platforms don't have a 80 bit FP type anyway.

    To be more precise here: there are some differences in how x86
    compilers handle bitfields, but there are also commonalities.
    And the binary layout of the above structure is definitely the
    same for all x86-compilers.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From red floyd@21:1/5 to Bonita Montero on Wed Oct 6 09:44:41 2021
    On 10/6/2021 5:48 AM, Bonita Montero wrote:


    As the 1 high-bit is alwas included in the 64 bit mantissa of a 80 bit FP-value that's much easier. In contrast to smaller FP-values where the
    one bit implicity except from denormal values or values with the maximum exponent.

    union
    {
        long double value;
        struct
        {
            uint64_t mantissa;
            uint16_t exponent : 15,
                     sign : 1;
        };
    }

    Just store your value into value and extract the mantissa from mantissa.

    Does anyone know if type punning through a union is still undefined
    behavior?

    Also, I believe bitfield allocation is implementation defined.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bonita Montero@21:1/5 to All on Wed Oct 6 18:52:40 2021
    Am 06.10.2021 um 18:44 schrieb red floyd:
    On 10/6/2021 5:48 AM, Bonita Montero wrote:


    As the 1 high-bit is alwas included in the 64 bit mantissa of a 80 bit
    FP-value that's much easier. In contrast to smaller FP-values where the
    one bit implicity except from denormal values or values with the maximum
    exponent.

    union
    {
         long double value;
         struct
         {
             uint64_t mantissa;
             uint16_t exponent : 15,
                      sign : 1;
         };
    }

    Just store your value into value and extract the mantissa from mantissa.

    Does anyone know if type punning through a union is still undefined
    behavior?

    It's a de-facto standard for all compilers because such constructs
    are needed very often.
    Otherwise it's specified that you can alias anything as a array of
    chars and an array of chars as anything - I think that's specified
    because this is nice to have for serialization-purposes. So you can
    cast a type to a char * and then further to the destination type to
    get the same effect. This definitely prevents any optimization tricks
    of the compiler which would sabotage this.

    Also, I believe bitfield allocation is implementation defined.

    The way than I did is at least portable among x86-compilers.
    On platforms where you have a differnt byte-order this won't
    work, but these platforms don't have a 80 bit FP type anyway.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Chris M. Thomasson@21:1/5 to Bart on Wed Oct 6 13:57:45 2021
    On 10/6/2021 4:12 AM, Bart wrote:
    On 06/10/2021 06:58, Bonita Montero wrote:
    Am 05.10.2021 um 20:21 schrieb Bart:
    On 05/10/2021 18:14, Bonita Montero wrote:
    Am 05.10.2021 um 18:04 schrieb Keith Thompson:
    David Brown <david.brown@hesbynett.no> writes:
    On 05/10/2021 07:12, Bonita Montero wrote:
    Am 04.10.2021 um 20:04 schrieb David Brown:

    MSVC for ARM has 64-bit "long doubles" even on 64-bit ARM, other >>>>>>>> 64-bit
    ARM targets have 128-bit (I don't know off-hand if they are IEEE >>>>>>>> quad
    precision).  For RISC-V, even 32-bit targets have 128-bit "long >>>>>>>> double".

    There isn't any ARM-implementation with 128 bit FP.

    And you know that because ... what?  Because you are confusing
    hardware
    floating point with floating point in general?

         $ uname -m
         aarch64
         $ cat c.c
         #include <stdio.h>
         #include <limits.h>
         #include <float.h>

         int main(void) {
             printf("sizeof (long double) = %zu (%zu bits), LDBL_DIG =
    %d\n",
                    sizeof (long double),
                    CHAR_BIT * sizeof (long double),
                    LDBL_DIG);
         }
         $ gcc c.c -o c && ./c
         sizeof (long double) = 16 (128 bits), LDBL_DIG = 33
         $

    That's pure software - your CPU doesn't natively support 128 bit FP.


    Does it matter?

    Yes, It's rare that you need 128 bit FP and it's even more rare that
    the speed doesn't matter.



    You keep avoiding my point

    Suppose you HAVE 80-bit or 128-FP, and need to extract the mantissa, how would you do it?

    It's like someone asking how to work out the 5th root of a number, and
    you give a method for the square root. Then when pressed, you say that
    is is rare to need a 5th root!

    This does seem to be a pattern for her. Humm...

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Juha Nieminen@21:1/5 to red floyd on Thu Oct 7 05:35:16 2021
    red floyd <no.spam.here@its.invalid> wrote:
    union
    {
    long double value;
    struct
    {
    uint64_t mantissa;
    uint16_t exponent : 15,
    sign : 1;
    };
    }

    Just store your value into value and extract the mantissa from mantissa.

    Does anyone know if type punning through a union is still undefined
    behavior?

    Also, I believe bitfield allocation is implementation defined.

    Also, the above union assumes that the long double value is stored in the
    same byte order as the members of the struct. It also assumes that the long double occupies exactly 10 bytes and isn't padded in the wrong end.

    And, as you say, it's not defined whether that sign bit will be the lowest
    or highest bit of that 16-bit bitfield. (I don't think the standard even guarantees that the 1-bit will be stored in the same bytes as the 15-bits.)

    You could make some compile-time checks to see that the union will have
    the proper internal structure (and refuse to compile otherwise), although
    IIRC there's no way to check endianess at compile time (unless C++20
    added some new features to do that).

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Juha Nieminen on Thu Oct 7 08:20:20 2021
    On 07/10/2021 07:35, Juha Nieminen wrote:
    red floyd <no.spam.here@its.invalid> wrote:
    union
    {
    long double value;
    struct
    {
    uint64_t mantissa;
    uint16_t exponent : 15,
    sign : 1;
    };
    }

    Just store your value into value and extract the mantissa from mantissa.

    Does anyone know if type punning through a union is still undefined
    behavior?

    Also, I believe bitfield allocation is implementation defined.

    Also, the above union assumes that the long double value is stored in the same byte order as the members of the struct. It also assumes that the long double occupies exactly 10 bytes and isn't padded in the wrong end.

    And, as you say, it's not defined whether that sign bit will be the lowest
    or highest bit of that 16-bit bitfield. (I don't think the standard even guarantees that the 1-bit will be stored in the same bytes as the 15-bits.)

    You could make some compile-time checks to see that the union will have
    the proper internal structure (and refuse to compile otherwise), although IIRC there's no way to check endianess at compile time (unless C++20
    added some new features to do that).


    C++20 added std::endian for convenience and standardisation of common
    compiler features for endianness:

    <https://en.cppreference.com/w/cpp/types/endian>

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to red floyd on Thu Oct 7 08:17:23 2021
    On 06/10/2021 18:44, red floyd wrote:
    On 10/6/2021 5:48 AM, Bonita Montero wrote:


    As the 1 high-bit is alwas included in the 64 bit mantissa of a 80 bit
    FP-value that's much easier. In contrast to smaller FP-values where the
    one bit implicity except from denormal values or values with the maximum
    exponent.

    union
    {
         long double value;
         struct
         {
             uint64_t mantissa;
             uint16_t exponent : 15,
                      sign : 1;
         };
    }

    Just store your value into value and extract the mantissa from mantissa.

    Does anyone know if type punning through a union is still undefined
    behavior?

    Yes, it is. It's not uncommon to for compilers to generate code as
    though it /were/ defined in C++ (it is defined behaviour in C),
    especially for unions of simple types. But compilers don't (IME)
    guarantee it.

    The standard method for accessing "raw" bit patterns that is always
    safe, is memcpy(). In C++20, there is now std::bit_cast<>, which also
    lets you do get type-punning effects.

    (And if anyone tells you type-punning unions "work" in C++, then ask why std::bit_cast<> was added to the language.)



    Also, I believe bitfield allocation is implementation defined.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bonita Montero@21:1/5 to All on Thu Oct 7 08:38:02 2021
    Am 07.10.2021 um 07:35 schrieb Juha Nieminen:
    red floyd <no.spam.here@its.invalid> wrote:
    union
    {
    long double value;
    struct
    {
    uint64_t mantissa;
    uint16_t exponent : 15,
    sign : 1;
    };
    }

    Just store your value into value and extract the mantissa from mantissa.

    Does anyone know if type punning through a union is still undefined
    behavior?

    Also, I believe bitfield allocation is implementation defined.

    Also, the above union assumes that the long double value is stored in the same byte order as the members of the struct. It also assumes that the long double occupies exactly 10 bytes and isn't padded in the wrong end.

    It actually fits for all x86-compilers.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bonita Montero@21:1/5 to All on Thu Oct 7 08:42:14 2021
    Am 07.10.2021 um 08:38 schrieb Bonita Montero:
    Am 07.10.2021 um 08:20 schrieb David Brown:

    C++20 added std::endian for convenience and standardisation of common
    compiler features for endianness:

    Why an endianess check here ?
    There are no big-endian machines with 80 bit FP.

    Oh, I just remembered the 68K FPUs. These have 80 bit FP.
    But 68K is dead today.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Bonita Montero on Thu Oct 7 10:23:38 2021
    On 07/10/2021 08:42, Bonita Montero wrote:
    Am 07.10.2021 um 08:38 schrieb Bonita Montero:
    Am 07.10.2021 um 08:20 schrieb David Brown:

    C++20 added std::endian for convenience and standardisation of common
    compiler features for endianness:

    Why an endianess check here ?
    There are no big-endian machines with 80 bit FP.

    Oh, I just remembered the 68K FPUs. These have 80 bit FP.
    But 68K is dead today.

    The 68k ISA lives on in the microcontroller world, as the ColdFire
    processors, though I don't believe any new ColdFire microcontrollers
    have been released since NXP bought Freescale in 2015. Even at that
    stage it was no longer a major development line for Freescale. A decade
    or so before that, ColdFire was one of the most popular architectures in
    small network devices such as SOHO NAT routers, and was the main target
    for the MMU-less Linux version ucLinux. This was all long after the 68k
    was gone from desktops, workstations, home computers, etc.

    (Because ucLinux does not support fork(), this lead to an increased use
    of spawn() instead of fork-exec, which then made porting to Windows
    easier. So if you use any *nix-heritage software on your Windows
    machine, that may be partly thanks to the 68k architecture.)

    Some of the 68k-based microcontrollers are immortal. People still make
    devices using the renowned 68332, though it is around 30 years old.

    However, few of these embedded uses used floating point, and the the
    bigger ColdFire processors with hardware floating point support all used
    64-bit floats. 80-bit floats were used in the 68882 FPU co-processor,
    and the 68040 and 68060 processors.

    The first serious electronics board I designed had a 68332 with a 68882 co-processor, many years ago. (The current version of the same system
    is, unsurprisingly, ARM based.)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Juha Nieminen@21:1/5 to Bonita Montero on Fri Oct 8 04:37:38 2021
    Bonita Montero <Bonita.Montero@gmail.com> wrote:
    Am 07.10.2021 um 07:35 schrieb Juha Nieminen:
    red floyd <no.spam.here@its.invalid> wrote:
    union
    {
    long double value;
    struct
    {
    uint64_t mantissa;
    uint16_t exponent : 15,
    sign : 1;
    };
    }

    Just store your value into value and extract the mantissa from mantissa. >>>
    Does anyone know if type punning through a union is still undefined
    behavior?

    Also, I believe bitfield allocation is implementation defined.

    Also, the above union assumes that the long double value is stored in the
    same byte order as the members of the struct. It also assumes that the long >> double occupies exactly 10 bytes and isn't padded in the wrong end.

    It actually fits for all x86-compilers.

    ARM is becoming more and more common.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Juha Nieminen@21:1/5 to David Brown on Fri Oct 8 04:39:10 2021
    David Brown <david.brown@hesbynett.no> wrote:
    (And if anyone tells you type-punning unions "work" in C++, then ask why std::bit_cast<> was added to the language.)

    Why hasn't type-punning been standardized in C++, given that it's
    standardized in C?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From red floyd@21:1/5 to Bonita Montero on Thu Oct 7 22:44:06 2021
    On 10/6/2021 11:38 PM, Bonita Montero wrote:
    Am 07.10.2021 um 07:35 schrieb Juha Nieminen:
    red floyd <no.spam.here@its.invalid> wrote:
    union
    {
    long double value;
    struct
    {
    uint64_t mantissa;
    uint16_t exponent : 15,
    sign : 1;
    };
    }

    Just store your value into value and extract the mantissa from
    mantissa.

    Does anyone know if type punning through a union is still undefined
    behavior?

    Also, I believe bitfield allocation is implementation defined.

    Also, the above union assumes that the long double value is stored in the
    same byte order as the members of the struct. It also assumes that the
    long
    double occupies exactly 10 bytes and isn't padded in the wrong end.

    It actually fits for all x86-compilers.

    Back in the early '80s, there was something called "all-the-world's- a-vax-running-BSD Syndrome". You appear to have the modern variant,
    known as "All-the-world's-an-x86-running-Windows Syndrome."

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bonita Montero@21:1/5 to All on Fri Oct 8 07:54:00 2021
    Am 08.10.2021 um 06:37 schrieb Juha Nieminen:
    Bonita Montero <Bonita.Montero@gmail.com> wrote:
    Am 07.10.2021 um 07:35 schrieb Juha Nieminen:
    red floyd <no.spam.here@its.invalid> wrote:
    union
    {
    long double value;
    struct
    {
    uint64_t mantissa;
    uint16_t exponent : 15,
    sign : 1;
    };
    }

    Just store your value into value and extract the mantissa from mantissa. >>>>
    Does anyone know if type punning through a union is still undefined
    behavior?

    Also, I believe bitfield allocation is implementation defined.

    Also, the above union assumes that the long double value is stored in the >>> same byte order as the members of the struct. It also assumes that the long >>> double occupies exactly 10 bytes and isn't padded in the wrong end.

    It actually fits for all x86-compilers.

    ARM is becoming more and more common.

    ARM hasn't 80 bit FP, so there's no need for the above code on ARM.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Juha Nieminen on Fri Oct 8 09:25:40 2021
    On 08/10/2021 06:39, Juha Nieminen wrote:
    David Brown <david.brown@hesbynett.no> wrote:
    (And if anyone tells you type-punning unions "work" in C++, then ask why
    std::bit_cast<> was added to the language.)

    Why hasn't type-punning been standardized in C++, given that it's standardized in C?


    That's a fair question. First, I think you'd have to ask why was it standardised in C? AFAIUI (and this is from memory rather than
    reference), in C90 and before, it was quite unclear whether the
    standards defined type-punning union behaviour. However, code relied on
    it. It's not something that turns up very often - you very rarely have
    need for this kind of thing. But because it turns up in low-level code
    that is in turn used by lots of other code - such as in the heart of a
    software floating point library - it becomes important.

    A few compilers, such as gcc, actually documented that type-punning
    unions worked - most did not, though people expected them to support
    them. I've never been clear as to whether the C standards committee
    changed their mind to make type-punning fully defined, or if they simply changed the wording of the standard to make it less ambiguous.

    In C++, however, the idea of type-punning did not fit in. The original
    aim was that most C++ code would be about objects that get created using
    a constructor, maintain an invariant by using methods to access the
    private data, and get destroyed cleanly with a destructor. Messing
    directly with the internals of an object using different types - that's
    the kind of bad behaviour C programmers use, and stops you relying on
    your types and their safety and correctness.

    C++ certainly could have made it defined behaviour for unions that are
    limited to POD types. But they have never done so - maybe there are complicating factors that I haven't thought of. The current idea in
    C++20 is std::bit_cast<>. I don't know how useful or convenient that
    will be.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to David Brown on Fri Oct 8 14:34:35 2021
    David Brown <david.brown@hesbynett.no> writes:
    .

    A few compilers, such as gcc, actually documented that type-punning
    unions worked - most did not, though people expected them to support
    them. I've never been clear as to whether the C standards committee
    changed their mind to make type-punning fully defined, or if they simply >changed the wording of the standard to make it less ambiguous.


    Reading through the Unisys C compiler manual is interesting, due
    to the radically different underlying architecture, for example
    in the porting section:

    The comparison of negative numbers with unsigned types may behave differently on
    A Series systems than on other platforms. Platforms that store arithmetic values in
    one's or two's complement form store the sign when assigning to an unsigned type.
    On A Series systems, the sign is not stored when assigning to an unsigned type. On
    A Series systems, comparing a negative value with the value in an unsigned type will
    never be true unless the CHAR2 or UNSIGNED subordinate options of the PORT
    compiler control option are used to emulate two's complement arithmetic on
    unsigned types. Another workaround is to change negative literals to their one's
    complement values (for example, -1 becomes 0xFF).

    The representation of scalar types differs between A Series systems and other
    platforms. On A Series systems, integer types are 6-bytes in length and start on word
    boundaries. Any calculations that assume the size of an integer type to be anything
    other than 6 bytes will result in problems when portation occurs.

    long Ary[ (sizeof(SomeObject)+3) / sizeof(long)];

    The addition of the numeric literal 3 to the size of the type of SomeObject assumes that
    sizeof(long) returns 4. In A Series C, sizeof(long) returns 6, causing the calculation
    to return unexpected results. The following code fragment illustrates how you can
    avoid this type of portation problem:

    struct{ unsigned short Type;
    unsigned char SeqNum;

    } Info;
    char *InfoPtr = &Info;
    seq = InfoPtr[2];

    Using InfoPtr[2] to access SeqNum assumes that bytes 0 and 1 contain the structure
    member Type and that byte 2 contains the structure member SeqNum. On A Series
    systems, Type occupies bytes 0 to 5, and SeqNum occupies byte 6, which means that
    InfoPtr[2] accesses the wrong data.

    When a pointer is implicitly or explicitly cast from a pointer to an object of a given
    alignment to a pointer to an object of a more strict alignment, the resulting pointer
    may not be aligned with the original pointer. For example, casting a pointer to char to a
    pointer to int causes the pointer index to be divided by 6 to change from character to
    word units. The divide by 6 operation causes the pointer to int to point to the
    beginning of the word. If the char pointer points to the middle of the word, the two
    pointers do not point to the same data. To catch pointer alignment errors of this type
    at run time, use the $BOUNDS(ALIGNMENT) compiler control option.

    Two's complement arithmetic is used on many platforms. On A Series systems,
    arithmetic is performed on data in signed-magnitude form. This can cause
    discrepancies in algorithms that depend on the two's complement representation. For
    example, C applications that use encryption algorithms to match data, such as
    passwords, between client and server must perform the encryption the same way on
    the client-end and the server-end. The differences between the two's complement
    and signed-magnitude representation may result in different values when fragments
    of data are extracted, encrypted, and reinserted into the data.

    To obtain matching results, you can define macros that return arithmetic results in
    two's complement form. The following example illustrates macros for two's
    complement addition and subtraction:

    #define tc_add(arg1, arg2) (((arg1) + (arg2)) & 0xFF)
    #define tc_sub(arg1, arg2) (((arg1) + (0x100 - (arg2))) & 0xFF)

    The macro errno is defined as an array indexed by the unique stack number of the
    execution process when $SET CONCURRENTEXECUTION or
    $SHARING=SHAREDBYALL. As a result, each client of a C library has a unique errno
    location. [ed. Note stack number in this context is equivalent to task/process id]

    Although each errno location starts at zero, the location is not reset to zero when a
    client delinks from a library or when another client links with the same stack number.
    In order to avoid this issue, the C library should explicitly set errno to zero before
    calling a function that sets errno.

    Note: The macro errno cannot be used as a declarator when
    $CONCURRENTEXECUTION or $SHARING=SHAREDBYALL and any of the standard
    heads have been included.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bonita Montero@21:1/5 to All on Fri Oct 8 20:23:52 2021
    Am 07.10.2021 um 10:23 schrieb David Brown:

    The 68k ISA lives on in the microcontroller world, as the ColdFire processors, though I don't believe any new ColdFire microcontrollers
    have been released since NXP bought Freescale in 2015. Even at that
    stage it was no longer a major development line for Freescale. A
    decade or so before that, ColdFire was one of the most popular
    architectures in small network devices such as SOHO NAT routers, ...

    MIPS was dominant in routers before it was replaced with ARM.
    68K had a straighter instruction-set than x86, but the two times
    indirect addressing-modes introduced with the 68020 were totally
    brain-damaged.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Bonita Montero on Sat Oct 9 10:23:36 2021
    On 08/10/2021 20:23, Bonita Montero wrote:
    Am 07.10.2021 um 10:23 schrieb David Brown:

    The 68k ISA lives on in the microcontroller world, as the ColdFire
    processors, though I don't believe any new ColdFire microcontrollers
    have been released since NXP bought Freescale in 2015. Even at that
    stage it was no longer a major development line for Freescale. A
    decade or so before that, ColdFire was one of the most popular
    architectures in small network devices such as SOHO NAT routers, ...

    MIPS was dominant in routers before it was replaced with ARM.

    MIPS was dominant in high-end routers and fast switches (with PowerPC
    being the main competitor). ColdFire had a substantial share of the
    small device market for quite a while, as ucLinux became a popular
    choice for the system, though MIPS was also used there (mostly with
    proprietary OSes). Later, MIPS was also used with Linux in such
    routers, and as you say, ARM is now the most common choice (though MIPS
    is still used in many low-end and high-end network devices, and PowerPC
    is still found in some big systems).

    68K had a straighter instruction-set than x86, but the two times
    indirect addressing-modes introduced with the 68020 were totally brain-damaged.

    68k was a better ISA than x86 in almost every way imaginable. But it
    did get a few overly complicated addressing modes - some of these were
    dropped in later 68k devices. And the /implementation/ in the 68k
    family was not as good - Motorola didn't have as many smart people and
    as big budgets as Intel or even AMD. On the 68030, IIRC, someone
    discovered that a software division routine worked faster than the
    hardware division instruction.

    The ColdFire was a clean slate re-implementation of a simplified and
    modernised 68k ISA. It dropped the more advanced addressing modes and
    some of the rarely used complex instructions, but added a few new useful
    ones and streamlined the primary ones. It was marketed as a "variable instruction length RISC architecture".

    When you look back at the original 68000 compared to the 8086, it is
    clear that technically the 68000 ISA was a modern and forward-looking architecture while the 8086 was outdated and old-fashioned before the
    first samples were made. The story of the IBM PC shows how technical brilliance is not enough to succeed - the worst cpu architecture around, combined with the worst OS ever hacked together, ended up dominant.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bonita Montero@21:1/5 to All on Sat Oct 9 10:50:40 2021
    Am 09.10.2021 um 10:23 schrieb David Brown:

    MIPS was dominant in routers before it was replaced with ARM.

    MIPS was dominant in high-end routers and fast switches (with PowerPC
    being the main competitor). ...

    I don't know about former high-end routers, but MIPS was by far
    the most dominant architecture on SOHO-Routers before ARM. 68k
    played almost no role then. F.e. in Germany almost anyone uses
    the Fritz!Box routers and they all were MIPS-based before AVM
    switched to ARM.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Branimir Maksimovic@21:1/5 to Bonita Montero on Sat Oct 9 09:02:34 2021
    On 2021-10-09, Bonita Montero <Bonita.Montero@gmail.com> wrote:
    Am 09.10.2021 um 10:23 schrieb David Brown:

    MIPS was dominant in routers before it was replaced with ARM.

    MIPS was dominant in high-end routers and fast switches (with PowerPC
    being the main competitor). ...

    I don't know about former high-end routers, but MIPS was by far
    the most dominant architecture on SOHO-Routers before ARM. 68k
    played almost no role then. F.e. in Germany almost anyone uses
    the Fritz!Box routers and they all were MIPS-based before AVM
    switched to ARM.

    Well I have router with 1GB of RAM and 4 cores :P
    running as server :P

    --

    7-77-777
    Evil Sinner!
    with software, you repeat same experiment, expecting different results...

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bart@21:1/5 to David Brown on Sat Oct 9 12:16:03 2021
    On 09/10/2021 09:23, David Brown wrote:
    On 08/10/2021 20:23, Bonita Montero wrote:

    68K had a straighter instruction-set than x86, but the two times
    indirect addressing-modes introduced with the 68020 were totally
    brain-damaged.

    68k was a better ISA than x86 in almost every way imaginable. But it
    did get a few overly complicated addressing modes - some of these were dropped in later 68k devices. And the /implementation/ in the 68k
    family was not as good - Motorola didn't have as many smart people and
    as big budgets as Intel or even AMD. On the 68030, IIRC, someone
    discovered that a software division routine worked faster than the
    hardware division instruction.


    When you look back at the original 68000 compared to the 8086, it is
    clear that technically the 68000 ISA was a modern and forward-looking architecture while the 8086 was outdated and old-fashioned before the
    first samples were made.

    That was my initial impression when I first looked at 68000 in the 80s.

    Until I had a closer look at the instruction set, with a view to
    generating code for it from a compiler. Then it had almost as much lack
    of orthogonality as the 8086.

    The obvious one is in have two lots of integer registers, 8 Data
    registers and 8 Address registers, instead of just 16 general registers,
    so that you are constantly thinking about which register set your
    operands and intermediate results should go in.

    (I never got round to using the chip; my company had moved on to doing
    stuff for the IBM PC, instead of developing own hardware products.)

    The story of the IBM PC shows how technical
    brilliance is not enough to succeed - the worst cpu architecture around, combined with the worst OS ever hacked together, ended up dominant.

    I was looking forward to the Zilog Z80000, but unfortunately that never happened.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Bart on Sat Oct 9 15:10:35 2021
    On 09/10/2021 13:16, Bart wrote:
    On 09/10/2021 09:23, David Brown wrote:
    On 08/10/2021 20:23, Bonita Montero wrote:

    68K had a straighter instruction-set than x86, but the two times
    indirect addressing-modes introduced with the 68020 were totally
    brain-damaged.

    68k was a better ISA than x86 in almost every way imaginable. But it
    did get a few overly complicated addressing modes - some of these were
    dropped in later 68k devices. And the /implementation/ in the 68k
    family was not as good - Motorola didn't have as many smart people and
    as big budgets as Intel or even AMD. On the 68030, IIRC, someone
    discovered that a software division routine worked faster than the
    hardware division instruction.


    When you look back at the original 68000 compared to the 8086, it is
    clear that technically the 68000 ISA was a modern and forward-looking
    architecture while the 8086 was outdated and old-fashioned before the
    first samples were made.

    That was my initial impression when I first looked at 68000 in the 80s.

    Until I had a closer look at the instruction set, with a view to
    generating code for it from a compiler. Then it had almost as much lack
    of orthogonality as the 8086.


    It is not as orthogonal as most RISC architectures, but a world ahead of
    x86.

    The obvious one is in have two lots of integer registers, 8 Data
    registers and 8 Address registers, instead of just 16 general registers,
    so that you are constantly thinking about which register set your
    operands and intermediate results should go in.

    Sure. But you have just two sorts of registers - A0..7 and D0..7. Some
    common instructions can use either set, while ALU and address operations
    tend to be limited to one set. On the 8086, every register - A, B, C,
    D, SI, DI, BP, SP - has wildly different uses and instructions. (Later
    x86 devices got more regular.)


    (I never got round to using the chip; my company had moved on to doing
    stuff for the IBM PC, instead of developing own hardware products.)

    The story of the IBM PC shows how technical
    brilliance is not enough to succeed - the worst cpu architecture around,
    combined with the worst OS ever hacked together, ended up dominant.

    I was looking forward to the Zilog Z80000, but unfortunately that never happened.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Bonita Montero on Sat Oct 9 14:57:13 2021
    Bonita Montero <Bonita.Montero@gmail.com> writes:
    Am 09.10.2021 um 10:23 schrieb David Brown:

    MIPS was dominant in routers before it was replaced with ARM.

    MIPS was dominant in high-end routers and fast switches (with PowerPC
    being the main competitor). ...

    I don't know about former high-end routers, but MIPS was by far
    the most dominant architecture on SOHO-Routers before ARM. 68k
    played almost no role then. F.e. in Germany almost anyone uses
    the Fritz!Box routers and they all were MIPS-based before AVM
    switched to ARM.


    There are still very large numbers of MIPS-based chips being produced (at legacy nodes like 65, 45 and 22nm) today. Not new designs, mind,
    but rather ten to fifteen year old designs.

    This third generation ARM processor for routers (high-end) is now sampling:

    https://semiaccurate.com/2021/06/28/marvell-announces-their-5nm-octeon-10-dpu/ https://www.theregister.com/2021/10/06/marvell_ai_chip/

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From red floyd@21:1/5 to Bart on Sat Oct 9 10:26:27 2021
    On 10/9/2021 4:16 AM, Bart wrote:
    \
    I was looking forward to the Zilog Z80000, but unfortunately that never happened.


    Same here. The Z8k had a great instruction set. I was really hoping
    the Z80000 would succeed.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Vir Campestris@21:1/5 to David Brown on Tue Oct 12 21:23:17 2021
    On 09/10/2021 09:23, David Brown wrote:
    When you look back at the original 68000 compared to the 8086, it is
    clear that technically the 68000 ISA was a modern and forward-looking architecture while the 8086 was outdated and old-fashioned before the
    first samples were made. The story of the IBM PC shows how technical brilliance is not enough to succeed - the worst cpu architecture around, combined with the worst OS ever hacked together, ended up dominant.

    Very nicely put.

    Of course one reason for that is the success of the 8080, and its
    successors the 8085 and Zilog's Z80 (which had an even less regular
    instruction set).

    AIUI Intel had a world leader on their hands, and felt that having some
    sort of compatibility in the next generation was important.

    While the 6800 had some success (and the 6809 was my favourite 8-bit
    CPU) it was nowhere near that of the 8080.

    Andy

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From RadicalRabbit@theburrow.co.uk@21:1/5 to Vir Campestris on Wed Oct 13 10:30:18 2021
    On Tue, 12 Oct 2021 21:23:17 +0100
    Vir Campestris <vir.campestris@invalid.invalid> wrote:
    On 09/10/2021 09:23, David Brown wrote:
    When you look back at the original 68000 compared to the 8086, it is
    clear that technically the 68000 ISA was a modern and forward-looking
    architecture while the 8086 was outdated and old-fashioned before the
    first samples were made. The story of the IBM PC shows how technical
    brilliance is not enough to succeed - the worst cpu architecture around,
    combined with the worst OS ever hacked together, ended up dominant.

    Very nicely put.

    Of course one reason for that is the success of the 8080, and its
    successors the 8085 and Zilog's Z80 (which had an even less regular >instruction set).

    AIUI Intel had a world leader on their hands, and felt that having some
    sort of compatibility in the next generation was important.

    While the 6800 had some success (and the 6809 was my favourite 8-bit
    CPU) it was nowhere near that of the 8080.

    https://en.wikipedia.org/wiki/Motorola_6809

    "In 1980 a 6809 in single-unit quantities was $37 compared to $9 for a Zilog Z80 and $6 for a 6502."

    Oops. No wonder it sank without trace.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)