Как переинтерпретировать приведение 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);
}