Mathematics7 min readExamples run on PHP 8.5.10

acos()

Learn how PHP 8.4 acos() converts a cosine value into an angle in radians, what happens outside the valid range, and how to avoid common mistakes.

Signature

acos(float $num): float

Purpose

acos() returns the arc cosine of a number. It answers the question: "Which angle has this cosine?" The angle is returned in radians, not degrees. The function is the inverse of cos(): for any value in its domain, cos(acos($num)) gives back the original number, apart from tiny floating-point rounding differences.

Typical uses include finding the angle between two vectors, working out the angle of a triangle from its side lengths, and some geometry or graphics calculations.

Signature

Parameters and defaults

$num is the only parameter and it has no default. It is a float, and the valid domain is from -1.0 to 1.0 inclusive, because no real angle has a cosine outside that range. Integers are accepted and converted to floats, so acos(1) works as expected. Values that are not numeric, such as an array or a non-numeric string, cause a TypeError.

Return value and failure cases

The return value is a float between 0 and M_PI (about 3.14159). Some reference points:

  • acos(1) is 0
  • acos(0) is half of pi, about 1.5708
  • acos(-1) is pi, about 3.1416

If $num is outside the range -1 to 1, the function does not throw an exception. It returns NAN (not a number). Any later arithmetic with NAN also produces NAN, so you should check for it with is_nan() when the input is not guaranteed to be valid. Note that NAN is never equal to anything, including itself, so $x === NAN is not a valid test.

Example 1: Familiar values

The first example prints a few well-known results rounded to four decimals. Formatting with sprintf() keeps the output stable and avoids showing long floating-point tails.

Example
<?php
echo sprintf("%.4f", acos(1)), "\n";
echo sprintf("%.4f", acos(0)), "\n";
echo sprintf("%.4f", acos(-1)), "\n";
echo sprintf("%.4f", acos(0.5)), "\n";
Output
0.0000
1.5708
3.1416
1.0472

Example 2: Angle between two vectors

The dot product of two vectors divided by the product of their lengths equals the cosine of the angle between them. Applying acos() gives the angle, and rad2deg() converts it to degrees. The code clamps the cosine into the valid range first, which is a good habit for reasons explained below.

Example
<?php
function angleDegrees(array $a, array $b): float
{
    $dot = $a[0] * $b[0] + $a[1] * $b[1];
    $lengthA = sqrt($a[0] ** 2 + $a[1] ** 2);
    $lengthB = sqrt($b[0] ** 2 + $b[1] ** 2);
    $cosine = $dot / ($lengthA * $lengthB);
    $cosine = max(-1.0, min(1.0, $cosine));
    return rad2deg(acos($cosine));
}

echo sprintf("%.2f", angleDegrees([1, 0], [1, 1])), "\n";
echo sprintf("%.2f", angleDegrees([1, 0], [0, 1])), "\n";
echo sprintf("%.2f", angleDegrees([1, 0], [-1, 0])), "\n";
Output
45.00
90.00
180.00

Example 3: Out-of-range input and clamping

Calculated cosines can drift just past 1 or -1 because of floating-point rounding. In that case acos() returns NAN even though the mathematical result is valid. Clamping the value with min() and max() fixes this.

Example
<?php
$value = 1 + PHP_FLOAT_EPSILON;

echo json_encode([
    is_nan(acos(2)),
    is_nan(acos($value)),
    acos(min(1.0, max(-1.0, $value))) == 0.0,
]), "\n";
Output
[true,true,true]

Edge cases

  • Exact endpoints: 1 and -1 are valid and give 0 and pi.
  • Slightly out of range: values like 1.0000000000000002 return NAN. This often appears after dividing dot products by vector lengths.
  • Zero-length vectors: dividing by zero length fails before acos() is reached. Check lengths first.
  • Floating-point comparison: compare results with a tolerance or round them for display, instead of using === on computed floats.
  • Result range: the answer is never negative. If you need a signed angle, use atan2() with additional information.

Common mistakes

  1. Treating the result as degrees. acos(0) is about 1.5708, not 90. Use rad2deg() when you need degrees.
  2. Passing degrees to trigonometric functions. If you go back with cos(), give it radians.
  3. Ignoring NAN. An out-of-range argument does not raise an error, so the problem can silently spread into later calculations.
  4. Testing with === NAN. Use is_nan() instead.
  5. Printing raw floats and expecting short output. Round or format values when showing them to users.
  • cos() is the cosine function that acos() inverts.
  • acosh() is the inverse hyperbolic cosine, which is a different function with a different domain.
  • asin() returns the arc sine.
  • atan() returns the arc tangent.
  • rad2deg() converts radians to degrees.
  • is_nan() detects invalid results.

Recap

acos(float $num): float returns an angle in radians from 0 to pi for a cosine between -1 and 1. Values outside that range produce NAN rather than an exception. Clamp computed cosines, convert to degrees only when needed, and format floats before displaying them.

Tested examples

Familiar values rounded to four decimals
<?php
echo sprintf("%.4f", acos(1)), "\n";
echo sprintf("%.4f", acos(0)), "\n";
echo sprintf("%.4f", acos(-1)), "\n";
echo sprintf("%.4f", acos(0.5)), "\n";
Output
0.0000
1.5708
3.1416
1.0472
Angle between two vectors in degrees
<?php
function angleDegrees(array $a, array $b): float
{
    $dot = $a[0] * $b[0] + $a[1] * $b[1];
    $lengthA = sqrt($a[0] ** 2 + $a[1] ** 2);
    $lengthB = sqrt($b[0] ** 2 + $b[1] ** 2);
    $cosine = $dot / ($lengthA * $lengthB);
    $cosine = max(-1.0, min(1.0, $cosine));
    return rad2deg(acos($cosine));
}

echo sprintf("%.2f", angleDegrees([1, 0], [1, 1])), "\n";
echo sprintf("%.2f", angleDegrees([1, 0], [0, 1])), "\n";
echo sprintf("%.2f", angleDegrees([1, 0], [-1, 0])), "\n";
Output
45.00
90.00
180.00
Out-of-range input and clamping
<?php
$value = 1 + PHP_FLOAT_EPSILON;

echo json_encode([
    is_nan(acos(2)),
    is_nan(acos($value)),
    acos(min(1.0, max(-1.0, $value))) == 0.0,
]), "\n";
Output
[true,true,true]