Math::Trig(3perl)

🌸 NAME 🌸

Math::Trig β€” trigonometric functions. That's it, that's the whole name, and yeah bestie it's literally just the trig girlies: angles, radians, circles, spheres, the whole vibe πŸ’…


✨ SYNOPSIS ✨

    use Math::Trig;

    $x = tan(0.9);
    $y = acos(3.7);
    $z = asin(2.4);

    $halfpi = pi/2;

    $rad = deg2rad(120);

    # Import constants pi2, pi4, pip2, pip4 (2*pi, 4*pi, pi/2, pi/4).
    use Math::Trig ':pi';

    # Import the conversions between cartesian/spherical/cylindrical.
    use Math::Trig ':radial';

        # Import the great circle formulas.
    use Math::Trig ':great_circle';

πŸ¦‹ DESCRIPTION πŸ¦‹

Okay so picture this: core Perl is out here defining only sin() and cos(). That's it. Two of them. That's the whole roster. Not very girlboss of it, ngl 😭

Math::Trig is what fixes that. It defines so many trigonometric functions that core Perl just… doesn't. She's carrying the whole squad. On top of that you get the constant pi, a few convenience functions for converting between angles, and the great circle formulas for when you're doing spherical movement (yes, like on an actual sphere, main character energy 🧚).


πŸ”₯ TRIGONOMETRIC FUNCTIONS πŸ”₯

Let's meet the cast, no cap:

  • The tangent β€” tan
  • The cofunctions of the sine, cosine, and tangent β€” csc, cosec, sec, sec, cot, cotan (cosec/csc and cotan/cot are aliases)
  • The arcus functions (also known as the inverse functions) of the sine, cosine, and tangent β€” asin, acos, atan
  • The principal value of the arc tangent of y/x β€” atan2(y, x)
  • The arcus cofunctions of the sine, cosine, and tangent β€” acsc, acosec, asec, acot, acotan (acosec/acsc and acotan/acot are aliases). Heads up bestie: atan2(0, 0) is not well-defined.
  • The hyperbolic sine, cosine, and tangent β€” sinh, cosh, tanh
  • The cofunctions of the hyperbolic sine, cosine, and tangent β€” csch, cosech, sech, coth, cotanh (cosech/csch and cotanh/coth are aliases)
  • The area functions (also known as the inverse functions) of the hyperbolic sine, cosine, and tangent β€” asinh, acosh, atanh
  • The area cofunctions of the hyperbolic sine, cosine, and tangent β€” acsch, acosech, asech, acoth, acotanh (acsch/acosech and acoth/acotanh are aliases)

And the moment you've all been waiting for β€” the trigonometric constant pi, plus some handy little multiples of it, are also defined:

pi, pi2, pi4, pip2, pip4 πŸŽ€


😭 ERRORS DUE TO DIVISION BY ZERO 😭

Okay so these functions right here:

    acoth
    acsc
    acsch
    asec
    asech
    atanh
    cot
    coth
    csc
    csch
    sec
    sech
    tan
    tanh

…cannot be computed for all arguments, because that would mean dividing by zero or taking the logarithm of zero. And when that happens you don't get a cute little warning, you get a fatal runtime error that looks like this:

    cot(0): Division by zero.
    (Because in the definition of cot(0), the divisor sin(0) is 0)
    Died at ...

or like this:

    atanh(-1): Logarithm of zero.
    Died at...

So here's the tea on which arguments are off-limits:

  • For csc, cot, asec, acsc, acot, csch, coth, asech, acsch, the argument cannot be 0 (zero).
  • For atanh, acoth, the argument cannot be 1 (one).
  • For atanh, acoth, the argument cannot be -1 (minus one).
  • For tan, sec, tanh, sech, the argument cannot be pi/2 + k * pi, where k is any integer.
And once more with feeling: atan2(0, 0) is not well-defined. She said what she said πŸ’€

🌈 SIMPLE (REAL) ARGUMENTS, COMPLEX RESULTS 🌈

Okay this part is lowkey iconic. Some of these trigonometric functions can just… break out of the real axis and slide on into the complex plane. Like, asin(2) has no definition for plain old real numbers β€” but it does have a definition for complex numbers. She contains multitudes, periodt.

In Perl terms this means: if you feed the usual Perl numbers (also known as scalars, go read perldata if you need the lore) into the trigonometric functions, the output might not be simple real numbers anymore β€” instead they're complex numbers.

Math::Trig handles all of this by using the Math::Complex package, which actually knows how to handle complex numbers (peep Math::Complex for more). And in practice you do not need to stress about getting complex results back, because Math::Complex takes care of the details β€” like, for example, how to display complex numbers. Watch:

    print asin(2), "\n";

