c# – Specifying the size of a structure bit field

Question:

For the convenience of working with numbers of the System.Double type ( float64 ), I would like to describe a similar structure:

// cpp code
union float64
{
    double x;
    struct
    {
        unsigned long long mant : 52;
        unsigned long long exp  : 11;
        unsigned long long sign : 1;
    };

    float64(double val) { x = val; }
};

float64 f = -4.0;
// f.mant == 0
// f.exp == 1025 (- 1023 == 2)
// f.sign == 1

In other words, I need the bottom line of floating point numbers, described by the IEC 60559:1989 (IEEE 754) standard , in a quick, so to speak, access

In C++ , this is very easy to express in terms of bit fields . However, I couldn’t figure out how to do this in C# (elegantly): using MarshalAsAttribute.SizeConst is only valid for strings and arrays

So the only option that I see so far is to use fixed fields, from which the number I need will then be loaded. But this solution seems a bit cumbersome to me…


Is it possible to specify a certain size of a bit field using C#, and if so , how to do this?

Answer:

https://ideone.com/wGW2qq

using System;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Explicit)]
struct Float64
{
  public Float64(double x) { ULong = 0; Double = x; }
  public static implicit operator Float64(double x) { return new Float64(x); }
  public static implicit operator double(Float64 x) { return x.Double; }

  [FieldOffset(0)] public double Double;
  [FieldOffset(0)] public ulong  ULong;

  public ulong Mantissa
  {
    get { return ULong & 0xFFFFFFFFFFFFF; }
    set { ULong = ULong & ~0xFFFFFFFFFFFFFULL | value & 0xFFFFFFFFFFFFFULL; }
  }

  public uint Exp
  {
    get { return (uint)((ULong >> 52) & 0x7FF); }
    set { ULong = ULong & 0x800FFFFFFFFFFFFFULL | ((ulong)(value & 0x7FF) << 52); }
  }

  public uint Sign
  {
    get { return (uint)(ULong >> 63); }
    set { ULong = ULong & 0x7FFFFFFFFFFFFFFFULL | ((ulong)value << 63); }
  }
}

public class Test
{
  private static void Print(Float64 x)
  {
    Console.WriteLine("{0,7} {1:X16} s={4} m={2:X13} e={3:X3}", x.Double, x.ULong, x.Mantissa, x.Exp, x.Sign);
  }

  public static void Main()
  {
    foreach (var d in new double [] { 0,1,-1,2,-2,3,-3,3.25,-3.25 })
      Print(d);

    Float64 x = 1;
    Print(x);
    ++x.Exp; Print(x); // 2
    x.Sign = 1; Print(x); // -2
    x.Mantissa += 1ULL << 51; Print(x); // -3
    --x.Exp; Print(x); // -1.5
  }
}
      0 0000000000000000 s=0 m=0000000000000 e=000
      1 3FF0000000000000 s=0 m=0000000000000 e=3FF
     -1 BFF0000000000000 s=1 m=0000000000000 e=3FF
      2 4000000000000000 s=0 m=0000000000000 e=400
     -2 C000000000000000 s=1 m=0000000000000 e=400
      3 4008000000000000 s=0 m=8000000000000 e=400
     -3 C008000000000000 s=1 m=8000000000000 e=400
   3.25 400A000000000000 s=0 m=A000000000000 e=400
  -3.25 C00A000000000000 s=1 m=A000000000000 e=400
      1 3FF0000000000000 s=0 m=0000000000000 e=3FF
      2 4000000000000000 s=0 m=0000000000000 e=400
     -2 C000000000000000 s=1 m=0000000000000 e=400
     -3 C008000000000000 s=1 m=8000000000000 e=400
   -1.5 BFF8000000000000 s=1 m=8000000000000 e=3FF
Scroll to Top