Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Arrays 将二维双精度阵列转换为动态二维双精度阵列的最快方法_Arrays_Delphi_Pointers_Dynamic Arrays_Variant - Fatal编程技术网

Arrays 将二维双精度阵列转换为动态二维双精度阵列的最快方法

Arrays 将二维双精度阵列转换为动态二维双精度阵列的最快方法,arrays,delphi,pointers,dynamic-arrays,variant,Arrays,Delphi,Pointers,Dynamic Arrays,Variant,我有一个由doublexyinport:=varrarycreate([0,Count-1,0,1],varDouble)组成的二维OLEVANT矩阵 我希望使用move()将(尽可能快的)转换为普通2D动态数组DestArray:Double数组的数组[0..1] 在解决这个问题的过程中,我使用了Count=5给出了每个维度预期的40字节。但是我发现指针(DestArray[0])和指针(DestArray[1])之间的地址差是56字节 那么中间的16个字节是什么呢?我不知道前8个字节,但最后

我有一个由double
xyinport:=varrarycreate([0,Count-1,0,1],varDouble)组成的二维OLEVANT矩阵

我希望使用
move()
将(尽可能快的)转换为普通2D动态数组
DestArray:Double数组的数组[0..1]

在解决这个问题的过程中,我使用了
Count=5
给出了每个维度预期的40字节。但是我发现
指针(DestArray[0])
指针(DestArray[1])
之间的地址差是56字节

那么中间的16个字节是什么呢?我不知道前8个字节,但最后8个字节是关于数组维度的信息

因此,
move()
无法在一个步骤中工作
move(VarArrayData^,指针(destary[0])^,BytesToMove)

我已经找到了一种方法,使用两个单独的动作,但我仍然有一种感觉,它可以做得更优雅

