开发者

Javascript's geometrical methods: Zero isn't exactly zero, is it?

开发者 https://www.devze.com 2023-04-07 13:31 出处:网络
In a simple geometric program written in Javascript and Canvas, when I set the angle to 270° (1½π), I expected the Math.cos(θ) to go to zero.The vector is straight down from the ce

In a simple geometric program written in Javascript and Canvas, when I set the angle to 270° (1½π), I expected the Math.cos(θ) to go to zero. The vector is straight down from the center, there's no x distance on a cartesian grid. Instead, I get this:

demo_angle = 270
ang = demo_angle * Math.PI / 180
x = Math.cos(ang) 
console.log(x)
> -1.836909530733566e-16

To see the output of the math functions, view the console. The source code is visible (in coffeescript) one level up in the URL.

I've had to define in my code "Any number whose absolute value is smaller than 1e-15 should be considered zero," but that's really unsatisfying. Needless to say, when I try doing开发者_开发问答 math with the x value that small, especially since I'm trying to use x as the denominator in a slope calculation and then doing some quadratic manipulations, I eventually come up with figures that exceed Number.MAX_VALUE (or Number.MIN_VALUE).

I know floating point mathematics is, at the assembly language level, something of a dark art, but results like this just seem weirder than is acceptable. Any hints on what I should do?


The problem is not that "zero isn't exactly zero". On the contrary, zero is exactly zero.

The issue that you're encountering is that 3π/2 is not representable as a floating point number. So you're actually taking the cosine of a value that is not quite equal to 3π/2. How big is this representation error? About 1.8e-16, which is the source of the error you see in the cosine.

Some languages get around this problem by providing functions like sinpi and cospi that implicitly scale their arguments by a factor of π; that's one way to deliver exact results. Obviously, that's not an option for you because javascript doesn't have such functions. You could roll your own if you want, taking advantage of the symmetries of these functions, or you can simply clamp "nearly zero" values to zero, as you are now. Neither is particularly satisfactory, but both will probably work for your purposes.


The problem is that Math.PI isn't exactly equal to Pi, but is instead the number of the form m*2^e with 2^52 <= m < 2^53 closest to it.

Then multiplying by 270 introduces a small round-off error.

Then dividing by 180 causes some more round-off error.

So your ang value is not exactly equal to 3*Pi/2, and as a result, what you get back is not the 0 you expect.

The calculation itself is actually done very accurately.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号