Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 213
Elf Sternberg Avatar asked Dec 17 '22 09:12

Elf Sternberg


1 Answers

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.

like image 118
Stephen Canon Avatar answered Dec 29 '22 01:12

Stephen Canon