# SIMD

## Overview

SIMD (pronounced `/sim-dee/`) is the abbreviation of "Single Instruction/Multiple Data", which means "single instruction, multiple data". It is the interface for JavaScript to operate the corresponding instructions of the CPU. You can see this as a different operation execution mode. The opposite of it is SISD ("Single Instruction/Single Data"), which means "single instruction, single data".

The meaning of SIMD is to use one instruction to complete the operation of multiple data; the meaning of SISD is to use one instruction to complete the operation of a single data, which is the default operation mode of JavaScript. Obviously, the execution efficiency of SIMD is higher than that of SISD, so it is widely used in 3D graphics operations, physical simulations and other projects with large computational complexity.

In order to understand SIMD, please look at the following example.

``````var a = [1, 2, 3, 4];
var b = [5, 6, 7, 8];
var c = [];

c[0] = a[0] + b[0];
c[1] = a[1] + b[1];
c[2] = a[2] + b[2];
c[3] = a[3] + b[3];
c; // Array[6, 8, 10, 12]
``````

In the above code, the corresponding members of the arrays `a` and `b` are added, and the result is put into the array `c`. Its operation mode is to process each array member in turn. There are four array members in total, so 4 operations are required.

If the SIMD mode is used, only one calculation is enough.

``````var a = SIMD.Float32x4(1, 2, 3, 4);
var b = SIMD.Float32x4(5, 6, 7, 8);
var c = SIMD.Float32x4.add(a, b); // Float32x4[6, 8, 10, 12]
``````

In the above code, the addition of the four members of the arrays `a` and `b` is completed with only one instruction. Therefore, the speed is 4 times faster than the previous writing method.

One SIMD operation can process multiple data. These data are called "lane". In the above code, four data are calculated at one time, so there are four channels.

SIMD is usually used for vector operations.

``````v + w = ​​〈v1, …, vn〉 + 〈w1, …, wn〉
= 〈V1+w1, …, vn+wn〉
``````

In the above code, `v` and `w` are two multivariate vectors. Their addition operation is completed by one instruction instead of n instructions under SIMD, which greatly improves efficiency. This is very important for operations such as 3D animation, image processing, signal processing, numerical processing, and encryption. For example, Canvas `getImageData()` will read the image file as a binary array, and SIMD is very suitable for processing this kind of array.

In general, SIMD is a means of data parallelism, which can speed up some computationally intensive operations. In the future, when combined with WebAssembly, JavaScript can reach the running speed of binary code.

## type of data

SIMD provides 12 data types with a total length of 128 binary bits.

-Float32x4: Four 32-bit floating point numbers -Float64x2: Two 64-bit floating point numbers -Int32x4: Four 32-bit integers -Int16x8: Eight 16-bit integers -Int8x16: Sixteen 8-bit integers -Uint32x4: Four unsigned 32-bit integers -Uint16x8: Eight unsigned 16-bit integers -Uint8x16: Sixteen unsigned 8-bit integers -Bool32x4: Four 32-bit Boolean values -Bool16x8: Eight 16-bit Boolean values -Bool8x16: Sixteen 8-bit Boolean values -Bool64x2: Two 64-bit Boolean values

Each data type is separated into two parts by the `x` symbol, the latter part represents the number of channels, and the front part represents the width and type of each channel. For example, `Float32x4` means that this value has 4 channels, and each channel is a 32-bit floating point number.

In each channel, four types of data can be placed.

-Floating point number (float, such as 1.0) -Signed integer (Int, such as -1) -Unsigned integer (Uint, such as 1) -Boolean value (Bool, contains two values ​​of `true` and `false`)

Each data type of SIMD is a function method, you can pass in parameters to generate the corresponding value.

``````var a = SIMD.Float32x4(1.0, 2.0, 3.0, 4.0);
``````

In the above code, the variable `a` is a 128-bit value containing four 32-bit floating point numbers (that is, four channels).

Note that these data type methods are not constructors, and `new` cannot be added in front, otherwise an error will be reported.

``````var v = new SIMD.Float32x4(0, 1, 2, 3);
// TypeError: SIMD.Float32x4 is not a constructor
``````

## Static method: mathematical operations

Each data type has a series of operators that support basic mathematical operations.

### SIMD.%type%.abs(), SIMD.%type%.neg()

