Как переинтерпретировать приведение float в int? Существует ли оператор нестатического преобразования или пользовательский оператор присваивания для преобразования на 'this'?

1. Как я могу переинтерпретировать приведение float к int (или двойному к длинному)?

float f = 2.0f;
int i = (int)f; // causes conversion

Я хочу только скопировать бит-шаблон из f в i. Как это можно сделать?

2. Неявные и явные операторы в С# используют один промежуточный объект, потому что операционная функция статична

public static implicit operator MyClass(double s)
{
    return new MyClass(s);
} 
..
..
MyClass m = 2.2; // this code uses 'm' and one intermediate object.

Это подходит для ссылочных типов, но для больших значений (например, 20-30 байтов) это приведет к ненужной копии данных. Правильно ли я понимаю? И если да, то почему у С# нет оператора нестатического преобразования или пользовательского оператора присваивания, чтобы преобразование/присвоение выполнялось на 'this'? Если да, то как это сделать?

Ответ 1

  • Класс BitConverter может извлекать байты для любого примитивного типа, который затем можно использовать для создания int. Другой вариант - Buffer.BlockCopy, если у вас есть большое количество конверсий.

    float ff = 2.0f;
    int ii = BitConverter.ToInt32(BitConverter.GetBytes(ff), 0);
    
    float[] ff = new float[...];
    int[] ii = new int[ff.Length];
    Buffer.BlockCopy(ff, 0, ii, 0, ff.Length * 4); // byte-wise copy of ff into ii
    
  • Нет никакого другого параметра, указанного в С#, однако, я думаю, что, хотя вы правы в том смысле, что будет сделана копия, любая достаточно простая реализация будет иметь оптимизацию JIT, возможно, необходимо для копирования.

Ответ 2

1: битконвертер (как шесть переменных переменных) является вариантом; как небезопасный код (который не нуждается в промежуточном буфере):

    float f = 2.0f;
    int i;
    // perform unsafe cast (preserving raw binary)
    unsafe
    {
        float* fRef = &f;
        i = *((int*)fRef);
    }
    Console.WriteLine(i);

    // prove same answer long-hand
    byte[] raw = BitConverter.GetBytes(f);
    int j = BitConverter.ToInt32(raw, 0);        
    Console.WriteLine(j);

2: обратите внимание, что вы должны ограничить размер структур. Я не могу найти цитату из этого, но число "16 байт" (макс, как рекомендация), похоже, остается в моем сознании. Выше этого, рассмотрите неизменный ссылочный тип (класс).

Ответ 3

Запрет небезопасного кода - это самый быстрый метод, который я знаю для выполнения реинтерпрета:

    [StructLayout(LayoutKind.Explicit)]
    private struct IntFloat
    {
        [FieldOffset(0)]
        public int IntValue;
        [FieldOffset(0)]
        public float FloatValue;
    }
    private static float Foo(float x)
    {
        var intFloat = new IntFloat { FloatValue = x };
        var floatAsInt = intFloat.IntValue;
        ...

Надеюсь, это поможет кому-то.

Ответ 4

Этот подход, хотя и небезопасный, работает как общее решение

static unsafe TDest ReinterpretCast<TSource, TDest>(TSource source)
{
    var tr = __makeref(source);
    TDest w = default(TDest);
    var trw = __makeref(w);
    *((IntPtr*)&trw) = *((IntPtr*)&tr);
    return __refvalue(trw, TDest);
}