Skip to content

Instantly share code, notes, and snippets.

@StagPoint
Last active May 19, 2021 17:49
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save StagPoint/89c0bd378f446c843de79d946906ce96 to your computer and use it in GitHub Desktop.
Save StagPoint/89c0bd378f446c843de79d946906ce96 to your computer and use it in GitHub Desktop.
Convert between floating point and integral types in C# / Unity
// Copyright (c) 2016 StagPoint Software
// NOTE: C#-style unions (structs using FieldOffset to cause multiple fields to 'overlap' in memory) may not be allowed on
// some IL2CPP platforms? If you get a compile error related to using FieldOffset on your target platform, comment the
// following #define to force this code to use another method.
//
// The UnityEngine.Networking code on BitBucket uses (#if !INCLUDE_IL2CPP) to control whether to use unions, but that code
// may be out of date (Unity has so far failed to respond), but testing confirms that this method does work on at least one
// of the IL2CPP target platforms, so we've chosen a more explicit #define instead.
#define USE_UNION_FOR_CONVERSION
// If unions don't work on your target platform, the next best option is to use 'unsafe' code - https://msdn.microsoft.com/en-us/library/t2yzs44b.aspx
// If unsafe code is allowed on your target platform, you can allow unsafe code in Unity by following this link - http://answers.unity3d.com/answers/804152/view.html
// Once you have enabled Unity to use unsafe code, uncomment the following #define
//#define ALLOW_UNSAFE
namespace StagPoint.HoverNet
{
using System;
using System.Runtime.InteropServices;
public static class FloatConversion
{
#if USE_UNION_FOR_CONVERSION
public static uint ToInt32( float value )
{
var uf = new IntegerFloatUnion() { floatValue = value };
return uf.intValue;
}
public static ulong ToInt64( double value )
{
var uf = new IntegerFloatUnion() { doubleValue = value };
return uf.longValue;
}
public static float ToSingle( uint value )
{
var uf = new IntegerFloatUnion() { intValue = value };
return uf.floatValue;
}
public static double ToDouble( ulong value )
{
var uf = new IntegerFloatUnion() { longValue = value };
return uf.doubleValue;
}
/// <summary>
/// C#-style union used to convert between floating point and integral types, as an alternative to unsafe code.
/// This cannot be used with IL2CPP because the version of IL2CPP used by Unity does not convert FieldOffset,
/// or at least this is suggested in the Unity.Networking code available on BitBucket.
/// </summary>
[StructLayout( LayoutKind.Explicit )]
internal struct IntegerFloatUnion
{
[FieldOffset( 0 )]
public float floatValue;
[FieldOffset( 0 )]
public uint intValue;
[FieldOffset( 0 )]
public double doubleValue;
[FieldOffset( 0 )]
public ulong longValue;
}
#elif ALLOW_UNSAFE
public static unsafe float ToSingle( uint value )
{
return *(float*)&value;
}
public static unsafe double ToDouble( ulong value )
{
return *(double*)&value;
}
public static unsafe uint ToInt32( float value )
{
return *(uint*)&value;
}
public static unsafe ulong ToInt64( double value )
{
return *(ulong*)&value;
}
#else // Cannot use unions, and ALLOW_UNSAFE is not defined. There is no choice but to allocate memory each time a value is converted.
#warning "Converting between floating point types and integral types for network transmission causes memory allocations on IL2CPP platforms due to limitations in IL2CPP"
public static float ToSingle( uint value )
{
return BitConverter.ToSingle( BitConverter.GetBytes( value ), 0 );
}
public static double ToDouble( ulong value )
{
return BitConverter.ToDouble( BitConverter.GetBytes( value ), 0 );
}
public static uint ToInt32( float value )
{
return BitConverter.ToUInt32( BitConverter.GetBytes( value ), 0 );
}
public static ulong ToInt64( double value )
{
return BitConverter.ToUInt64( BitConverter.GetBytes( value ), 0 );
}
#endif
}
}
@benzsuankularb
Copy link

benzsuankularb commented Apr 15, 2017

Great, Any update for IL2CPP testing in every platforms.

Do I have to define "ALLOW_UNSAFE" myself, Or it's a system defined.

Thanks.

@StagPoint
Copy link
Author

@benzsuankularb sorry for the very late reply, didn't realize that I would not get notifications for comments....

You would have to define ALLOW_UNSAFE yourself, there is no system define for it. You can just comment out line 10 and uncomment line 15.

For what it's worth for everyone else reading this, I always use the "unsafe" option personally, and the only reason that it's not the default in the code is because Unity makes it a bit of a pain to enable unsafe and that isn't the default option.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment