Click here to Skip to main content
15,390,997 members

Welcome to the Lounge

   

For discussing anything related to a software developer's life but is not for programming questions. Got a programming question?

The Lounge is rated Safe For Work. If you're about to post something inappropriate for a shared office environment, then don't post it. No ads, no abuse, and no programming questions. Trolling, (political, climate, religious or whatever) will result in your account being removed.

 
GeneralTalk about demoralizing Pin
honey the codewitch17-Jun-21 10:42
mvahoney the codewitch17-Jun-21 10:42 
GeneralRe: Talk about demoralizing Pin
Greg Utas17-Jun-21 11:02
mveGreg Utas17-Jun-21 11:02 
GeneralRe: Talk about demoralizing Pin
honey the codewitch17-Jun-21 11:12
mvahoney the codewitch17-Jun-21 11:12 
GeneralRe: Talk about demoralizing Pin
Greg Utas17-Jun-21 11:52
mveGreg Utas17-Jun-21 11:52 
GeneralRe: Talk about demoralizing Pin
honey the codewitch17-Jun-21 11:56
mvahoney the codewitch17-Jun-21 11:56 
GeneralRe: Talk about demoralizing Pin
PIEBALDconsult17-Jun-21 11:06
professionalPIEBALDconsult17-Jun-21 11:06 
GeneralRe: Talk about demoralizing Pin
Super Lloyd17-Jun-21 13:48
MemberSuper Lloyd17-Jun-21 13:48 
GeneralRe: Talk about demoralizing Pin
Espen Harlinn17-Jun-21 15:56
professionalEspen Harlinn17-Jun-21 15:56 
I guess you do a bit of rounding then? If you do, it may be that it is possible to improve that by a lot of bit-fiddling …
On x64 I've seen significant performance improvement, between 20% and 300%, for the following:
isnan, isinf, signbit, frexp, min, max, trunc, round, clamp and lerp