问题

  • 事实上,有没有更简单、更快捷的方法
  • 是否有任何编译器指令或类似指令可以更改动态数组的内存布局,以允许
    move()
    在一个步骤中工作
  • 出于好奇,在
    指针(DestArray[0])
    指针(DestArray[1])
    之间的内存间隙的前8个字节是多少
  • 以下是完整的代码片段:

    procedure TForm1.FormCreate(Sender: TObject);
    
    procedure PrintEqualityVerdictLine( value1 : Double; value2 : Double );
    const
      cEqualVerdict : array[Boolean] of String = ( '!!!Not Equal!!!', 'Equal' );
    begin
      Memo1.Lines.Add(FloatToStr(value1) + ' =? ' + FloatToStr(value2) + '      ' + cEqualVerdict[ SameValue( value1, value2, 0.001 ) ] );
    end;
    
    procedure VariantArrayOfDoubleToDynamicDoubleArray;
    var
      xyInput : OleVariant;
      Count: Integer;
      n: Integer;
    
      DestArray : packed array[0..1] of packed array of Double;
    
      V_Ptr: PVarData;
      VarArrayData: PVarData;
      BytesToMove: Integer;
    
      SourceBytePtr : PByte;
      BytesToMovePerColumn: Integer;
      DestBytePtr: PByte;
    begin
      // create 2 column OleVariant array:
      Count := 5;
      xyInput := VarArrayCreate([0, Count-1, 0, 1], varDouble );
    
      // fill test data:
      for n := 0 to Count-1 do
      begin
        xyInput[n, 0] := 1.0 * n;
        xyInput[n, 1] := 2.0 * Count + n;
      end;
    
      SetLength(DestArray[0], Count);
      SetLength(DestArray[1], Count);
    
      V_Ptr := PVarData(@xyInput);
      if ((V_Ptr^.VType and $F000 ) = varArray) and
         ((V_Ptr^.VType and varTypeMask ) = varDouble)
      then
      begin
        VarArrayData := PVarData(V_Ptr^.VArray^.Data);
        BytesToMovePerColumn := Count * V_Ptr^.VArray^.ElementSize;
        BytesToMove := BytesToMovePerColumn*V_Ptr^.VArray^.DimCount;
    
        // print 16 discovered intermediate bytes of the DestArray:
        DestBytePtr := Pointer(DestArray[0]);
        Inc(DestBytePtr, BytesToMovePerColumn);
        for n := 1 to 16 do
        begin
          Memo1.Lines.Add('byte['+IntToStr(n) + ']: ' + IntToStr( DestBytePtr^ ) );
          Inc(DestBytePtr);
        end;
    
    //    This does NOT work: col 1 of arr gets offset due to 16 discovered intermediate bytes:
    //        Move(VarArrayData^, Pointer(DestArray[0])^, BytesToMove );
    
    //    This works:
        SourceBytePtr := PByte(VarArrayData);
        Move(SourceBytePtr^, Pointer(DestArray[0])^, BytesToMovePerColumn );
        Inc(SourceBytePtr, BytesToMovePerColumn);
        Move(SourceBytePtr^, Pointer(DestArray[1])^, BytesToMovePerColumn );
      end;
    
      // print:
      Memo1.Lines.Add('VariantArrayOfDoubleToDoubleArray:');
    
      Memo1.Lines.Add('col 0:');
      for n := 0 to Count - 1 do
        PrintEqualityVerdictLine( xyInput[n, 0], DestArray[0, n] );
      Memo1.Lines.Add('');
    
      Memo1.Lines.Add('col 1:');
      for n := 0 to Count - 1 do
        PrintEqualityVerdictLine( xyInput[n, 1], DestArray[1, n] );
    end;
    
    begin
      Memo1.Lines.Clear;
      VariantArrayOfDoubleToDynamicDoubleArray;
    end;
    
    但是我发现
    指针(DestArray[0])
    指针(DestArray[1])
    之间的地址差是56字节

    这是非常值得期待的。好的,更清楚地说,没有理由期望
    DestArray[0]
    DestArray[1]
    将指向相邻的内存块

    你的类型是

    array[0..1] of array of Double;
    
    请注意,我删除了
    packed
    关键字,该关键字在应用于数组时被忽略。这里有一个包含两个指针的数组。这两个指针是独立的。看看如何分配动态数组

    SetLength(DestArray[0], Count);
    SetLength(DestArray[1], Count);
    
    每次调用
    SetLength
    都会导致单独的堆分配。没有任何理由使内存相邻。这是在讨论一个问题之前,动态数组在数组有效负载之前存储了一个额外的元数据块,每个内存块都有自己的元数据供内存管理器使用。因此,即使内存管理器碰巧提供了相邻的内存块,元数据也会位于两个数组之间。顺便说一句,这个内存管理器元数据就是问题3的答案

    从技术角度讲,您在
    DestArray
    中看到的是一个。另一方面,您似乎在寻找多维数组。Delphi实际上不支持动态多维数组。您所拥有的只是锯齿阵列。如果您想要一个连续的内存块,那么您需要分配一个一维内存块并自己执行索引计算

    因此,就目前情况而言,如果继续使用锯齿阵列,则需要为每个内部阵列执行一个副本。如果您切换到线性阵列,那么您可以只复制一个副本,但您必须执行自己的索引。当然,索引是非常容易做的,这可能是有效的。最后,您可以提前在Delphi中分配一个线性数组,并将指向该数组的指针放入变体中,从而完全避免复制

    但是我发现
    指针(DestArray[0])
    指针(DestArray[1])
    之间的地址差是56字节

    这是非常值得期待的。好的,更清楚地说,没有理由期望
    DestArray[0]
    DestArray[1]
    将指向相邻的内存块

    你的类型是

    array[0..1] of array of Double;
    
    请注意,我删除了
    packed
    关键字,该关键字在应用于数组时被忽略。这里有一个包含两个指针的数组。这两个指针是独立的。看看如何分配动态数组

    SetLength(DestArray[0], Count);
    SetLength(DestArray[1], Count);
    
    每次调用
    SetLength
    都会导致单独的堆分配。没有任何理由使内存相邻。这是在讨论一个问题之前,动态数组在数组有效负载之前存储了一个额外的元数据块,每个内存块都有自己的元数据供内存管理器使用。因此,即使内存管理器碰巧提供了相邻的内存块,元数据也会位于两个数组之间。顺便说一句,这个内存管理器元数据就是问题3的答案

    从技术角度讲,您在
    DestArray
    中看到的是一个。另一方面,您似乎在寻找多维数组。Delphi实际上不支持动态多维数组。您所拥有的只是锯齿阵列。如果您想要一个连续的内存块,那么您需要分配一个一维内存块并自己执行索引计算


    因此,就目前情况而言,如果继续使用锯齿阵列,则需要为每个内部阵列执行一个副本。如果您切换到线性阵列,那么您可以只复制一个副本,但您必须执行自己的索引。当然,索引是非常容易做的,这可能是有效的。最后,您可以提前在Delphi中分配一个线性数组,并将指向该数组的指针放入变体中,从而完全避免复制。谢谢您的输入和我对锯齿数组的首次介绍。如果元数据放在动态数组的末尾,那就太好了。但我会用一个长阵列的方法来尝试一下,这不会有帮助的。然后它将位于第一个数组的末尾。加上内存管理器元数据。另外,不保证块是相邻的。感谢您的输入和m