Est-il possible de convertir C # double [,,] tableau en double [] sans faire de copie

StackOverflow https://stackoverflow.com/questions/96054

  •  01-07-2019
  •  | 
  •  

Question

J'ai une énorme matrice de nombres en 3D dans mon application .NET. Je dois les convertir en tableau 1D pour le transmettre à une bibliothèque COM. Y at-il un moyen de convertir le tableau sans faire une copie de toutes les données?

Je peux faire la conversion de cette façon, mais j'utilise deux fois plus de mémoire, ce qui pose problème dans mon application:

  double[] result = new double[input.GetLength(0) * input.GetLength(1) * input.GetLength(2)];
  for (i = 0; i < input.GetLength(0); i++) 
    for (j = 0; j < input.GetLength(1); j++) 
      for (k = 0; k < input.GetLength(2); k++) 
        result[i * input.GetLength(1) * input.GetLength(2) + j * input.GetLength(2) + k)] = input[i,j,l];
  return result;
Était-ce utile?

La solution

Je ne crois pas que la manière dont C # stocke ces données en mémoire le rende réalisable de la même manière que le ferait une distribution simple en C. Pourquoi ne pas utiliser un tableau 1d pour commencer et peut-être créer une classe pour le type afin de pouvoir y accéder dans votre programme comme s'il s'agissait d'un tableau 3D?

Autres conseils

Malheureusement, il n’est pas garanti que les tableaux C # se trouvent dans une mémoire contiguë comme ils le sont dans des langages plus proches du métal, tels que C. Donc, non. Il n’ya aucun moyen de convertir double [,,] en double [] sans une copie élément par élément.

Envisagez de supprimer l'accès aux données avec un proxy (similaire à des itérateurs / pointeurs intelligents). en C ++). Malheureusement, la syntaxe n’est pas aussi simple que C ++, car operator () n’est pas disponible pour la surcharge et operator [] est à argument unique, mais reste proche.

Bien sûr, ce niveau supplémentaire d’abstraction ajoute à la complexité et au travail qui lui est propre, mais il vous permettrait d’apporter des modifications minimales au code existant qui utilise des objets doubles [,,], tout en vous permettant d’utiliser un simple double []. tableau pour interop et votre calcul en C #.

class Matrix3
{
    // referece-to-element object
    public struct Matrix3Elem{
        private Matrix3Impl impl;
        private uint dim0, dim1, dim2;
        // other constructors
        Matrix3Elem(Matrix3Impl impl_, uint dim0_, uint dim1_, uint dim2_) {
            impl = impl_; dim0 = dim0_; dim1 = dim1_; dim2 = dim2_;
        }
        public double Value{
            get { return impl.GetAt(dim0,dim1,dim2); }
            set { impl.SetAt(dim0, dim1, dim2, value); }
        }
    }

    // implementation object
    internal class Matrix3Impl
    {
        private double[] data;
        uint dsize0, dsize1, dsize2; // dimension sizes
        // .. Resize() 
        public double GetAt(uint dim0, uint dim1, uint dim2) {
            // .. check bounds
            return data[ (dim2 * dsize1 + dim1) * dsize0 + dim0 ];
        }
        public void SetAt(uint dim0, uint dim1, uint dim2, double value) {
            // .. check bounds
            data[ (dim2 * dsize1 + dim1) * dsize0 + dim0 ] = value;
        }
    }

    private Matrix3Impl impl;

    public Matrix3Elem Elem(uint dim0, uint dim1, uint dim2){
        return new Matrix2Elem(dim0, dim1, dim2);
    }
    // .. Resize
    // .. GetLength0(), GetLength1(), GetLength1()
}

Ensuite, en utilisant ce type à la fois en lecture et en écriture, 'foo [1,2,3]' s’écrit désormais sous la forme 'foo.Elem (1,2,3) .Value', en lecture et en écriture valeurs, à gauche des expressions d'affectation et de valeur.

void normalize(Matrix3 m){

    double s = 0;
    for (i = 0; i < input.GetLength0; i++)     
        for (j = 0; j < input.GetLength(1); j++)       
            for (k = 0; k < input.GetLength(2); k++)
    {
        s += m.Elem(i,j,k).Value;
    }
    for (i = 0; i < input.GetLength0; i++)     
        for (j = 0; j < input.GetLength(1); j++)       
            for (k = 0; k < input.GetLength(2); k++)
    {
        m.Elem(i,j,k).Value /= s;
    }
}

Encore une fois, des coûts de développement supplémentaires ont été ajoutés, mais les données sont partagées, ce qui élimine les frais généraux liés à la copie et les coûts de développement associés. C'est un compromis.

Pour contourner le problème, vous pouvez créer une classe qui conserve le tableau sous une forme à une dimension (peut-être même plus proche du métal nu afin de pouvoir le transmettre facilement à la bibliothèque COM?), puis surcharger l'opérateur [] de cette classe à rendez-le utilisable comme tableau multidimensionnel dans votre code C #.

Sans connaître les détails de votre bibliothèque COM, je chercherais à créer une classe de façade dans .Net et à l'exposer à COM, si nécessaire.

Votre façade prendrait un double [,,] et aurait un indexeur qui mapperait de [] à [,,].

Edit: je suis d’accord sur les points soulevés dans les commentaires, la suggestion de Lorens est meilleure.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top