The `abs` method accepts a SIMD value as a parameter, converts each channel of it to an absolute value, and returns it as a new SIMD value.

``````var a = SIMD.Float32x4(-1, -2, 0, NaN);
SIMD.Float32x4.abs(a);
// Float32x4[1, 2, 0, NaN]
``````

The `neg` method accepts a SIMD value as a parameter, converts each of its channels to a negative value, and returns it as a new SIMD value.

``````var a = SIMD.Float32x4(-1, -2, 3, 0);
SIMD.Float32x4.neg(a);
// Float32x4[1, 2, -3, -0]

var b = SIMD.Float64x2(NaN, Infinity);
SIMD.Float64x2.neg(b);
// Float64x2[NaN, -Infinity]
``````

The `add` method accepts two SIMD values ​​as parameters, adds them for each channel, and returns as a new SIMD value.

``````var a = SIMD.Float32x4(1.0, 2.0, 3.0, 4.0);
var b = SIMD.Float32x4(5.0, 10.0, 15.0, 20.0);
``````

In the above code, after addition, the new SIMD value is `(6.0, 12.0, 18.0. 24.0)`.

The `addSaturate` method has the same effect as the `add` method. Both channels are added, but the overflow handling is inconsistent. For the `add` method, if the addition of two values ​​overflows, the overflowed binary bits will be discarded; the `addSaturate` method returns the maximum value of the data type.

``````var a = SIMD.Uint16x8(65533, 65534, 65535, 65535, 1, 1, 1, 1);
var b = SIMD.Uint16x8(1, 1, 1, 5000, 1, 1, 1, 1);
// Uint16x8[65534, 65535, 65535, 65535, 2, 2, 2, 2]

var c = SIMD.Int16x8(32765, 32766, 32767, 32767, 1, 1, 1, 1);
var d = SIMD.Int16x8(1, 1, 1, 5000, 1, 1, 1, 1);
// Int16x8[32766, 32767, 32767, 32767, 2, 2, 2, 2]
``````

In the above code, the maximum value of `Uint16` is 65535, and the maximum value of `Int16` is 32767. Once overflow occurs, these two values ​​are returned.

Note that the two data types `Uint32x4` and `Int32x4` do not have the `addSaturate` method.

### SIMD.%type%.sub(), SIMD.%type%.subSaturate()

The `sub` method accepts two SIMD values ​​as parameters, subtracts each of their channels, and returns them as a new SIMD value.

``````var a = SIMD.Float32x4(-1, -2, 3, 4);
var b = SIMD.Float32x4(3, 3, 3, 3);
SIMD.Float32x4.sub(a, b);
// Float32x4[-4, -5, 0, 1]
``````

The `subSaturate` method has the same function as the `sub` method. Both channels are subtracted, but the overflow handling is inconsistent. For the `sub` method, if the subtraction of two values ​​overflows, the overflowed binary bits will be discarded; the `subSaturate` method returns the minimum value of the data type.

``````var a = SIMD.Uint16x8(5, 1, 1, 1, 1, 1, 1, 1);
var b = SIMD.Uint16x8(10, 1, 1, 1, 1, 1, 1, 1);
SIMD.Uint16x8.subSaturate(a, b);
// Uint16x8[0, 0, 0, 0, 0, 0, 0, 0]

var c = SIMD.Int16x8(-100, 0, 0, 0, 0, 0, 0, 0);
var d = SIMD.Int16x8(32767, 0, 0, 0, 0, 0, 0, 0);
SIMD.Int16x8.subSaturate(c, d);
// Int16x8[-32768, 0, 0, 0, 0, 0, 0, 0, 0]
``````

In the above code, the minimum value of `Uint16` is `0`, and the minimum value of `Int16` is `-32678`. Once the operation overflows, it returns to the minimum value.

### SIMD.%type%.mul(), SIMD.%type%.div(), SIMD.%type%.sqrt()

The `mul` method accepts two SIMD values ​​as parameters, multiplies each of their channels, and returns them as a new SIMD value.

``````var a = SIMD.Float32x4(-1, -2, 3, 4);
var b = SIMD.Float32x4(3, 3, 3, 3);
SIMD.Float32x4.mul(a, b);
// Float32x4[-3, -6, 9, 12]
``````

The `div` method accepts two SIMD values ​​as parameters, divides each of their channels, and returns them as a new SIMD value.

``````var a = SIMD.Float32x4(2, 2, 2, 2);
var b = SIMD.Float32x4(4, 4, 4, 4);
SIMD.Float32x4.div(a, b);
// Float32x4[0.5, 0.5, 0.5, 0.5]
``````

The `sqrt` method accepts a SIMD value as a parameter, finds the square root of each channel, and returns it as a new SIMD value.

``````var b = SIMD.Float64x2(4, 8);
SIMD.Float64x2.sqrt(b);
// Float64x2[2, 2.8284271247461903]
``````

### SIMD.%FloatType%.reciprocalApproximation(), SIMD.%type%.reciprocalSqrtApproximation()

The `reciprocalApproximation` method accepts a SIMD value as a parameter, finds the reciprocal of each channel (`1 / x`), and returns it as a new SIMD value.

``````var a = SIMD.Float32x4(1, 2, 3, 4);
SIMD.Float32x4.reciprocalApproximation(a);
// Float32x4[1, 0.5, 0.3333333432674408, 0.25]
``````

The `reciprocalSqrtApproximation` method accepts a SIMD value as a parameter, finds the reciprocal of the square root of each channel (`1 / (x^0.5)`), and returns it as a new SIMD value.

``````var a = SIMD.Float32x4(1, 2, 3, 4);
SIMD.Float32x4.reciprocalSqrtApproximation(a);
// Float32x4[1, 0.7071067690849304, 0.5773502588272095, 0.5]
``````

Note that only floating-point data types have these two methods.

### SIMD.%IntegerType%.shiftLeftByScalar()

The `shiftLeftByScalar` method accepts a SIMD value as a parameter, and then shifts the value of each channel to the left by the specified number of bits, and returns it as a new SIMD value.

``````var a = SIMD.Int32x4(1, 2, 4, 8);
SIMD.Int32x4.shiftLeftByScalar(a, 1);
// Int32x4[2, 4, 8, 16]
``````

If after shifting to the left, the new value exceeds the number of digits of the current data type, the overflow part will be discarded.

``````var ix4 = SIMD.Int32x4(1, 2, 3, 4);
var jx4 = SIMD.Int32x4.shiftLeftByScalar(ix4, 32);
// Int32x4[0, 0, 0, 0]
``````

Note that only integer data types have this method.

### SIMD.%IntegerType%.shiftRightByScalar()

The `shiftRightByScalar` method accepts a SIMD value as a parameter, and then shifts the value of each channel to the right by the specified number of bits, and returns a new SIMD value.

``````var a = SIMD.Int32x4(1, 2, 4, -8);
SIMD.Int32x4.shiftRightByScalar(a, 1);
// Int32x4[0, 1, 2, -4]
``````

If the value of the original channel is a signed value, the sign bit remains unchanged and is not affected by the right shift. If it is a value without a sign bit, the header will be filled with `0` after shifting to the right.

``````var a = SIMD.Uint32x4(1, 2, 4, -8);
SIMD.Uint32x4.shiftRightByScalar(a, 1);
// Uint32x4[0, 1, 2, 2147483644]
``````

In the above code, shifting `-8` to the right by one bit becomes `2147483644`, because for 32-bit unsigned integers, the binary form of `-8` is `11111111111111111111111111111000`, and shifting one bit to the right becomes `2147483644` `01111111111111111111111111111100` is equivalent to `2147483644`.

Note that only integer data types have this method.

## Static method: channel processing

### SIMD.%type%.check()

The `check` method is used to check whether a value is a SIMD value of the current type. If yes, return this value, otherwise report an error.

``````var a = SIMD.Float32x4(1, 2, 3, 9);

SIMD.Float32x4.check(a);
// Float32x4[1, 2, 3, 9]

SIMD.Float32x4.check([1, 2, 3, 4]); // error
SIMD.Int32x4.check(a); // error
SIMD.Int32x4.check("hello world"); // error
``````

### SIMD.%type%.extractLane(), SIMD.%type%.replaceLane()

The `extractLane` method is used to return the value of a given channel. It accepts two parameters, namely SIMD value and channel number.

``````var t = SIMD.Float32x4(1, 2, 3, 4);
SIMD.Float32x4.extractLane(t, 2); // 3
``````

