2008-10-06 6 views
11

1. Jak mogę ponownie zinterpretować rzutowanie zmiennoprzecinkowe na int (lub podwójne na długie)?Jak ponownie zinterpretować rzutowanie float na int? Czy istnieje niestatyczny operator konwersji lub operator przypisania przypisany przez użytkownika do konwersji na "to"?

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

Chcę tylko, aby skopiować-bitowy wzorzec z f do i. Jak to zrobić?

2. niejawne i jawnych operatorów C# wykorzystuje jeden pośredni obiektu, ponieważ funkcja operator statyczne

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

Jest to dobre w przypadku grup odniesienia, ale wartość typów, które są duże (powiedzmy 20- 30 bajtów), spowoduje to niepotrzebne kopiowanie danych. Czy moje zrozumienie jest poprawne? A jeśli tak, to dlaczego C# nie ma operatora konwersji statycznej lub operatora przypisania zdefiniowanego przez użytkownika, tak aby konwersja/przypisanie odbywało się w "tym"? Jeśli tak, to w jaki sposób to zrobić?

+4

W przyszłości proszę umieszczać dwa odrębne pytania. –

+4

i nie pisz całego tekstu w nagłówku. – shoosh

Odpowiedz

8
  1. Klasa BitConverter można pobrać bajtów dla każdego typu prymitywnego, które można następnie wykorzystać do tworzenia int. Inną opcją jest Buffer.BlockCopy, jeśli masz dużą liczbę konwersji do zrobienia.

    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 
    
  2. Nie istnieje żadna inna opcja podana w języku C#, jednak myślę, że gdy jesteś poprawne w tym sensie, że nie będzie kopia wykonana, każda dostatecznie prosta implementacja będzie miał optymalizacje JIT zrobić, ewentualnie usunięcie potrzeby kopiowania.

+0

Nie jest jasne, czy uczynienie operatora operatorem instancji i tak usunęłoby potrzebę kopiowania. Pytanie wydaje mi się nieco zdezorientowane. –

+0

Wracając do '08, założyłem, że JIT będzie zachowywał się podobnie do kompilatora C++ w.r.t. metody członkowskie, ale jeszcze nie widziałem, żeby to działało w praktyce. – user7116

8

1: BitConverter (jako sześć zmiennych binarnych) jest opcją; tak jak kod niebezpieczny (który nie potrzebuje bufora pośredniego):

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: należy pamiętać, że należy ograniczyć rozmiar struktur. Nie mogę znaleźć cytatu z tego, ale liczba "16 bajtów" (max, jako zalecenie) wydaje się trzymać w mojej głowie. Przede wszystkim rozważ niezmienny typ referencyjny (klasa).

8

Blokowanie niebezpieczny kod - jest to najszybsza metoda znam wykonać reinterpretacji:

[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; 
     ... 

Hope this helps kogoś.

1

To podejście, choć niebezpieczne, pracuje jako ogólne rozwiązanie

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); 
} 
Powiązane problemy