mirror of
https://github.com/ruanyf/es6tutorial.git
synced 2025-05-24 18:32:22 +00:00
docs(simd): add simd chapter
This commit is contained in:
parent
96b6c5a3fd
commit
bf30299b48
@ -1252,3 +1252,62 @@ async function chainAnimationsAsync(elem, animations) {
|
|||||||
|
|
||||||
可以看到Async函数的实现最简洁,最符合语义,几乎没有语义不相关的代码。它将Generator写法中的自动执行器,改在语言层面提供,不暴露给用户,因此代码量最少。如果使用Generator写法,自动执行器需要用户自己提供。
|
可以看到Async函数的实现最简洁,最符合语义,几乎没有语义不相关的代码。它将Generator写法中的自动执行器,改在语言层面提供,不暴露给用户,因此代码量最少。如果使用Generator写法,自动执行器需要用户自己提供。
|
||||||
|
|
||||||
|
## 异步遍历器
|
||||||
|
|
||||||
|
《遍历器》一章说过,Iterator接口是一种数据遍历的协议,只要调用遍历器的`next`方法,就会得到一个对象值`{value, done}`。其中,`value`表示当前的数据的值,`done`是一个布尔值,表示遍历是否结束。
|
||||||
|
|
||||||
|
这意味着,`next`方法是同步的,只要调用就必须立刻返回值。也就是说,一旦执行`next`方法,就必须同步地得到`value`和`done`这两方面的信息。这对于同步操作,当然没有问题,但对于异步操作,就不太合适了。目前的解决方法是,Generator函数里面的异步操作,返回一个Thunk函数或者Promise对象,即`value`属性是一个Thunk函数或者Promise对象,等待以后返回真正的值,而`done`属性则还是同步产生的。
|
||||||
|
|
||||||
|
目前,有一个[提案](https://github.com/tc39/proposal-async-iteration),为异步操作提供原生的遍历器接口,即`value`和`done`这两个属性都是异步产生,这称为”异步遍历器“(Async Iterator)。
|
||||||
|
|
||||||
|
### 异步遍历的接口
|
||||||
|
|
||||||
|
异步遍历器的最大的语法特点,就是调用遍历器的`next`方法,返回的是一个Promise对象。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
asyncIterator
|
||||||
|
.next()
|
||||||
|
.then(
|
||||||
|
({ value, done }) => /* ... */
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
上面代码中,`asyncIterator`是一个异步遍历器,调用`next`方法以后,返回一个Promise对象。因此,可以使用`then`方法指定,这个Promise对象的状态变为`resolve`以后的回调函数。回调函数的参数,则是一个具有`value`和`done`两个属性的对象,这个跟同步遍历器是一样的。
|
||||||
|
|
||||||
|
我们知道,一个对象的同步遍历器的接口,部署在`Symbol.iterator`属性上面。同样地,对象的异步遍历器接口,部署在`Symbol.asyncIterator`属性上面。不管是什么样的对象,只要它的`Symbol.asyncIterator`属性有值,就表示应该对它进行异步遍历。
|
||||||
|
|
||||||
|
### for await...of
|
||||||
|
|
||||||
|
前面介绍过,`for...of`循环用于遍历同步的Iterator接口。新引入的`for await...of`循环,则是用于遍历异步的Iterator接口。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
for await (const line of readLines(filePath)) {
|
||||||
|
console.log(line);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
上面代码中,`readLines`函数返回一个异步遍历器,每次调用它的`next`方法,就会返回一个Promise对象。`await`表示等待这个Promise对象`resolve`,一旦完成,变量`line`就是Promise对象返回的`value`值。
|
||||||
|
|
||||||
|
### 异步Generator函数
|
||||||
|
|
||||||
|
就像Generator函数返回一个同步遍历器对象一样,异步Generator函数的作用,是返回一个异步遍历器对象。
|
||||||
|
|
||||||
|
在语法上,异步Generator函数就是`async`函数与Generator函数的结合。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
async function* readLines(path) {
|
||||||
|
let file = await fileOpen(path);
|
||||||
|
|
||||||
|
try {
|
||||||
|
while (!file.EOF) {
|
||||||
|
yield await file.readLine();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
await file.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
上面代码中,异步操作前面使用`await`关键字标明,`next`方法所在的中断之处使用`yield`关键字标明。
|
||||||
|
|
||||||
|
注意,普通的`async`函数返回的是一个Promise对象,而异步Generator函数返回的是一个异步Iterator对象。
|
||||||
|
@ -1446,9 +1446,9 @@ sum(1, 100000)
|
|||||||
|
|
||||||
## 函数参数的尾逗号
|
## 函数参数的尾逗号
|
||||||
|
|
||||||
ES7有一个[提案](https://github.com/jeffmo/es-trailing-function-commas),允许函数的最后一个参数有尾逗号(trailing comma)。
|
ECMAScript 2017将[允许](https://github.com/jeffmo/es-trailing-function-commas)函数的最后一个参数有尾逗号(trailing comma)。
|
||||||
|
|
||||||
目前,函数定义和调用时,都不允许有参数的尾逗号。
|
此前,函数定义和调用时,都不允许最后一个参数后面出现逗号。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
function clownsEverywhere(
|
function clownsEverywhere(
|
||||||
@ -1462,7 +1462,9 @@ clownsEverywhere(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
如果以后要在函数的定义之中添加参数,就势必还要添加一个逗号。这对版本管理系统来说,就会显示,添加逗号的那一行也发生了变动。这看上去有点冗余,因此新提案允许定义和调用时,尾部直接有一个逗号。
|
上面代码中,如果在`param2`或`bar`后面加一个逗号,就会报错。
|
||||||
|
|
||||||
|
这样的话,如果以后修改代码,想为函数`clownsEverywhere`添加第三个参数,就势必要在第二个参数后面添加一个逗号。这对版本管理系统来说,就会显示,添加逗号的那一行也发生了变动。这看上去有点冗余,因此新的语法允许定义和调用时,尾部直接有一个逗号。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
function clownsEverywhere(
|
function clownsEverywhere(
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
- [ECMAScript® 2017 Language Specification](https://tc39.github.io/ecma262/):ECMAScript 2017规格(草案)
|
- [ECMAScript® 2017 Language Specification](https://tc39.github.io/ecma262/):ECMAScript 2017规格(草案)
|
||||||
- [ECMAScript Current Proposals](https://github.com/tc39/ecma262): ECMAScript当前的所有提案
|
- [ECMAScript Current Proposals](https://github.com/tc39/ecma262): ECMAScript当前的所有提案
|
||||||
- [ECMAScript Active Proposals](https://github.com/tc39/proposals): 已经进入正式流程的提案
|
- [ECMAScript Active Proposals](https://github.com/tc39/proposals): 已经进入正式流程的提案
|
||||||
|
- [ECMAscript proposals](https://github.com/hemanth/es-next):从阶段0到阶段4的所有提案列表
|
||||||
- [ECMAScript Daily](https://ecmascript-daily.github.io/): TC39委员会的动态
|
- [ECMAScript Daily](https://ecmascript-daily.github.io/): TC39委员会的动态
|
||||||
|
|
||||||
## 综合介绍
|
## 综合介绍
|
||||||
|
421
docs/simd.md
421
docs/simd.md
@ -1,4 +1,4 @@
|
|||||||
# SIMD 的用法
|
# SIMD
|
||||||
|
|
||||||
## 概述
|
## 概述
|
||||||
|
|
||||||
@ -47,7 +47,7 @@ v + w = 〈v1, …, vn〉+ 〈w1, …, wn〉
|
|||||||
|
|
||||||
## 数据类型
|
## 数据类型
|
||||||
|
|
||||||
SIMD提供多种数据类型。
|
SIMD提供12种数据类型,总长度都是128个二进制位。
|
||||||
|
|
||||||
- Float32x4:四个32位浮点数
|
- Float32x4:四个32位浮点数
|
||||||
- Float64x2:两个64位浮点数
|
- Float64x2:两个64位浮点数
|
||||||
@ -62,9 +62,16 @@ SIMD提供多种数据类型。
|
|||||||
- Bool8x16:十六个8位布尔值
|
- Bool8x16:十六个8位布尔值
|
||||||
- Bool64x2:两个64位布尔值
|
- Bool64x2:两个64位布尔值
|
||||||
|
|
||||||
每种数据类型被`x`号分隔成两部分,后面的部分表示通道数,前面的部分表示每个通道的宽度和类型。比如,`Float32x4`就表示这个值有4个通道,每个通道是一个32位浮点数。
|
每种数据类型被`x`符号分隔成两部分,后面的部分表示通道数,前面的部分表示每个通道的宽度和类型。比如,`Float32x4`就表示这个值有4个通道,每个通道是一个32位浮点数。
|
||||||
|
|
||||||
每种数据类型都是一个方法,可以传入参数,生成对应的值。
|
每个通道之中,可以放置四种数据。
|
||||||
|
|
||||||
|
- 浮点数(float,比如1.0)
|
||||||
|
- 带符号的整数(Int,比如-1)
|
||||||
|
- 无符号的整数(Uint,比如1)
|
||||||
|
- 布尔值(Bool,包含`true`和`false`两种值)
|
||||||
|
|
||||||
|
每种SIMD的数据类型都是一个函数方法,可以传入参数,生成对应的值。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var a = SIMD.Float32x4(1.0, 2.0, 3.0, 4.0);
|
var a = SIMD.Float32x4(1.0, 2.0, 3.0, 4.0);
|
||||||
@ -79,46 +86,35 @@ var v = new SIMD.Float32x4(0, 1, 2, 3);
|
|||||||
// TypeError: SIMD.Float32x4 is not a constructor
|
// TypeError: SIMD.Float32x4 is not a constructor
|
||||||
```
|
```
|
||||||
|
|
||||||
如果所有数据通道都是同样的值,可以使用`splat`方法生成值。
|
## 静态方法:数学运算
|
||||||
|
|
||||||
|
每种数据类型都有一系列运算符,支持基本的数学运算。
|
||||||
|
|
||||||
|
### SIMD.%type%.abs(),SIMD.%type%.neg()
|
||||||
|
|
||||||
|
`abs`方法接受一个SIMD值作为参数,将它的每个通道都转成绝对值,作为一个新的SIMD值返回。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var v = SIMD.Float32x4.splat(0.0);
|
var a = SIMD.Float32x4(-1, -2, 0, NaN);
|
||||||
|
SIMD.Float32x4.abs(a)
|
||||||
|
// Float32x4[1, 2, 0, NaN]
|
||||||
```
|
```
|
||||||
|
|
||||||
上面代码中,`v`的四个通道都是`0.0`。
|
`neg`方法接受一个SIMD值作为参数,将它的每个通道都转成负值,作为一个新的SIMD值返回。
|
||||||
|
|
||||||
如果要取出单个通道的值,可以使用`extractLane`方法。
|
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var a = SIMD.Float32x4(1.0, 2.0, 3.0, 4.0);
|
var a = SIMD.Float32x4(-1, -2, 3, 0);
|
||||||
var b = SIMD.Float32x4.extractLane(a, 0); // 1.0
|
SIMD.Float32x4.neg(a)
|
||||||
|
// Float32x4[1, 2, -3, -0]
|
||||||
|
|
||||||
|
var b = SIMD.Float64x2(NaN, Infinity);
|
||||||
|
SIMD.Float64x2.neg(b)
|
||||||
|
// Float64x2[NaN, -Infinity]
|
||||||
```
|
```
|
||||||
|
|
||||||
上面代码中,`extractLane`方法的第一个参数是一个SIMD值,第二个参数是通道的编号(从0开始)。
|
### SIMD.%type%.add(),SIMD.%type%.addSaturate()
|
||||||
|
|
||||||
如果要修改某个通道的值,可以使用`replaceLane`方法。
|
`add`方法接受两个SIMD值作为参数,将它们的每个通道相加,作为一个新的SIMD值返回。
|
||||||
|
|
||||||
```javascript
|
|
||||||
var a = SIMD.Float32x4(1.0, 2.0, 3.0, 4.0);
|
|
||||||
var c = SIMD.Float32x4.replaceLane(a, 0, 5.0);
|
|
||||||
```
|
|
||||||
|
|
||||||
上面代码中,经过替换后,得到一个新的SIMD值:`(5.0, 2.0, 3.0, 4.0)`。可以看到,`replaceLane`接受三个参数:SIMD值、通道的编号(从0开始)、新的值。
|
|
||||||
|
|
||||||
## 方法:数学运算
|
|
||||||
|
|
||||||
每种数据类型都有一系列运算符,下面是其中的一些。
|
|
||||||
|
|
||||||
- float32x4.abs(v):返回`v`的绝对值
|
|
||||||
- float32x4.neg(v):返回`v`的绝对值的负值
|
|
||||||
- float32x4.sqrt(v):返回`v`的平方根
|
|
||||||
- float32x4.add(v, w):`v`和`w`对应项的相加
|
|
||||||
- float32x4.mul(v, w):`v`和`w`对应项的相乘
|
|
||||||
- float32x4.equal(v, w):比较`v`和`w`对应项是否相等,返回的布尔值组成一个`uint32x4`的值
|
|
||||||
|
|
||||||
### SIMD.%type%.add()
|
|
||||||
|
|
||||||
`add`方法接受两个SIMD值作为参数,将它们的每个通道相加,返回一个新的SIMD值。
|
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var a = SIMD.Float32x4(1.0, 2.0, 3.0, 4.0);
|
var a = SIMD.Float32x4(1.0, 2.0, 3.0, 4.0);
|
||||||
@ -128,20 +124,102 @@ var c = SIMD.Float32x4.add(a, b);
|
|||||||
|
|
||||||
上面代码中,经过加法运算,新的SIMD值为`(6.0, 12.0, 18.0. 24.0)`。
|
上面代码中,经过加法运算,新的SIMD值为`(6.0, 12.0, 18.0. 24.0)`。
|
||||||
|
|
||||||
### SIMD.%type%.mul()
|
`addSaturate`方法跟`add`方法的作用相同,都是两个通道相加,但是溢出的处理不一致。对于`add`方法,如果两个值相加发生溢出,溢出的二进制位会被丢弃; `addSaturate`方法则是返回该数据类型的最大值。
|
||||||
|
|
||||||
`mul`方法接受两个SIMD值作为参数,将它们的每个通道相乘,返回一个新的SIMD值。
|
```javascript
|
||||||
|
var a = SIMD.Uint16x8(65533, 65534, 65535, 65535, 1, 1, 1, 1);
|
||||||
|
var b = SIMD.Uint16x8(1, 1, 1, 5000, 1, 1, 1, 1);
|
||||||
|
SIMD.Uint16x8.addSaturate(a, b);
|
||||||
|
// 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);
|
||||||
|
SIMD.Int16x8.addSaturate(c, d);
|
||||||
|
// Int16x8[32766, 32767, 32767, 32767, 2, 2, 2, 2]
|
||||||
|
```
|
||||||
|
|
||||||
|
上面代码中,`Uint16`的最大值是65535,`Int16`的最大值是32767。一旦发生溢出,就返回这两个值。
|
||||||
|
|
||||||
|
注意,`Uint32x4`和`Int32x4`这两种数据类型没有`addSaturate`方法。
|
||||||
|
|
||||||
|
### SIMD.%type%.sub(),SIMD.%type%.subSaturate()
|
||||||
|
|
||||||
|
`sub`方法接受两个SIMD值作为参数,将它们的每个通道相减,作为一个新的SIMD值返回。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var a = SIMD.Float32x4(-1, -2, 3, 4);
|
var a = SIMD.Float32x4(-1, -2, 3, 4);
|
||||||
var b = SIMD.Float32x4(3, 3, 3, 3);
|
var b = SIMD.Float32x4(3, 3, 3, 3);
|
||||||
SIMD.Float32x4.mul(a, b);
|
SIMD.Float32x4.sub(a, b)
|
||||||
|
// Float32x4[-4, -5, 0, 1]
|
||||||
|
```
|
||||||
|
|
||||||
|
`subSaturate`方法跟`sub`方法的作用相同,都是两个通道相减,但是溢出的处理不一致。对于`sub`方法,如果两个值相减发生溢出,溢出的二进制位会被丢弃; `subSaturate`方法则是返回该数据类型的最小值。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
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]
|
||||||
|
```
|
||||||
|
|
||||||
|
上面代码中,`Uint16`的最小值是`0`,`subSaturate`的最小值是`-32678`。一旦运算发生溢出,就返回最小值。
|
||||||
|
|
||||||
|
### SIMD.%type%.mul(),SIMD.%type%.div(),SIMD.%type%.sqrt()
|
||||||
|
|
||||||
|
`mul`方法接受两个SIMD值作为参数,将它们的每个通道相乘,作为一个新的SIMD值返回。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
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]
|
// Float32x4[-3, -6, 9, 12]
|
||||||
```
|
```
|
||||||
|
|
||||||
### SIMD.%type%.shiftLeftByScalar()
|
`div`方法接受两个SIMD值作为参数,将它们的每个通道相除,作为一个新的SIMD值返回。
|
||||||
|
|
||||||
`shiftLeftByScalar`方法接受一个SIMD值作为参数,然后将每个通道的值左移指定的位数,返回一个新的SIMD值。
|
```javascript
|
||||||
|
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]
|
||||||
|
```
|
||||||
|
|
||||||
|
`sqrt`方法接受一个SIMD值作为参数,求出每个通道的平方根,作为一个新的SIMD值返回。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var b = SIMD.Float64x2(4, 8);
|
||||||
|
SIMD.Float64x2.sqrt(b)
|
||||||
|
// Float64x2[2, 2.8284271247461903]
|
||||||
|
```
|
||||||
|
|
||||||
|
### SIMD.%FloatType%.reciprocalApproximation(),SIMD.%type%.reciprocalSqrtApproximation()
|
||||||
|
|
||||||
|
`reciprocalApproximation`方法接受一个SIMD值作为参数,求出每个通道的倒数(`1 / x`),作为一个新的SIMD值返回。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var a = SIMD.Float32x4(1, 2, 3, 4);
|
||||||
|
SIMD.Float32x4.reciprocalApproximation(a);
|
||||||
|
// Float32x4[1, 0.5, 0.3333333432674408, 0.25]
|
||||||
|
```
|
||||||
|
|
||||||
|
`reciprocalSqrtApproximation`方法接受一个SIMD值作为参数,求出每个通道的平方根的倒数(`1 / (x^0.5)`),作为一个新的SIMD值返回。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var a = SIMD.Float32x4(1, 2, 3, 4);
|
||||||
|
SIMD.Float32x4.reciprocalSqrtApproximation(a)
|
||||||
|
// Float32x4[1, 0.7071067690849304, 0.5773502588272095, 0.5]
|
||||||
|
```
|
||||||
|
|
||||||
|
注意,只有浮点数的数据类型才有这两个方法。
|
||||||
|
|
||||||
|
### SIMD.%IntegerType%.shiftLeftByScalar()
|
||||||
|
|
||||||
|
`shiftLeftByScalar`方法接受一个SIMD值作为参数,然后将每个通道的值左移指定的位数,作为一个新的SIMD值返回。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var a = SIMD.Int32x4(1, 2, 4, 8);
|
var a = SIMD.Int32x4(1, 2, 4, 8);
|
||||||
@ -157,7 +235,9 @@ var jx4 = SIMD.Int32x4.shiftLeftByScalar(ix4, 32);
|
|||||||
// Int32x4[0, 0, 0, 0]
|
// Int32x4[0, 0, 0, 0]
|
||||||
```
|
```
|
||||||
|
|
||||||
### SIMD.%type%.shiftRightByScalar()
|
注意,只有整数的数据类型才有这个方法。
|
||||||
|
|
||||||
|
### SIMD.%IntegerType%.shiftRightByScalar()
|
||||||
|
|
||||||
`shiftRightByScalar`方法接受一个SIMD值作为参数,然后将每个通道的值右移指定的位数,返回一个新的SIMD值。
|
`shiftRightByScalar`方法接受一个SIMD值作为参数,然后将每个通道的值右移指定的位数,返回一个新的SIMD值。
|
||||||
|
|
||||||
@ -177,7 +257,41 @@ SIMD.Uint32x4.shiftRightByScalar(a, 1);
|
|||||||
|
|
||||||
上面代码中,`-8`右移一位变成了`2147483644`,是因为对于32位无符号整数来说,`-8`的二进制形式是`11111111111111111111111111111000`,右移一位就变成了`01111111111111111111111111111100`,相当于`2147483644`。
|
上面代码中,`-8`右移一位变成了`2147483644`,是因为对于32位无符号整数来说,`-8`的二进制形式是`11111111111111111111111111111000`,右移一位就变成了`01111111111111111111111111111100`,相当于`2147483644`。
|
||||||
|
|
||||||
## 方法:通道处理
|
注意,只有整数的数据类型才有这个方法。
|
||||||
|
|
||||||
|
## 静态方法:通道处理
|
||||||
|
|
||||||
|
### SIMD.%type%.check()
|
||||||
|
|
||||||
|
`check`方法用于检查一个值是否为当前类型的SIMD值。如果是的,就返回这个值,否则就报错。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var a = SIMD.Float32x4(1, 2, 3, 9);
|
||||||
|
|
||||||
|
SIMD.Float32x4.check(a);
|
||||||
|
// Float32x4[1, 2, 3, 9]
|
||||||
|
|
||||||
|
SIMD.Float32x4.check([1,2,3,4]) // 报错
|
||||||
|
SIMD.Int32x4.check(a) // 报错
|
||||||
|
SIMD.Int32x4.check('hello world') // 报错
|
||||||
|
```
|
||||||
|
|
||||||
|
### SIMD.%type%.extractLane(),SIMD.%type%.replaceLane()
|
||||||
|
|
||||||
|
`extractLane`方法用于返回给定通道的值。它接受两个参数,分别是SIMD值和通道编号。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var t = SIMD.Float32x4(1, 2, 3, 4);
|
||||||
|
SIMD.Float32x4.extractLane(t, 2) // 3
|
||||||
|
```
|
||||||
|
|
||||||
|
`replaceLane`方法用于替换指定通道的值,并返回一个新的SIMD值。它接受三个参数,分别是原来的SIMD值、通道编号和新的通道值。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var t = SIMD.Float32x4(1, 2, 3, 4);
|
||||||
|
SIMD.Float32x4.replaceLane(t, 2, 42)
|
||||||
|
// Float32x4[1, 2, 42, 4]
|
||||||
|
```
|
||||||
|
|
||||||
### SIMD.%type%.load()
|
### SIMD.%type%.load()
|
||||||
|
|
||||||
@ -214,6 +328,33 @@ SIMD.Int32x4.load3(a, 0);
|
|||||||
// Int32x4[1, 2, 3,0]
|
// Int32x4[1, 2, 3,0]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### SIMD.%type%.store()
|
||||||
|
|
||||||
|
`store`方法用于将一个SIMD值,写入一个二进制数组。它接受三个参数,分别是二进制数组、开始写入的数组位置、SIMD值。它返回写入值以后的二进制数组。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
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]
|
||||||
|
```
|
||||||
|
|
||||||
|
上面代码中,`t1`是一个二进制数组,`v1`是一个SIMD值,只有四个通道。所以写入`t1`以后,只有前四个位置有值,后四个位置都是0。而`t2`是从2号位置开始写入,所以前两个位置和后两个位置都是0。
|
||||||
|
|
||||||
|
这个方法还有三个变种`store1()`、`store2()`和`store3()`,表示只写入一个通道、二个通道和三个通道的值。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
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()
|
### SIMD.%type%.splat()
|
||||||
|
|
||||||
`splat`方法返回一个新的SIMD值,该值的所有通道都会设成同一个预先给定的值。
|
`splat`方法返回一个新的SIMD值,该值的所有通道都会设成同一个预先给定的值。
|
||||||
@ -269,30 +410,51 @@ SIMD.Float32x4.shuffle(a, b, 1, 5, 7, 2);
|
|||||||
|
|
||||||
上面代码中,`a`和`b`一共有8个通道,依次编号为0到7。`shuffle`根据编号,取出相应的通道,返回一个新的SIMD值。
|
上面代码中,`a`和`b`一共有8个通道,依次编号为0到7。`shuffle`根据编号,取出相应的通道,返回一个新的SIMD值。
|
||||||
|
|
||||||
## 方法:比较运算
|
## 静态方法:比较运算
|
||||||
|
|
||||||
### SIMD.%type%.greaterThan()
|
### SIMD.%type%.equal(),SIMD.%type%.notEqual()
|
||||||
|
|
||||||
`greatThan`方法用来比较两个SIMD值`a`和`b`的每一个通道,如果在该通道中,`a`较大就得到`true`,否则得到`false`。最后,所有通道的比较结果,会组成一个新的SIMD值,作为掩码返回。
|
`equal`方法用来比较两个SIMD值`a`和`b`的每一个通道,根据两者是否精确相等(`a === b`),得到一个布尔值。最后,所有通道的比较结果,组成一个新的SIMD值,作为掩码返回。`notEqual`方法则是比较两个通道是否不相等(`a !== b`)。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
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()
|
||||||
|
|
||||||
|
`greatThan`方法用来比较两个SIMD值`a`和`b`的每一个通道,如果在该通道中,`a`较大就得到`true`,否则得到`false`。最后,所有通道的比较结果,组成一个新的SIMD值,作为掩码返回。`greaterThanOrEqual`则是比较`a`是否大于等于`b`。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var a = SIMD.Float32x4(1, 6, 3, 11);
|
var a = SIMD.Float32x4(1, 6, 3, 11);
|
||||||
var b = SIMD.Float32x4(1, 4, 7, 9);
|
var b = SIMD.Float32x4(1, 4, 7, 9);
|
||||||
|
|
||||||
var mask = SIMD.Float32x4.greaterThan(a,b);
|
SIMD.Float32x4.greaterThan(a, b)
|
||||||
// Bool32x4[false, true, false, true]
|
// Bool32x4[false, true, false, true]
|
||||||
|
|
||||||
|
SIMD.Float32x4.greaterThanOrEqual(a, b)
|
||||||
|
// Bool32x4[true, true, false, true]
|
||||||
```
|
```
|
||||||
|
|
||||||
### SIMD.%type%.lessThan()
|
### SIMD.%type%.lessThan(),SIMD.%type%.lessThanOrEqual()
|
||||||
|
|
||||||
`lessThan`方法用来比较两个SIMD值`a`和`b`的每一个通道,如果在该通道中,`a`较小就得到`true`,否则得到`false`。最后,所有通道的比较结果,会组成一个新的SIMD值,作为掩码返回。
|
`lessThan`方法用来比较两个SIMD值`a`和`b`的每一个通道,如果在该通道中,`a`较小就得到`true`,否则得到`false`。最后,所有通道的比较结果,会组成一个新的SIMD值,作为掩码返回。`lessThanOrEqual`方法则是比较`a`是否等于`b`。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var a = SIMD.Float32x4(1, 2, 3, 11);
|
var a = SIMD.Float32x4(1, 2, 3, 11);
|
||||||
var b = SIMD.Float32x4(1, 4, 7, 9);
|
var b = SIMD.Float32x4(1, 4, 7, 9);
|
||||||
|
|
||||||
var mask = SIMD.Float32x4.lessThan(a,b);
|
SIMD.Float32x4.lessThan(a, b)
|
||||||
// Bool32x4[false, true, true, false]
|
// Bool32x4[false, true, true, false]
|
||||||
|
|
||||||
|
SIMD.Float32x4.lessThanOrEqual(a, b)
|
||||||
|
// Bool32x4[true, true, true, false]
|
||||||
```
|
```
|
||||||
|
|
||||||
### SIMD.%type%.select()
|
### SIMD.%type%.select()
|
||||||
@ -326,7 +488,7 @@ var result = SIMD.Float32x4.select(mask, a, b);
|
|||||||
|
|
||||||
上面代码中,先通过`lessThan`方法生成一个掩码,然后通过`select`方法生成一个由每个通道的较小值组成的新的SIMD值。
|
上面代码中,先通过`lessThan`方法生成一个掩码,然后通过`select`方法生成一个由每个通道的较小值组成的新的SIMD值。
|
||||||
|
|
||||||
### SIMD.%type%.allTrue(),SIMD.%type%.anyTrue()
|
### SIMD.%BooleanType%.allTrue(),SIMD.%BooleanType%.anyTrue()
|
||||||
|
|
||||||
`allTrue`方法接受一个SIMD值作为参数,然后返回一个布尔值,表示该SIMD值的所有通道是否都为`true`。
|
`allTrue`方法接受一个SIMD值作为参数,然后返回一个布尔值,表示该SIMD值的所有通道是否都为`true`。
|
||||||
|
|
||||||
@ -348,6 +510,8 @@ SIMD.Bool32x4.anyTrue(a); // false
|
|||||||
SIMD.Bool32x4.anyTrue(b); // true
|
SIMD.Bool32x4.anyTrue(b); // true
|
||||||
```
|
```
|
||||||
|
|
||||||
|
注意,只有四种布尔值数据类型(`Bool32x4`、`Bool16x8`、`Bool8x16`、`Bool64x2`)才有这两个方法。
|
||||||
|
|
||||||
这两个方法通常与比较运算符结合使用。
|
这两个方法通常与比较运算符结合使用。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
@ -360,7 +524,7 @@ var b2 = SIMD.Int32x4.anyTrue(ix4); // true
|
|||||||
|
|
||||||
### SIMD.%type%.min(),SIMD.%type%.minNum()
|
### SIMD.%type%.min(),SIMD.%type%.minNum()
|
||||||
|
|
||||||
`min`方法接受两个SIMD值作为参数,将它们的每个通道的较小值,组成一个新的SIMD值返回。
|
`min`方法接受两个SIMD值作为参数,将两者的对应通道的较小值,组成一个新的SIMD值返回。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var a = SIMD.Float32x4(-1, -2, 3, 5.2);
|
var a = SIMD.Float32x4(-1, -2, 3, 5.2);
|
||||||
@ -369,7 +533,7 @@ SIMD.Float32x4.min(a, b);
|
|||||||
// Float32x4[-1, -4, 3, 5.2]
|
// Float32x4[-1, -4, 3, 5.2]
|
||||||
```
|
```
|
||||||
|
|
||||||
如果有一个通道的值是`NaN`,则会返回`NaN`。
|
如果有一个通道的值是`NaN`,则会优先返回`NaN`。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var c = SIMD.Float64x2(NaN, Infinity)
|
var c = SIMD.Float64x2(NaN, Infinity)
|
||||||
@ -378,7 +542,7 @@ SIMD.Float64x2.min(c, d);
|
|||||||
// Float64x2[NaN, 42]
|
// Float64x2[NaN, 42]
|
||||||
```
|
```
|
||||||
|
|
||||||
`minNum`方法与`min`方法的作用一模一样,唯一的区别是如果有一个通道的值是`NaN`,则会优先返回另一个通道的值。
|
`minNum`方法与`min`的作用一模一样,唯一的区别是如果有一个通道的值是`NaN`,则会优先返回另一个通道的值。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var ax4 = SIMD.Float32x4(1.0, 2.0, NaN, NaN);
|
var ax4 = SIMD.Float32x4(1.0, 2.0, NaN, NaN);
|
||||||
@ -389,6 +553,130 @@ var dx4 = SIMD.Float32x4.minNum(ax4, bx4);
|
|||||||
// Float32x4[1.0, 1.0, 3.0, NaN]
|
// Float32x4[1.0, 1.0, 3.0, NaN]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### SIMD.%type%.max(),SIMD.%type%.maxNum()
|
||||||
|
|
||||||
|
`max`方法接受两个SIMD值作为参数,将两者的对应通道的较大值,组成一个新的SIMD值返回。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
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]
|
||||||
|
```
|
||||||
|
|
||||||
|
如果有一个通道的值是`NaN`,则会优先返回`NaN`。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var c = SIMD.Float64x2(NaN, Infinity)
|
||||||
|
var d = SIMD.Float64x2(1337, 42);
|
||||||
|
SIMD.Float64x2.max(c, d)
|
||||||
|
// Float64x2[NaN, Infinity]
|
||||||
|
```
|
||||||
|
|
||||||
|
`maxNum`方法与`max`的作用一模一样,唯一的区别是如果有一个通道的值是`NaN`,则会优先返回另一个通道的值。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var c = SIMD.Float64x2(NaN, Infinity)
|
||||||
|
var d = SIMD.Float64x2(1337, 42);
|
||||||
|
SIMD.Float64x2.maxNum(c, d)
|
||||||
|
// Float64x2[1337, Infinity]
|
||||||
|
```
|
||||||
|
|
||||||
|
## 静态方法:位运算
|
||||||
|
|
||||||
|
### SIMD.%type%.and(),SIMD.%type%.or(),SIMD.%type%.xor(),SIMD.%type%.not()
|
||||||
|
|
||||||
|
`and`方法接受两个SIMD值作为参数,返回两者对应的通道进行二进制`AND`运算(`&`)后得到的新的SIMD值。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
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]
|
||||||
|
```
|
||||||
|
|
||||||
|
上面代码中,以通道`0`为例,`1`的二进制形式是`0001`,`5`的二进制形式是`01001`,所以进行`AND`运算以后,得到`0001`。
|
||||||
|
|
||||||
|
`or`方法接受两个SIMD值作为参数,返回两者对应的通道进行二进制`OR`运算(`|`)后得到的新的SIMD值。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
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]
|
||||||
|
```
|
||||||
|
|
||||||
|
`xor`方法接受两个SIMD值作为参数,返回两者对应的通道进行二进制”异或“运算(`^`)后得到的新的SIMD值。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
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]
|
||||||
|
```
|
||||||
|
|
||||||
|
`not`方法接受一个SIMD值作为参数,返回每个通道进行二进制”否“运算(`~`)后得到的新的SIMD值。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var a = SIMD.Int32x4(1, 2, 4, 8);
|
||||||
|
SIMD.Int32x4.not(a)
|
||||||
|
// Int32x4[-2, -3, -5, -9]
|
||||||
|
```
|
||||||
|
|
||||||
|
上面代码中,`1`的否运算之所以得到`-2`,是因为在计算机内部,负数采用”2的补码“这种形式进行表示。也就是说,整数`n`的负数形式`-n`,是对每一个二进制位取反以后,再加上1。因此,直接取反就相当于负数形式再减去1,比如`1`的负数形式是`-1`,再减去1,就得到了`-2`。
|
||||||
|
|
||||||
|
## 静态方法:数据类型转换
|
||||||
|
|
||||||
|
SIMD提供以下方法,用来将一种数据类型转为另一种数据类型。
|
||||||
|
|
||||||
|
- `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()`
|
||||||
|
|
||||||
|
带有`Bits`后缀的方法,会原封不动地将二进制位拷贝到新的数据类型;不带后缀的方法,则会进行数据类型转换。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
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]
|
||||||
|
```
|
||||||
|
|
||||||
|
上面代码中,`fromFloat32x4`是将浮点数转为整数,然后存入新的数据类型;`fromFloat32x4Bits`则是将二进制位原封不动地拷贝进入新的数据类型,然后进行解读。
|
||||||
|
|
||||||
|
`Bits`后缀的方法,还可以用于通道数目不对等的拷贝。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
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]
|
||||||
|
```
|
||||||
|
|
||||||
|
上面代码中,原始SIMD值`t`是4通道的,而目标值是8通道的。
|
||||||
|
|
||||||
|
如果数据转换时,原通道的数据大小,超过了目标通道的最大宽度,就会报错。
|
||||||
|
|
||||||
|
## 实例方法
|
||||||
|
|
||||||
|
### SIMD.%type%.prototype.toString()
|
||||||
|
|
||||||
|
`toString`方法返回一个SIMD值的字符串形式。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var a = SIMD.Float32x4(11, 22, 33, 44);
|
||||||
|
a.toString() // "SIMD.Float32x4(11, 22, 33, 44)"
|
||||||
|
```
|
||||||
|
|
||||||
## 实例:求平均值
|
## 实例:求平均值
|
||||||
|
|
||||||
正常模式下,计算`n`个值的平均值,需要运算`n`次。
|
正常模式下,计算`n`个值的平均值,需要运算`n`次。
|
||||||
@ -426,33 +714,6 @@ function average(list) {
|
|||||||
|
|
||||||
上面代码先是每隔四位,将所有的值读入一个SIMD,然后立刻累加。然后,得到累加值四个通道的总和,再除以`n`就可以了。
|
上面代码先是每隔四位,将所有的值读入一个SIMD,然后立刻累加。然后,得到累加值四个通道的总和,再除以`n`就可以了。
|
||||||
|
|
||||||
## 二进制数组
|
|
||||||
|
|
||||||
SIMD可以与二进制数组结合,生成数组实例。
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
var _f64x2 = new Float64Array(_f32x4.buffer);
|
|
||||||
var _i32x4 = new Int32Array(_f32x4.buffer);
|
|
||||||
var _i16x8 = new Int16Array(_f32x4.buffer);
|
|
||||||
var _i8x16 = new Int8Array(_f32x4.buffer);
|
|
||||||
var _ui32x4 = new Uint32Array(_f32x4.buffer);
|
|
||||||
var _ui16x8 = new Uint16Array(_f32x4.buffer);
|
|
||||||
var _ui8x16 = new Uint8Array(_f32x4.buffer);
|
|
||||||
```
|
|
||||||
|
|
||||||
下面是一个例子。
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// a 和 b 是float32x4数组实例
|
|
||||||
function addArrays(a, b) {
|
|
||||||
var c = new Float32x4Array(a.length);
|
|
||||||
for (var i = 0; i < a.length; i++) {
|
|
||||||
c[i] = SIMD.float32x4.add(a[i], b[i]);
|
|
||||||
}
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 参考链接
|
## 参考链接
|
||||||
|
|
||||||
- TC39, [SIMD.js Stage 2](https://docs.google.com/presentation/d/1MY9NHrHmL7ma7C8dyNXvmYNNGgVmmxXk8ZIiQtPlfH4/edit#slide=id.p19)
|
- TC39, [SIMD.js Stage 2](https://docs.google.com/presentation/d/1MY9NHrHmL7ma7C8dyNXvmYNNGgVmmxXk8ZIiQtPlfH4/edit#slide=id.p19)
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
1. [对象的扩展](#docs/object)
|
1. [对象的扩展](#docs/object)
|
||||||
1. [Symbol](#docs/symbol)
|
1. [Symbol](#docs/symbol)
|
||||||
1. [Proxy和Reflect](#docs/proxy)
|
1. [Proxy和Reflect](#docs/proxy)
|
||||||
1. [二进制数组](#docs/arraybuffer)
|
|
||||||
1. [Set和Map数据结构](#docs/set-map)
|
1. [Set和Map数据结构](#docs/set-map)
|
||||||
1. [Iterator和for...of循环](#docs/iterator)
|
1. [Iterator和for...of循环](#docs/iterator)
|
||||||
1. [Generator函数](#docs/generator)
|
1. [Generator函数](#docs/generator)
|
||||||
@ -28,6 +27,8 @@
|
|||||||
1. [Module](#docs/module)
|
1. [Module](#docs/module)
|
||||||
1. [编程风格](#docs/style)
|
1. [编程风格](#docs/style)
|
||||||
1. [读懂规格](#docs/spec)
|
1. [读懂规格](#docs/spec)
|
||||||
|
1. [二进制数组](#docs/arraybuffer)
|
||||||
|
1. [SIMD](#docs/simd)
|
||||||
1. [参考链接](#docs/reference)
|
1. [参考链接](#docs/reference)
|
||||||
|
|
||||||
## 其他
|
## 其他
|
||||||
|
Loading…
x
Reference in New Issue
Block a user