RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1125489
Accepted
Данил Черкашин
Данил Черкашин
Asked:2020-05-14 20:34:47 +0000 UTC2020-05-14 20:34:47 +0000 UTC 2020-05-14 20:34:47 +0000 UTC

如何加快速度(为什么这么慢)?

  • 772

关于任务的一点点:
我有一个函数(js),它接受一个参数并返回一个由数学公式计算的值

var f = function(x) {
    return 3*Math.sin(2*x)*Math.pow(Math.cos(x), 4);
}

我还有一个数组,索引是区间数(从零开始索引),索引元素的值是该值落入该索引的次数。

比如我数组中有2个元素,我感兴趣的值是从0到1,那么如果f(x)返回一个小于0.5的数,那么数组的第一个元素会增加加 1,如果大于 0.5,则第二个元素将相应增加 1。

我修改了函数,使其立即返回给定参数的值将落入的区间数。

var hist_min = 0;
var hist_max = 2;
var hist_range = hist_max-hist_min;
var hist_cols = 30;

var f = function(x) {
    return  Math.floor(((3*Math.sin(2*x)*Math.pow(Math.cos(x), 4)-hist_min)/hist_range) * hist_cols);
}

在上面的例子中,我有 30 个区间,最左边的左边框是 0,最右边的右边是 2。

接下来,我测量了这个函数 3 * 10^6 次迭代的速度。

var iteratitions = 3000000;

var start_time = Date.now();
for (var i=0; i < iteratitions; i++) {
    var need_col = f(Math.random())
}
console.log("Finished in",Date.now()-start_time+"ms")

结果很快,在我的电脑上 ~ 100-200ms

但是,我需要以某种方式存储这些间隔,例如,在一个数组中。

我这样做

var start_time = Date.now();

for (var i=0; i < iteratitions; i++) {
    var need_col = f(Math.random())
    arr[need_col]++;
}

console.log("Finished in",Date.now()-start_time+"ms")

然而,这已经花费了更长的时间~1300ms

起初我以为这是因为arr[need_col]++它需要很长时间才能完成,但如果你这样做:

for (var i=0; i < iteratitions; i++) {
    var need_col = f(Math.random())
    var need_col2 = 3
    arr[need_col2]++;
}

这已经在 ~130ms 内完成

问题出现了,为什么如果我只是将函数 f 的值存储在 need_col 变量中,一切都会很快运行,但是一旦我使用 need_col 变量(将其作为索引传递),那么有时一切都会变慢?

我把所有的代码

var hist_min = 0;
var hist_max = 2;
var hist_range = hist_max-hist_min;
var hist_cols = 30;

var need_col = 0;

/*
var f = function(x) {
	return 3*Math.sin(2*x)*Math.pow(Math.cos(x), 4)
}
*/

var f = function(x) {
	return  Math.floor(((3*Math.sin(2*x)*Math.pow(Math.cos(x), 4)-hist_min)/hist_range) * hist_cols);
}

var iteratitions = 3000000;
var arr = [];

// инициализация
for (var i=0; i < hist_cols; i++) {
	arr.push(0)
}

// пустой цикл занимает время
var start_time = Date.now();

for (var i=0; i < iteratitions; i++) {
}
console.log("empty loop finished in",Date.now()-start_time+"ms")


// просто увеличение элемента массива по индексу
var start_time = Date.now();

for (var i=0; i < iteratitions; i++) {
	var need_col = 3
	arr[need_col]++;
}
console.log("arr[need_col]++; Finished in",Date.now()-start_time+"ms")


// просто выполение f(x) 
var start_time = Date.now();

for (var i=0; i < iteratitions; i++) {
	need_col = f(Math.random())
	//var need_col2 = 3
	//arr[need_col2]++;
}
console.log("just f(x) finished in",Date.now()-start_time+"ms")
//console.log(need_col)

// заполнение массива тем, что нам нужно
var start_time = Date.now();

for (var i=0; i < iteratitions; i++) {
	var need_col = f(Math.random())
	arr[need_col]++;
}
console.log("filling array f(x) finished in",Date.now()-start_time+"ms")

console.log("arr=", arr)

PS在我的电脑上,数字略有不同(我是通过node执行代码) 控制台输出

javascript
  • 2 2 个回答
  • 10 Views

2 个回答

  • Voted
  1. Best Answer
    Alexey Ten
    2020-05-15T15:42:06Z2020-05-15T15:42:06Z

    在这个特定的问题中,问题在于3*Math.sin(2*x)*Math.pow(Math.cos(x), 4)区间上的函数[0, 1)具有从 about0到 about的值1.553,但是对区间数的转换函数(在问题更改之前)是针对值 from0到计算的1。因此,对于大于1调用的值arr[need_col]++超出了数组的边界,这导致了强烈的减速(以及NaN数组中的值)。

    比较for(..) { f(x); }不for(..) { arr[f(x)]++; }正确。在第一种情况下,引擎知道函数调用的结果没有被使用,并节省了返回值。如果他注意到这通常是一个纯函数,那么理论上他可能根本不会调用它。

    与 (for example) 比较更正确s = 0; for(..) { s += f(x) },这里的结果与访问数组没有太大区别。

    因此,我们可以假设在 JS 框架内可以完成的所有事情都已经完成。如果您需要更快,那么您需要查看其他 PL,但这超出了此问题的范围。

    • 1
  2. lijil
    2020-05-15T04:50:44Z2020-05-15T04:50:44Z

    索引是一个字符串,时间差在数组getter里面的need_col.toString()。

    new Proxy ([ 1 ],{
        get : function ( target , key ){
            console . log ( target , typeof key , key );
            // [ 1 ] string 0
        }
    })[ 0 ] ++ ;
    
    • -2

相关问题

  • 第二个 Instagram 按钮的 CSS 属性

  • 由于模糊,内容不可见

  • 弹出队列。消息显示不正确

  • 是否可以在 for 循环中插入提示?

  • 如何将 JSON 请求中的信息输出到数据表 Vuetify vue.js?

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    如何从列表中打印最大元素(str 类型)的长度?

    • 2 个回答
  • Marko Smith

    如何在 PyQT5 中清除 QFrame 的内容

    • 1 个回答
  • Marko Smith

    如何将具有特定字符的字符串拆分为两个不同的列表?

    • 2 个回答
  • Marko Smith

    导航栏活动元素

    • 1 个回答
  • Marko Smith

    是否可以将文本放入数组中?[关闭]

    • 1 个回答
  • Marko Smith

    如何一次用多个分隔符拆分字符串?

    • 1 个回答
  • Marko Smith

    如何通过 ClassPath 创建 InputStream?

    • 2 个回答
  • Marko Smith

    在一个查询中连接多个表

    • 1 个回答
  • Marko Smith

    对列表列表中的所有值求和

    • 3 个回答
  • Marko Smith

    如何对齐 string.Format 中的列?

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5