--- name: sin signature: 'sin EXPR' status: documented categories: ["Numeric functions"] --- ```{index} single: sin; Perl built-in ``` *[Numeric functions](../perlfunc-by-category)* # sin Return the sine of a number given in radians. `sin` is the standard trigonometric sine: it takes an angle measured in **radians** and returns the ratio of the opposite side to the hypotenuse of the corresponding right triangle. If `EXPR` is omitted, `sin` operates on [`$_`](../perlvar). The result is always a floating-point number in the closed interval `[-1, 1]`. ## Synopsis ```perl sin EXPR sin ``` ## What you get back A double-precision float in `[-1, 1]`. Perl forwards the call to the platform's C `sin(3)` routine, so the precision and rounding behaviour match your libm. Special values follow IEEE 754: `sin(0)` is exactly `0`, `sin("inf")` and `sin("nan")` are both `NaN`. ## Radians, not degrees The single most common mistake with `sin` is feeding it degrees. A full turn is `2 * π` radians, not `360`. Convert once and keep the converted value: ```perl use POSIX qw(acos); my $pi = acos(-1); # π to full double precision sub deg2rad { $_[0] * $pi / 180 } print sin( deg2rad(30) ), "\n"; # 0.5 print sin( 30 ), "\n"; # -0.988031624092862 — wrong if you meant degrees ``` {ext}`Math::Trig` exports `deg2rad` and `rad2deg` if you would rather not write the conversion yourself. ## Examples `sin(π/2)` is mathematically exactly `1`, but because `π` is not representable in binary floating-point the computed result falls a few ulps short: ```perl use POSIX qw(acos); my $pi = acos(-1); printf "%.17f\n", sin($pi / 2); # 1.00000000000000000 printf "%.17f\n", sin($pi); # 0.00000000000000012 — not exactly 0 ``` Treat any "should be zero" trig result as approximately zero. Compare with a tolerance, not with `==`. Degree-to-radian conversion inline, without pulling in a module. `3.14159` is accurate to six digits — fine for plotting, not for numeric analysis: ```perl for my $deg (0, 30, 45, 60, 90) { printf "sin(%2d°) = %+.4f\n", $deg, sin($deg * 3.14159 / 180); } # sin( 0°) = +0.0000 # sin(30°) = +0.5000 # sin(45°) = +0.7071 # sin(60°) = +0.8660 # sin(90°) = +1.0000 ``` For work that needs full double precision, replace `3.14159` with `acos(-1)` or `atan2(1, 1) * 4`. Numerical derivative of `sin` by finite differences. The symmetric two-point formula `(f(x+h) - f(x-h)) / (2h)` should recover `cos(x)`: ```perl my $x = 1.0; my $h = 1e-6; my $deriv = (sin($x + $h) - sin($x - $h)) / (2 * $h); printf "derivative: %.10f\n", $deriv; # 0.5403023059 printf "cos(%.1f): %.10f\n", $x, cos($x); ``` Picking `$h` is a trade-off: too large and truncation error dominates, too small and subtraction cancellation destroys the result. `1e-6` is a reasonable default for double precision. Walk the unit circle and print `(cos θ, sin θ)` at eight evenly spaced angles: ```perl use POSIX qw(acos); my $pi = acos(-1); for my $k (0 .. 7) { my $theta = $k * $pi / 4; printf "%.3f %+.3f %+.3f\n", $theta, cos($theta), sin($theta); } ``` Inverse sine (arcsine) via the identity from `perlfunc`: ```perl sub asin { atan2( $_[0], sqrt(1 - $_[0] * $_[0]) ) } print asin(0.5), "\n"; # 0.523598775598299 (= π/6) ``` ## Edge cases - **Non-numeric arguments coerce to `0`**. `sin("hello")` returns `0` because the string is numified to `0` first. Under `use warnings` this produces an `Argument "hello" isn't numeric in sin` warning. Validate input with `looks_like_number` from `Scalar::Util` if the source is untrusted. - **Very large arguments lose precision**. `sin` first reduces its argument modulo `2π`, and for `|x|` on the order of `1e16` the nearest representable double differs from `x` by more than `π`. The result is still a number in `[-1, 1]`, but it is essentially random. Reduce the angle yourself before the call if you are accumulating a phase over many iterations. - **[`undef`](undef) coerces to `0`** and returns `0`, with the usual `uninitialized` warning under `use warnings`. - **IEEE specials**: `sin("inf")`, `sin("-inf")`, and `sin("nan")` all return `NaN`. Compare with `$result != $result` (the only value not equal to itself) to detect `NaN`, or use `POSIX::isnan`. - **Default argument**. `sin;` with no argument reads [`$_`](../perlvar). Inside a `while (<>)` loop this operates on the current line, which is almost always a bug. - **No complex-number support** in the built-in. For complex arguments use {ext}`Math::Complex`, which overloads `sin` via operator overloading: ```perl use Math::Complex; my $z = cplx(1, 2); print sin($z), "\n"; # 3.16577851321617+1.9596010414216i ``` ## Differences from upstream Fully compatible with upstream Perl 5.42. ## See also - [`cos`](cos) — cosine of an angle in radians; the companion function most often used alongside `sin` - [`atan2`](atan2) — two-argument arctangent, the usual building block for inverse trig (`asin`, `acos`) in pure Perl - [`sqrt`](sqrt) — square root; appears in the classical `asin` identity `asin(x) = atan2(x, sqrt(1 - x*x))` - {ext}`Math::Trig` — `asin`, `acos`, `atan`, hyperbolic variants, `deg2rad`/`rad2deg`, and great-circle helpers - {ext}`Math::Complex` — overloads `sin` (and the rest of the trig family) for complex arguments - `POSIX` — exposes `asin` directly, plus `isnan`/`isinf` for detecting the non-finite results discussed above