The `replaceLane` method is used to replace the value of the specified channel and return a new SIMD value. It accepts three parameters, which are the original SIMD value, channel number and new channel value.

``````var t = SIMD.Float32x4(1, 2, 3, 4);
SIMD.Float32x4.replaceLane(t, 2, 42);
// Float32x4[1, 2, 42, 4]
``````

The `load` method is used to read in data from a binary array and generate a new SIMD value.

``````var a = new Int32Array([1, 2, 3, 4, 5, 6, 7, 8]);
// Int32x4[1, 2, 3, 4]

var b = new Int32Array([1, 2, 3, 4, 5, 6, 7, 8]);
// Int32x4[3, 4, 5, 6]
``````

The `load` method accepts two parameters: a binary array and the position to start reading (starting from 0). If the position is illegal (such as `-1` or exceeds the size of the binary array), an error will be thrown.

There are three variants of this method, `load1()`, `load2()`, and `load3()`, which means that starting from the specified position, only load the values ​​of one channel, two channels, and three channels.

``````// format

// instance
var a = new Int32Array([1, 2, 3, 4, 5, 6, 7, 8]);
// Int32x4[1, 0, 0, 0]
// Int32x4[1, 2, 0, 0]
// Int32x4[1, 2, 3,0]
``````

### SIMD.%type%.store()

The `store` method is used to write a SIMD value into a binary array. It accepts three parameters, which are the binary array, the position of the array to start writing, and the SIMD value. It returns the binary array after the value is written.

``````var t1 = new Int32Array(8);
var v1 = SIMD.Int32x4(1, 2, 3, 4);
SIMD.Int32x4.store(t1, 0, v1);
// Int32Array[1, 2, 3, 4, 0, 0, 0, 0]

var t2 = new Int32Array(8);
var v2 = SIMD.Int32x4(1, 2, 3, 4);
SIMD.Int32x4.store(t2, 2, v2);
// Int32Array[0, 0, 1, 2, 3, 4, 0, 0]
``````

In the above code, `t1` is a binary array, `v1` is a SIMD value, and there are only four channels. So after writing `t1`, only the first four positions have values, and the last four positions are all 0. And `t2` is written from position 2, so the first two positions and the last two positions are both 0.

There are three variants of this method `store1()`, `store2()` and `store3()`, which means that only one channel, two channels and three channels are written.

``````var tarray = new Int32Array(8);
var value = SIMD.Int32x4(1, 2, 3, 4);
SIMD.Int32x4.store1(tarray, 0, value);
// Int32Array[1, 0, 0, 0, 0, 0, 0, 0]
``````

### SIMD.%type%.splat()

The `splat` method returns a new SIMD value, and all channels of this value will be set to the same predetermined value.

``````SIMD.Float32x4.splat(3);
// Float32x4[3, 3, 3, 3]
SIMD.Float64x2.splat(3);
// Float64x2[3, 3]
``````

If the parameter is omitted, all SIMD values ​​of integer type will be set to `0`, and SIMD values ​​of floating point type will be set to `NaN`.

### SIMD.%type%.swizzle()

The `swizzle` method returns a new SIMD value and rearranges the channel order of the original SIMD value.

``````var t = SIMD.Float32x4(1, 2, 3, 4);
SIMD.Float32x4.swizzle(t, 1, 2, 0, 3);
// Float32x4[2,3,1,4]
``````

In the above code, the first parameter of the `swizzle` method is the original SIMD value, and the following parameters correspond to the four channels of the SIMD value to be returned. It means the four channels of the new SIMD, which are channel 1, channel 2, channel 0, and channel 3 of the original SIMD value in sequence. Since the SIMD value can have up to 16 channels, the `swizzle` method can accept up to 16 parameters in addition to the first parameter.

Here is another example.

``````var a = SIMD.Float32x4(1.0, 2.0, 3.0, 4.0);
// Float32x4[1.0, 2.0, 3.0, 4.0]

var b = SIMD.Float32x4.swizzle(a, 0, 0, 1, 1);
// Float32x4[1.0, 1.0, 2.0, 2.0]

var c = SIMD.Float32x4.swizzle(a, 3, 3, 3, 3);
// Float32x4[4.0, 4.0, 4.0, 4.0]