and that should produce something like this (take or leave a few last decimals, she's not doing your sig figs for you):

    1.5707963267949-1.31695789692482i

Which is just a complex number with the real part of approximately 1.571 and the imaginary part of approximately -1.317. Slay πŸ’…


πŸŽ€ PLANE ANGLE CONVERSIONS πŸŽ€

(Plane, 2-dimensional) angles may be converted with the following functions. Six of them. All cute.

  • deg2rad
    $radians  = deg2rad($degrees);
  • grad2rad
    $radians  = grad2rad($gradians);
  • rad2deg
    $degrees  = rad2deg($radians);
  • grad2deg
    $degrees  = grad2deg($gradians);
  • deg2grad
    $gradians = deg2grad($degrees);
  • rad2grad
    $gradians = rad2grad($radians);

So the full circle is 2 pi radians, or 360 degrees, or 400 gradians β€” pick your fighter ✨

And here's the important bit: the result is by default wrapped to be inside the [0, {2pi,360,400}) circle. If you don't want that β€” if you want the raw, unfiltered, untamed number β€” just supply a true second argument:

    $zillions_of_radians  = deg2rad($zillions_of_degrees, 1);
    $negative_degrees     = rad2deg($negative_radians, 1);

You can also do the wrapping explicitly, if you're the type who likes to do things on purpose:

  • rad2rad
    $radians_wrapped_by_2pi = rad2rad($radians);
  • deg2deg
    $degrees_wrapped_by_360 = deg2deg($degrees);
  • grad2grad
    $gradians_wrapped_by_400 = grad2grad($gradians);

🫢 RADIAL COORDINATE CONVERSIONS 🫢

Radial coordinate systems are the spherical and the cylindrical systems β€” don't worry, we explain both in a sec, in more detail.

You can import the radial coordinate conversion functions by using the :radial tag:

    use Math::Trig ':radial';

    ($rho, $theta, $z)     = cartesian_to_cylindrical($x, $y, $z);
    ($rho, $theta, $phi)   = cartesian_to_spherical($x, $y, $z);
    ($x, $y, $z)           = cylindrical_to_cartesian($rho, $theta, $z);
    ($rho_s, $theta, $phi) = cylindrical_to_spherical($rho_c, $theta, $z);
    ($x, $y, $z)           = spherical_to_cartesian($rho, $theta, $phi);
    ($rho_c, $theta, $z)   = spherical_to_cylindrical($rho_s, $theta, $phi);

All angles are in radians. All of them. Every single one. No exceptions bestie 🌸


πŸ‘‘ COORDINATE SYSTEMS πŸ‘‘

Cartesian coordinates are the usual rectangular (x, y, z)-coordinates. You know them. They're the ones from math class. The defaults. The basic bitches of geometry and honestly? We respect them.

Spherical coordinates, (rho, theta, phi), are three-dimensional coordinates that define a point in three-dimensional space. They're based on a sphere surface. Breakdown:

  • The radius of the sphere is rho, also known as the radial coordinate.
  • The angle in the xy-plane (around the z-axis) is theta, also known as the azimuthal coordinate.
  • The angle from the z-axis is phi, also known as the polar coordinate.

So the North Pole is therefore rho, 0, 0, and the Gulf of Guinea (think of the missing big chunk of Africa) is rho, 0, pi/2. In geographical terms, phi is latitude (northward positive, southward negative) and theta is longitude (eastward positive, westward negative). Geography crossover episode fr fr πŸ—ΊοΈ

BEWARE: some texts define theta and phi the other way round, some texts define the phi to start from the horizontal plane, and some texts use r in place of rho. So if your numbers are giving nonsense, it might not be you β€” it might be the textbook. 😭

Cylindrical coordinates, (rho, theta, z), are three-dimensional coordinates that define a point in three-dimensional space. They're based on a cylinder surface. Here's the layout:

  • The radius of the cylinder is rho, also known as the radial coordinate.
  • The angle in the xy-plane (around the z-axis) is theta, also known as the azimuthal coordinate.
  • The third coordinate is the z, pointing up from the theta-plane.

πŸ’œ 3-D ANGLE CONVERSIONS πŸ’œ

Conversions to and from spherical and cylindrical coordinates are available. Please notice that the conversions are not necessarily reversible, because of the equalities like pi angles being equal to -pi angles. It's not a bug, it's just what happens when you live on a circle πŸŒ€

  • cartesian_to_cylindrical
    ($rho, $theta, $z) = cartesian_to_cylindrical($x, $y, $z);
  • cartesian_to_spherical
    ($rho, $theta, $phi) = cartesian_to_spherical($x, $y, $z);
  • cylindrical_to_cartesian
    ($x, $y, $z) = cylindrical_to_cartesian($rho, $theta, $z);
  • cylindrical_to_spherical
    ($rho_s, $theta, $phi) = cylindrical_to_spherical($rho_c, $theta, $z);

Notice that when $z is not 0, $rho_s is not equal to $rho_c.

  • spherical_to_cartesian
    ($x, $y, $z) = spherical_to_cartesian($rho, $theta, $phi);
  • spherical_to_cylindrical
    ($rho_c, $theta, $z) = spherical_to_cylindrical($rho_s, $theta, $phi);

Notice that when $z is not 0, $rho_c is not equal to $rho_s.

🌍 GREAT CIRCLE DISTANCES AND DIRECTIONS 🌍

okay so picture this: a great circle is a slice of a sphere that goes right through the center β€” it contains the circle's diameter, bestie. and the shortest path between two points on a sphere (as long as they're not antipodal, we'll get to that drama) literally just walks along the great circle connecting them. it's giving "the planet said the shortest route is this one, no notes". ✨


🧭 great_circle_distance

hands you the great circle distance between two points on a sphere. iconic.

$distance = great_circle_distance($theta0, $phi0, $theta1, $phi1, [, $rho]);

so ($theta0, $phi0) and ($theta1, $phi1) are the spherical coordinates of your two points, in that order. the distance comes back measured in $rho units. and $rho? totally optional, defaults to 1 (the unit sphere, she's simple like that πŸ’…).

now if you're out here using geographic coordinates β€” latitude and longitude β€” you gotta adjust, because latitude is zero at the equator, goes up toward the north and down toward the south. so assuming ($lat0, $lon0) and ($lat1, $lon1) are your geographic coordinates in radians, you compute the distance like this:

$distance = great_circle_distance($lon0, pi/2 - $lat0,
                                  $lon1, pi/2 - $lat1, $rho);

see that pi/2 - $lat? that's the whole trick. iykyk. 🫢


🧭 great_circle_direction

the direction you gotta follow along the great circle β€” also known as the bearing β€” comes from the great_circle_direction() function:

use Math::Trig 'great_circle_direction';

$direction = great_circle_direction($theta0, $phi0, $theta1, $phi1);

🧭 great_circle_bearing

good news, an alias exists: 'great_circle_bearing' for 'great_circle_direction'. slay, less typing.

use Math::Trig 'great_circle_bearing';

$direction = great_circle_bearing($theta0, $phi0, $theta1, $phi1);

the result of great_circle_direction is in radians, and here's how to read it:

  • zero β†’ straight north
  • pi or -pi β†’ straight south
  • pi/2 β†’ straight west
  • -pi/2 β†’ straight east

(yes, west is positive and east is negative, that's just the vibe of it, don't fight it πŸŽ€)


🧭 great_circle_destination

you can also flip it around β€” if you know your starting point, the direction and the distance, you get the destination:

use Math::Trig 'great_circle_destination';

# $diro is the original direction,
# for example from great_circle_bearing().
# $distance is the angular distance in radians,
# for example from great_circle_distance().
# $thetad and $phid are the destination coordinates,
# $dird is the final direction at the destination.

($thetad, $phid, $dird) =
  great_circle_destination($theta, $phi, $diro, $distance);

or you can snag the midpoint if you already know both endpoints πŸ‘‡


🧭 great_circle_midpoint

use Math::Trig 'great_circle_midpoint';

($thetam, $phim) =
  great_circle_midpoint($theta0, $phi0, $theta1, $phi1);

and honestly? great_circle_midpoint() is just a special case of β€”


🧭 great_circle_waypoint

use Math::Trig 'great_circle_waypoint';

($thetai, $phii) =
  great_circle_waypoint($theta0, $phi0, $theta1, $phi1, $way);

$way tells you where along the great circle arc your waypoint sits, travelling through the start point ($theta0, $phi0) and the end point ($theta1, $phi1), relative to the distance from start to end. so bestie:

  • $way = 0 β†’ the starting point ✨
  • $way = 1 β†’ the end point ✨
  • $way < 0 β†’ a point "behind" the starting point
  • $way > 1 β†’ a point beyond the end point

and $way defaults to 0.5 if you don't hand one over. the iconic middle, the main character position. πŸ’…

⚠️ heads up though: antipodal points (where the distance between them is pi radians) do not have unique waypoints between them, so "undef" gets returned in those cases. if the points are literally the same and the distance between them is zero, then all waypoints are identical to the starting/end point. no drama, just math.

the thetas, phis, direction and distance in all of the above are radians, fr fr.

you can import every single great circle formula in one go with:

use Math::Trig ':great_circle';

also quick reality check πŸͺž β€” the resulting directions might look a lil surprising if you're staring at a flat world map: in those map projections, great circles quite often do not look like the shortest routes. but for example, the shortest possible routes from Europe or North America to Asia do often cross the polar regions. (and the common Mercator projection doesn't show great circles as straight lines: straight lines in the Mercator projection are lines of constant bearing.) so like, the map lied to you, not the math. 😭


πŸ§ͺ EXAMPLES πŸ§ͺ

let's calculate the distance between London (51.3N 0.5W) and Tokyo (35.7N 139.8E) in kilometers:

use Math::Trig qw(great_circle_distance deg2rad);

# Notice the 90 - latitude: phi zero is at the North Pole.
sub NESW { deg2rad($_[0]), deg2rad(90 - $_[1]) }
my @L = NESW( -0.5, 51.3);
my @T = NESW(139.8, 35.7);
my $km = great_circle_distance(@L, @T, 6378); # About 9600 km.

and the direction you'd have to go from London to Tokyo (in radians, straight north being zero, straight east being pi/2):

use Math::Trig qw(great_circle_direction);

my $rad = great_circle_direction(@L, @T); # About 0.547 or 0.174 pi.

the midpoint between London and Tokyo being:

use Math::Trig qw(great_circle_midpoint rad2deg);

my @M = great_circle_midpoint(@L, @T);
sub SWNE { rad2deg( $_[0] ), 90 - rad2deg( $_[1] ) }
my @lonlat = SWNE(@M);

or about 69 N 89 E, on the Putorana Plateau of Siberia. she's remote, she's mysterious. πŸ¦‹

NOTE: you cannot get from A to B like this: Dist = great_circle_distance(A, B) Dir = great_circle_direction(A, B) C = great_circle_destination(A, Dist, Dir) ...and just expect C to be B, because the bearing constantly changes while you travel from A to B (except in some special case like the meridians or the circles of latitudes). and in great_circle_destination() you're handing over one constant bearing to follow. so no, it's not a round trip, bestie, sorry. πŸ’€

⚠️ CAVEAT FOR GREAT CIRCLE FORMULAS

the answers may be off by a few percentages because the Earth is irregular (slightly aspherical, she's not a perfect sphere, it's not her fault 🌸). the errors are at worst about 0.55%, but generally below 0.3%.


πŸŒ€ Real-valued asin and acos

for small inputs, asin() and acos() may return complex numbers even when real numbers would be totally enough and correct β€” this happens because of floating-point inaccuracies. you can witness this chaos yourself by trying these:

print cos(1e-6)**2+sin(1e-6)**2 - 1,"\n";
printf "%.20f", cos(1e-6)**2+sin(1e-6)**2,"\n";

which will print something like this:

-1.11022302462516e-16
0.99999999999999988898

even though the expected results are of course exactly zero and one. the formulas used to compute asin() and acos() are quite sensitive to this, and therefore they might accidentally slip into the complex plane even when they really shouldn't. to counter this, there are two interfaces that are guaranteed to return a real-valued output. 🫢

asin_real

use Math::Trig qw(asin_real);

$real_angle = asin_real($input_sin);

returns a real-valued arcus sine if the input is between [-1, 1], inclusive of the endpoints. for inputs greater than one, pi/2 is returned. for inputs less than minus one, -pi/2 is returned.

acos_real

use Math::Trig qw(acos_real);

$real_angle = acos_real($input_cos);

returns a real-valued arcus cosine if the input is between [-1, 1], inclusive of the endpoints. for inputs greater than one, zero is returned. for inputs less than minus one, pi is returned.


πŸ› BUGS πŸ›

saying use Math::Trig; exports many mathematical routines into the caller environment and even overrides some ("sin", "cos"). this is construed as a feature by the Authors, actually... ;-)

the code is not optimized for speed, especially because we use "Math::Complex" and thus go quite near complex numbers while doing the computations even when the arguments aren't. this, however, cannot be completely avoided if we want things like asin(2) to give an answer instead of giving a fatal runtime error. so like, trade-offs. 😌

πŸ›‘ Do not attempt navigation using these formulas. fr fr. please. your boat deserves better.

πŸ‘€ SEE ALSO

  • Math::Complex

✍️ AUTHORS

  • Jarkko Hietaniemi <jhi!at!iki.fi>
  • Raphael Manfredi <Raphael_Manfredi!at!pobox.com>
  • Zefram <zefram@fysh.org>

legends, honestly. πŸ‘‘


πŸ“œ LICENSE

this library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.


and that's a wrap on this whole page, bestie πŸ’– the source and version vibes: this is perl v5.44.0, dated 2026-10-17 β€” Math::Trig(3perl), out. go calculate something beautiful. 🌈✨

πŸ“¦ where this page comes from
  • arch rolling: perl 5.44.0-1 Β· Artistic-1.0-Perl AND GPL-1.0-or-later
  • πŸ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms