- xml - AJAX/Jquery XML 解析
- 具有多重继承的 XML 模式
- .net - 枚举序列化 Json 与 XML
- XML 简单类型、简单内容、复杂类型、复杂内容
我在 JavaScript 中发现了一个有趣的异常现象。其中重点是我尝试通过预先计算 sin(x) 和 cos(x) 并简单地引用预先计算的值来加速三 Angular 变换计算。
直觉上,预计算比每次计算 Math.sin() 和 Math.cos() 函数更快。特别是如果您的应用程序设计将仅使用一组受限制的值作为三 Angular 函数的参数(在我的例子中,区间 [0°, 360°] 中的整数度),这足以满足我的目的。
所以,我进行了一些测试。在预先计算 sin(x) 和 cos(x) 的值并将它们存储在 360 个元素的数组中之后,我编写了一个简短的测试函数,通过一个简单的测试 HTML 页面中的按钮激活,以比较两者的速度方法。一个循环简单地将一个值乘以预先计算的数组元素值,而另一个循环将一个值乘以 Math.sin()。
我的预期是预先计算的循环明显快于涉及对 trig 函数的函数调用的循环。令我惊讶的是,预先计算的循环较慢。
这是我写的测试函数:
function MyTest()
{
var ITERATION_COUNT = 1000000;
var angle = Math.floor(Math.random() * 360);
var test1 = 200 * sinArray[angle];
var test2 = 200 * cosArray[angle];
var ref = document.getElementById("Output1");
var outData = "Test 1 : " + test1.toString().trim() + "<br><br>";
outData += "Test 2 : "+test2.toString().trim() + "<br><br>";
var time1 = new Date(); //Time at the start of the test
for (var i=0; i<ITERATION_COUNT; i++)
{
var angle = Math.floor(Math.random() * 360);
var test3 = (200 * sinArray[angle]);
//End i loop
}
var time2 = new Date();
//This somewhat unwieldy procedure is how we find out the elapsed time ...
var msec1 = (time1.getUTCSeconds() * 1000) + time1.getUTCMilliseconds();
var msec2 = (time2.getUTCSeconds() * 1000) + time2.getUTCMilliseconds();
var elapsed1 = msec2 - msec1;
outData += "Test 3 : Elapsed time is " + elapsed1.toString().trim() + " milliseconds<br><br>";
//Now comparison test with the same number of sin() calls ...
var time1 = new Date();
for (var i=0; i<ITERATION_COUNT; i++)
{
var angle = Math.floor(Math.random() * 360);
var test3 = (200 * Math.sin((Math.PI * angle) / 180));
//End i loop
}
var time2 = new Date();
var msec1 = (time1.getUTCSeconds() * 1000) + time1.getUTCMilliseconds();
var msec2 = (time2.getUTCSeconds() * 1000) + time2.getUTCMilliseconds();
var elapsed2 = msec2 - msec1;
outData += "Test 4 : Elapsed time is " + elapsed2.toString().trim() + " milliseconds<br><br>";
ref.innerHTML = outData;
//End function
}
我这样做的动机是,乘以从数组中获取的预先计算的值比调用触发函数的函数调用更快,但我获得的结果很奇怪。
一些示例运行产生以下结果(测试 3 是预先计算的运行时间,测试 4 是 Math.sin() 运行时间):
运行 1:
Test 3 : Elapsed time is 153 milliseconds
Test 4 : Elapsed time is 67 milliseconds
运行 2:
Test 3 : Elapsed time is 167 milliseconds
Test 4 : Elapsed time is 69 milliseconds
运行 3:
Test 3 : Elapsed time is 265 milliseconds
Test 4 : Elapsed time is 107 milliseconds
运行 4:
Test 3 : Elapsed time is 162 milliseconds
Test 4 : Elapsed time is 69 milliseconds
为什么调用三 Angular 函数的速度是引用数组中预计算值的两倍,而预计算方法至少在直觉上应该更快一些?更重要的是,因为我在预先计算的循环中使用整数参数来索引数组,而函数调用循环还包括一个额外的计算来将度数转换为弧度?
这里发生了一些有趣的事情,但目前我不确定是什么。通常,数组访问预先计算的数据比调用复杂的三 Angular 函数要快得多(或者至少,它们回到了我在汇编程序中编写类似代码的时代!),但 JavaScript 似乎颠覆了这一点。我能想到的唯一原因是,JavaScript 在幕后为数组访问增加了很多开销,但如果真是这样,这将影响许多其他代码,这些代码似乎以完全合理的速度运行。
那么,这里到底发生了什么?
我在谷歌浏览器中运行这段代码:
版本 60.0.3112.101(官方构建)(64 位)
在 Windows 7 64 位系统上运行。我还没有在 Firefox 中尝试过,看看是否会出现相同的异常结果,但这是待办事项列表中的下一个。
任何深入了解 JavaScript 引擎内部工作原理的人,请帮忙!
最佳答案
两个相同的测试函数,差不多吧。
在基准测试中运行它们,结果令人惊讶。
{
func : function (){
var i,a,b;
D2R = 180 / Math.PI
b = 0;
for (i = 0; i < count; i++ ) {
// single test start
a = (Math.random() * 360) | 0;
b += Math.sin(a * D2R);
// single test end
}
},
name : "summed",
},{
func : function (){
var i,a,b;
D2R = 180 / Math.PI;
b = 0;
for (i = 0; i < count; i++ ) {
// single test start
a = (Math.random() * 360) | 0;
b = Math.sin(a * D2R);
// single test end
}
},
name : "unsummed",
},
结果
=======================================
Performance test. : Optimiser check.
Use strict....... : false
Duplicates....... : 4
Samples per cycle : 100
Tests per Sample. : 10000
---------------------------------------------
Test : 'summed'
Calibrated Mean : 173µs ±1µs (*1) 11160 samples 57,803,468 TPS
---------------------------------------------
Test : 'unsummed'
Calibrated Mean : 0µs ±1µs (*1) 11063 samples Invalid TPS
----------------------------------------
Calibration zero : 140µs ±0µs (*)
(*) Error rate approximation does not represent the variance.
(*1) For calibrated results Error rate is Test Error + Calibration Error.
TPS is Tests per second as a calculated value not actual test per second.
基准测试几乎没有为未总结的测试(必须强制它完成)花费任何时间。
优化器知道只需要未求和测试循环的最后一个结果。它仅对最后一次迭代有效,所有其他结果均未使用,所以为什么要使用它们。
javascript 中的基准测试充满陷阱。使用质量基准测试器,了解优化器可以做什么。
测试数组和 sin。为了公平起见,我没有将度数转换为弧度。
tests : [{
func : function (){
var i,a,b;
b=0;
for (i = 0; i < count; i++ ) {
a = (Math.random() * 360) | 0;
b += a;
}
},
name : "Calibration",
},{
func : function (){
var i,a,b;
b = 0;
for (i = 0; i < count; i++ ) {
a = (Math.random() * 360) | 0;
b += array[a];
}
},
name : "lookup",
},{
func : function (){
var i,a,b;
b = 0;
for (i = 0; i < count; i++ ) {
a = (Math.random() * 360) | 0;
b += Math.sin(a);
}
},
name : "Sin",
}
],
结果
=======================================
Performance test. : Lookup compare to calculate sin.
Use strict....... : false
Data view........ : false
Duplicates....... : 4
Cycles........... : 1055
Samples per cycle : 100
Tests per Sample. : 10000
---------------------------------------------
Test : 'Calibration'
Calibrator Mean : 107µs ±1µs (*) 34921 samples
---------------------------------------------
Test : 'lookup'
Calibrated Mean : 6µs ±1µs (*1) 35342 samples 1,666,666,667TPS
---------------------------------------------
Test : 'Sin'
Calibrated Mean : 169µs ±1µs (*1) 35237 samples 59,171,598TPS
-All ----------------------------------------
Mean : 0.166ms Totals time : 17481.165ms 105500 samples
Calibration zero : 107µs ±1µs (*);
(*) Error rate approximation does not represent the variance.
(*1) For calibrated results Error rate is Test Error + Calibration Error.
TPS is Tests per second as a calculated value not actual test per second.
再次强制完成,因为查找太接近错误率。但是校准后的查找几乎与时钟速度完美匹配???巧合..我不确定。
关于javascript - 为什么预计算 sin(x) *比在 Javascript 中使用 Math.sin() *慢*?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45896703/
这个问题在这里已经有了答案: Converting result of Math.sin(x) into a result for degrees in java (4 个答案) 关闭 5 年前。
我在学习 Kotlin 并在数学课上遇到了这个问题: java.lang.Math 和 kotlin.math 不兼容。这对我来说有点尴尬和困惑,因为 Kotlin 声称它与 Java 100% 兼容
我在其他问题中读到,例如由于浮点表示,sin(2π) 不为零,但非常接近。这个非常小的错误在我的代码中不是问题,因为例如我可以四舍五入 5 位小数。 但是当2π乘以一个非常大的数时,误差就会放大很多。
我正在用 C# 编写一个计算器。 textBoxResult 是我显示数字的文本框 recount 是一个以度为单位的角度并以弧度为单位返回的函数 我从 texBoxInput 获取角度 public
首先,让我们从我的数学背景开始。我已经学习了微积分 I - IV 和微分方程。我参加了第一学期的计算机图形类(class),在该类(class)中我们实现了几乎我们自己的图形管道,包括使用 Phong
早上好! 我只是想磨练我的数学能力,我特别有一些关于 Cocos2D 的问题。由于 Cocos2D 想要“简化”事物,所有 Sprite 都有一个旋转属性,范围从 0-360(359?)CW。这迫使你
是否有人对Intel Math Kernel Library和AMD Math Core Library都有编程经验?我正在建立一台用于高性能统计计算的个人计算机,并对正在购买的组件进行辩论。 AMD
函数的反函数是什么 math.atan2 我在 Lua 中使用它,我可以通过 math.tan 获得 math.atan 的逆。 但我在这里迷路了。 编辑 好的,让我向您提供更多详细信息。 我需要计算
我有一道等轴测投影的数学题。我读了一篇文章:Axonometric projections - a technical overview .对于等距投影部分,它给出了将 x 部分的 3D 点转换为 2
在 MySQL (5.1) 数据库表中,有数据表示: 用户执行任务需要多长时间 用户在任务中处理了多少项目。 MySQL 是否支持关联数据,还是我需要使用 PHP/C# 来计算? 我在哪里可以找到计算
关闭。这个问题是opinion-based 。目前不接受答案。 想要改进这个问题吗?更新问题,以便 editing this post 可以用事实和引文来回答它。 . 已关闭 9 年前。 Improv
我正在尝试使用这两种方法在 C# 中解决这个问题: public double NormalPowerMethod(double x, double toPower) { return Mat
如何分配: var randomNumber = Math.random()*50 + Math.random()*20; 比较: var randomNumber = Math.random()*7
我正在查看我的代码,希望提高它的性能,然后我看到了这个: int sqrt = (int) Math.floor(Math.sqrt(n)); 哦,好的,我真的不需要调用 Math.floor,因为转
尝试调用 math.h 中的函数时, 我收到如下链接错误 undefined reference to sqrt 但我正在做一个 #include 我正在使用 gcc 并编译如下: gcc -Wall
祝大家有个愉快的一天,我有话要问你,为了更好地理解这里是我的代码: {math equation=((($order_total-$commission)+$discount+$delivery_ch
我尝试学习一些Clojure,因为该语言看起来不错。 但是似乎没有关于如何安装/使用库的信息,例如clojure.math.numeric-tower。 现在,我通过在Linux shell中键入以下
As Math.sign() 接受数字参数或数字作为字符串,如 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Gl
如何将scala.math.BigDecimal转换为java.math.BigDecimal? 最佳答案 无需在字符串之间进行双重转换。 val sb = scala.math.BigDecimal
为什么下面的 JavaScript 会这样 Math instanceof Math 抛出错误 TypeError: Expecting a function in instanceof check,
我是一名优秀的程序员,十分优秀!