var d = SIMD.Float32x4.swizzle(a, 3, 2, 1, 0);
// Float32x4[4.0, 3.0, 2.0, 1.0]
``````

### SIMD.%type%.shuffle()

The `shuffle` method takes the specified channel from the two SIMD values ​​and returns a new SIMD value.

``````var a = SIMD.Float32x4(1, 2, 3, 4);
var b = SIMD.Float32x4(5, 6, 7, 8);

SIMD.Float32x4.shuffle(a, b, 1, 5, 7, 2);
// Float32x4[2, 6, 8, 3]
``````

In the above code, `a` and `b` have a total of 8 channels, which are numbered from 0 to 7. `shuffle` takes out the corresponding channel according to the number, and returns a new SIMD value.

## Static method: comparison operation

### SIMD.%type%.equal(), SIMD.%type%.notEqual()

The `equal` method is used to compare each channel of two SIMD values ​​`a` and `b`, and get a boolean value according to whether the two are exactly equal (`a === b`). Finally, the comparison results of all channels form a new SIMD value, which is returned as a mask. The `notEqual` method compares whether the two channels are not equal (`a !== b`).

``````var a = SIMD.Float32x4(1, 2, 3, 9);
var b = SIMD.Float32x4(1, 4, 7, 9);

SIMD.Float32x4.equal(a, b);
// Bool32x4[true, false, false, true]

SIMD.Float32x4.notEqual(a, b);
// Bool32x4[false, true, true, false]
``````

### SIMD.%type%.greaterThan(), SIMD.%type%.greaterThanOrEqual()

The `greatThan` method is used to compare each channel of the two SIMD values ​​`a` and `b`. If in this channel, `a` is larger, you get `true`, otherwise, you get `false`. Finally, the comparison results of all channels form a new SIMD value, which is returned as a mask. `greaterThanOrEqual` compares whether `a` is greater than or equal to `b`.

``````var a = SIMD.Float32x4(1, 6, 3, 11);
var b = SIMD.Float32x4(1, 4, 7, 9);

SIMD.Float32x4.greaterThan(a, b);
// Bool32x4[false, true, false, true]

SIMD.Float32x4.greaterThanOrEqual(a, b);
// Bool32x4[true, true, false, true]
``````

### SIMD.%type%.lessThan(), SIMD.%type%.lessThanOrEqual()

The `lessThan` method is used to compare each channel of the two SIMD values ​​`a` and `b`. If in this channel, `a` is smaller, you get `true`, otherwise, you get `false`. Finally, the comparison results of all channels will form a new SIMD value and return it as a mask. The `lessThanOrEqual` method compares whether `a` is equal to `b`.

``````var a = SIMD.Float32x4(1, 2, 3, 11);
var b = SIMD.Float32x4(1, 4, 7, 9);

SIMD.Float32x4.lessThan(a, b);
// Bool32x4[false, true, true, false]

SIMD.Float32x4.lessThanOrEqual(a, b);
// Bool32x4[true, true, true, false]
``````

### SIMD.%type%.select()

The `select` method generates a new SIMD value through the mask. It accepts three parameters, namely the mask and two SIMD values.

``````var a = SIMD.Float32x4(1, 2, 3, 4);
var b = SIMD.Float32x4(5, 6, 7, 8);

var mask = SIMD.Bool32x4(true, false, false, true);

// Float32x4[1, 6, 7, 4]
``````

In the above code, the `select` method accepts a mask and two SIMD values ​​as parameters. When the mask corresponding to a channel is `true`, the channel corresponding to the first SIMD value will be selected, otherwise the channel corresponding to the second SIMD value will be selected.

This method is usually used in combination with comparison operators.

``````var a = SIMD.Float32x4(0, 12, 3, 4);
var b = SIMD.Float32x4(0, 6, 7, 50);

// Bool32x4[false, false, true, true]

var result = SIMD.Float32x4.select(mask, a, b);
// Float32x4[0, 6, 3, 4]
``````

In the above code, a mask is first generated by the `lessThan` method, and then a new SIMD value composed of the smaller value of each channel is generated by the `select` method.

### SIMD.%BooleanType%.allTrue(), SIMD.%BooleanType%.anyTrue()

The `allTrue` method accepts a SIMD value as a parameter, and then returns a boolean value indicating whether all channels of the SIMD value are `true`.

``````var a = SIMD.Bool32x4(true, true, true, true);
var b = SIMD.Bool32x4(true, false, true, true);

SIMD.Bool32x4.allTrue(a); // true
SIMD.Bool32x4.allTrue(b); // false
``````

The `anyTrue` method returns `true` as long as one channel is `true`, otherwise it returns `false`.

``````var a = SIMD.Bool32x4(false, false, false, false);
var b = SIMD.Bool32x4(false, false, true, false);

SIMD.Bool32x4.anyTrue(a); // false
SIMD.Bool32x4.anyTrue(b); // true
``````

Note that only four Boolean data types (`Bool32x4`, `Bool16x8`, `Bool8x16`, `Bool64x2`) have these two methods.

These two methods are usually combined with comparison operators.

``````var ax4 = SIMD.Float32x4(1.0, 2.0, 3.0, 4.0);
var bx4 = SIMD.Float32x4(0.0, 6.0, 7.0, 8.0);
var ix4 = SIMD.Float32x4.lessThan(ax4, bx4);
var b1 = SIMD.Int32x4.allTrue(ix4); // false
var b2 = SIMD.Int32x4.anyTrue(ix4); // true
``````

### SIMD.%type%.min(), SIMD.%type%.minNum()

The `min` method accepts two SIMD values ​​as parameters, and returns the smaller value of the two corresponding channels to form a new SIMD value.

``````var a = SIMD.Float32x4(-1, -2, 3, 5.2);
var b = SIMD.Float32x4(0, -4, 6, 5.5);
SIMD.Float32x4.min(a, b);
// Float32x4[-1, -4, 3, 5.2]
``````

If there is a channel whose value is `NaN`, it will return `NaN` first.

``````var c = SIMD.Float64x2(NaN, Infinity);
var d = SIMD.Float64x2(1337, 42);
SIMD.Float64x2.min(c, d);
// Float64x2[NaN, 42]
``````

The function of `minNum` is exactly the same as that of `min`, the only difference is that if the value of one channel is `NaN`, the value of the other channel will be returned first.

``````var ax4 = SIMD.Float32x4(1.0, 2.0, NaN, NaN);
var bx4 = SIMD.Float32x4(2.0, 1.0, 3.0, NaN);
var cx4 = SIMD.Float32x4.min(ax4, bx4);
// Float32x4[1.0, 1.0, NaN, NaN]
var dx4 = SIMD.Float32x4.minNum(ax4, bx4);
// Float32x4[1.0, 1.0, 3.0, NaN]
``````

### SIMD.%type%.max(), SIMD.%type%.maxNum()

The `max` method accepts two SIMD values ​​as parameters, and returns the larger value of the two corresponding channels to form a new SIMD value.

``````var a = SIMD.Float32x4(-1, -2, 3, 5.2);
var b = SIMD.Float32x4(0, -4, 6, 5.5);
SIMD.Float32x4.max(a, b);
// Float32x4[0, -2, 6, 5.5]
``````

If there is a channel whose value is `NaN`, it will return `NaN` first.

``````var c = SIMD.Float64x2(NaN, Infinity);
var d = SIMD.Float64x2(1337, 42);
SIMD.Float64x2.max(c, d);
// Float64x2[NaN, Infinity]
``````

The function of `maxNum` is exactly the same as that of `max`, the only difference is that if the value of one channel is `NaN`, the value of the other channel will be returned first.

``````var c = SIMD.Float64x2(NaN, Infinity);
var d = SIMD.Float64x2(1337, 42);
SIMD.Float64x2.maxNum(c, d);
// Float64x2[1337, Infinity]
``````

## Static method: bit operation

### SIMD.%type%.and(), SIMD.%type%.or(), SIMD.%type%.xor(), SIMD.%type%.not()

The `and` method accepts two SIMD values ​​as parameters, and returns the new SIMD value obtained after the binary `AND` operation (`&`) is performed on the corresponding channels of the two.

``````var a = SIMD.Int32x4(1, 2, 4, 8);
var b = SIMD.Int32x4(5, 5, 5, 5);
SIMD.Int32x4.and(a, b);
// Int32x4[1, 0, 4, 0]
``````

In the above code, taking channel `0` as an example, the binary form of `1` is `0001`, and the binary form of `5` is `01001`, so after performing the `AND` operation, `0001` is obtained.

