如何提高Math.atan()的准确性?

时间:2016-12-14 14:55:47

标签: javascript math

我试图在点的角度之间做一些比较,但很快我遇到了一些奇怪的结果。

在这个例子中,我尝试旋转线条使它们指向中心,但线条看起来比它们应该很快的角度。然后,在中心的正上方和下方,线条开始指向各种方向(These values are beyond the mathematical range of atan(x))

如何从Math.atan()获得准确的结果?有没有其他方法可以进行此计算?

我上传了一个'工作'这个小提琴的版本: https://jsfiddle.net/0y2p6p3n/。我在Chrome工作。

HTML:

  <div id="content">                
  </div>

的javascript:

let points = [];
let amount = 1000;
let width = 300;
let height = 300;

for (let i = 0; i<amount;i++) {
    let x = Math.random(); 
    let y = Math.random();
    let point = {x, y};
    points.push(point);
    points[i].tan = Math.atan(0.5 - points[i].y)/(0.5 - points[i].x);
    points[i].error = Math.abs(points[i].tan) > 3.14/2 ? true : false;
}   
for (let point of points) {
    let line = document.createElement("div");
    line.classList.add("line");
    line.style.marginTop = point.y*height + "px";
    line.style.marginLeft = point.x*width + "px";
    line.style.transform = "rotateZ(" + ((point.tan*(180/Math.PI))) + "deg)";
    point.error == true && line.classList.add("error");

    document.getElementById("content").appendChild(line);
}

的CSS:

#content {
    position: relative;
}
.line {
    position: absolute;
    height: 1px;
    width: 10px;
    background-color: black;
}
.error {
    background-color: red;
}

2 个答案:

答案 0 :(得分:4)

您正在使用

points[i].tan = Math.atan(0.5 - points[i].y)/(0.5 - points[i].x);

应该是

points[i].tan = Math.atan( (0.5 - points[i].y)/(0.5 - points[i].x) );

let points = [];
let amount = 1000;
let width = 300;
let height = 300;
for (let i = 0; i<amount;i++) {
  let x = Math.random(); 
  let y = Math.random();
  let point = {x, y};
  points.push(point);
  points[i].tan = Math.atan( (0.5 - points[i].y)/(0.5 - points[i].x) );
  points[i].error = Math.abs(points[i].tan) > 3.14/2 ? true : false;
}	
for (let point of points) {
  let line = document.createElement("div");
  line.classList.add("line");
  line.style.marginTop = point.y*height + "px";
  line.style.marginLeft = point.x*width + "px";
  line.style.transform = "rotateZ(" + ((point.tan*(180/Math.PI))) + "deg)";
  point.error == true && line.classList.add("error");
  document.getElementById("content").appendChild(line);
}
#content {
  position: relative;
}
.line {
  position: absolute;
  height: 1px;
  width: 10px;
  background-color: black;
}
.error {
  background-color: red;
}
<div id="content"></div>

答案 1 :(得分:3)

正如您所提到的,确切的渐近线(即pi / 2和-pi / 2)不在atan的有效域之内,这使得这些值的atan成为不可能。您还可能需要处理这样一个事实:atan始终返回一个参考角度,这可能不是您希望答案所在的象限。这些都是众所周知的问题,大多数语言都有一个简单的治疗方法,称为atan2。如果是javascript,请参阅the MDN reference for atan2

对代码的更改很简单;只需更改

points[i].tan = Math.atan(0.5 - points[i].y)/(0.5 - points[i].x);

points[i].tan = Math.atan2(0.5 - points[i].y, 0.5 - points[i].x);

如果您查看updated fiddle,您可能会发现其行为有了很大改善。

atan2没有给你更高的精度,但它确实给你超过[0..2pi]的整个范围的值,而你不必做任何额外的工作来弄清楚答案应该在哪个象限,以及在其范围内支持pi / 2和-pi / 2。通过了解x或y(或两者)是否为负值来帮助这样做,如果你自己进行除法,这个事实会被隐藏。

应该注意的是,我对您的代码所做的最重大的更改不是atan2,但是,它正在改变您对括号的使用。虽然我通常使用atan时主动使用atan2,但你的实际问题是误用括号,使得Oriol的回答是正确的。