繁体   English   中英

如何将数组长度划分为长度为3的倍数的数组

[英]How to divide Array Length into arrays with lengths that are multiples of 3

所以我有一个相当大的数组,其中包含xyz坐标,其中array [0] = x0,array [1] = y0,array [2] = z0,array [3] = x1,array [4] = y1 ...等等。

我正在此数组上运行算法,该算法花费的时间比我想要的要长,并且我想将工作分配给多个线程。 我已经设置了线程,但是我不确定如何正确划分此数组,因此我可以在3个线程中分配此工作。

即使我的数组长度可以被3整除,这也不起作用,因为将其拆分为3可以拆分xyz坐标(例如,如果我的数组大小为15,则将其除以3会得到5个数组,这意味着我正在分割XYZ坐标。

我如何拆分此数组(它的大小不必一定相等)以便可以分配工作? (例如,在前面的示例中,我希望有两个大小为6的数组和一个大小为3的数组)。

注意:数组的大小是可变的,但始终可以被3整除。

编辑:对不起,应该提到我正在使用Java。 我的算法会遍历一组坐标,并确定哪些坐标位于特定的3d形状(例如椭圆形)内。 它会保存这些坐标,并使用这些坐标执行其他任务(我正在使用计算机图形应用程序)。

EDIT2:我将详细说明算法。

基本上,我正在使用Android OpenGL-ES-3.0。 我有一个复杂的3D对象,大约有230000个顶点,接近一百万个三角形。

在应用程序中,用户将椭圆形或框(他们选择哪个)移动到靠近对象或在对象上的位置。 移动它之后,他们单击一个按钮,该按钮将运行我的算法。

该算法的目的是确定我的物体中的哪些点位于椭圆形或盒子内。 这些点随后更改为其他颜色。 但是,更复杂的是,我将变换矩阵应用于对象的点和椭球/盒子的点。

我当前的算法始于遍历对象的所有点。 对于那些在我的迭代中不清楚的人,这就是我的循环。

for(int i = 0; i < numberOfVertices*3;)
{ 
   pointX = vertices[i];
   i++;
   pointY = vertices[i];
   i++;
   pointZ = vertices[i];
   i++;
   //consider transformations, then run algorithm
 }

我执行必要的步骤来考虑所有转换,然后完成操作,从对象和椭圆形/盒形质心的位置得出一个点。

然后,根据形状,使用以下算法之一:

椭球体:我使用椭圆的质心并应用公式(x-c)T RT AR(x-c)(对不起,我不知道该如何格式化,我将解释该公式)。 x是一个列向量,描述了我在迭代中所处的对象的xyz点。 c是描述我质心的xyz点的列向量。 T应该意味着转置。 R是我的旋转矩阵。 A是一个对角矩阵,其条目为(1 / a ^ 2、1 / b ^ 2、1 / c ^ 2),并且我具有ab和c的值。 如果此公式> 1,则x位于我的椭球之外,并且不是有效点。 如果<= 1,则保存x。

方框:我只是检查该点是否在范围内。 如果对象的点与质心在X方向,Y方向和Z方向上相距一定距离,则将其保存。

这些算法是准确的,并且可以按预期工作。 问题显然是效率。 我似乎对什么使我的应用程序感到压力,而哪些没有导致压力,没有很好的了解。 我以为多线程可以工作,因此我尝试了所描述的一些技术,但是它们在性能上没有显着改善。 如果有人对过滤掉我的搜索有想法,所以我不必遍历所有这些观点,那将会有所帮助。

我可以建议一种稍微不同的处理方式。 我知道这不是您问题的直接答案,但请考虑一下。

如果将其实现为坐标对象(每个对象分别具有x,y和z值),则可能更容易看到。 您的“数组”现在将是1/3的长度。 您可能会认为这样做效率不高(也许是正确的),但是您会对Java可以优化事物的效果感到惊讶。 Java通常会针对人们使用最多的情况进行优化,并且您建议的手动操作该数组可能比使用对象还要慢。 在证明最易读的设计太慢之前,不应对它进行优化。

现在,您有了坐标对象的集合。 Java具有多个线程可以有效地从中拉出的队列。 将所有对象转储到队列中,并让每个线程将其拉出并通过处理并将其放入“已完成”队列中进行处理。 请注意,这使您能够轻松添加或删除线程,而不会影响代码(除了1个数字)。 您如何将基于数组的解决方案带到4个或6个线程?

祝好运

这是下面解释的工作的演示

意见

  • 每个坐标是3个索引。
  • 您有3个线程。

假设您有17个坐标,即51个​​索引。 您想在3个线程中分配17个坐标。

var arraySize = 51;
var numberOfThreads = 3;
var numberOfIndexesPerCoordinate = 3;
var numberOfCoordinates = arraySize / numberOfIndexesPerCoordinate; //17 coordinates

现在在线程之间拆分那17个坐标。

var coordinatesPerThread = numberOfCoordinates / numberOfThreads; //5.6667

这不是偶数,因此您需要分配不均。 我们可以使用Math.floor和modulo进行分发。

var floored = Math.floor(coordinatesPerThread); //5 - every thread gets at least 5.
var modulod = numberOfCoordinates % floored; // 2 - there will be 2 left that need to be placed sequentially into your thread pool

这应该为您提供所需的所有信息。 在不知道您使用哪种语言的情况下,我不想提供任何实际的代码示例。


我看到您编辑了问题以将Java指定为您的语言。 我不会为您做线程工作,但是我会给出一个大概的想法。

float[] coordinates = new float[17 * 3]; //17 coordinates with 3 indexes each.
int numberOfThreads = 3;
int numberOfIndexesPerCoordinate = 3;
int numberOfCoordinates = coordinates.length / numberOfIndexesPerCoordinate ; //coordinates * 3 indexes each = 17

//Every thread has this many coordinates
int coordinatesPerThread = Math.floor(numberOfCoordinates / numberOfThreads);
//This is the number of coordinates remaining that couldn't evenly be split.
int remainingCoordinates = numberOfCoordinates % coordinatesPerThread

//To make things easier, I'm just going to track the offset in the original array. It could probably be computed instead, but its just an int.
int offset = 0;
for (int i = 0; i < numberOfThreads; i++) {
    int numberOfIndexes = coordinatesPerThread * numberOfIndexesPerCoordinate;

    //If this index is one of the remainders, then increase by 1 coordinate (3 indexes).
    if (i < remainingCoordinates)
        numberOfIndexes += numberOfIndexesPerCoordinate ;

    float[] dest = new float[numberOfIndexes];
    System.arraycopy(coordinates, offset, dest, 0, numberOfIndexes);
    offset += numberOfIndexes;

    //Put the dest array of indexes into your threads.
}

另一个可能更好的选择是使用并发双端队列,该并发双端队列具有您的所有坐标,并且每个线程都需要从中拉出,因为它们需要使用新的坐标。 对于此解决方案,您需要创建Coordinate对象。

声明一个坐标对象

public static class Coordinate {
    protected float x;
    protected float y;
    protected float z;

    public Coordinate(float x, float y, float z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }
}

声明一个任务来完成您的工作,然后将其并发双端队列传递给它。

public static class CoordinateTask implements Runnable {
    private final Deque<Coordinate> deque;

    public CoordinateTask(Deque<Coordinate> deque) {
        this.deque = deque;
    }

    public void run() {
        Coordinate coordinate;

        while ((coordinate = this.deque.poll()) != null) {
            //Do your processing here.
            System.out.println(String.format("Proccessing coordinate <%f, %f, %f>.",
                coordinate.x,
                coordinate.y,
                coordinate.z));
        }
    }
}

这是显示实际示例的主要方法

public static void main(String []args){

    Coordinate[] coordinates = new Coordinate[17];

    for (int i = 0; i < coordinates.length; i++)
        coordinates[i] = new Coordinate(i, i + 1, i + 2);

    final Deque<Coordinate> deque = new ConcurrentLinkedDeque<Coordinate>(Arrays.asList(coordinates));

    Thread t1 = new Thread(new CoordinateTask(deque));
    Thread t2 = new Thread(new CoordinateTask(deque));
    Thread t3 = new Thread(new CoordinateTask(deque));

    t1.start();
    t2.start();
    t3.start();

}

看到这个演示

在尝试并发优化之前,请尝试使用可使用的最有效的冲突检测方法,以尽量减少需要测试的点数,并最小化这些测试的成本。

一些一般性建议:

  • 在进行计算之前,请考虑将所有内容归一化为公共参考系。 例如,不对每个点应用变换,而是将选择框/椭球变换为形状的坐标系,这样就可以执行碰撞检测,而无需在每次迭代中进行变换。

    您也许还可以将部分或全部转换(旋转,平移等)合并到一个矩阵计算中,但是除非您执行大量转换,否则您将不会获得太多收益,您应该尝试这样做避免。

    一般来说,使转换管线尽可能简化是有益的,并且将所有坐标计算保持在同一空间中,以尽可能避免转换。

  • 尽量减少执行最慢计算所需的点数。 仅对于不能通过更快的方法排除在形状内部的点,才需要进行最精确的碰撞测试,方法是使用形状的近似值,例如球体的集合或形状的凸包。 简化形状可以使最慢的计算仅限于非常接近形状实际边界的那些点。

    在过去的2D工作中,我发现即使实时计算数百个复杂动画形状的凸包,也比不使用凸包直接进行碰撞检测要快,因为它们可以更快地计算碰撞。

  • 考虑计算/存储有关形状的其他信息,例如内部和外部碰撞球体(所有点内部为一个球体,所有点外部为一个球体),您可以将其用作快速初始过滤器。 较小球体内部的任何东西都可以保证在您的形状内,而外部球体外部的任何东西都可以在您的形状外。 您甚至可能想要存储形状的简化版本(或其凸包),可以预先计算并用于碰撞检测。

  • 同样,在初始计算中考虑使用一个或多个球体近似椭圆体,以最大程度地减少需要测试碰撞的点。

  • 代替计算实际距离,而是计算平方距离并将其用于比较。 但是,如果可能的话,最好使用更快的碰撞测试。 例如,对于凸多边形,可以使用“分离轴定理”,该定理将顶点投影到公共轴/平面上,从而可以非常快速地进行重叠计算。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM