类 Vector<E>

java.lang.Object
jdk.incubator.vector.Vector<E>
类型参数:
E - ETYPE 的盒装版本,向量的元素类型
已知子类:
ByteVector , DoubleVector , FloatVector , IntVector , LongVector , ShortVector

public abstract class Vector<E> extends Object
Vector 依赖于 Java 平台的预览特性:
程序只能在启用预览功能时使用 Vector
预览功能可能会在未来的版本中删除,或升级为 Java 平台的永久功能。
A 固定数量的 lanes 的序列,所有一些固定的 element type 例如 bytelong ,或 float 。每个泳道包含一个独立的元素类型值。对向量的操作通常是 lane-wise ,将一些标量运算符(例如 添加 )分布在参与向量的通道上,通常生成一个向量结果,其通道包含各种标量结果。当在支持平台上运行时,车道级操作可以由硬件并行执行。这种并行方式称为Single Instruction Multiple Data (SIMD) 并行。

在 SIMD 编程风格中,向量通道内的大多数操作都是无条件的,但条件执行的效果可以使用 masked operations 实现,例如 blend() ,在关联的 VectorMask 的控制下。使用cross-lane 操作实现除严格的车道流以外的数据移动,通常在关联的VectorShuffle 的控制下。车道数据和/或整个矢量可以使用各种车道方式重新格式化 转换 和字节方式重新格式化 重新诠释 ,通常在反射 VectorSpecies 对象的控制下,该对象选择不同于输入矢量的替代矢量格式。

Vector<E> 声明了一组对所有元素类型通用的向量操作(方法)。这些常见操作包括对通道值的一般访问、数据选择和移动、重新格式化以及所有原始类型共有的某些算术和逻辑操作(例如加法或比较)。

Public subtypes of Vector 对应特定的元素类型。这些声明了特定于该元素类型的进一步操作,包括对通道值的未装箱访问、对整数元素类型值的按位操作或对浮点元素类型值的超越操作。

一些 lane-wise 操作,例如 add 运算符,被定义为全服务命名操作,其中 Vector 上的相应方法出现在屏蔽和未屏蔽的重载中,并且(在子类中)也出现在协变覆盖(返回子类)中以及额外的标量广播重载(屏蔽和非屏蔽)。其他基于车道的操作,例如 min 运算符,被定义为部分服务(而非全服务)命名操作,其中 Vector 和/或子类上的相应方法提供一些但所有可能的重载和覆盖(通常是具有标量广播重载的未屏蔽变体)。最后,所有 lane-wise 操作(那些如前所述命名的,或者未命名的方法)都有一个相应的 operator token 声明为 VectorOperators 上的静态常量。每个运算符标记为操作定义一个符号 Java 表达式,例如 a + b 代表 ADD 运算符标记。 Vector 上提供了通用的 lane-wise 操作令牌接受方法,例如 一元车道 操作,并且与全服务命名操作具有相同的变体。

此包包含 Vector 的公共子类型,对应于每个受支持的元素类型:ByteVector ShortVector IntVector LongVector FloatVector DoubleVector

向量的 元素类型,称为 ETYPE,是基本类型 byteshortintlong floatdouble 之一。

Vector<E> 中的类型 EETYPEboxed 版本。例如,在类型 Vector<Integer> 中,E 参数为 IntegerETYPEint。在这样的向量中,每条车道都带有一个原始 int 值。这种模式也适用于其他原始类型。 (另见第 5.1.75.1.8 部分Java 语言规范.)

向量的 length 是通道数,它包含的通道数。当上下文清楚它属于哪个向量时,这个数字也被称为 VLENGTH。每个向量都有自己固定的VLENGTH,但不同的向量实例可能有不同的长度。 VLENGTH 是一个重要的数字,因为它估计单个向量运算的 SIMD 性能增益与作为向量运算基础的 VLENGTH 标量运算符的标量执行相比。

形状和种类

向量的信息容量由其 vector shape 决定,也称为其 VSHAPE 。每个可能的 VSHAPEVectorShape 枚举的成员表示,并表示该形状的所有向量共同共享的实现格式。因此,矢量的 位大小 是通过求助于其矢量形状来确定的。

某些 Java 平台仅对一种形状提供特殊支持,而其他平台则支持多种形状。典型平台不太可能支持此 API 描述的所有形状。出于这个原因,大多数矢量运算都在单个输入形状上工作,并在输出上产生相同的形状。改变形状的操作被清楚地记录为 shape-changing ,而大多数操作是 shape-invariant ,以避免仅支持一种形状的平台处于不利地位。对于当前的 Java 平台,有一些查询可以发现用于一般 SIMD 计算的 首选形状 或任何给定通道类型的最大可用形状。为了便于移植,使用此 API 的代码应首先查询支持的形状,然后在所选形状内使用形状不变操作处理所有数据。

元素类型和矢量形状的每个唯一组合确定一个唯一的 vector species 。矢量种类由 VectorSpecies<E> 的固定实例表示,所有相同形状的矢量和 ETYPE 共享。

除非另有说明,车道向量操作要求所有向量输入具有完全相同的 VSHAPEVLENGTH ,也就是说它们必须具有完全相同的种类。这允许相应的通道明确配对。 check() 方法提供了一种显式执行此检查的简单方法。

矢量形状 VLENGTHETYPE 都是相互约束的,因此 VLENGTH 乘以 每条通道的位大小 必须始终匹配矢量形状的位大小。因此,重新诠释 向量可以将其长度加倍当且仅当它要么将通道大小减半,要么改变形状。同样,当且仅当它要么将长度减半,要么改变向量的形状时,重新解释向量可能会使通道大小加倍。

向量子类型

Vector 声明了一组对所有元素类型(例如加法)通用的向量操作(方法)。具有具体元素类型的 Vector 子类声明了特定于该元素类型的进一步操作(例如访问通道中的元素值、对整数元素类型值的逻辑操作或对浮点元素类型值的超越操作) . Vector 有六个抽象子类对应于支持的元素类型集,ByteVector ShortVector IntVector LongVector FloatVector DoubleVector 。除了特定于类型的操作之外,这些类还支持创建矢量值(Vector 的实例)。它们公开与支持的物种相对应的静态常量,这些类型上的静态方法通常将物种作为参数。例如,FloatVector.fromArray 创建并返回指定种类的浮点向量,其中的元素从指定的浮点数组加载。建议将 Species 实例保存在 static final 字段中,以便运行时编译器优化创建和使用 Vector 值。

作为由类型化向量类定义的静态常量的示例,常量 FloatVector.SPECIES_256 是通道为 float 且向量大小为 256 位的唯一种类。同样,常量 FloatVector.SPECIES_PREFERRED 是在当前运行的 Java 平台上最支持处理 float 矢量通道的种类。

作为另一个示例,可以通过调用 DoubleVector.broadcast(dsp, 0.5) 获得 (double)0.5 的广播标量值,但需要参数 dsp 来选择结果向量的种类(以及因此的形状和长度)。

车道操作

在定义向量运算时,我们使用术语 lanes。向量中的车道数是它包含的标量元素的数量。例如,类型为 float 且形状为 S_256_BIT 的向量有八个通道,因为 32*8=256

对向量的大多数操作都是按车道进行的,这意味着该操作由一个底层标量运算符组成,它对输入向量的每个不同车道重复。如果有相同类型的其他向量参数,则它们的通道与第一个输入向量的通道对齐。 (它们必须都有一个共同的 VLENGTH 。)对于大多数 lane-wise 操作,从 lane-wise 操作产生的输出将有一个 VLENGTH,它等于操作输入的 VLENGTH。因此,这种基于车道的操作在其基本定义中是 length-invariant

长度不变的原则与另一个基本原则相结合,即大多数长度不变的 lane-wise 操作也是 shape-invariant ,这意味着 lane-wise 操作的输入和输出将具有共同的 VSHAPE 。当原则发生冲突时,因为逻辑结果(具有不变量 VLENGTH)不适合不变量 VSHAPE,由此产生的扩展和收缩将使用 特别公约 显式处理。

矢量运算可以分为不同的类别,它们的行为通常可以根据底层标量运算符来指定。在下面的示例中,ETYPE 是操作的元素类型(例如 int.class ),而 EVector 是相应的具体向量类型(例如 IntVector.class )。

  • lane-wise unary 操作(例如 w = v0. neg () )采用一个输入向量,在通道上分布一元标量运算符,并生成相同类型和形状的结果向量。对于输入向量 a 的每个车道,基础标量运算符应用于车道值。结果被放入同一车道的矢量结果中。以下伪代码说明了此操作类别的行为:
    
     ETYPE scalar_unary_op(ETYPE s);
     EVector a = ...;
     VectorSpecies<E> species = a.species();
     ETYPE[] ar = new ETYPE[a.length()];
     for (int i = 0; i < ar.length; i++) {
       ar[i] = scalar_unary_op(a.lane(i));
     }
     EVector r = EVector.fromArray(species, ar, 0);
      
  • lane-wise binary 操作(例如 w = v0. add (v1) )采用两个输入向量,跨通道分布二进制标量运算符,并生成相同类型和形状的结果向量。对于两个输入向量 ab 的每个车道,基础标量运算符应用于车道值。结果被放入同一车道的矢量结果中。以下伪代码说明了此操作类别的行为:
    
     ETYPE scalar_binary_op(ETYPE s, ETYPE t);
     EVector a = ...;
     VectorSpecies<E> species = a.species();
     EVector b = ...;
     b.check(species); // must have same species
     ETYPE[] ar = new ETYPE[a.length()];
     for (int i = 0; i < ar.length; i++) {
       ar[i] = scalar_binary_op(a.lane(i), b.lane(i));
     }
     EVector r = EVector.fromArray(species, ar, 0);
      
  • 从一元和二元运算概括,lane-wise n-ary 运算采用 N 输入向量 v[j],在通道上分布 n 元标量运算符,并产生相同类型和形状的结果向量。除了一些三元运算,例如 w = v0. fma (v1,v2) ,此 API 不支持 lane-wise n 元运算。对于所有输入向量 v[j] 的每个车道,基础标量运算符应用于车道值。结果被放入同一车道的矢量结果中。以下伪代码说明了此操作类别的行为:
    
     ETYPE scalar_nary_op(ETYPE... args);
     EVector[] v = ...;
     int N = v.length;
     VectorSpecies<E> species = v[0].species();
     for (EVector arg : v) {
       arg.check(species); // all must have same species
     }
     ETYPE[] ar = new ETYPE[a.length()];
     for (int i = 0; i < ar.length; i++) {
       ETYPE[] args = new ETYPE[N];
       for (int j = 0; j < N; j++) {
         args[j] = v[j].lane(i);
       }
       ar[i] = scalar_nary_op(args);
     }
     EVector r = EVector.fromArray(species, ar, 0);
      
  • lane-wise conversion 操作(例如 w0 = v0. convert (VectorOperators.I2D, 0) )采用一个输入向量,跨通道分布一元标量转换运算符,并生成转换值的逻辑结果。逻辑结果(或至少其一部分)呈现在与输入向量形状相同的向量中。

    与其他 lane-wise 操作不同,转换可以更改 lane 类型,从输入(域)类型到输出(范围)类型。车道大小可能随类型而变化。为了管理大小变化,车道转换方法可以在 part 参数(即 在别处解释 )的控制下生成 partial results 。 (按照上面的例子,第二组转换后的车道值可以作为 w1 = v0.convert(VectorOperators.I2D, 1) 获得。)

    以下伪代码在从 intdouble 的转换的具体示例中说明了此操作类别的行为,保留较低或较高的车道(取决于 part )以保持形状不变性:

    
     IntVector a = ...;
     int VLENGTH = a.length();
     int part = ...; // 0 or 1
     VectorShape VSHAPE = a.shape();
     double[] arlogical = new double[VLENGTH];
     for (int i = 0; i < limit; i++) {
       int e = a.lane(i);
       arlogical[i] = (double) e;
     }
     VectorSpecies<Double> rs = VSHAPE.withLanes(double.class);
     int M = Double.BITS / Integer.BITS; // expansion factor
     int offset = part * (VLENGTH / M);
     DoubleVector r = DoubleVector.fromArray(rs, arlogical, offset);
     assert r.length() == VLENGTH / M;
      
  • cross-lane reduction 操作(例如 e = v0. reduceLanes (VectorOperators.ADD) )对输入向量的所有通道元素进行操作。将累积函数应用于所有车道元素以产生标量结果。如果归约运算是关联的,则可以通过使用指定的关联标量二元运算和标识值以任何顺序对通道元素进行运算来累积结果。否则,归约操作指定累加的顺序。以下伪代码说明了此操作类别在关联时的行为:
    
     ETYPE assoc_scalar_binary_op(ETYPE s, ETYPE t);
     EVector a = ...;
     ETYPE r = <identity value>;
     for (int i = 0; i < a.length(); i++) {
       r = assoc_scalar_binary_op(r, a.lane(i));
     }
      
  • cross-lane movement 操作,例如 w = v0. rearrange (shuffle) 对输入向量的所有通道元素进行操作,并以数据相关的方式将它们移动到输出向量的 different lanes 中。运动由辅助数据引导,例如 VectorShuffle 或定义运动原点的标量索引。以下伪代码说明了此操作类别在洗牌情况下的行为:
    
     EVector a = ...;
     Shuffle<E> s = ...;
     ETYPE[] ar = new ETYPE[a.length()];
     for (int i = 0; i < ar.length; i++) {
       int source = s.laneSource(i);
       ar[i] = a.lane(source);
     }
     EVector r = EVector.fromArray(a.species(), ar, 0);
      
  • masked operation 是先前操作之一(车道方向或交叉车道)的变体,其中该操作采用额外的尾随 VectorMask 参数。在设置了掩码的通道中,操作的行为就像不存在掩码参数一样,但在未设置掩码的通道中,底层标量操作被抑制。 别处更详细 中解释了屏蔽操作。
  • 掩码车道二元运算的一个非常特殊的情况是 blend ,它在两个输入向量 ab 上按车道运行,根据掩码 m 从一个输入或另一个输入中选择车道值。在设置m的通道中,从b中选择相应的值到结果中;否则选择 a 中的值。因此,混合充当 Java 的三元选择表达式 m?b:a :
    
     ETYPE[] ar = new ETYPE[a.length()];
     for (int i = 0; i < ar.length; i++) {
       boolean isSet = m.laneIsSet(i);
       ar[i] = isSet ? b.lane(i) : a.lane(i);
     }
     EVector r = EVector.fromArray(species, ar, 0);
      
    的矢量化版本
  • lane-wise binary test 操作(例如 m = v0. lt (v1) )采用两个输入向量,在通道之间分配二进制标量比较,并生成不是布尔向量,而是 矢量蒙版。对于两个输入向量 ab 的每个通道,基础标量比较运算符应用于通道值。生成的boolean被放入同一通道中的向量掩码结果中。以下伪代码说明了此操作类别的行为:
    
     boolean scalar_binary_test_op(ETYPE s, ETYPE t);
     EVector a = ...;
     VectorSpecies<E> species = a.species();
     EVector b = ...;
     b.check(species); // must have same species
     boolean[] mr = new boolean[a.length()];
     for (int i = 0; i < mr.length; i++) {
       mr[i] = scalar_binary_test_op(a.lane(i), b.lane(i));
     }
     VectorMask<E> m = VectorMask.fromArray(species, mr, 0);
      
  • 与二进制比较类似,lane-wise unary test 操作(例如 m = v0. test (IS_FINITE) )采用一个输入向量,在通道上分布标量谓词(测试函数),并生成 矢量蒙版