The `or` method accepts two SIMD values ​​as parameters, and returns the new SIMD value obtained after the binary `OR` operation (`|`) is performed on the corresponding channels of the two.

``````var a = SIMD.Int32x4(1, 2, 4, 8);
var b = SIMD.Int32x4(5, 5, 5, 5);
SIMD.Int32x4.or(a, b);
// Int32x4[5, 7, 5, 13]
``````

The `xor` method accepts two SIMD values ​​as parameters, and returns the new SIMD value obtained by performing the binary "exclusive OR" operation (`^`) on the corresponding channels of the two.

``````var a = SIMD.Int32x4(1, 2, 4, 8);
var b = SIMD.Int32x4(5, 5, 5, 5);
SIMD.Int32x4.xor(a, b);
// Int32x4[4, 7, 1, 13]
``````

The `not` method accepts a SIMD value as a parameter, and returns the new SIMD value obtained after each channel performs a binary "no" operation (`~`).

``````var a = SIMD.Int32x4(1, 2, 4, 8);
SIMD.Int32x4.not(a);
// Int32x4[-2, -3, -5, -9]
``````

In the above code, the reason why the negation of `1` gets `-2` is because in the computer, negative numbers are expressed in the form of "2's complement". That is to say, the negative number form of the integer `n`, `-n`, is to add 1 after the inversion of each binary digit. Therefore, directly negating is equivalent to subtracting 1 from the negative number form. For example, the negative number form of `1` is `-1`, and subtracting 1 again, you get `-2`.

## Static method: data type conversion

SIMD provides the following methods to convert one data type to another data type.

-`SIMD.%type%.fromFloat32x4()` -`SIMD.%type%.fromFloat32x4Bits()` -`SIMD.%type%.fromFloat64x2Bits()` -`SIMD.%type%.fromInt32x4()` -`SIMD.%type%.fromInt32x4Bits()` -`SIMD.%type%.fromInt16x8Bits()` -`SIMD.%type%.fromInt8x16Bits()` -`SIMD.%type%.fromUint32x4()` -`SIMD.%type%.fromUint32x4Bits()` -`SIMD.%type%.fromUint16x8Bits()` -`SIMD.%type%.fromUint8x16Bits()`

The method with the `Bits` suffix will copy the binary bits to the new data type intact; the method without the suffix will perform the data type conversion.

``````var t = SIMD.Float32x4(1.0, 2.0, 3.0, 4.0);
SIMD.Int32x4.fromFloat32x4(t);
// Int32x4[1, 2, 3, 4]

SIMD.Int32x4.fromFloat32x4Bits(t);
// Int32x4[1065353216, 1073741824, 1077936128, 1082130432]
``````

In the above code, `fromFloat32x4` converts a floating-point number to an integer, and then stores it in a new data type; `fromFloat32x4Bits` copies the binary bits intact into the new data type, and then decodes it.

The method of `Bits` suffix can also be used for copying with unequal channels.

``````var t = SIMD.Float32x4(1.0, 2.0, 3.0, 4.0);
SIMD.Int16x8.fromFloat32x4Bits(t);
// Int16x8[0, 16256, 0, 16384, 0, 16448, 0, 16512]
``````

In the above code, the original SIMD value `t` is for 4 channels, and the target value is for 8 channels.

If the data size of the original channel exceeds the maximum width of the target channel during data conversion, an error will be reported.

## Example method

### SIMD.%type%.prototype.toString()

The `toString` method returns the string form of a SIMD value.

``````var a = SIMD.Float32x4(11, 22, 33, 44);
a.toString(); // "SIMD.Float32x4(11, 22, 33, 44)"
``````

## Example: Find the average

In normal mode, calculating the average of `n` values ​​requires `n` operations.

``````function average(list) {
var n = list.length;
var sum = 0.0;
for (var i = 0; i < n; i++) {
sum += list[i];
}
return sum / n;
}
``````

Using SIMD, the number of calculations can be reduced to a quarter of `n` times.

``````function average(list) {
var n = list.length;
var sum = SIMD.Float32x4.splat(0.0);
for (var i = 0; i < n; i += 4) {
The above code first reads all the values ​​into a SIMD every four digits, and then accumulates them immediately. Then, get the sum of the accumulated value of the four channels, and divide it by `n`.