I have no idea about how well this will work out for an ARM cpu, but here is the core of my implementation (Sorry about the formatting, paste and encode as HTML doesn't work well for C++ code anymore Cry | :(( ):

C++
template <typename T> 
struct FractionWidth;

template <> 
struct FractionWidth<float>
{
    static constexpr UInt32 value = 23;
};
template <> 
struct FractionWidth<double>
{
    static constexpr UInt32 value = 52;
};


template <typename T> 
struct ExponentWidth;
template <> 
struct ExponentWidth<float>
{
    static constexpr UInt32 value = 8;
};
template <> 
struct ExponentWidth<double>
{
    static constexpr UInt32 value = 11;
};

template <typename T>
struct ExponenBias;
template <>
struct ExponenBias<float>
{
    static constexpr UInt32 value = _FBIAS;
};
template <>
struct ExponenBias<double>
{
    static constexpr UInt32 value = _DBIAS;
};

template <typename T>
struct InfinityUnsignedValue;
template <>
struct InfinityUnsignedValue<float>
{
    static constexpr UInt32 value = 0X7F800000UL;
};
template <>
struct InfinityUnsignedValue<double>
{
    static constexpr UInt64 value = 0x7FF0000000000000ULL;
};

template <typename T>
struct NegativeInfinityUnsignedValue;
template <>
struct NegativeInfinityUnsignedValue<float>
{
    static constexpr UInt32 value = 0xFF800000UL;
};
template <>
struct NegativeInfinityUnsignedValue<double>
{
    static constexpr UInt64 value = 0xFFF0000000000000ULL;
};
template <typename T>
struct QuietNaNUnsignedValue;
template <>
struct QuietNaNUnsignedValue<float>
{
    static constexpr UInt32 value = 0XFFC00001UL;
};
template <>
struct QuietNaNUnsignedValue<double>
{
    static constexpr UInt64 value = 0x7FF0000000000001ULL;
};


#pragma pack(push,1)
template<typename T>
struct FloatingPoint
{
    using ValueType = std::remove_cvref_t<T>;
    using UIntType = MakeUnsigned<ValueType>;

    static constexpr Int32 FractionWidth = static_cast<Int32>( Internal::FractionWidth<ValueType>::value );
    static constexpr Int32 ExponentWidth = static_cast<Int32>( Internal::ExponentWidth<ValueType>::value );

    static constexpr Int32 ExponentBias = ( 1 << ( ExponentWidth - 1 ) ) - 1;

    static constexpr Int32 MaxExponentValue = ( 1 << ExponentWidth ) - 1;

    static constexpr UIntType MaxExponent = static_cast<UIntType>( MaxExponentValue ) << FractionWidth;

    static constexpr UIntType MinSubnormal = UIntType( 1 );
    static constexpr UIntType MaxSubnormal = ( UIntType( 1 ) << FractionWidth ) - 1;
    static constexpr UIntType MinNormal = ( UIntType( 1 ) << FractionWidth );
    static constexpr UIntType MaxNormal = ( ( UIntType( MaxExponentValue ) - 1 ) << FractionWidth ) | MaxSubnormal;

    static constexpr UIntType FractionMask = FractionMask<ValueType, UIntType>;
    static constexpr UIntType ExponentMask = ExponentMask<ValueType, UIntType>;
    static constexpr UIntType SignMask = ~( FractionMask | ExponentMask );

    static constexpr UIntType InfinityValue = InfinityUnsignedValue<ValueType>::value;
    static constexpr UIntType NegativeInfinityValue = NegativeInfinityUnsignedValue<ValueType>::value;
    static constexpr UIntType QuietNaNValue = QuietNaNUnsignedValue<ValueType>::value;
    static constexpr UIntType ZeroValue = static_cast<UIntType>( 0 );
    static constexpr UIntType NegativeZeroValue = SignMask;

    UIntType value_;

    constexpr FloatingPoint( ) noexcept
        : value_( std::bit_cast<UIntType>( static_cast<ValueType>( 0.0 ) ) )
    {
    }

    constexpr explicit FloatingPoint( ValueType value ) noexcept
        : value_( std::bit_cast<UIntType>( value ) )
    {
    }
        
    constexpr explicit FloatingPoint( UIntType value, bool ) noexcept
        : value_( value )
    {
    }

    constexpr explicit FloatingPoint( UIntType fraction, Int32 exponent, bool sign) noexcept
        : value_( (fraction & FractionMask ) | 
            ((  static_cast<UIntType>( exponent ) << FractionWidth ) & ExponentMask) |
            ( sign? SignMask : 0 )  )
    {
    }
        
            


    constexpr FloatingPoint& operator = ( ValueType value ) noexcept
    {
        value_ = std::bit_cast<UIntType>( value );
        return *this;
    }
        
    constexpr bool Sign( ) const noexcept
    {
        return ( value_ & SignMask ) != 0;
    }
    constexpr void SetSign( bool value = true ) noexcept
    {
        if ( value )
        {
            value_ |= SignMask;
        }
        else
        {
            value_ &= ~SignMask;
        }
    }

    constexpr Int32 Exponent( ) const noexcept
    { 
        return static_cast<Int32>( ( value_ & ExponentMask ) >> FractionWidth ) - ExponentBias;
    }
private:
    constexpr void SetExponent( UIntType value ) noexcept
    {
        value_ = ( value << FractionWidth ) & ExponentMask;
    }
public:
    constexpr UIntType Fraction( ) const noexcept
    {
        return value_ & FractionMask;
    }
private:
    constexpr void SetFraction( UIntType value ) noexcept
    {
        value_ = value & FractionMask;
    }
public:

    constexpr bool IsZero( ) const noexcept
    { 
        return (value_ & ( ExponentMask | FractionMask )) == 0;
    }

    constexpr bool IsInf( ) const noexcept
    { 
        return ( value_ & FractionMask ) == 0 && ( ( value_ & ExponentMask ) == MaxExponent );
    }

    constexpr bool IsNaN( ) const noexcept
    { 
        return ( ( value_ & ExponentMask ) == MaxExponent ) && ( ( value_ & FractionMask ) != 0 );
    }

    constexpr bool IsInfOrNaN( ) const noexcept
    { 
        return ( value_ & ExponentMask )  == MaxExponent;
    }

    static constexpr ValueType MakeNaN( UIntType value ) noexcept
    {
        UIntType result;
        result = MaxExponent | (value & FractionMask);
        return std::bit_cast<ValueType>( result );
    }

    constexpr ValueType AsFloatingPoint( ) const noexcept
    {
        return std::bit_cast<ValueType>( value_ );
    }

    constexpr UIntType AsUnsigned( ) const noexcept
    {
        return value_;
    }

    static constexpr FloatingPoint Zero( ) noexcept
    { 
        return FloatingPoint( );
    }

    static constexpr FloatingPoint NegZero( ) noexcept
    {
        FloatingPoint result;
        result.value_ = SignMask;
        return result;
    }

    static constexpr FloatingPoint Inf( ) noexcept
    {
        FloatingPoint result;
        result.value_ = MaxExponent;
        return result;
    }

    static constexpr FloatingPoint NegInf( ) noexcept
    {
        FloatingPoint result;
        result.value_ = MaxExponent | SignMask;
        return result;
    }

    constexpr ValueType Trunc( ) const noexcept
    {
        if ( IsInfOrNaN( ) )
        {
            return std::bit_cast<ValueType>(value_);
        }
        Int32 exponent = Exponent( );

        // is this already an integer?
        if ( exponent >= static_cast<Int32>( FractionWidth ) )
        {
            return std::bit_cast<ValueType>( value_ );
        }

        // If abs(x) is less than 1, then return 0.
        if ( exponent <= -1 )
        {
            return Sign() ? static_cast<ValueType>( -0.0 ) : static_cast<ValueType>( 0.0 );
        }


        Int32 trimSize = FractionWidth - exponent;
                
        UIntType result = (value_ & (SignMask | ExponentMask)) | (( (value_ & FractionMask) >> trimSize ) << trimSize);
        return std::bit_cast<ValueType>( result );
    }

    constexpr ValueType Ceil( ) const noexcept
    {
        if ( IsInfOrNaN( ) || IsZero( ) )
        {
            return std::bit_cast<ValueType>( value_ );
        }

        Int32 exponent = Exponent( );

        // is this already an integer?
        if ( exponent >= static_cast<Int32>( FractionWidth ) )
        {
            return std::bit_cast<ValueType>( value_ );
        }

        // If abs(x) is less than 1
        if ( exponent <= -1 )
        {
            return Sign() ? ValueType( -0.0 ) : ValueType( 1.0 );
        }

        Int32 trimSize = FractionWidth - exponent;
        UIntType result = ( value_ & ( SignMask | ExponentMask ) ) | ( ( ( value_ & FractionMask ) >> trimSize ) << trimSize );

        // If this is already an integer, return it.
        if ( result == value_ )
        {
            return std::bit_cast<ValueType>( value_ );
        }
        // If negative, the ceil operation is equivalent to the trunc operation.
        return Sign( ) ? std::bit_cast<ValueType>( result ) : std::bit_cast<ValueType>( result ) + static_cast<ValueType>( 1.0 );
    }

    constexpr ValueType Floor( ) const noexcept
    {
        if ( Sign() )
        {
            FloatingPoint tmp( value_ & ( ExponentMask | FractionMask ), true );
            return -tmp.Ceil( );
        }
        else
        {
            return Trunc( );
        }
    }


    constexpr ValueType Round( ) const noexcept
    {
        // If infinity NaN or zero, return it.
        if ( IsInfOrNaN( ) || IsZero( ) )
        {
            return std::bit_cast<ValueType>(value_);
        }
                
        int exponent = Exponent( );

        // If the exponent is greater than the most negative 
        // exponent, then this is already an integer.
        if ( exponent >= static_cast<int>( FractionWidth ) )
        {
            return std::bit_cast<ValueType>( value_ );
        }
                
        if ( exponent == -1 )
        {
            bool isNegative = Sign( );
            // Absolute value is greater than equal to 0.5 but less than 1.
            if ( isNegative )
            {
                return static_cast<ValueType>( -1.0 );
            }
            else
            {
                return static_cast<ValueType>( 1.0 );
            }
        }

        if ( exponent <= -2 )
        {
            bool isNegative = Sign( );
            // Absolute value is less than 0.5.
            if ( isNegative )
            {
                return static_cast<ValueType>( -0.0 );
            }
            else
            {
                return static_cast<ValueType>( 0.0 );
            }
        }

        UInt32 trimSize = FractionWidth - exponent;

        bool middleBitSet = (value_ & FractionMask) & ( UIntType( 1 ) << ( trimSize - 1 ) );

        UIntType result = ( value_ & ( SignMask | ExponentMask ) ) | ( ( ( value_ & FractionMask ) >> trimSize ) << trimSize );

        // If this is already an integer, return it.
        if ( result == value_ )
        {
            return std::bit_cast<ValueType>( value_ );
        }

        if ( !middleBitSet )
        {
            // Franctional part is less than 0.5 so round value is the
            // same as the trunc value.
            return std::bit_cast<ValueType>( result );
        }
        else
        {
            bool isNegative = Sign( );
            return isNegative ? 
                std::bit_cast<ValueType>( result ) - static_cast<ValueType>( 1.0 ) :
                std::bit_cast<ValueType>( result ) + static_cast<ValueType>( 1.0 );
        }
    }
};
#pragma pack(pop)

Espen Harlinn
Senior Architect - Ulriken Consulting AS

The competent programmer is fully aware of the strictly limited size of his own skull; therefore he approaches the programming task in full humility, and among other things he avoids clever tricks like the plague.Edsger W.Dijkstra


modified 21-Jun-21 19:41pm.

GeneralRe: Talk about demoralizing Pin
honey the codewitch17-Jun-21 16:45
mvahoney the codewitch17-Jun-21 16:45 
GeneralRe: Talk about demoralizing Pin
David O'Neil17-Jun-21 20:32
professionalDavid O'Neil17-Jun-21 20:32 
GeneralRe: Talk about demoralizing Pin
lmoelleb17-Jun-21 20:19
Memberlmoelleb17-Jun-21 20:19 
GeneralRe: Talk about demoralizing Pin
honey the codewitch17-Jun-21 20:25
mvahoney the codewitch17-Jun-21 20:25 
QuestionRe: Talk about demoralizing Pin
honey the codewitch17-Jun-21 20:27
mvahoney the codewitch17-Jun-21 20:27 
AnswerRe: Talk about demoralizing Pin
lmoelleb21-Jun-21 3:49
Memberlmoelleb21-Jun-21 3:49 
GeneralRe: Talk about demoralizing Pin
honey the codewitch21-Jun-21 6:30
mvahoney the codewitch21-Jun-21 6:30 
GeneralRe: Talk about demoralizing Pin
lmoelleb22-Jun-21 1:45
Memberlmoelleb22-Jun-21 1:45 
GeneralRe: Talk about demoralizing Pin
honey the codewitch22-Jun-21 1:59
mvahoney the codewitch22-Jun-21 1:59 
GeneralRe: Talk about demoralizing Pin
Daniel Pfeffer17-Jun-21 22:50
professionalDaniel Pfeffer17-Jun-21 22:50 
GeneralRe: Talk about demoralizing Pin
honey the codewitch18-Jun-21 2:09
mvahoney the codewitch18-Jun-21 2:09 
GeneralThought of the Day Pin
OriginalGriff17-Jun-21 4:34
mveOriginalGriff17-Jun-21 4:34 
GeneralRe: Thought of the Day Pin
Daniel Pfeffer17-Jun-21 4:58
professionalDaniel Pfeffer17-Jun-21 4:58 
GeneralRe: Thought of the Day Pin
W Balboos, GHB17-Jun-21 5:15
mveW Balboos, GHB17-Jun-21 5:15 
GeneralRe: Thought of the Day Pin
Daniel Pfeffer17-Jun-21 5:33
professionalDaniel Pfeffer17-Jun-21 5:33 
GeneralRe: Thought of the Day Pin
W Balboos, GHB17-Jun-21 5:13
mveW Balboos, GHB17-Jun-21 5:13 
GeneralRe: Thought of the Day Pin
PIEBALDconsult17-Jun-21 5:30
professionalPIEBALDconsult17-Jun-21 5:30 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.


Straw Poll

Do you feel you fully understand the vision and purpose of the software project you're working on?
Sure you can be told the "what", but do you have the "why"?
  Results   164 votes