There are three ugly possibilities.
- use pointer aliasing,
- BitConverter.GetBytes,
- simulate an union.
[StructLayout(LayoutKind.Explicit)] struct FloatIntUnion { [FieldOffset(0)] public int i; [FieldOffset(0)] public float f; } // Returns the next float after x in the direction of y. float NextAfter(float x, float y) { if (float.IsNaN(x) || float.IsNaN(y)) return x + y; if (x == y) return y; // nextafter(0, -0) = -0 FloatIntUnion u; u.i = 0; u.f = x; // shut up the compiler if (x == 0) { u.i = 1; return y > 0 ? u.f : -u.f; } if ((x > 0) == (y > x)) u.i++; else u.i--; return u.f; }
Thanks a lot, great stuff!
ReplyDeleteAre there likely to be any issues when using this technique on mobile platforms like iOS, the varying flavours of Android, Windows Phone, etc?
(using Mono)
For future seekers like me, coming here from Google:
ReplyDeleteIt can also be done with BitConverter.DoubleToInt64Bits method which doesn't seem to allocate anything. It is done this way in C.math.NET library, take a look at its source here: https://github.com/MachineCognitis/C.math.NET/blob/master/C.math/math.cs#L1649-L1803
Well, seems like actually I might be wrong... In case of Mono and Unity even DoubleToInt64Bits seems to generate some garbage - probably Unity/Mono implementation differs from VC#'s one.
Delete