+;;; Commentary:
+;;
+;; @cindex normalise angle
+;; @cindex sine
+;; @cindex cosine
+;; @cindex angle, normalised
+;; @cindex angle, sine of
+;; @cindex angle, cosine of
Some others you can add:
* tangent
* arcsine
* arccosine
* arctan
Those can be quite convenient as well.
+;; This module defines functions for computing the sine and cosine of an angle,
+;; as more robust versions of the built-in sin and cos functions in Guile.
The built-in are robust too, as far as I know.
+;; They return exact values for angles representing up, down, left and right,
+;; regardless of whether they're negative or how many rotations occurred.
May be good to mention that is is in degrees instead of radians.
Also, why limit this to pi/2 increments?
Let 'f: R->R' be some trigonometric function (in degrees). Then, let
S={x | x is rational and f(x) is rational}. What would be nice, is that
f(x) would be exact whenever x is in S.
Looking at
<https://math.stackexchange.com/questions/87756/when-is-sinx-rational>,
it appears that for the sine, S is exactly the multiples of pi. (Ditto
for cosine.)
I'm going to look into what's the case for 'tan'. For 'tan',
tan(pi/4)=tan(45°) is rational as well - I'm going to look into whether
the 'S' of 'tan' is only the integer multiples pi/4, or whether there
are more.
I was wondering for a moment why the conversion to degrees instead of
radians, but multiples of pi aren't exact, so that's all ok.
+;;; Code:
+
+(define-module (math trigonometry)
+ #:use-module (scheme documentation)
+ #:export (normalise-angle
+ sine
+ cosine))
+
+(define (normalise-angle angle)
+ "Return a normalised angle where 0 <= angle < 360."
+ (define angle-from-north (remainder angle 360))
+ (+ angle-from-north
+ (if (< angle-from-north 0) 360 0)))
You can avoid this 'if' by using 'floor-remainder' instead of 'remainder'.
You are assuming 'angle' is real. In this setting that seems quite
reasonable, but it needs to be mentioned (sin can be, and is, extended
to the complex plane).
+
+(define (sine angle)
+ "Calculate the sine of an angle,
+with full precision for 90 degree increments."
+ (define normalised-angle (normalise-angle angle))
+ (cond ((or (= normalised-angle 0) (= normalised-angle 180)) 0)
+ ((= normalised-angle 90) 1)
+ ((= normalised-angle 270) -1)
+ (else (sin normalised-angle))))
Err, please test 'sine' for some other angles, so that 'sin' is used for
things not integer multiples of 90 (with some error margin to deal with
inexactness). I'm pretty sure it's in radians.
(Usually I'd mention something about documentation here, but IIRC
Guile-Lib has some set-up where it copies docstrings.)
Best regards, Maxime Devos