如果向量操作不属于上述类别之一,则方法文档明确指定它如何处理输入向量的通道,并在适当的地方使用伪代码说明行为。

大多数 lane-wise 二进制和比较操作提供方便的重载,它们接受标量作为第二个输入,而不是向量。在这种情况下,标量值通过 广播它 提升为向量,进入与第一个输入相同的通道结构。例如,要将 double 向量的所有通道乘以标量值 1.1 ,表达式 v.mul(1.1) 比具有显式广播操作的等效表达式(例如 v.mul(v.broadcast(1.1))v.mul(DoubleVector.broadcast(v.species(), 1.1)) )更容易使用。除非另有说明,否则标量变体始终表现得好像每个标量值首先使用适当的broadcast操作转换为与第一个向量输入相同种类的向量。

屏蔽操作

许多矢量运算接受可选的 mask 参数,选择哪些通道参与底层标量运算符。如果存在,掩码参数出现在方法参数列表的末尾。

mask 参数的每个通道都是一个boolean,它处于 setunset 状态。对于未设置 mask 参数的通道,底层标量运算符被抑制。通过这种方式,掩码允许向量操作模拟标量控制流操作,而不会丢失 SIMD 并行性,除非掩码通道未设置。

被掩码抑制的操作永远不会导致异常或任何类型的副作用,即使底层标量运算符可能会这样做。例如,似乎访问越界数组元素或将整数值除以零的未设置通道将被忽略。抑制通道中的值从不参与或出现在整体操作的结果中。

一个被抑制的操作对应的结果通道将被填充一个默认值,这个值取决于具体的操作,如下:

  • 如果掩码运算是一元、二元或 n 元算术或逻辑运算,则从第一个向量操作数(即接收方法调用的向量)填充抑制通道,就好像由 blend 一样。
  • 如果屏蔽操作是内存加载或来自另一个向量的 slice(),则不会加载抑制的通道,并用 ETYPE 的默认值填充,在每种情况下都由全零位组成。未设置的通道永远不会导致异常,即使假设的对应内存位置不存在(因为它超出了数组的索引范围)。
  • 如果操作是跨车道操作,其操作数提供车道索引(类型为 VectorShuffleVector ,则不计算抑制车道,并填充零默认值。通常,无效的车道索引会引发 IndexOutOfBoundsException ,但如果lane 未设置,零值被悄悄替换,不管索引如何。这条规则类似于前面的规则,用于屏蔽内存加载。
  • 如果掩码操作是内存存储或 unslice() 到另一个向量,则不存储抑制的通道,并且相应的内存或向量位置(如果有)不变。

    (注意:对于被抑制的通道,竞争条件等内存效应永远不会发生。也就是说,实现不会秘密地为未设置的通道重写现有值。在 Java 内存模型中,将内存变量重新分配为其当前值并不是不行的-op;它可能会悄悄地从另一个线程撤消赛车商店。)

  • 如果屏蔽操作是缩减,则在缩减中忽略抑制的车道。如果所有车道都被抑制,则返回一个合适的中性值,具体取决于特定的减少操作,并由该方法的掩码变体记录。 (这意味着用户可以通过对具有全部未设置掩码的虚拟向量执行归约,以编程方式获得中性值。)
  • 如果掩码操作是比较操作,则结果掩码中抑制的输出通道本身未设置,就好像抑制的比较操作返回 false 而不管抑制的输入值。实际上,就好像比较操作是在未屏蔽的情况下执行的,然后结果与控制屏蔽相交。
  • 在其他情况下,例如 masked cross-lane movements ,屏蔽的具体效果由方法的屏蔽变体记录。

例如,对两个输入向量 ab 进行掩码二元运算会抑制未设置掩码的通道的二元运算,并保留来自 a 的原始通道值。以下伪代码说明了此行为:


 ETYPE scalar_binary_op(ETYPE s, ETYPE t);
 EVector a = ...;
 VectorSpecies<E> species = a.species();
 EVector b = ...;
 b.check(species); // must have same species
 VectorMask<E> m = ...;
 m.check(species); // must have same species
 boolean[] ar = new boolean[a.length()];
 for (int i = 0; i < ar.length; i++) {
   if (m.laneIsSet(i)) {
     ar[i] = scalar_binary_op(a.lane(i), b.lane(i));
   } else {
     ar[i] = a.lane(i); // from first input
   }
 }
 EVector r = EVector.fromArray(species, ar, 0);
  

通道顺序和字节顺序

存储在给定向量中的通道值的数量称为其 矢量长度VLENGTH 。将向量通道视为从头到尾按 sequentially 顺序排列很有用,第一条通道编号为 0,下一条通道编号为 1,依此类推,直到最后一条通道编号为 VLENGTH-1。这是一个时间顺序,其中编号较低的车道被认为比编号较高(较晚)的车道更早。此 API 优先使用这些术语,而不是空间术语,例如“左”、“右”、“高”和“低”。

时间术语适用于向量,因为它们(通常)表示一长串工作负载元素中固定大小的小段,其中工作负载在概念上按时间顺序从头到尾遍历。 (这是一种心理模型:它不排除多核分而治之的技术。)因此,当标量循环转换为向量循环时,工作负载中相邻的标量项(一个在前,一个在后)最终成为相邻的单个向量中的车道(同样,一个更早,一个更晚)。在向量边界处,较早向量中的最后一个车道项与紧随其后的向量中的第一个车道项相邻(并且就在其之前)。

矢量有时也被认为是空间术语,其中第一道位于一些虚拟纸的边缘,随后的道在它旁边按顺序呈现。当使用空间术语时,所有方向都同样合理:一些矢量符号表示车道从左到右,而另一些则从右到左;还有一些人从上到下出现,反之亦然。使用时间(之前、之后、首先、最后)而不是空间(左、右、高、低)的语言通常更有可能避免误解。

关于向量通道更喜欢时间语言而不是空间语言的第二个原因是术语“左”、“右”、“高”和“低”被广泛用于描述标量值中位之间的关系。给定类型中最左边或最高位可能是符号位,而最右边或最低位可能是算术上最低位,依此类推。然而,将这些术语应用于矢量车道存在混淆的风险,因为相对较少找到这样的算法:给定两个相邻的矢量车道,其中一个车道在某种程度上比其相邻车道在算术上更重要,即使在这些情况下,也没有通用的方法来知道哪个邻居更重要。

将这些术语放在一起,我们将向量的信息结构视为内部的位串的通道时间序列(“第一个”、“下一个”、“较早的”、“稍后的”、“最后的”等)空间排序(“低”到“高”或“右”到“左”)。通道中的原始值以通常的方式从这些位串中解码。大多数向量运算,就像大多数 Java 标量运算符一样,将原始值视为原子值,但有些运算会揭示内部位串结构。

当向量从内存加载或存储到内存时,向量通道的顺序是always consistent ,具有内存容器的固有顺序。由于字节顺序的细节,无论单个通道元素是否受到“字节交换”的影响,都是如此。因此,虽然 vector 的标量通道元素可能被“字节交换”,但通道本身永远不会重新排序,除非通过执行跨通道重新排序的显式方法调用。

当向量通道值存储到相同类型的 Java 变量时,当且仅当向量硬件的实现需要这种交换时,才会执行字节交换。因此,它是无条件的和不可见的。

作为一个有用的虚构,此 API 呈现出一种一致的错觉,即矢量通道字节在 little endian order 中组成更大的通道标量。这意味着将向量存储到 Java 字节数组中将在所有平台上以小端顺序显示向量通道值的连续字节,而不管本机内存顺序如何,也不管向量单元寄存器中的字节顺序(如果有的话) .

重新诠释 以丢弃通道边界并以不同方式重新绘制,同时保持矢量位不变的方式应用时,也会出现这种假设的小端顺序。在这样的操作中,两个相邻的通道将字节贡献给一个新的通道(反之亦然),并且两个通道的顺序将决定单个通道中字节的算术顺序。在这种情况下,小端约定提供了可移植的结果,因此在所有平台上,较早的通道倾向于提供较低(向右)的位,而较晚的通道倾向于提供较高(向左)的位。 ByteVector 和其他非字节向量之间的 重新解释演员表 使用此约定来阐明它们的可移植语义。

将通道顺序与每个通道字节顺序相关联的小端小说比等效的大端小说更可取,因为一些相关公式要简单得多,特别是那些在通道结构更改后重新编号字节的公式。最早的字节在所有通道结构更改中总是最早的,但前提是使用小端约定。其根本原因是标量中的字节从最低位(最右边)到最高位(最左边)编号,几乎从不相反。如果我们习惯性地将符号位编号为零(就像在某些计算机上一样),那么此 API 将达到大端小说的目的,以创建矢量字节的统一寻址。

内存操作

正如已经提到的,向量可以从内存中加载并存储回来。一个可选的掩码可以控制读取或写入哪些单独的内存位置。矢量的形状决定了它将占用多少内存。一个实现通常具有这样的属性,在没有掩码的情况下,车道在内存中存储为密集的背靠背值序列,与密集(无间隙)系列的单个标量值在数组中相同标量类型。在这种情况下,内存顺序与通道顺序完全对应。第一个向量通道值占据内存中的第一个位置,依此类推,直到向量的长度。此外,存储向量通道的内存顺序对应于 Java 数组或 MemorySegment 中递增的索引值PREVIEW .

选择通道存储的字节顺序,以便存储的矢量值可以作为单个原始值在保存矢量的数组或段内读取或写入,从而产生与矢量内的通道值相同的值。这个事实与向量内部的车道值以小端顺序存储的便利虚构无关。

例如,FloatVector.fromArray(fsp,fa,i) 创建并返回某个特定种类的浮点向量 fsp,其中的元素从某个浮点数组 fa 加载。第一条车道从 fa[i] 加载,最后一条车道从 fa[i+VL-1] 加载,其中 VL 是从物种 fsp 派生的向量的长度。然后,fv=fv.add(fv2) 将生成该物种的另一个浮点向量 fsp,给定相同物种 fsp 的向量 fv2。接下来,mnz=fv.compare(NE, 0.0f) 测试结果是否为零,生成掩码 mnz。然后可以使用语句 fv.intoArray(fa,i,mnz) 将非零车道(并且只有那些车道)存储回原始数组元素。

扩展、收缩和部分结果

由于向量的大小是固定的,因此经常会出现运算的逻辑结果与建议输出向量的物理大小不同的情况。为了鼓励用户编写尽可能可移植和可预测的代码,此 API 采用系统方法来设计此类 resizing 向量操作。

作为一个基本原则,车道操作是 length-invariant ,除非另有明确标记。长度不变性只是意味着如果 VLENGTH 通道进入一个操作,相同数量的通道就会出来,没有任何东西被丢弃,也没有额外的填充。

作为第二个原则,有时与第一个原则有冲突,车道方向的操作也是 shape-invariant ,除非另有明确标记。形状不变性意味着 VSHAPE 对于典型计算是恒定的。在整个计算过程中保持相同的形状有助于确保有效地使用稀缺的矢量资源。 (在某些硬件平台上,形状变化可能会导致不必要的影响,例如额外的数据移动指令、内存往返或管道气泡。)

当操作产生的 logical result 对于所需的输出 VSHAPE 来说太大时,这些原则之间就会出现冲突。在其他情况下,当逻辑结果小于输出 VSHAPE 的容量时,逻辑结果的定位是有问题的,因为物理输出向量必须包含逻辑结果和填充的混合。

在第一种情况下,一个太大的逻辑结果被塞进一个太小的输出 VSHAPE ,我们说数据有 expanded 。换句话说,expansion operation 导致输出形状溢出。对称地,在适合宽敞输出 VSHAPE 的小逻辑结果的第二种情况下,数据具有 contracted,并且 contraction operation 要求输出形状用额外的零通道填充自身。

在这两种情况下,我们都可以使用参数 M 来衡量逻辑结果大小(以位为单位)与实际输出形状的位大小之间的 expansion ratiocontraction ratio。当矢量形状改变而通道大小不变时,M 只是输出形状与逻辑结果的整数比。 (除了 最大形状 之外,所有向量大小都是 2 的幂,因此比率 M 始终是整数。在非整数比率的假设情况下,值 M 将向上舍入为下一个整数,然后同样的一般考虑将适用。)

如果逻辑结果大于物理输出形状,这样的形状变化必然会丢弃结果通道(除了逻辑结果的1/M之外的所有通道)。如果逻辑大小小于输出,则形状更改必须引入零填充的填充通道(除了物理输出的 1/M 之外)。第一种情况是删除通道,是扩展,而第二种情况是添加填充通道,是收缩。

类似地,考虑一个 lane-wise 转换操作,它保持形状不变但按 M 的比率改变车道大小。如果逻辑结果大于输出(或输入),则此转换必须将输出的 VLENGTH 通道减少 M ,丢弃除 1/M 逻辑结果通道之外的所有通道。和以前一样,减少车道是扩张的标志。按 M 比例收缩车道大小的车道操作必须将 VLENGTH 增加相同的因子 M ,用零填充值填充额外的车道;因为必须添加填充,所以这是一种收缩。

也可以(虽然有些混乱)在执行车道转换 and 重塑的一次操作中同时更改车道大小和容器大小。如果这样做,则适用相同的规则,但逻辑结果大小是输入大小乘以变道大小的任何扩展或收缩比率的乘积。

为了完整起见,我们还可以将 in-place operations 用于不发生调整大小时的常见情况。通过就地操作,数据只是从逻辑输出复制到它的物理容器,没有截断或填充。在这种情况下,比率参数 M 是统一的。

请注意,收缩与扩展的分类取决于逻辑结果和物理输出容器的相对大小。在不改变分类的情况下,输入容器的大小可能大于或小于其他两个值中的任何一个。例如,从 128 位形状到 256 位形状的转换在许多情况下将是收缩,但如果它与从 bytelong 的转换相结合,它将是一个扩展,因为在那种情况下逻辑结果大小为 1024 位。此示例还说明逻辑结果不需要对应于任何特定平台支持的矢量形状。

虽然 lane-wise masked 操作可以被视为产生部分操作,但它们不被分类(在这个 API 中)为扩展或收缩。来自数组的掩码加载肯定会产生一个部分向量,但是没有有意义的“逻辑输出向量”来收缩这个部分结果。

这些术语需要注意一些,因为它是 data,而不是 container size,相对于其输出容器的大小正在扩展或收缩。因此,将 128 位输入调整为 512 位向量具有 contraction 的效果。尽管 128 位有效负载的大小没有变化,但我们可以说它在其新的 512 位主目录中“看起来更小了”,这将捕捉到实际情况的细节。

如果矢量方法可能会扩展其数据,它会接受一个名为 part 的额外 int 参数,或“部件号”。零件编号必须在 [0..M-1] 范围内,其中 M 是膨胀率。部件号从逻辑结果中选择 M 个连续不相交的大小相等的车道块之一,并用该车道块填充物理输出向量。

具体来说,从扩展的逻辑结果中选择的通道在 [R..R+L-1] 范围内编号,其中 L 是物理输出向量的 VLENGTH,块的原点 Rpart*L

类似的约定适用于任何可能收缩其数据的矢量方法。这种方法还接受一个额外的部件号参数(再次称为 part ),该参数将合同数据通道引导到物理输出向量中 M 连续不相交的等大小通道块之一。剩余的车道用零填充,或按方法指定。

具体来说,数据被引导到编号在 [R..R+L-1] 范围内的通道中,其中 L 是逻辑结果向量的 VLENGTH,而块的原点 R 又是部件号选择的 L 的倍数,具体来说是 |part|*L

在收缩的情况下,零件号必须在非正范围 [-M+1..0] 内。采用此约定是因为某些方法可以以数据相关的方式执行扩展和收缩,并且部件号上的额外符号用作错误检查。如果向量方法采用零件号并被调用以执行就地操作(既不收缩也不扩展),part 参数必须正好为零。超出允许范围的零件号将引发索引异常。请注意,在所有情况下,零部件号都是有效的,并且对应于从逻辑结果的开头保留尽可能多的通道并将它们放入物理输出容器的开头的操作。这通常是一个理想的默认值,因此零件号为零在所有情况下都是安全的,并且在大多数情况下都是有用的。

本API合约的各种调整大小操作或扩展其数据如下:

  • Vector.convert() 将按比率 M 扩展(分别收缩)其操作数,如果其输出的 元素大小 较大(分别较小) M 倍。如果输入和输出的元素大小相同,则convert() 是就地操作。
  • 如果其逻辑结果的位大小大于(分别小于)其输出形状的位大小,Vector.convertShape() 将按比率 M 扩展(分别收缩)其操作数。逻辑结果的大小定义为输出的 元素大小 乘以其输入的 VLENGTH。根据更改的通道大小的比率,逻辑大小可能(在各种情况下)大于或小于输入向量,与操作是扩展还是收缩无关。
  • 由于 Vector.castShape() convertShape() 的便捷方法,它作为扩展或收缩的分类与 convertShape() 相同。
  • Vector.reinterpretShape() 是比例为 M 的扩展(分别为收缩),如果其输入的 向量位大小M 的因子塞入较小的(分别为放入较大的)输出容器中。否则就是就地操作。由于此方法是一种重新解释转换,可以擦除和重绘车道边界以及修改形状,因此输入向量的车道大小和车道数与其扩展或收缩分类无关。
  • unslice() 方法按 M=2 的比率扩展,因为单个输入切片被定位并插入到两个连续背景向量中的某处。部件号选择第一个或第二个背景矢量,由插入的切片更新。请注意,相应的 slice() 方法虽然与 unslice() 方法相反,但不会收缩它们的数据,因此不需要部件号。这是因为 slice() 提供了从两个输入向量中提取的恰好 VLENGTH 通道的切片。
在执行任何扩展或收缩操作之前,可以使用 VectorSpecies 上的方法 partLimit() 来查询零件参数的限制值以进行建议的扩展或收缩。从 partLimit() 返回的值对于扩展为正,对于收缩为负,对于就地操作为零。它的绝对值是参数 M ,因此它作为相关方法的有效部件号参数的唯一限制。因此,对于扩展,partLimit()M 是零件编号的唯一上限,而对于收缩,partLimit()-M 是唯一的 lower 限制。

跨通道边界移动数据

不重绘车道或改变物种的交叉车道方法结构更规则,更容易推理。这些操作是:
  • slice() 系列方法,它从一对串联的向量中的给定原点提取连续的 VLENGTH 字段切片。
  • unslice() 系列方法,它将 VLENGTH 字段的连续切片插入给定原点处的串联向量对。
  • rearrange() 系列方法,从一个或两个输入向量中选择任意一组 VLENGTH 通道,并以任意顺序组装它们。通道的选择和顺序由 VectorShuffle 对象控制,该对象充当将源通道映射到目标通道的路由表。 VectorShuffle 可以对数学排列以及许多其他数据移动模式进行编码。
  • compress(VectorMask) expand(VectorMask) 方法,它们从输入向量中选择多达 VLENGTH 条通道,并按通道顺序组装它们。车道的选择由 VectorMask 控制,设置车道元素映射,按车道顺序压缩或扩展,源车道到目标车道。

一些向量操作不是基于车道的,而是跨车道边界移动数据。此类操作在 SIMD 代码中通常很少见,尽管它们有时对于在低级别处理数据格式的特定算法是必需的,和/或需要 SIMD 数据以复杂的本地模式移动。 (大量数据的小窗口中的局部移动相对不常见,尽管一些高度模式化的算法需要它。)在这个 API 中,这样的方法总是清晰可辨,因此可以自信地将更简单的车道推理应用于其余的代码。

在某些情况下,矢量通道边界被丢弃并“从头开始重新绘制”,因此给定输入通道中的数据可能会出现(在几个部分中)分布在多个输出通道中,或者(相反)来自多个输入通道的数据可能会合并为单个输出通道。可以重绘车道边界的基本方法是 reinterpretShape() 。建立在这种方法之上,某些方便的方法,如 reinterpretAsBytes() reinterpretAsInts() 将(可能)重绘车道边界,同时保持相同的整体矢量形状。

产生或消耗标量结果的操作可以被视为非常简单的跨车道操作。 reduceLanes() 系列中的方法将方法的所有通道(或掩码选择的通道)折叠在一起并返回单个结果。相反,broadcast 系列方法可以被认为是在另一个方向上交叉车道,从标量到输出向量的所有车道。 lane(I)withLane(I,E) 等单车道访问方法也可能被视为非常简单的跨车道操作。

同样,将非字节向量移入或移出字节数组的方法可以被视为跨通道操作,因为向量通道必须分布到单独的字节中,或者(在另一个方向上)从数组字节合并。

实现注意事项:

硬件平台依赖性和限制

Vector API 用于加速单指令多数据 (SIMD) 风格的计算,使用可用的硬件资源,例如矢量硬件寄存器和矢量硬件指令。 API 旨在有效利用多个 SIMD 硬件平台。

即使在不包含对 SIMD 计算的专门硬件支持的 Java 平台上,此 API 也能正常工作。 Vector API 不太可能在此类平台上提供任何特殊的性能优势。

目前,该实现已优化以在以下情况下发挥最佳作用:

  • 至少支持 AVX2 到 AVX-512 的 Intel x64 平台。当前不支持在 AVX-512 上使用掩码寄存器进行掩码和接受硬件指令的掩码。
  • 支持 NEON 的 ARM AArch64 平台。尽管 API 旨在确保可以支持 ARM SVE 指令(向量大小在 128 到 2048 位之间),但目前尚未实现此类指令和一般屏蔽功能。
该实现目前支持跨平台方式的屏蔽车道操作,方法是将未屏蔽的车道操作与 blend 组合在一起,如表达式 a.blend(a.lanewise(op, b), m) ,其中 ab 是向量,op 是向量操作,m 是掩码。

该实现目前不支持浮点超越函数的最佳矢量化指令(例如运算符 SIN LOG )。

没有原语装箱

尽管像 Vector<Integer> 这样的向量类型似乎可以与装箱的 Integer 值一起使用,但通过让每个向量子类型在内部处理实际 ETYPE 的通道值(例如 int ),可以避免与装箱相关的开销。

基于值的类和身份操作

Vector 连同其所有子类型和许多辅助类型(如 VectorMaskVectorShuffle )是一个 value-based 类。

一旦创建,向量就永远不会发生变化,即使只有 改变了一条车道 也不会发生变化。始终会创建一个新向量来保存车道值的新配置。可变方法的不可用性是抑制所有向量的对象标识(作为基于值的类)的必然结果。

随着 Vector== 等身份敏感操作可能会产生不可预知的结果,或降低性能。奇怪的是,v.equals(w) 可能比 v==w 更快,因为 equalsnot 身份敏感方法。此外,这些对象可以存储在局部变量和参数中以及作为 static final 常量,但是将它们存储在其他 Java 字段或数组元素中,虽然在语义上是有效的,但可能会导致性能下降。

  • 方法详情

    • species

      public abstract VectorSpecies <E > species()
      返回此向量的种类。
      返回:
      这个向量的种类
    • elementType

      public abstract Class <E > elementType()
      返回此向量的原语 元素类型 (ETYPE )。
      实现要求:
      这与 this.species().elementType() 的值相同。
      返回:
      此向量的原始元素类型
    • elementSize

      public abstract int elementSize()
      返回此向量的每个通道的大小(以位为单位)。
      实现要求:
      这与 this.species().elementSize() 的值相同。
      返回:
      此向量的通道大小(以位为单位)
    • shape

      public abstract VectorShape  shape()
      返回此向量的形状。
      实现要求:
      这与 this.species().vectorShape() 的值相同。
      返回:
      这个向量的形状
    • length

      public abstract int length()
      返回通道计数,或 矢量长度 (VLENGTH )。
      返回:
      车道数
    • bitSize

      public abstract int bitSize()
      返回此向量的总大小(以位为单位)。
      实现要求:
      这与 this.shape().vectorBitSize() 的值相同。
      返回:
      此向量的总大小(以位为单位)
    • byteSize

      public abstract int byteSize()
      返回此向量的总大小(以字节为单位)。
      实现要求:
      这与 this.bitSize()/Byte.SIZE 的值相同。
      返回:
      此向量的总大小(以字节为单位)
    • lanewise

      public abstract Vector <E > lanewise(VectorOperators.Unary  op)
      对该向量的车道值进行操作。这是一个 lane-wise 一元操作,它将所选操作应用于每个通道。
      API 注意:
      子类型通过锐化方法返回类型来改进此方法。
      参数:
      op - 用于处理车道值的操作
      返回:
      将操作按车道应用于输入向量的结果
      抛出:
      UnsupportedOperationException - 如果此向量不支持请求的操作
      参见:
    • lanewise

      public abstract Vector <E > lanewise(VectorOperators.Unary  op, VectorMask <E > m)
      对该向量的车道值进行操作,选择由掩码控制的车道元素。这是一个 lane-wise 一元操作,它将选定的操作应用于每个车道。
      API 注意:
      子类型通过锐化方法返回类型来改进此方法。
      参数:
      op - 用于处理车道值的操作
      m - 掩码控制车道选择
      返回:
      将操作按车道应用于输入向量的结果
      抛出:
      UnsupportedOperationException - 如果此向量不支持请求的操作
      参见:
    • lanewise

      public abstract Vector <E > lanewise(VectorOperators.Binary  op, Vector <E > v)
      将此向量的相应车道值与第二个输入向量的车道值相结合。这是一个 lane-wise 二元运算,它将选定的运算应用于每个通道。
      API 注意:
      子类型通过锐化方法返回类型来改进此方法。
      参数:
      op - 用于组合车道值的操作
      v - 输入向量
      返回:
      将操作按车道应用于两个输入向量的结果
      抛出:
      UnsupportedOperationException - 如果此向量不支持请求的操作
      参见:
    • lanewise

      public abstract Vector <E > lanewise(VectorOperators.Binary  op, Vector <E > v, VectorMask <E > m)
      将此向量的相应车道值与第二个输入向量的车道值相结合,并选择由掩码控制的车道元素。这是一个 lane-wise 二元操作,它将选择的操作应用到每个 lane。
      API 注意:
      子类型通过锐化方法返回类型来改进此方法。
      参数:
      op - 用于组合车道值的操作
      v - 第二个输入向量
      m - 掩码控制车道选择
      返回:
      将操作按车道应用于两个输入向量的结果
      抛出:
      UnsupportedOperationException - 如果此向量不支持请求的操作
      参见:
    • lanewise

      public abstract Vector <E > lanewise(VectorOperators.Binary  op, long e)
      将此向量的车道值与广播标量的值相结合。这是一个 lane-wise 二元操作,它将选择的操作应用到每个 lane。返回值将等于此表达式:this.lanewise(op, this.broadcast(e))
      API 注意:
      longe 必须由该向量种类的 ETYPE 准确表示,以便 e==(long)(ETYPE)e 。此规则由对 broadcast() 的隐式调用强制执行。

      子类型通过锐化方法返回类型和标量参数 e 的类型来改进此方法。

      参数:
      op - 用于组合车道值的操作
      e - 输入标量
      返回:
      将操作按车道应用于输入向量和标量的结果
      抛出:
      UnsupportedOperationException - 如果此向量不支持请求的操作
      IllegalArgumentException - 如果给定的 long 值不能用向量运算的右操作数类型表示
      参见:
    • lanewise

      public abstract Vector <E > lanewise(VectorOperators.Binary  op, long e, VectorMask <E > m)
      将此向量的相应车道值与第二个输入向量的车道值相结合,并选择由掩码控制的车道元素。这是一个 lane-wise 二元操作,它将选择的操作应用到每个 lane。第二个操作数是一个广播整数值。返回值将等于此表达式:this.lanewise(op, this.broadcast(e), m)
      API 注意:
      longe 必须由该向量种类的 ETYPE 准确表示,以便 e==(long)(ETYPE)e 。此规则由对 broadcast() 的隐式调用强制执行。

      子类型通过锐化方法返回类型和标量参数 e 的类型来改进此方法。

      参数:
      op - 用于组合车道值的操作
      e - 输入标量
      m - 掩码控制车道选择
      返回:
      将操作按车道应用于输入向量和标量的结果
      抛出:
      UnsupportedOperationException - 如果此向量不支持请求的操作
      IllegalArgumentException - 如果给定的 long 值不能用向量运算的右操作数类型表示
      参见:
    • lanewise

      public abstract Vector <E > lanewise(VectorOperators.Ternary  op, Vector <E > v1, Vector <E > v2)
      将此向量的相应车道值与第二个和第三个输入向量的车道组合。这是一个 lane-wise 三元运算,它将选定的运算应用于每个通道。
      API 注意:
      子类型通过锐化方法返回类型来改进此方法。
      参数:
      op - 用于组合车道值的操作
      v1 - 第二个输入向量
      v2 - 第三个输入向量
      返回:
      将操作按车道应用于三个输入向量的结果
      抛出:
      UnsupportedOperationException - 如果此向量不支持请求的操作
      参见:
    • lanewise

      public abstract Vector <E > lanewise(VectorOperators.Ternary  op, Vector <E > v1, Vector <E > v2, VectorMask <E > m)
      将此向量的相应车道值与第二个和第三个输入向量的车道相结合,并选择由掩码控制的车道元素。这是一个车道三元操作,它将所选操作应用于每个车道。
      API 注意:
      子类型通过锐化方法返回类型来改进此方法。
      参数:
      op - 用于组合车道值的操作
      v1 - 第二个输入向量
      v2 - 第三个输入向量
      m - 掩码控制车道选择
      返回:
      将操作按车道应用于三个输入向量的结果
      抛出:
      UnsupportedOperationException - 如果此向量不支持请求的操作
      参见:
    • add

      public abstract Vector <E > add(Vector <E > v)
      将此向量添加到第二个输入向量。这是一个车道二元运算,它将原始加法运算 (+) 应用于每对对应的车道值。此方法也等效于表达式 lanewise ( ADD , v)

      作为一个全服务命名操作,此方法出现在屏蔽和未屏蔽的重载中,并且(在子类中)也出现在标量广播重载(屏蔽和未屏蔽)中。

      参数:
      v - 第二个输入向量
      返回:
      将此向量添加到第二个输入向量的结果
      参见:
    • add

      public abstract Vector <E > add(Vector <E > v, VectorMask <E > m)
      将此向量添加到第二个输入向量,在掩码的控制下选择通道。这是一个掩码车道二元运算,它将原始加法运算 (+) 应用于每对对应的车道值。对于掩码中未设置的任何车道,原始操作被抑制并且该向量保留存储在该车道中的原始值。此方法也等效于表达式 lanewise ( ADD , v, m)

      作为一个全服务命名操作,此方法出现在屏蔽和未屏蔽的重载中,并且(在子类中)也出现在标量广播重载(屏蔽和未屏蔽)中。

      参数:
      v - 第二个输入向量
      m - 掩码控制车道选择
      返回:
      将此向量添加到给定向量的结果
      参见:
    • sub

      public abstract Vector <E > sub(Vector <E > v)
      从该向量中减去第二个输入向量。这是一个车道二元运算,它将原始减法运算 (-) 应用于每对对应的车道值。此方法也等效于表达式 lanewise ( SUB , v)

      作为一个全服务命名操作,此方法出现在屏蔽和未屏蔽的重载中,并且(在子类中)也出现在标量广播重载(屏蔽和未屏蔽)中。

      参数:
      v - 第二个输入向量
      返回:
      从这个向量中减去第二个输入向量的结果
      参见:
    • sub

      public abstract Vector <E > sub(Vector <E > v, VectorMask <E > m)
      在掩码的控制下从该向量中减去第二个输入向量。这是一个掩码车道二元运算,它将原始减法运算 (-) 应用于每对对应的车道值。对于掩码中未设置的任何车道,原始操作被抑制并且该向量保留存储在该车道中的原始值。此方法也等效于表达式 lanewise ( SUB , v, m)

      作为一个全服务命名操作,此方法出现在屏蔽和未屏蔽的重载中,并且(在子类中)也出现在标量广播重载(屏蔽和未屏蔽)中。

      参数:
      v - 第二个输入向量
      m - 掩码控制车道选择
      返回:
      从这个向量中减去第二个输入向量的结果
      参见:
    • mul

      public abstract Vector <E > mul(Vector <E > v)
      将此向量乘以第二个输入向量。这是一个车道二元运算,它将原始乘法运算 (*) 应用于每对对应的车道值。此方法也等效于表达式 lanewise ( MUL , v)

      作为一个全服务命名操作,此方法出现在屏蔽和未屏蔽的重载中,并且(在子类中)也出现在标量广播重载(屏蔽和未屏蔽)中。

      参数:
      v - 第二个输入向量
      返回:
      这个向量乘以第二个输入向量的结果
      参见:
    • mul

      public abstract Vector <E > mul(Vector <E > v, VectorMask <E > m)
      在掩码的控制下将此向量乘以第二个输入向量。这是一个车道二元运算,它将原始乘法运算 (*) 应用于每对对应的车道值。对于掩码中未设置的任何车道,原始操作被抑制并且该向量保留存储在该车道中的原始值。此方法也等效于表达式 lanewise ( MUL , v, m)

      作为一个全服务命名操作,此方法出现在屏蔽和未屏蔽的重载中,并且(在子类中)也出现在标量广播重载(屏蔽和未屏蔽)中。

      参数:
      v - 第二个输入向量
      m - 掩码控制车道选择
      返回:
      这个向量乘以给定向量的结果
      参见:
    • div

      public abstract Vector <E > div(Vector <E > v)
      将此向量除以第二个输入向量。这是一个车道二元运算,它将原始除法运算 (/) 应用于每对对应的车道值。此方法也等效于表达式 lanewise ( DIV , v)

      作为一个全服务命名操作,此方法出现在屏蔽和未屏蔽的重载中,并且(在子类中)也出现在标量广播重载(屏蔽和未屏蔽)中。

      API 注意:
      如果底层标量运算符不支持除以零,但提供了零除数,则会抛出 ArithmeticException
      参数:
      v - 第二个输入向量
      返回:
      这个向量除以第二个输入向量的结果
      抛出:
      ArithmeticException - 如果 v 中的任何通道为零且 ETYPE 不是 floatdouble
      参见:
    • div

      public abstract Vector <E > div(Vector <E > v, VectorMask <E > m)
      在掩码的控制下将此向量除以第二个输入向量。这是一个车道二元运算,它将原始除法运算 (/) 应用于每对对应的车道值。对于掩码中未设置的任何车道,原始操作被抑制,并且该向量保留存储在该车道中的原始值。此方法也等效于表达式 lanewise ( DIV , v, m)

      作为一个全服务命名操作,此方法出现在屏蔽和未屏蔽的重载中,并且(在子类中)也出现在标量广播重载(屏蔽和未屏蔽)中。

      API 注意:
      如果底层标量运算符不支持除以零,但提供了零除数,则会抛出 ArithmeticException
      参数:
      v - 第二个输入向量
      m - 掩码控制车道选择
      返回:
      这个向量除以第二个输入向量的结果
      抛出:
      ArithmeticException - 如果 mv 中选择的任何通道为零且 ETYPE 不是 floatdouble
      参见:
    • neg

      public abstract Vector <E > neg()
      否定这个向量。这是一个 lane-wise 一元操作,它将原语否定操作 (-x) 应用于每个输入通道。此方法也等效于表达式 lanewise ( NEG )
      API 注意:
      此方法没有屏蔽变体,但可以从 巷道法 获得相应的屏蔽操作。
      返回:
      这个向量的否定
      参见:
    • abs

      public abstract Vector <E > abs()
      返回此向量的绝对值。这是一个 lane-wise 一元操作,它将方法 Math.abs 应用于每个输入通道。此方法也等效于表达式 lanewise ( ABS )
      API 注意:
      此方法没有屏蔽变体,但可以从 巷道法 获得相应的屏蔽操作。
      返回:
      这个向量的绝对值
      参见:
    • min

      public abstract Vector <E > min(Vector <E > v)
      计算此向量和第二个输入向量中的较小者。这是一个车道二元运算,它将运算Math.min()应用于每对对应的车道值。此方法也等效于表达式 lanewise ( MIN , v)
      API 注意:
      这不是像 add() 这样的全服务命名操作。此操作的屏蔽版本不能直接获得,但可以通过 lanewise 的屏蔽版本获得。子类定义了此方法的附加标量广播重载。
      参数:
      v - 第二个输入向量
      返回:
      此向量和第二个输入向量的车道最小值
      参见:
    • max

      public abstract Vector <E > max(Vector <E > v)
      计算此向量和第二个输入向量中的较大者。这是一个车道二元运算,它将运算Math.max()应用于每对对应的车道值。此方法也等效于表达式 lanewise ( MAX , v)

      这不是像 add() 这样的全服务命名操作。此操作的屏蔽版本不能直接获得,但可以通过 lanewise 的屏蔽版本获得。子类定义了此方法的附加标量广播重载。

      参数:
      v - 第二个输入向量
      返回:
      此向量和第二个输入向量的车道最大值
      参见:
    • reduceLanesToLong

      public abstract long reduceLanesToLong(VectorOperators.Associative  op)
      返回从该向量的所有通道中累积的值。这是一个关联的跨车道减少操作,它将指定的操作应用于所有车道元素。返回值将等于此表达式:(long) ((EVector)this).reduceLanes(op),其中 EVector 是特定于此向量的元素类型 ETYPE 的向量类。

      在操作 ADDMUL 的情况下,当 ETYPEfloatdouble 时,在转换之前的精确结果将反映任意操作顺序的选择,甚至可能随时间变化。有关详细信息,请参阅 浮点向量运算 部分。

      API 注意:
      如果 ETYPEfloatdouble ,此操作可能会丢失精度和/或范围,作为将结果向下转换为 long 的正常部分。如果您正在使用具有已知元素类型的矢量子类型,通常 强类型访问 更可取。
      参数:
      op - 用于组合车道值的操作
      返回:
      累积的结果,转换为 long
      抛出:
      UnsupportedOperationException - 如果此向量不支持请求的操作
      参见:
    • reduceLanesToLong

      public abstract long reduceLanesToLong(VectorOperators.Associative  op, VectorMask <E > m)
      返回从该向量的选定通道中累积的值,由掩码控制。这是一个关联的跨车道减少操作,它将指定的操作应用于选定的车道元素。返回值将等于此表达式:(long) ((EVector)this).reduceLanes(op, m),其中 EVector 是特定于此向量的元素类型 ETYPE 的向量类。

      如果未选择任何元素,则返回特定于操作的标识值。

      • 如果操作是 ADDXOROR ,则标识值为零。
      • 如果操作是 MUL ,则标识值为 1。
      • 如果操作是 AND ,则标识值是负一(所有位都设置)。
      • 如果操作是 MAX ,那么标识值是向量的本机 ETYPEMIN_VALUE 。 (在浮点类型的情况下,使用值 NEGATIVE_INFINITY,并将在转换后显示为 Long.MIN_VALUE
      • 如果操作是 MIN ,那么标识值是向量的本机 ETYPEMAX_VALUE 。 (在浮点类型的情况下,使用值 POSITIVE_INFINITY,并将在转换后显示为 Long.MAX_VALUE

      在操作 ADDMUL 的情况下,当 ETYPEfloatdouble 时,在转换之前的精确结果将反映任意操作顺序的选择,甚至可能随时间变化。有关详细信息,请参阅 浮点向量运算 部分。

      API 注意:
      如果 ETYPEfloatdouble ,此操作可能会丢失精度和/或范围,作为将结果向下转换为 long 的正常部分。如果您正在使用具有已知元素类型的矢量子类型,通常 强类型访问 更可取。
      参数:
      op - 用于组合车道值的操作
      m - 掩码控制车道选择
      返回:
      从所选车道值累积的减少结果
      抛出:
      UnsupportedOperationException - 如果此向量不支持请求的操作
      参见:
    • test

      public abstract VectorMask <E > test(VectorOperators.Test  op)
      根据给定的操作测试此向量的通道。这是一个车道一元测试操作,它将给定的测试操作应用于每个车道值。
      参数:
      op - 用于测试车道值的操作
      返回:
      根据选定的测试运算符测试此向量的通道的掩码结果
      参见:
    • test

      public abstract VectorMask <E > test(VectorOperators.Test  op, VectorMask <E > m)
      根据给定的操作,测试该向量的选定通道。这是一个屏蔽的车道一元测试操作,它将给定的测试操作应用于每个车道值。返回结果等于表达式 test(op).and(m)
      参数:
      op - 用于测试车道值的操作
      m - 掩码控制车道选择
      返回:
      根据选定的测试运算符,测试此向量的通道的掩码结果,并且仅在掩码选择的通道中
      参见:
    • eq

      public abstract VectorMask <E > eq(Vector <E > v)
      测试此向量是否等于另一个输入向量。这是一个基于车道的二进制测试操作,它将原语等于操作 (==) 应用于每对对应的车道值。结果与 compare(VectorOperators.EQ, v) 相同。
      参数:
      v - 第二个输入向量
      返回:
      如果此向量等于第二个输入向量,则按车道测试掩码结果
      参见:
    • lt

      public abstract VectorMask <E > lt(Vector <E > v)
      测试此向量是否小于另一个输入向量。这是一个车道二进制测试操作,它将原始小于操作 (<) 应用于每个车道。结果与 compare(VectorOperators.LT, v) 相同。
      参数:
      v - 第二个输入向量
      返回:
      如果此向量小于第二个输入向量,则按车道测试掩码结果
      参见:
    • compare

      public abstract VectorMask <E > compare(VectorOperators.Comparison  op, Vector <E > v)
      根据给定的比较操作,通过将此向量与另一个输入向量进行比较来测试此向量。这是一个车道二进制测试操作,它将给定的比较操作应用于每对对应的车道值。
      参数:
      op - 用于比较车道值的操作
      v - 第二个输入向量
      返回:
      根据选定的比较运算符,如果此向量与输入进行比较,则按车道测试掩码结果
      参见:
    • compare

      public abstract VectorMask <E > compare(VectorOperators.Comparison  op, Vector <E > v, VectorMask <E > m)
      根据给定的比较操作,在掩码选择的通道中,通过将它与另一个输入向量进行比较来测试该向量。这是一个掩码车道二进制测试操作,它将给定的比较操作应用于每对对应的车道值。返回结果等于表达式 compare(op,v).and(m)
      参数:
      op - 用于比较车道值的操作
      v - 第二个输入向量
      m - 掩码控制车道选择
      返回:
      如果此向量与输入进行比较,根据选定的比较运算符,并且仅在掩码选择的车道中,则按车道测试掩码结果
      参见:
    • compare

      public abstract VectorMask <E > compare(VectorOperators.Comparison  op, long e)
      根据给定的比较操作,通过将它与输入标量进行比较来测试该向量。这是一个车道二进制测试操作,它将给定的比较操作应用于每个车道值,与广播值配对。

      结果与 this.compare(op, this.broadcast(e)) 相同。也就是说,可以将标量视为广播到同一物种的向量,然后使用选定的比较操作与原始向量进行比较。

      API 注意:
      longe 必须由该向量种类的 ETYPE 准确表示,以便 e==(long)(ETYPE)e 。此规则由对 broadcast() 的隐式调用强制执行。

      子类型通过锐化标量参数 e 的类型来改进此方法。

      参数:
      op - 用于比较车道值的操作
      e - 输入标量
      返回:
      根据选定的比较运算符,如果此向量与输入进行比较,则按车道测试掩码结果
      抛出:
      IllegalArgumentException - 如果给定的 long 值不能由向量的 ETYPE 表示
      参见:
    • compare

      public abstract VectorMask <E > compare(VectorOperators.Comparison  op, long e, VectorMask <E > m)
      根据给定的比较操作,在掩码选择的通道中,通过将其与输入标量进行比较来测试该向量。这是一个掩码车道二进制测试操作,它将给定的比较操作应用于每个车道值,与广播值配对。返回结果等于表达式 compare(op,e).and(m)
      API 注意:
      longe 必须由该向量种类的 ETYPE 准确表示,以便 e==(long)(ETYPE)e 。此规则由对 broadcast() 的隐式调用强制执行。

      子类型通过锐化标量参数 e 的类型来改进此方法。

      参数:
      op - 用于比较车道值的操作
      e - 输入标量
      m - 掩码控制车道选择
      返回:
      如果此向量与输入进行比较,根据选定的比较运算符,并且仅在掩码选择的车道中,则按车道测试掩码结果
      抛出:
      IllegalArgumentException - 如果给定的 long 值不能由向量的 ETYPE 表示
      参见:
    • blend

      public abstract Vector <E > blend(Vector <E > v, VectorMask <E > m)
      在掩码的控制下,用来自第二个输入向量的相应车道替换此向量的选定车道。这是一种屏蔽的车道二元运算,它从一个或另一个输入中选择每个车道值。
      • 对于掩码中的任何车道 set,新的车道值取自第二个输入向量,并替换该向量的该车道中的任何值。
      • 对于掩码中的任何通道 unset,替换被抑制并且该向量保留存储在该通道中的原始值。
      以下伪代码说明了此行为:
      
       Vector<E> a = ...;
       VectorSpecies<E> species = a.species();
       Vector<E> b = ...;
       b.check(species);
       VectorMask<E> m = ...;
       ETYPE[] ar = a.toArray();
       for (int i = 0; i < ar.length; i++) {
         if (m.laneIsSet(i)) {
           ar[i] = b.lane(i);
         }
       }
       return EVector.fromArray(s, ar, 0);
        
      参数:
      v - 第二个输入向量,包含替换车道值
      m - 从第二个输入向量中控制通道选择的掩码
      返回:
      将此向量的车道元素与第二个输入向量的车道元素混合的结果
    • blend

      public abstract Vector <E > blend(long e, VectorMask <E > m)
      在掩码控制下用标量值替换此向量的选定通道。这是一种屏蔽的车道二元运算,它从一个或另一个输入中选择每个车道值。返回结果等于表达式 blend(broadcast(e),m)
      API 注意:
      longe 必须由该向量种类的 ETYPE 准确表示,以便 e==(long)(ETYPE)e 。此规则由对 broadcast() 的隐式调用强制执行。

      子类型通过锐化标量参数 e 的类型来改进此方法。

      参数:
      e - 输入标量,包含替换车道值
      m - 标量控制通道选择的掩码
      返回:
      将此向量的车道元素与标量值混合的结果
    • addIndex

      public abstract Vector <E > addIndex(int scale)
      将此向量的车道添加到它们相应的车道编号,按给定常数缩放。这是一个基于车道的一元运算,对于每个车道 N ,计算缩放索引值 N*scale 并将其添加到当前向量的车道 N 中已有的值。

      规模不能太大,元素大小不能太小,以至于在计算任何 N*scaleVLENGTH*scale 时会出现溢出,当结果使用向量通道类型 ETYPE 表示时。

      以下伪代码说明了此行为:

      
       Vector<E> a = ...;
       VectorSpecies<E> species = a.species();
       ETYPE[] ar = a.toArray();
       for (int i = 0; i < ar.length; i++) {
         long d = (long)i * scale;
         if (d != (ETYPE) d) throw ...;
         ar[i] += (ETYPE) d;
       }
       long d = (long)ar.length * scale;
       if (d != (ETYPE) d) throw ...;
       return EVector.fromArray(s, ar, 0);
        
      参数:
      scale - 要乘以每个车道索引 N 的数字,通常为 1
      返回:
      每个车道元素增加其对应的车道索引 N 的结果,按 scale 缩放
      抛出:
      IllegalArgumentException - 如果区间 [0..VLENGTH*scale] 中的值不能由 ETYPE 表示
    • slice

      public abstract Vector <E > slice(int origin, Vector <E > v1)
      从当前向量中的给定 origin 车道开始,并继续(根据需要)进入紧随其后的向量,对相邻车道的一段进行切片。 VLENGTH 车道的块被提取到它自己的向量中并返回。

      这是一个跨车道操作,将车道元素从当前向量和第二个向量移到前面。这两个向量都可以看作是长度为 2*VLENGTH 的组合“背景”,从中提取切片。输出向量中编号为 N 的通道是从输入向量的通道 origin+N 复制的,如果该通道存在,则从第二个向量(保证存在)的通道 origin+N-VLENGTH 复制。

      origin 值必须在包含范围 0..VLENGTH 内。作为极限情况,v.slice(0,w)v.slice(VLENGTH,w) 分别返回 vw

      API 注意:
      此方法可被视为 unslice() 的反函数,因为可以将切片值解切片回到其在两个输入向量中的原始位置,而不会干扰不相关的元素,如以下伪代码所示:
      
       EVector slice = v1.slice(origin, v2);
       EVector w1 = slice.unslice(origin, v1, 0);
       EVector w2 = slice.unslice(origin, v2, 1);
       assert v1.equals(w1);
       assert v2.equals(w2);
        

      该方法还支持多种跨车道换档和轮换,如下:

      • 要将车道向前移动到向量的前面,请为第二个操作数提供零向量并将移动计数指定为原点。例如:v.slice(shift, v.broadcast(0))
      • 要将车道向后移动到向量的后面,请为 first 操作数提供一个零向量,并将负移动计数指定为原点(模 VLENGTH 。例如: v.broadcast(0).slice(v.length()-shift, v)
      • 要将车道向前旋转到向量的前端,将最早的车道循环到后面,为两个操作数提供相同的向量并将旋转计数指定为原点。例如:v.slice(rotate, v)
      • 要向后向向量的后端旋转车道,将最新的车道循环到前面,为两个操作数提供相同的向量,并将旋转计数的负数(模 VLENGTH )指定为原点。例如:v.slice(v.length() - rotate, v)
      • 由于 origin 值小于零或大于 VLENGTH 将被拒绝,如果您需要旋转不可预测的 VLENGTH 倍数,请务必将原点值减小到所需范围内。 loopBound() 方法可以帮助解决这个问题。例如:v.slice(rotate - v.species().loopBound(rotate), v)
      参数:
      origin - 传输到切片中的第一个输入通道
      v1 - 在获取切片之前,第二个向量与第一个向量逻辑连接(如果省略,则默认为零)
      返回:
      VLENGTH 车道的连续切片,从指定的原点开始从该向量中获取,并继续(根据需要)进入第二个向量
      抛出:
      ArrayIndexOutOfBoundsException - 如果 origin 为负或大于 VLENGTH
      参见:
    • slice

      public abstract Vector <E > slice(int origin, Vector <E > v1, VectorMask <E > m)
      在掩码的控制下分割一段相邻的车道,从当前向量中给定的 origin 车道开始,并继续(根据需要)进入紧随其后的向量。 VLENGTH 车道的块被提取到它自己的向量中并返回。在给定掩码中未设置的所有通道中,生成的向量将为零。掩码中设置的通道将包含从 thisv1 的选定通道复制的数据。

      这是一个跨车道操作,将车道元素从当前向量和第二个向量移到前面。这两个向量都可以看作是长度为 2*VLENGTH 的组合“背景”,从中提取切片。返回结果等于表达式 broadcast(0).blend(slice(origin,v1),m)

      API 注意:
      此方法可被视为 #unslice(int,Vector,int,VectorMask) unslice() 的反函数,因为可以将切片值解切片回到其在两个输入向量中的原始位置,而不会干扰不相关的元素,如以下伪代码所示:
      
       EVector slice = v1.slice(origin, v2, m);
       EVector w1 = slice.unslice(origin, v1, 0, m);
       EVector w2 = slice.unslice(origin, v2, 1, m);
       assert v1.equals(w1);
       assert v2.equals(w2);
        
      参数:
      origin - 传输到切片中的第一个输入通道
      v1 - 在获取切片之前,第二个向量与第一个向量逻辑连接(如果省略,则默认为零)
      m - 掩码控制车道选择到结果向量中
      返回:
      VLENGTH 车道的连续切片,从指定的原点开始从该向量中获取,并继续(根据需要)进入第二个向量
      抛出:
      ArrayIndexOutOfBoundsException - 如果 origin 为负或大于 VLENGTH
      参见:
    • slice

      public abstract Vector <E > slice(int origin)
      从当前向量中给定的 origin 车道开始,对相邻车道的一段进行切片。 VLENGTH 车道的块,可能用零车道填充,被提取到它自己的向量中并返回。这是一种方便的方法,它根据零车道的扩展背景从单个向量中切片。它相当于 slice (origin, broadcast (0)) 。它也可以简单地看作是从较晚的车道到较早的车道的跨车道移位,在向量末端的空出车道中填充零。在此视图中,移位计数为 origin
      参数:
      origin - 传输到切片中的第一个输入通道
      返回:
      最后 VLENGTH-origin 输入通道,从输出的第一通道开始放置,最后用零填充
      抛出:
      ArrayIndexOutOfBoundsException - 如果 origin 为负或大于 VLENGTH
      参见:
    • unslice

      public abstract Vector <E > unslice(int origin, Vector <E > w, int part)
      反转 slice() ,将当前向量作为切片插入另一个“背景”输入向量中,该向量被视为假设的后续 slice() 操作的一个或另一个输入。

      这是一个跨车道操作,它将当前向量的车道元素向后排列,并将它们插入一对逻辑背景向量中。但是,只有一对中的一个会被退回。背景是通过复制第二个输入向量形成的。 (但是,输出永远不会包含来自同一输入通道的两个副本。)输入向量中编号为 N 的通道被复制到第一个背景向量的通道 origin+N 中,如果该通道存在,则复制到第二个背景向量的通道 origin+N-VLENGTH 中(保证存在)。返回用插入的切片更新的第一个或第二个背景向量。 part 数为零或一个选择第一个或第二个更新的背景向量。

      origin 值必须在包含范围 0..VLENGTH 内。作为极限情况,v.unslice(0,w,0)v.unslice(VLENGTH,w,1) 都返回 v ,而 v.unslice(0,w,1)v.unslice(VLENGTH,w,0) 都返回 w

      API 注意:
      该方法支持多种跨车道插入操作,如下:
      • 要以某个偏移量在背景矢量 w 的末尾附近插入,请将偏移量指定为原点并选择零部分。例如:v.unslice(offset, w, 0)
      • 要在背景向量 w 的末尾附近插入,但将溢出捕获到下一个向量 x 中,请将偏移量指定为原点并选择第一个部分。例如:v.unslice(offset, x, 1)
      • 要在背景向量 w 的开头附近插入最后的 N 项,请提供 VLENGTH-N 作为原点并选择第一个部分。例如:v.unslice(v.length()-N, w)
      参数:
      origin - 接收切片的第一个输出通道
      w - 背景向量(作为两个副本)将接收插入的切片
      part - 结果的部分编号(零或一)
      返回:
      一对背景向量 w 的第一部分或第二部分,通过在指定原点插入该向量进行更新
      抛出:
      ArrayIndexOutOfBoundsException - 如果 origin 为负或大于 VLENGTH ,或者如果 part 不是零或一
      参见:
    • unslice

      public abstract Vector <E > unslice(int origin, Vector <E > w, int part, VectorMask <E > m)
      反转 slice() ,将当前向量作为切片插入(在掩码的控制下)另一个“背景”输入向量中,该输入向量被视为假设的后续 slice() 操作的一个或另一个输入。

      这是一个跨车道操作,它向前排列当前向量的车道元素并将其车道(当被掩码选择时)插入一对逻辑背景向量。与此方法的 未屏蔽版本 一样,将仅返回一对中的一个,由 part 编号选择。对于掩码选择的每个车道N,车道值被复制到第一个背景向量的车道origin+N,如果该车道存在,则复制到第二个背景向量的车道origin+N-VLENGTH(保证存在)。如果相应的输入通道 N 在掩码中未设置,则背景通道将保留其原始值。返回第一个或第二个背景向量,更新为插入切片的设置通道。 part 数为零或一个选择第一个或第二个更新的背景矢量。

      参数:
      origin - 接收切片的第一个输出通道
      w - 背景向量(作为两个副本)将接收插入的切片,如果它们在 m 中设置
      part - 结果的部分编号(零或一)
      m - 从当前向量中控制车道选择的掩码
      返回:
      一对背景向量 w 的第一部分或第二部分,通过在指定原点插入该向量的选定通道进行更新
      抛出:
      ArrayIndexOutOfBoundsException - 如果 origin 为负或大于 VLENGTH ,或者如果 part 不是零或一
      参见:
    • unslice

      public abstract Vector <E > unslice(int origin)
      反转 slice() ,将当前向量作为切片插入零通道值的“背景”输入中。与其他 unslice() 方法相比,此方法仅返回一对背景向量中的第一个。这是一个返回 unslice (origin, broadcast (0), 0) 结果的便捷方法。它也可以简单地看作是从较早的车道到较晚的车道的跨车道移位,在向量的开头处用零填充空出的车道。在此视图中,移位计数为 origin
      参数:
      origin - 接收切片的第一个输出通道
      返回:
      第一个 VLENGTH-origin 输入通道,从给定的原点开始放置,在开头用零填充
      抛出:
      ArrayIndexOutOfBoundsException - 如果 origin 为负或大于 VLENGTH
      参见:
    • rearrange

      public abstract Vector <E > rearrange(VectorShuffle <E > s)
      重新排列此向量的泳道元素,在特定洗牌的控制下选择泳道。这是一个跨车道操作,重新排列该向量的车道元素。对于洗牌的每个通道N,以及洗牌中的每个通道源索引I=s.laneSource(N),输出通道N从通道I的输入向量中获取值。
      参数:
      s - 洗牌控制车道索引选择
      返回:
      该向量的车道元素的重新排列
      抛出:
      IndexOutOfBoundsException - 如果洗牌中有任何异常的源索引
      参见:
    • rearrange

      public abstract Vector <E > rearrange(VectorShuffle <E > s, VectorMask <E > m)
      重新排列此向量的泳道元素,在特定洗牌和遮罩的控制下选择泳道。这是一个跨车道操作,重新排列该向量的车道元素。对于洗牌的每个通道N,以及洗牌中的每个通道源索引I=s.laneSource(N),如果设置了掩码,则输出通道N从通道I的输入向量中获取值。否则输出通道 N 设置为零。

      此方法返回此伪代码的值:

      
       Vector<E> r = this.rearrange(s.wrapIndexes());
       VectorMask<E> valid = s.laneIsValid();
       if (m.andNot(valid).anyTrue()) throw ...;
       return broadcast(0).blend(r, m);
        
      参数:
      s - 洗牌控制车道索引选择
      m - 随机播放的掩码控制应用程序
      返回:
      该向量的车道元素的重新排列
      抛出:
      IndexOutOfBoundsException - 如果在设置掩码的洗牌中有任何异常源索引
      参见:
    • rearrange

      public abstract Vector <E > rearrange(VectorShuffle <E > s, Vector <E > v)
      重新排列两个向量的通道元素,在特定洗牌的控制下选择通道,使用洗牌中的正常和异常索引来引导数据。这是一个跨车道操作,重新排列两个输入向量(当前向量和第二个向量v)的车道元素。对于洗牌的每个通道N,以及洗牌中的每个通道源索引I=s.laneSource(N),输出通道N从通道I如果I>=0的第一个向量获得值。否则,异常索引 I 通过向其添加 VLENGTH 进行包装,并用于在索引 I+VLENGTH 处索引 second 向量。

      此方法返回此伪代码的值:

      
       Vector<E> r1 = this.rearrange(s.wrapIndexes());
       // or else: r1 = this.rearrange(s, s.laneIsValid());
       Vector<E> r2 = v.rearrange(s.wrapIndexes());
       return r2.blend(r1,s.laneIsValid());
        
      参数:
      s - 来自两个输入向量的洗牌控制车道选择
      v - 第二个输入向量
      返回:
      该向量和第二个输入向量的车道元素的重新排列
      参见:
    • compress

      public abstract Vector <E > compress(VectorMask <E > m)
      在特定掩码的控制下压缩此矢量选择车道的车道元素。这是一个跨车道操作,它压缩由指定掩码选择的此向量的车道元素。对于掩码的每个通道N,如果设置了通道N处的掩码,则选择输入向量的通道N处的元素并将其存储到从通道0开始连续的输出向量中。输出向量的所有上部剩余通道(如果有的话)都设置为零。
      参数:
      m - 控制压缩的掩码
      返回:
      此向量的压缩车道元素
      自从:
      19
    • expand

      public abstract Vector <E > expand(VectorMask <E > m)
      在特定掩码的控制下扩展此矢量的车道元素。这是一个跨车道操作,它将此向量的连续车道元素扩展到由指定掩码选择的输出向量的车道中。对于掩码的每个通道 N,如果设置了通道 N 处的掩码,则选择从通道 0 开始的输入向量的下一个连续元素,并将其存储到通道 N 的输出向量中。输出向量的所有剩余通道(如果有的话)都设置为零。
      参数:
      m - 控制压缩的掩码
      返回:
      此向量的扩展车道元素
      自从:
      19
    • selectFrom

      public abstract Vector <E > selectFrom(Vector <E > v)
      使用存储在此向量通道中的索引值,组装存储在第二个向量 v 中的值。因此,第二个向量用作表,其元素由当前向量中的索引选择。这是一个跨车道操作,在该向量的控制下重新排列参数向量的车道元素。对于此向量的每个通道 N,以及此向量中的每个通道值 I=this.lane(N),输出通道 N 从通道 I 的参数向量中获取值。通过这种方式,结果仅包含存储在参数向量 v 中的值,但显示顺序取决于 this 中的索引值。结果与表达式 v.rearrange(this.toShuffle()) 相同。
      参数:
      v - 提供结果值的向量
      返回:
      v 车道元素的重新排列
      抛出:
      IndexOutOfBoundsException - 如果在 this 中发现任何无效的源索引
      参见:
    • selectFrom

      public abstract Vector <E > selectFrom(Vector <E > v, VectorMask <E > m)
      使用存储在该向量通道中的索引值,在掩码的控制下组装存储在第二个向量中的值。使用存储在此向量通道中的索引值,组装存储在第二个向量 v 中的值。因此,第二个向量用作表,其元素由当前向量中的索引选择。掩码中未设置的通道接收零而不是表中的值。这是一个跨车道操作,在该向量和掩码的控制下重新排列参数向量的车道元素。结果与表达式 v.rearrange(this.toShuffle(), m) 相同。
      参数:
      v - 提供结果值的向量
      m - 来自 v 的掩码控制选择
      返回:
      v 车道元素的重新排列
      抛出:
      IndexOutOfBoundsException - 如果在 this 中发现任何无效的源索引,在掩码中设置的通道中
      参见:
    • broadcast

      public abstract Vector <E > broadcast(long e)
      返回一个与这个相同种类的向量,其中所有车道元素都设置为原始值 e 。当前向量的内容被丢弃;只有物种与此操作相关。

      此方法返回此表达式的值: EVector.broadcast(this.species(), (ETYPE)e) ,其中 EVector 是特定于此向量的元素类型 ETYPE 的向量类。

      longe 必须由该向量种类的 ETYPE 准确表示,以便 e==(long)(ETYPE)e 。如果违反此规则,则不会静态检测到问题,但会在运行时抛出 IllegalArgumentException。因此,这种方法在一定程度上削弱了对立即数和其他标量的静态类型检查,但它通过提高泛型 API 的表达能力来弥补这一点。请注意,[-128..127] 范围内的 e 值始终是可接受的,因为每个 ETYPE 都将接受每个 byte 值。

      API 注意:
      子类型通过锐化方法返回类型和标量参数 e 的类型来改进此方法。
      参数:
      e - 要广播的值
      返回:
      一个向量,其中所有车道元素都设置为原始值 e
      抛出:
      IllegalArgumentException - 如果给定的 long 值不能由向量的 ETYPE 表示
      参见:
    • maskAll

      public abstract VectorMask <E > maskAll(boolean bit)
      返回与此向量相同物种的掩码,其中根据给定的单个boolean设置或取消设置每个车道,该boolean广播到所有车道。

      此方法返回此表达式的值:species().maskAll(bit)

      参数:
      bit - 要复制的给定掩码位
      返回:
      根据给定位设置或取消设置每个通道的掩码
      参见:
    • toShuffle

      public abstract VectorShuffle <E > toShuffle()
      将此向量转换为随机播放,将通道值转换为 int 并将它们视为源索引。

      此方法的行为就像它返回给定向量元素数组创建洗牌的结果,如下所示:

      
       long[] a = this.toLongArray();
       int[] sa = new int[a.length];
       for (int i = 0; i < a.length; i++) {
         sa[i] = (int) a[i];
       }
       return VectorShuffle.fromValues(this.species(), sa);
        
      返回:
      此向量的随机表示
      参见:
    • reinterpretShape

      public abstract <F> Vector <F> reinterpretShape(VectorSpecies <F> species, int part)
      将此向量转换为元素类型为 F 的给定种类的向量,重新解释此向量的字节而不执行任何值转换。

      根据所选的物种,此操作可能会扩张或收缩其逻辑结果,在这种情况下,非零part数字可以进一步控制逻辑结果的选择和转向到物理输出向量。

      该向量的底层位被不加修改地复制到结果向量中,但是如果该向量的位大小大于所需向量的位大小,则这些位在复制之前可能会被截断,或者如果该向量的位-大小小于所需向量的位大小。

      如果新旧物种的形状不同,这是一个 shape-changing 操作,可能有特殊的实施成本。

      该方法的行为就像使用小端字节顺序将该向量存储到字节数组中,然后使用相同的顺序从相同的字节数组加载所需的向量。

      以下伪代码说明了该行为:

      
       int domSize = this.byteSize();
       int ranSize = species.vectorByteSize();
       int M = (domSize > ranSize ? domSize / ranSize : ranSize / domSize);
       assert Math.abs(part) < M;
       assert (part == 0) || (part > 0) == (domSize > ranSize);
       MemorySegment ms = MemorySegment.ofArray(new byte[Math.max(domSize, ranSize)]);
       if (domSize > ranSize) { // expansion
         this.intoMemorySegment(ms, 0, ByteOrder.native());
         int origin = part * ranSize;
         return species.fromMemorySegment(ms, origin, ByteOrder.native());
       } else { // contraction or size-invariant
         int origin = (-part) * domSize;
         this.intoMemorySegment(ms, origin, ByteOrder.native());
         return species.fromMemorySegment(ms, 0, ByteOrder.native());
       }
        
      API 注意:
      尽管此方法被定义为将所讨论的向量加载或存储到内存中,但内存语义与实际实现几乎没有关系或根本没有关系。对 little-endian 排序的诉求只是简写,否则可能是关于通道结构向量和字节结构向量之间映射的大量详细规则。
      类型参数:
      F - 物种的盒装元素类型
      参数:
      species - 所需的载体种类
      part - 结果的 零件号,如果既不扩展也不收缩则为零
      返回:
      从这个向量按形状和元素类型转换的向量
      参见:
    • reinterpretAsBytes

      public abstract ByteVector  reinterpretAsBytes()
      将此向量视为具有相同形状和内容但通道类型为 byte 的向量,其中根据小端顺序从通道中提取字节。它是表达式 reinterpretShape(species().withLanes(byte.class)) 的便捷方法。它可以被视为与将字节合并到同一向量内的更大通道的各种方法相反,例如 reinterpretAsInts()
      返回:
      具有相同形状和信息内容的ByteVector
      参见:
    • reinterpretAsShorts

      public abstract ShortVector  reinterpretAsShorts()
      将此向量重新解释为具有相同形状和内容但通道类型为 short 的向量,其中通道根据小端顺序从连续字节组装而成。它是表达式 reinterpretShape(species().withLanes(short.class)) 的便捷方法。它可以被认为是 reinterpretAsBytes() 的逆。
      返回:
      具有相同形状和信息内容的ShortVector
    • reinterpretAsInts

      public abstract IntVector  reinterpretAsInts()
      将此向量重新解释为具有相同形状和内容但通道类型为 int 的向量,其中通道根据小端顺序从连续字节组装而成。它是表达式 reinterpretShape(species().withLanes(int.class)) 的便捷方法。它可以被认为是 reinterpretAsBytes() 的逆。
      返回:
      具有相同形状和信息内容的IntVector
    • reinterpretAsLongs

      public abstract LongVector  reinterpretAsLongs()
      将此向量重新解释为具有相同形状和内容但通道类型为 long 的向量,其中通道根据小端顺序从连续字节组装而成。它是表达式 reinterpretShape(species().withLanes(long.class)) 的便捷方法。它可以被认为是 reinterpretAsBytes() 的逆。
      返回:
      具有相同形状和信息内容的LongVector
    • reinterpretAsFloats

      public abstract FloatVector  reinterpretAsFloats()
      将此向量重新解释为具有相同形状和内容但通道类型为 float 的向量,其中通道根据小端顺序从连续字节组装而成。它是表达式 reinterpretShape(species().withLanes(float.class)) 的便捷方法。它可以被认为是 reinterpretAsBytes() 的逆。
      返回:
      具有相同形状和信息内容的FloatVector
    • reinterpretAsDoubles

      public abstract DoubleVector  reinterpretAsDoubles()
      将此向量重新解释为具有相同形状和内容但通道类型为 double 的向量,其中通道根据小端顺序从连续字节组装而成。它是表达式 reinterpretShape(species().withLanes(double.class)) 的便捷方法。它可以被认为是 reinterpretAsBytes() 的逆。
      返回:
      具有相同形状和信息内容的DoubleVector
    • viewAsIntegralLanes

      public abstract Vector <?> viewAsIntegralLanes()
      将此向量视为具有相同形状、长度和内容的向量,但不是浮点类型的车道类型。这是对车道值的车道重新解释。因此,此方法不会更改 VSHAPEVLENGTH ,并且向量的按位内容也不会更改。如果向量的 ETYPE 已经是整数类型,则返回相同的向量不变。此方法返回此表达式的值: convert(conv,0) ,其中 convVectorOperators.Conversion.ofReinterpret(E.class,F.class) ,而 F 是与 E 大小相同的非浮点类型。
      API 注意:
      子类型通过锐化返回类型来改进此方法。
      返回:
      原始向量,重新解释为非浮点数
      参见:
    • viewAsFloatingLanes

      public abstract Vector <?> viewAsFloatingLanes()
      将此向量视为具有相同形状、长度和内容的向量,但通道类型为浮点类型。这是对车道值的车道重新解释。因此,此方法不会更改 VSHAPEVLENGTH ,并且向量的按位内容也不会更改。如果向量的 ETYPE 已经是浮点类型,则返回相同的向量不变。如果向量的元素大小与任何浮点类型大小都不匹配,则会抛出 IllegalArgumentException。此方法返回此表达式的值:convert(conv,0),其中 convVectorOperators.Conversion.ofReinterpret(E.class,F.class)F 是与 E 大小相同的浮点类型(如果有)。
      API 注意:
      子类型通过锐化返回类型来改进此方法。
      返回:
      原始向量,重新解释为浮点数
      抛出:
      UnsupportedOperationException - 如果没有与此向量的通道大小相同的浮点类型
      参见:
    • convert

      public abstract <F> Vector <F> convert(VectorOperators.Conversion <E ,F> conv, int part)
      将此向量转换为具有相同形状和新元素类型的向量,根据指示的 转换 将车道值从当前的 ETYPE 转换为新的车道类型(此处称为 FTYPE)。这是一个车道方向的形状不变操作,它将输入向量中的 ETYPE 个值复制到结果中相应的 FTYPE 个值。根据所选的转换,此操作可能扩张或收缩其逻辑结果,在这种情况下,非零part数字可以进一步控制逻辑结果的选择和转向到物理输出向量。

      每个特定的转换都由类 VectorOperators 中的转换常量描述。每个转换运算符都有一个指定的 域类型范围类型 。域类型必须与输入向量的车道类型完全匹配,而范围类型决定了输出向量的车道类型。

      转换运算符可分为(分别)就地、扩展或收缩,这取决于其域类型的位大小是否(分别)等于、小于或大于其范围类型的位大小.

      独立地,转换操作也可以分为重新解释或值转换,这取决于转换是复制未更改的表示位,还是更改表示位以保留(部分或全部)输入值的逻辑值。

      如果重新解释转换合同,它将截断输入的高位。如果它扩展,当没有相应的输入位时,它将用零位填充输出的高位。

      扩展转换,如 S2Ishort 值到 int)采用标量值并以更大的格式表示它(总是有一些信息冗余)。诸如 D2Fdouble 值到 float )之类的收缩转换采用标量值并以较小的格式表示它(总是会丢失一些信息)。一些就地转换也可能包括信息丢失,例如 L2Dlong 值到 double )或 F2Ifloat 值到 int )。重新解释就地转换不会有损,除非按位值在某种程度上在输出类型中不合法。转换 NaN 的位模式可能会丢弃 NaN 的有效数字中的位。

      这种分类很重要,因为除非另有说明,否则转换操作 never change vector shape ,无论它们如何更改 lane sizes 。因此,expanding 转换不能将其所有结果存储在其输出向量中,因为输出向量具有较少的较大尺寸的通道,以便具有与其输入相同的总体位大小。同样,收缩转换必须将其相对较小的结果存储到输出向量通道的子集中,将未使用的通道默认为零。

      例如,从 bytelong (M=8 ) 的转换将丢弃 87.5% 的输入值,以便将剩余的 12.5% 转换为输出向量的宽敞 long 通道。反向转换将转换回所有较大的结果,但会浪费输出向量中 87.5% 的通道。 In-place 转换 (M=1 ) 在一个输出向量中提供所有结果,而不会浪费通道。

      为了管理这些 扩张和收缩 的细节,一个非零的 part 参数从扩展中选择部分结果,或者将收缩的结果引导到相应的位置,如下所示:

      • M 扩展:part 必须在 [0..M-1] 范围内,并选择从 origin lane at part*VLENGTH/M 开始的 VLENGTH/M 输入通道块。

        VLENGTH/M 输出通道表示转换的整个逻辑结果的部分片段,填充整个物理输出向量。

      • M 收缩:part 必须在 [-M+1..0] 范围内,并将所有 VLENGTH 输入通道引导到位于 origin lane -part*VLENGTH 的输出。总共有 VLENGTH*M 个输出通道,那些没有保存转换输入值的通道用零填充。

        一组这样的输出向量,逻辑结果部分被引导到不相交的块,可以使用 按位或 或(对于浮点) FIRST_NONZERO 运算符重新组合。

      • 就地 (M=1):part 必须为零。两个向量具有相同的 VLENGTH 。结果始终位于零的origin lane

      此方法是更通用但不太常用的 shape-changing 方法 convertShape() 的受限版本。此方法的结果与表达式 this.convertShape(conv, rsp, this.broadcast(part)) 相同,其中输出物种为 rsp=this.species().withLanes(FTYPE.class)

      类型参数:
      F - 物种的盒装元素类型
      参数:
      conv - 应用 lane-wise 所需的标量转换
      part - 结果的 零件号,如果既不扩展也不收缩则为零
      返回:
      从此向量按形状和元素类型转换的向量
      抛出:
      ArrayIndexOutOfBoundsException - 除非 part 为零,否则膨胀比为 Mpart 为正且小于 M ,否则收缩比为 Mpart 为负且大于 -M
      参见:
    • convertShape

      public abstract <F> Vector <F> convertShape(VectorOperators.Conversion <E ,F> conv, VectorSpecies <F> rsp, int part)
      将此向量转换为给定种类、形状和元素类型的向量,根据指示的 转换 将车道值从当前的 ETYPE 转换为新的车道类型(此处称为 FTYPE)。这是一个 lane-wise 操作,它将输入向量中的 ETYPE 个值复制到结果中相应的 FTYPE 个值。

      如果新旧物种具有相同的形状,则行为与更简单的形状不变方法 convert() 完全相同。在这种情况下,应该使用更简单的方法 convert(),以使代码更易于推理。否则,这是一个 shape-changing 操作,可能有特殊的实施成本。

      作为形状变化和车道大小变化的综合影响,输入和输出物种可能具有不同的车道数,从而导致 扩张或收缩 。在这种情况下,非零 part 参数从扩展逻辑结果中选择部分结果,或将收缩逻辑结果的结果引导到所需输出种类的物理输出向量中。

      以下伪代码说明了此方法针对就地、扩展和收缩转换的行为。 (此伪代码也适用于形状不变方法,但对输出种类有形状限制。)请注意,三个代码路径中只有一个与转换运算符和形状的任何特定组合相关。

      
       FTYPE scalar_conversion_op(ETYPE s);
       EVector a = ...;
       VectorSpecies<F> rsp = ...;
       int part = ...;
       VectorSpecies<E> dsp = a.species();
       int domlen = dsp.length();
       int ranlen = rsp.length();
       FTYPE[] logical = new FTYPE[domlen];
       for (int i = 0; i < domlen; i++) {
        logical[i] = scalar_conversion_op(a.lane(i));
       }
       FTYPE[] physical;
       if (domlen == ranlen) { // in-place
         assert part == 0; //else AIOOBE
         physical = logical;
       } else if (domlen > ranlen) { // expanding
         int M = domlen / ranlen;
         assert 0 <= part && part < M; //else AIOOBE
         int origin = part * ranlen;
         physical = Arrays.copyOfRange(logical, origin, origin + ranlen);
       } else { // (domlen < ranlen) // contracting
         int M = ranlen / domlen;
         assert 0 >= part && part > -M; //else AIOOBE
         int origin = -part * domlen;
         System.arraycopy(logical, 0, physical, origin, domlen);
       }
       return FVector.fromArray(ran, physical, 0);
        
      类型参数:
      F - 输出物种的盒装元素类型
      参数:
      conv - 应用 lane-wise 所需的标量转换
      rsp - 所需的输出种类
      part - 结果的 零件号,如果既不扩展也不收缩则为零
      返回:
      从此向量按元素类型转换的向量
      参见:
    • castShape

      public abstract <F> Vector <F> castShape(VectorSpecies <F> rsp, int part)
      将向量从一种车道类型转换为另一种车道类型的便捷方法,并在车道大小发生变化时根据需要重新整形。此方法返回此表达式的值:convertShape(conv,rsp,part),其中 convVectorOperators.Conversion.ofCast(E.class,F.class)

      如果新旧物种的形状不同,这是一个 shape-changing 操作,可能有特殊的实施成本。

      类型参数:
      F - 输出物种的盒装元素类型
      参数:
      rsp - 所需的输出种类
      part - 结果的 零件号,如果既不扩展也不收缩则为零
      返回:
      从此向量按元素类型转换的向量
      参见:
    • check

      public abstract <F> Vector <F> check(Class <F> elementType)
      检查此向量是否具有给定的元素类型,并返回此向量不变。效果类似于此伪代码:elementType == species().elementType() ? this : throw new ClassCastException()
      类型参数:
      F - 所需车道类型的盒装元素类型
      参数:
      elementType - 所需的车道类型
      返回:
      同一个向量
      抛出:
      ClassCastException - 如果向量有错误的元素类型
      参见:
    • check

      public abstract <F> Vector <F> check(VectorSpecies <F> species)
      检查此向量是否具有给定的物种,并返回此向量不变。效果类似于此伪代码:species == species() ? this : throw new ClassCastException()
      类型参数:
      F - 所需物种的盒装元素类型
      参数:
      species - 所需品种
      返回:
      同一个向量
      抛出:
      ClassCastException - 如果向量有错误的物种
      参见:
    • intoMemorySegment

      public abstract void intoMemorySegment(MemorySegment PREVIEW  ms, long offset, ByteOrder  bo)
      将此向量存储到 内存段PREVIEW 使用显式字节顺序从偏移量开始。

      根据指定的字节顺序从原始通道元素中提取字节。车道根据它们的 内存排序 存储。

      此方法的行为就像它调用 intoMemorySegment() PREVIEW 如下:

      
       var m = maskAll(true);
       intoMemorySegment(ms, offset, bo, m);
        
      参数:
      ms - 内存段
      offset - 内存段的偏移量
      bo - 预期的字节顺序
      抛出:
      IndexOutOfBoundsException - 如果 offset+N*ESIZE < 0offset+(N+1)*ESIZE > ms.byteSize() 用于向量中的任何通道 N
      UnsupportedOperationException - 如果内存段是只读的
      IllegalArgumentException - 如果内存段是堆段且不受 byte[] 数组支持。
      IllegalStateException - 如果内存段的会话不活动,或者访问发生在线程拥有会话以外的线程。
      自从:
      19
    • intoMemorySegment

      public abstract void intoMemorySegment(MemorySegment PREVIEW  ms, long offset, ByteOrder  bo, VectorMask <E > m)
      将此向量存储到 内存段PREVIEW 使用显式字节顺序和掩码从偏移量开始。

      根据指定的字节顺序从原始通道元素中提取字节。车道根据它们的 内存排序 存储。

      以下伪代码说明了该行为,其中 JAVA_E 是原始元素类型的布局,ETYPE 是原始元素类型,EVector 是该向量的原始向量类型:

      
       ETYPE[] a = this.toArray();
       var slice = ms.asSlice(offset)
       for (int n = 0; n < a.length; n++) {
         if (m.laneIsSet(n)) {
           slice.setAtIndex(ValueLayout.JAVA_E.withBitAlignment(8), n);
         }
       }
        
      实现注意事项:
      如果指定的字节顺序与 平台原生订单 相同,此操作可能会更有效,因为此方法不需要重新排序通道值的字节。在 ETYPEbyte 的特殊情况下,字节顺序参数将被忽略。
      参数:
      ms - 内存段
      offset - 内存段的偏移量
      bo - 预期的字节顺序
      m - 掩码控制车道选择
      抛出:
      IndexOutOfBoundsException - 如果 offset+N*ESIZE < 0offset+(N+1)*ESIZE > ms.byteSize() 用于设置掩码的向量中的任何通道 N
      UnsupportedOperationException - 如果内存段是只读的
      IllegalArgumentException - 如果内存段是堆段且不受 byte[] 数组支持。
      IllegalStateException - 如果内存段的会话不活动,或者访问发生在线程拥有会话以外的线程。
      自从:
      19
    • toArray

      public abstract Object  toArray()
      返回包含所有车道值的压缩数组。数组长度与向量长度相同。数组的元素类型与向量的元素类型相同。数组元素按通道顺序存储。在指定元素类型的 Vector 子类型上重写此方法具有准确类型化的数组结果。
      API 注意:
      如果您正在使用具有已知元素类型的矢量子类型,通常 强类型访问 更可取。
      返回:
      包含此向量的车道值的准确类型数组
      参见:
    • toIntArray

      public abstract int[] toIntArray()
      返回包含所有车道值的 int[] 数组,转换为类型 int 。数组长度与向量长度相同。数组元素的转换就像通过强制转换一样,并按通道顺序存储。如果向量元素类型为 floatdouble,当泳道包含分数或超出范围的值时,此操作可能会失败。如果任何矢量通道值不能表示为 int ,则会抛出异常。
      API 注意:
      如果您正在使用具有已知元素类型的矢量子类型,通常 强类型访问 更可取。
      返回:
      包含此向量的车道值的 int[] 数组
      抛出:
      UnsupportedOperationException - 如果任何车道值不能表示为 int 数组元素
      参见:
    • toLongArray

      public abstract long[] toLongArray()
      返回包含所有车道值的 long[] 数组,转换为类型 long 。数组长度与向量长度相同。数组元素的转换就像通过强制转换一样,并按通道顺序存储。如果向量元素类型为 floatdouble,当泳道包含分数或超出范围的值时,此操作可能会失败。如果任何矢量通道值不能表示为 long ,则会抛出异常。
      API 注意:
      如果您正在使用具有已知元素类型的矢量子类型,通常 强类型访问 更可取。
      返回:
      包含此向量的车道值的 long[] 数组
      抛出:
      UnsupportedOperationException - 如果任何车道值不能表示为 long 数组元素
      参见:
    • toDoubleArray

      public abstract double[] toDoubleArray()
      返回包含所有车道值的 double[] 数组,转换为类型 double 。数组长度与向量长度相同。数组元素的转换就像通过强制转换一样,并按通道顺序存储。如果向量元素类型为 long,此操作可能会丢失精度。
      API 注意:
      如果您正在使用具有已知元素类型的矢量子类型,通常 strongly typed access 更可取。
      返回:
      包含此向量的车道值的 double[] 数组,可能四舍五入为可表示的 double
      参见:
    • toString

      public abstract String  toString()
      返回此向量的字符串表示形式,形式为 "[0,1,2...]" ,按车道顺序报告此向量的车道值。该字符串是通过调用 Arrays.toString() 生成的,适用于 this.toArray() 返回的数组。
      重写:
      toString 在类 Object
      返回:
      形式为 "[0,1,2...]" 的字符串,报告此向量的车道值
    • equals

      public abstract boolean equals(Object  obj)
      指示此向量是否与其他某个对象相同。仅当两个向量具有相同的物种和相同的泳道值且顺序相同时,它们才是相同的。

      通道值的比较就像调用 Arrays.equals() 一样产生,适用于 toArray() 在两个向量上返回的数组。

      重写:
      equals 在类 Object
      参数:
      obj - 要比较的参考对象。
      返回:
      此向量是否与其他某个对象相同
      参见:
    • hashCode

      public abstract int hashCode()
      返回向量的哈希码值。基于车道值和矢量种类。
      重写:
      hashCode 在类 Object
      返回:
      此向量的哈希码值
      参见:
    • getPayload

      protected final Object  getPayload()