the Fiddler's picture

OpenTK.Math.Half

Project:The Open Toolkit library
Component:Code
Category:feature request
Priority:normal
Assigned:Inertia
Status:closed
Description

This type should provide an interface similar to IntPtr, with a methods, conversion operators and constructors that can pack/unpack floats and doubles.

I'm opening this task so we can keep track of progress.


Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
the Fiddler's picture

#41

I just took a look at System.Single and it implements several useful interfaces. I'm adding these one by one and will post an update here when ready. We should also make the Positive/NegativeInfinity and NaN values public.

Inertia's picture

#42

[NaN]
It appears the half float spec works this:

(E=Exponent, M=Mantissa. E==31 means all 5 exponent bits are set.

Infinity: if E == 31 and M == 0, Sign bit determines positive or negative infinity
NaN: if E == 31 and M != 0, Sign irrelevant

0 11111 0000000000 = +infinity
1 11111 0000000000 = -infinity

* 11111 1000000000 = NAN
* 11111 1111111110 = NAN
* 11111 1111111111 = NAN

The IsNaN property should be changed to this:

return (((_internalBits & 0x7c00) == 0x7c00) && (_internalBits & 0x03ff) != 0x0000) ? true : false;

...and we should probably look at the throwOnError overloads again, because testing for Single.IsNaN might not be sufficient.

the Fiddler's picture

#43

I've been playing with the code, some remarks follow.

It seems there is a negative zero, 0xFFFF.

You don't need to use the ternary operator, the following are equivalent:

return (((_internalBits & 0x7c00) == 0x7c00) && (_internalBits & 0x03ff) != 0x0000) ? true : false;
return (((_internalBits & 0x7c00) == 0x7c00) && (_internalBits & 0x03ff) != 0x0000);

Does it make sense to have comparison operators? Equality can be written like this (algorithm explanation):

        // Defines how many numbers should lie between two halves before
        // the halves are considered unequal.
        const short max_difference = 1;
 
        // Untested
        public bool Equals(Half other)
        {
            short a, b;
            unchecked { aInt = (short)other._internalBits; }
            unchecked { bInt = (short)this._internalBits; }
 
            // Make aInt lexicographically ordered as a twos-complement int
            if (a < 0)
                aInt = (short)(0x8000 - aInt);
 
            // Make bInt lexicographically ordered as a twos-complement int
            if (b < 0)
                bInt = (short)(0x8000 - bInt);
 
            short diff = System.Math.Abs((short)(a - b));
 
            if (diff <= max_difference)
                return true;
 
            return false;
        }

Comparison is a little more difficult, as it has to follow more complex rules (when one is NaN and the other isn't.)

Attached is a slightly updated Half.cs (sorry, no project since I only have VS2008 here).

AttachmentSize
Half v6.1.7z4.71 KB
Inertia's picture

#44

[-0.0f]
Good catch.

[conditional]
Don't think I'll have to single-step through it again, np.

[comparison operators]
I'd have implemented it like this:

public bool Equals(Half other)
{
   return (this._bits == other._bits);
}

The only purpose I can think of for that method is testing if data you saved to disk is correct. Let's keep this type a container and not open the door for any math.

Inertia's picture

#45

Just noticed you made no modifications to Half4 at all, do you consider it good the way it is? I.e. time to derive Half23 from it?

the Fiddler's picture

#46

Half4 looks alright, but I didn't check thoroughly (went for Half first then ran out of time).

I'm kinda tied up with text rendering right now (need it for my project asap), so I've had to put Half on the back burner. I'll try to help whenever I can, but I'm a little pressed for time.

I think it's desirable to implement IEquatable, IComparable and IFormatable interfaces. Not so sure about IComparable (non-generic) and IConvertible - don't know how useful they will be in practice.

I'm also not sure that Pack = 0 is allowed for StructLayout (thought Pack = 1 was the smallest, but haven't verified).

Inertia's picture

#47

Sorry for bothering again, the other interfaces were a joke, but is there any reason why you wrote that huge documentation about Half.CompareTo() instead of just using this?

public int CompareTo(Half other)
{  
  return ((float)this).CompareTo((float)other);
}

I understand you want NaN and infinity dealt with, but on the other hand you don't want to move 1 inch away from established .Net protocol? *confused*

the Fiddler's picture

#48

The huge documentation describes exactly what your code snippet does (this *is* the established .Net protocol :) )

Inertia's picture

#49

Alright, the handling of NaN's sounded a bit weird when comparing them to numbers or infinity. But I guess it makes sense when you sort a list that all NaNs appear at the "bottom" of the list. Any objection to implement it by casting to float as seen above? (the cast is inevitable either way)

the Fiddler's picture

#50

Fine by me.