January 29, 2013
On 2013-49-29 08:01, Tove <tove@fransson.se> wrote:

> On Monday, 28 January 2013 at 23:58:40 UTC, Walter Bright wrote:
>> On 1/28/2013 3:30 PM, Era Scarecrow wrote:
>>> On Monday, 28 January 2013 at 23:11:11 UTC, Walter Bright wrote:
>>>> http://www.drdobbs.com/cpp/implementing-half-floats-in-d/240146674
>>>>
>>>> Anyone care to do the reddit honors?
>>>
>>> [quote]
>>>   and crushed back down to 16 bytes for storage.
>>> [/quote]
>>>
>>>  Should be bits. Otherwise it looks really well done.
>>
>> thank you. Sorry that didn't get caught in review!
>
> "HalfFloat h = hf!1.3f;"
>
> Maybe you could also demonstrate that it's possible to implement another literal syntax?
> HalfFloat h = 1.3.hf;
>
> some people will prefer that for sure.

Except that's not a literal. 1.3.hf would be a function call, while hf!1.3f
is a template instantiation.

-- 
Simen
January 29, 2013
On Tuesday, 29 January 2013 at 08:48:24 UTC, Simen Kjaeraas wrote:
> On 2013-49-29 08:01, Tove <tove@fransson.se> wrote:
>> Maybe you could also demonstrate that it's possible to implement another literal syntax?
>> HalfFloat h = 1.3.hf;
>>
>> some people will prefer that for sure.
>
> Except that's not a literal. 1.3.hf would be a function call, while hf!1.3f is a template instantiation.

 Unless it's an enum or something that requires it to know it during compile-time.

 enum h = 1.3.hf; //potentially correct

 But I doubt it would be that useful. More likely during optimization static values would be equal to it.
January 29, 2013
On Tuesday, 29 January 2013 at 08:48:24 UTC, Simen Kjaeraas wrote:
> Except that's not a literal. 1.3.hf would be a function call, while hf!1.3f
> is a template instantiation.

Can't help but point out, that some time ago, I made a suggestion to add a new function attribute to the language that would mean "evaluate any call to this function at compile time whenever it's possible". That would enable literals like:

1.3.hf
and
ComplexToConstruct(2.5, 7.5)

Given:
@property HalfFloat hf(float v) @aggressive_ctfe;
and...
struct ComplexToConstruct
{
    this(float x, float y) @aggressive_ctfe;
}
January 29, 2013
On Monday, 28 January 2013 at 23:11:11 UTC, Walter Bright wrote:
> http://www.drdobbs.com/cpp/implementing-half-floats-in-d/240146674
>
> Anyone care to do the reddit honors?

Very nice. I learnt quite a bit there.
btw:
"In order to restrict it to only accepting floats, turn it into a template and check the type with static if:" - you actually use a static assert. But while we're at it: Why *don't* you use a signature constraint with if? I feel it would be more fitting to constrain the constructor usage.

Stephan
January 29, 2013
On 1/29/2013 2:43 AM, Stephan wrote:
> Why *don't* you use a signature constraint with if?

To get a custom error message.
January 29, 2013
On 01/29/2013 11:40 AM, TommiT wrote:
> On Tuesday, 29 January 2013 at 08:48:24 UTC, Simen Kjaeraas wrote:
>> Except that's not a literal. 1.3.hf would be a function call, while
>> hf!1.3f
>> is a template instantiation.
>
> Can't help but point out, that some time ago, I made a suggestion to add
> a new function attribute to the language that would mean "evaluate any
> call to this function at compile time whenever it's possible". That
> would enable literals like:
>
> 1.3.hf
> and
> ComplexToConstruct(2.5, 7.5)
>
> Given:
> @property HalfFloat hf(float v) @aggressive_ctfe;
> and...
> struct ComplexToConstruct
> {
>      this(float x, float y) @aggressive_ctfe;
> }

I'd call it @constfold.
January 29, 2013
On Tuesday, 29 January 2013 at 11:26:00 UTC, Timon Gehr wrote:
>
> I'd call it @constfold.

That's a good name. Descriptive and short.

I'm not going to try to push this suggestion any harder, since it got no support on the first time I tried it. But I'd like to mention just one thing that came to mind:

The generic solution without any extra function attributes:

template ct(alias expr)
{
    enum ct = expr;
}

Literal of type TypeWithNonTrivialConstructor:

ct!(TypeWithNonTrivialConstructor(2.5, 7.5))

The above solution throws the responsibility of the correct use of TypeWithNonTrivialConstructor on the end-user. Whereas a @constfold attribute on the constructor of TypeWithNonTrivialConstructor automates the correct behaviour.
January 29, 2013
On Monday, 28 January 2013 at 23:11:11 UTC, Walter Bright wrote:
> http://www.drdobbs.com/cpp/implementing-half-floats-in-d/240146674


Since it got lost in the old thread on this topic, I'll repost my versions of floatToshort and shortToFloat, which are extremely fast (no unpredictable branches, no lookup tables) and respect the current rounding mode:

-----------------

float shortToFloat(ushort s)
{
    // note this is a signed shift, so sign bit gets smeared all the way into the int bit!
    uint u = ((cast(int)cast(short)s) << 13);

    if ( (s & EXPMASK) == 0 )
    {   // Subnormal or 0.
        // The simple conversion is wrong in two ways:
        // (1) it's added an implicit bit. This has value 0x1p-15.
        // (2) the mantissa bits got shifted along to make space for the hidden bit.
        //     So we need to multiply the result by 2.
        // Note that 0x3880_0000 means 0x1p-14.

        uint v = (u & 0x0FFF_FFFF ) + 0x3880_0000;
        float f = *cast(float *)&v - 0x1p-14;
        u = (u & 0x8000_0000) | *cast(uint *)&f;
        return *cast(float *)&u;
    }

    u = (u & 0x8FFF_FFFF) + 0x3800_0000;

    if ( (s & EXPMASK) == EXPMASK )
    {   // infinity or NaN
        u |= FEXPMASK;
    }
    return *cast(float *)&u;
}


-----------------
NOTE: this only works on 64-bit runtime, for 32bit or CTFE with 80-bit intermediates, the constants need to be changed. Unfortunately I don't know of a nice way to detect the size of the intermediates.
-----

ushort floatToShort(float f)
{
    // Remember the sign
    uint x = *cast(uint *)&f;

    ushort sgn = (x >> 16) & 0x8000;

    // Need to treat NaN and Inf specially, otherwise the
    // mantissa shortening step would generate a new NaN.
    if ( (x & FEXPMASK) == FEXPMASK)
        return ( (x >> 13) & 0x7FFF) | sgn;

    // Shorten the mantissa, rounding it according to the current rounding mode

    f = (f * (1.0f + 0x1p-13f) -f) * 0x1p13f;

    // Force large numbers to overflow my moving near float.max

    f *= 0x1p112f;
    f *= 0x1p-112f; // Then undo it

    // Force small numbers to underflow, and shift into position

    f *= 0x1p-112f;

    uint u = *cast(uint *)&f;

    return ((u>>13) & 0x7FFF) | sgn;
}
January 29, 2013
On Monday, 28 January 2013 at 23:11:11 UTC, Walter Bright wrote:
> http://www.drdobbs.com/cpp/implementing-half-floats-in-d/240146674

In the heat of coding, I think, the end-user is quite likely to make the honest mistake of writing:

HalfFloat h = HalfFloat(1.3f);

...when he should be writing:

HalfFloat h = hf!1.3f;

January 29, 2013
On 1/29/2013 4:31 AM, Don wrote:
> Since it got lost in the old thread on this topic, I'll repost my versions of
> floatToshort and shortToFloat, which are extremely fast (no unpredictable
> branches, no lookup tables) and respect the current rounding mode:

I was waiting on incorporating your improvements until after std.halffloat was merged into Phobos. This is because the old ones were easier to understand, and I wanted them in the repository history.