On 26 October 2015 at 20:19, Tom Lane <t...@sss.pgh.pa.us> wrote:
> Dean Rasheed <dean.a.rash...@gmail.com> writes:
>> I'm thinking something along the lines of:
>> 1. Reduce the range of the input (say to 0..90 degrees).
>> 2. Handle special cases (0, 30 and 90 for sind()).
>> 3. Otherwise convert to radians for the general case.
> I'd be okay with #1 and #3, but #2 is just a crock; it would risk creating
> problems that did not exist before, such as non-monotonicity of the
> function result (over ranges where that does not hold).

Well special-casing 0 and 90 are certainly no problem, and do not risk
introducing non-monotonicity. sin() changes sign at 0 and for very
small x, sin(x) ~= x, so special-casing sin(0) = 0, doesn't affect the
monotonic nature of the function in that vicinity. Near 90, sin(x) is
not monotonic, but rather that is a maxima, and the slope is 0, so
small perturbations in x do not affect the result and you have to move
quite far away from 90 for the result to become different from 1, so
special-casing sind(90) = 1 does not affect the continuity of the

Special-casing sind(30) = 0.5 could be more problematic, but a quick
test on my machine shows that it does remain monotonic. As I
understand it, most modern processors apply argument reduction to the
range 0..pi/4, using cos(pi/2-x)=sin(x) to extend this to the range
0..pi/2 and hence all inputs. So passing in an input close to pi/6 (30
degrees) will not undergo any further argument reduction and the
result would be expected to be very accurate. Of course, we could just
omit this special case, and accept whatever approximation to 0.5 the
underlying function returned. It's a question of which is worse in
practice -- a small chance that sind(29.999...) or sind(30.000...1)
might be the wrong side of 0.5, making the function non-monotonic, or
having sind(30) not be exactly 0.5.

Personally I'd rather have sind(30) be exactly 0.5, even if
sind(29.999...) or sind(30.000...1) ended up the wrong side of it.
Floating point arithmetic is inherently imprecise, so tiny errors are
to be expected. But the well-known exact cases ought to work exactly.
BTW, these are the *only* values for which sind() returns exact
answers (see Niven's Theorum -
http://mathworld.wolfram.com/NivensTheorem.html) and they also happen
to be exactly representable using floats, so it seems a shame not to
return the exact values whenever possible.

> I looked into my dusty old copy of Cody & Waite's "Software Manual for the
> Elementary Functions", which is what I used as a reference the last time
> I had to do code like this (which admittedly was quite a long time ago;
> the state of the art might've advanced).  C&W say that the key accuracy
> limit for sin and cos is reduction of the argument modulo pi (or whichever
> multiple of pi you choose to work with).  Now that problem just goes away
> for degrees, of course, so it might be that reduction mod 360 and then
> conversion to radians would be Good Enough(TM).

No that would lead to sind(180) being non-zero.

> If it's not good enough, a possible idea is reduction mod 45 degrees or
> even mod 30 degrees and then using trig identities to reconstruct the
> correct output.

Reduction mod 45 would be fairly trivial, and would result in things
like sind(10) being exactly equal to cosd(80), even though neither
answer would be exactly correct. I'm not sure that by itself is worth
the extra effort, but it would probably improve the chances of cosd()
staying monotonic near 60, if we special-cased cosd(60) = 0.5
(although it does anyway on my machine).


Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:

Reply via email to