<p>Most languages seem to only have <code>sin</code> <code>cos</code> and <code>tan</code>. While the other 3 are just <code>1/cos</code> <code>1/sin</code> and <code>1/tan</code>, is there any way that supporting the other 3 directly could be faster than calculating one and then performing a division? Are there any other reasons beyond the triviality of deriving the other <code>csc</code> <code>sec</code> and <code>cot</code> from the existing <code>sin</code> <code>cos</code> and <code>tan</code> to exclude them?</p>

<standard-library><math>
Is there any particular reason to only include 3 out of the 6 trigonometry functions?
CC BY-SA 4.0
2023-06-30T09:52:17.870Z
"Is there any way that supporting the other 3 directly could be faster than calculating one and performing the division?" - definitely could be. The major thing you'd worry about is accuracy, probably. e.g. if `x` is very small, you may look for a way of estimating `cscx)` without computing `sin(x)` first.
preferred_anon
CC BY-SA 4.0
2023-06-30T15:39:57.723Z
"only 3 out of the 6 trigonometry" --> it is the _degree_ versions of `sin,cos,tan` that are the 3 most need missing ones.  sind(x) = sin(x*2*pi/360) too often returns unsatisfactory results when degree angle is a large multiple of 15 degrees.
chux
CC BY-SA 4.0
2023-07-02T05:19:28.497Z
See also https://www.johndcook.com/blog/2009/09/25/how-many-trig-functions/
bishop
<p>This does just roll the barrel slightly lower on the hill (or whatever the saying is), but:</p>
<p>The IEEE 754 floating point standard includes the following trig-related operations as &quot;recommended&quot;</p>
<ul>
<li>sin(x)</li>
<li>cos(x)</li>
<li>tan(x)</li>
<li>arcsin(x)</li>
<li>arccos(x)</li>
<li>arctan(x)</li>
<li>atan2(y, x)</li>
</ul>
<p>Since the 2019 revision, these are also recommended (though I've never seen these):</p>
<ul>
<li>sinPi(x) = sin(pi * x)</li>
<li>cosPi(x)</li>
<li>tanPi(x)</li>
<li>arcsinPi(x) = arcsin(x) / pi</li>
<li>arccosPi(x)</li>
<li>arctanPi(x)</li>
<li>atan2Pi(y, x) = atan2(y, x) / pi</li>
</ul>
<p>Now, why does IEEE 754 not recommend (arc)sec/csc/cot I have no idea.</p>

CC BY-SA 4.0
2023-06-29T18:23:16.697Z
2023-06-29T18:23:16.697Z
RubenVerg
CC BY-SA 4.0
2023-06-29T18:24:46.073Z
Just as a side note I really like the `*Pi` functions because a) They're more precise and b) I don't need to manually multiply by pi
CPlus
CC BY-SA 4.0
2023-06-29T18:38:29.307Z
Do you have a link to the IEEE document that recommends these functions?
mousetail 'he-him'
CC BY-SA 4.0
2023-06-30T01:09:15.817Z
@mousetail Sadly, the IEEE-754 standard costs money.
Pseudonym
CC BY-SA 4.0
2023-06-30T04:38:46.867Z
I am surprised to see you say that you've never seen `sinpi` and friends! Off the top of my head, they are implemented in [MATLAB](https://www.mathworks.com/help/matlab/ref/double.sinpi.html), [Julia](https://docs.julialang.org/en/v1/base/math/#Base.Math.sinpi), in vendor libraries from [Intel](https://www.intel.com/content/www/us/en/docs/onemkl/developer-reference-vector-math-performance-accuracy-data/2021-1/sinpi.html) and [Apple](https://developer.apple.com/documentation/accelerate/sinpi), and as of 2023, even the [C standard library](https://en.cppreference.com/w/c/numeric/math/sinpi).
David Zhang
CC BY-SA 4.0
2023-06-30T08:48:32.680Z
Or just have your compiler recognise the pattern and replace it with an optimised version. It'd be far more user friendly.
SK-logic
CC BY-SA 4.0
2023-06-30T16:21:01.197Z
@SK-logic Numerical people are not fond of execution (generated code) being different from  what's written.
Pablo H
CC BY-SA 4.0
2023-06-30T16:25:31.317Z
@PabloH this is what `-ffast-math` and alike a for, telling the compiler that you don't really care if optimisations break accuracy.
SK-logic
CC BY-SA 4.0
2023-06-30T17:53:34.013Z
atan2 is a nice one. While the OP says there are six, this answer shows there are many more. Indeed there are more still, such as haversine ([useful in navigation](https://en.wikipedia.org/wiki/Haversine_formula)) and versine. [This page](https://en.wikipedia.org/wiki/Cofunction) mentions several cofunctions and cofunction identities.
tell
CC BY-SA 4.0
2023-06-30T20:46:40.570Z
@DavidZhang I guess I just live in the wrong corner of programming languages :) glad to see they're in c23 though
RubenVerg
<p>One possible reason is that it is quite difficult to implement these functions with high accuracy.</p>
<p>For + - * / the IEEE standard requires that the error is at most 1/2 of the least significant bit (0.5 ulp). For sin, cos, tan and others, that limit is quite difficult but not impossible to achieve, while a careful implementation can achieve an error of up to say 0.6ulp without major problems. I think Apple's implementation in C and C++ achieves that for inputs less than 10^15, and I'd hope other implementations do the same.</p>
<p>If you want to calculate 1 / sin x, and do this in the naive way by calculating z = sin x and dividing 1 / z, then your rounding error will be much larger. And 1 / sin x is not a polynomial but close to 1 / x, so if you try to calculate it directly you will also have difficulties keeping the rounding error small (close to 0.5ulp, and definitly less than 1.0ulp).</p>
<p>PS. Just noticed in <a href="https://langdev.stackexchange.com/a/1783/89">another post</a> &quot;1 - cos b&quot; was mentioned. Since cos b ≈ 1 - b^2/2 for small b, 1 - cos b could be calculated with much higher precision for small b without going through the cos function.</p>

CC BY-SA 4.0
2023-06-30T12:21:27.710Z
2023-06-30T13:47:59.570Z
2023-06-30T13:47:59.570Z
gnasher729
CC BY-SA 4.0
2023-06-30T13:51:04.200Z
Good point, and users who do want high precision often only need it in a certain range of inputs, which might be different to the range of inputs that other users need precision on.  I think the same reason is why many standard libraries offer `log (1 + x)` as a built-in function ─ it allows higher precision for small `x`.
kaya3
CC BY-SA 4.0
2023-06-30T15:33:34.257Z
"For sin, cos, tan and others, that limit is quite difficult but not impossible to achieve" is the classic [table-maker dilemma](https://en.wiktionary.org/wiki/table-maker%27s_dilemma).  With high precision floating point, it is certainly infeasible to fully test.  AFAIK, Getting a ULP of 0.500...0001 or less is reasonable.  ULP <= 0.5 is very challenging.
chux
CC BY-SA 4.0
2023-06-30T21:51:00.437Z
Isn't this a good reason why the language *should* include these functions, because it's hard for the application to implement them itself without losing accuracy?
Barmar
<p>Older processors had instructions to compute the sine, cosine and tangent of floating-point numbers, but not the secant, cosecant or cotangent. So the reason could just be that especially for older languages, the standard library's mathematical functions were just thin wrappers around the processor's capabilities; and newer languages might have just been copying from those languages ever since.</p>
<p>On the other hand, I can think of a concrete performance reason why it's better <em>not</em> to provide these functions in the standard library. In almost all use-cases, you don't want just the secant, cosecant or cotangent, you want it multiplied by some value; these trigonometric functions are defined as ratios of side lengths in triangles, so you can find an unknown side of a triangle by multiplying a known side by the appropriate trigonometric function of a known angle.</p>
<p>For example, you could write code like this:</p>
<pre class="lang-rs prettyprint-override"><code>let hypotenuse = adjacent * sec(theta);
</code></pre>
<p>But if <code>sec(theta)</code> is a function which returns <code>1.0 / cos(theta)</code> then (without compiler optimisations) this code will do an unnecessary multiplication by 1 and also an extra function call. The alternative way of writing it is:</p>
<pre class="lang-rs prettyprint-override"><code>let hypotenuse = adjacent / cos(theta);
</code></pre>
<p>For the compiler to optimise the former into the latter, it must inline the <code>sec</code> function, rewrite the expression <code>a * (1.0 / c)</code> as <code>(a * 1.0) / c</code>, and then eliminate the unnecessary multiplication. In reality, <a href="https://godbolt.org/z/W47qsGz1G" rel="noreferrer">even modern compilers don't do this optimisation</a>, because it can change the result slightly, and the compiler can't know that the user doesn't mind the slight difference (or that the latter version is slightly <em>more</em> accurate according to the user's intent).</p>
<p>But even though the version with <code>cos</code> is more efficient and slightly more accurate, many programmers might presume that if <code>sec</code> exists in the standard library then it must be better to use it. Therefore, excluding it from the standard library causes users to write the better version with <code>cos</code>. Exactly the same reasoning applies to <code>cosec</code> and <code>cot</code>.</p>

CC BY-SA 4.0
2023-06-29T21:00:09.100Z
2023-06-30T01:15:57.593Z
2023-06-30T01:15:57.593Z
kaya3
CC BY-SA 4.0
2023-08-17T23:43:26.537Z
@Pseudonym: The x87 advise to not use is because they're bugged and can't be unbugged due to massive compatibility breakage. Too bad really. (They do the wrong thing where the trig functions wrap around.)
Joshua
CC BY-SA 4.0
2023-06-29T21:53:08.270Z
The original APL implementation only had the three basic ones from the outset, even though [the target processors didn't have any trig instructions](https://en.wikibooks.org/wiki/360_Assembly/360_Instructions) at all.
Adám
CC BY-SA 4.0
2023-06-30T01:13:57.380Z
Modern processors generally don't have instructions to calculate any trig functions, and those that do (e.g. x87) advise you very strongly not to use them.
Pseudonym
<p>A very huge system library with functions for trivial, easy to derive features is more difficult to remember. The code using them may easily be less readable. Imagine you see:</p>
<pre><code>a = haversine(b)
</code></pre>
<p>Some will know, but for many, Google will be they friend, losing the productive time on that. And when the developer will need to write it next time, one may get in doubt, maybe it was <code>hav</code> or <code>hsin</code> or <code>haversed_sine</code> instead and need to google again. Maybe again. The only benefit, this would boost the page rank of web resources focused on this uncommon function. At the same time,</p>
<pre><code>a = (1 - cos(b) )/2
</code></pre>
<p>(<a href="https://mathworld.wolfram.com/Haversine.html" rel="nofollow noreferrer">the same</a>) would be understood by any developer in a fraction of second. <code>haversine</code> actually reduces readability, unless needed very often.</p>
<p><strong>P.S:</strong> As correctly pointed in the comment to this answer, some rarely used functions make sense if there are code readers that have the fundamental knowledge about them, bringing up lots of useful associations. Maybe haversine is actually not a so good example if used for the task where it is commonly used (not if the expression matched just by chance). In any case the answer argues that smaller API is easier to remember and used without excessive and repeated googling.</p>
<p><strong>P.S:</strong> Some &quot;easy&quot; functions may be present in the library if the naive formula may give overflow on intermediate result (like <code>hypot(x, y) = sqrt(x*x + y*y)</code>) or significant rounding errors. The actual way of computing in this case is actually different from naive.</p>
<p>It is important to keep the balance.</p>

CC BY-SA 4.0
2023-06-30T07:57:05.490Z
2023-11-14T18:14:58.410Z
2023-11-14T18:14:58.410Z
Audrius Meškauskas
CC BY-SA 4.0
2023-06-30T10:24:54.823Z
I actually disagree. If I read `(1-cos(b))/2` in code I might be mystified and have to wonder why they used that particular formula. If I read `haversine` in code I immediately know that they're using the haversine function, whose exact trigonometric formula I might have forgotten over the years, but whose usefulness in latitude/longitude I remember very well. So in this case, the name of the function is more important than the formula, and having a named function makes the code much easier to understand at a glance.
Stef
CC BY-SA 4.0
2023-06-30T11:18:29.763Z
This is because you know in depth about the function, and when you see the name this raises for you lots of the useful context. This is a useful observation.
Audrius Meškauskas
CC BY-SA 4.0
2023-11-13T21:41:13.000Z
I have no familiarity with haversines or the use thereof, but I've sometimes thought a function to compute `1-cos(x)` would make sense since computing that value by first computing the cosine and then subtracting from 1 would yield poor precision when `x` is small.  When using double precision, for example, the computation `1-cos(x)` would yield zero for all `x` all `x` in the range +/- `1.0536712127723508e-8`--i.e. the output would have no correct bits for any `x` value near zero, other than zero itself.
supercat
CC BY-SA 4.0
2023-11-14T18:04:45.077Z
Agree, extended
Audrius Meškauskas
<h3>Frequency of use</h3>
<p>The main three are vastly more commonly used than the other three.</p>

CC BY-SA 4.0
2023-06-29T17:59:12.577Z
2023-06-29T17:59:12.577Z
Adám
CC BY-SA 4.0
2023-06-29T18:07:32.213Z
Counterpoint: sinh and cosh are commonly included but used even more rarely can csc and sec
mousetail 'he-him'
CC BY-SA 4.0
2023-06-29T20:23:45.237Z
@mousetail But they are not easiliy defined in terms of the basic 3.
Adám
CC BY-SA 4.0
2023-06-30T01:13:03.257Z
And perhaps more to the point, calculating csc and sec from cos and sin doesn't involve any significance-losing calculations, since it's just one reciprocal. Calculating sinh from exp can cause problems with cancellation around x=0.
Pseudonym
CC BY-SA 4.0
2023-06-30T09:50:41.910Z
The frequency of use depends heavily on what you work with, I would claim that sinh and cosh are more commonly used than csc and sec.
Henrik supports the community
# Is there any particular reason to only include 3 out of the 6 trigonometry functions?
Posted by: username_0 on 2023-06-29
Most languages seem to only have `sin` `cos` and `tan`. While the other 3 are just `1/cos` `1/sin` and `1/tan`, is there any way that supporting the other 3 directly could be faster than calculating one and then performing a division? Are there any other reasons beyond the triviality of deriving the other `csc` `sec` and `cot` from the existing `sin` `cos` and `tan` to exclude them?
**Tags:** standard-library math
> **Comments:**
> **username_1**: "Is there any way that supporting the other 3 directly could be faster than calculating one and performing the division?" - definitely could be. The major thing you'd worry about is accuracy, probably. e.g. if `x` is very small, you may look for a way of estimating `cscx)` without computing `sin(x)` first.  
> **username_2**: "only 3 out of the 6 trigonometry" --> it is the _degree_ versions of `sin,cos,tan` that are the 3 most need missing ones.  sind(x) = sin(x*2*pi/360) too often returns unsatisfactory results when degree angle is a large multiple of 15 degrees.  
> **username_3**: See also https://www.johndcook.com/blog/2009/09/25/how-many-trig-functions/  
---
## 5 answers
### Answer by username_4 on 2023-06-29. Score: 21 | Accepted answer
This does just roll the barrel slightly lower on the hill (or whatever the saying is), but:

The IEEE 754 floating point standard includes the following trig-related operations as "recommended"

* sin(x)
* cos(x)
* tan(x)
* arcsin(x)
* arccos(x)
* arctan(x)
* atan2(y, x)

Since the 2019 revision, these are also recommended (though I've never seen these):

* sinPi(x) = sin(pi \* x)
* cosPi(x)
* tanPi(x)
* arcsinPi(x) = arcsin(x) / pi
* arccosPi(x)
* arctanPi(x)
* atan2Pi(y, x) = atan2(y, x) / pi

Now, why does IEEE 754 not recommend (arc)sec/csc/cot I have no idea.
> **Comments:**
> **username_0** (2023-06-29): Just as a side note I really like the `*Pi` functions because a) They're more precise and b) I don't need to manually multiply by pi  
> **username_5** (2023-06-29): Do you have a link to the IEEE document that recommends these functions?  
> **username_6** (2023-06-30): @mousetail Sadly, the IEEE-754 standard costs money.  
> **username_7** (2023-06-30): I am surprised to see you say that you've never seen `sinpi` and friends! Off the top of my head, they are implemented in [MATLAB](https://www.mathworks.com/help/matlab/ref/double.sinpi.html), [Julia](https://docs.julialang.org/en/v1/base/math/#Base.Math.sinpi), in vendor libraries from [Intel](https://www.intel.com/content/www/us/en/docs/onemkl/developer-reference-vector-math-performance-accuracy-data/2021-1/sinpi.html) and [Apple](https://developer.apple.com/documentation/accelerate/sinpi), and as of 2023, even the [C standard library](https://en.cppreference.com/w/c/numeric/math/sinpi).  
> **username_8** (2023-06-30): Or just have your compiler recognise the pattern and replace it with an optimised version. It'd be far more user friendly.  
> **username_9** (2023-06-30): @SK-logic Numerical people are not fond of execution (generated code) being different from  what's written.  
> **username_8** (2023-06-30): @PabloH this is what `-ffast-math` and alike a for, telling the compiler that you don't really care if optimisations break accuracy.  
> **username_10** (2023-06-30): atan2 is a nice one. While the OP says there are six, this answer shows there are many more. Indeed there are more still, such as haversine ([useful in navigation](https://en.wikipedia.org/wiki/Haversine_formula)) and versine. [This page](https://en.wikipedia.org/wiki/Cofunction) mentions several cofunctions and cofunction identities.  
> **username_4** (2023-06-30): @DavidZhang I guess I just live in the wrong corner of programming languages :) glad to see they're in c23 though  
---
### Answer by username_11 on 2023-06-30. Score: 12
One possible reason is that it is quite difficult to implement these functions with high accuracy.

For + - \* / the IEEE standard requires that the error is at most 1/2 of the least significant bit (0.5 ulp). For sin, cos, tan and others, that limit is quite difficult but not impossible to achieve, while a careful implementation can achieve an error of up to say 0.6ulp without major problems. I think Apple's implementation in C and C++ achieves that for inputs less than 10^15, and I'd hope other implementations do the same.

If you want to calculate 1 / sin x, and do this in the naive way by calculating z = sin x and dividing 1 / z, then your rounding error will be much larger. And 1 / sin x is not a polynomial but close to 1 / x, so if you try to calculate it directly you will also have difficulties keeping the rounding error small (close to 0.5ulp, and definitly less than 1.0ulp).

PS. Just noticed in [another post](https://langdev.stackexchange.com/a/1783/89) "1 - cos b" was mentioned. Since cos b ≈ 1 - b^2/2 for small b, 1 - cos b could be calculated with much higher precision for small b without going through the cos function.
> **Comments:**
> **username_12** (2023-06-30): Good point, and users who do want high precision often only need it in a certain range of inputs, which might be different to the range of inputs that other users need precision on.  I think the same reason is why many standard libraries offer `log (1 + x)` as a built-in function ─ it allows higher precision for small `x`.  
> **username_2** (2023-06-30): "For sin, cos, tan and others, that limit is quite difficult but not impossible to achieve" is the classic [table-maker dilemma](https://en.wiktionary.org/wiki/table-maker%27s_dilemma).  With high precision floating point, it is certainly infeasible to fully test.  AFAIK, Getting a ULP of 0.500...0001 or less is reasonable.  ULP <= 0.5 is very challenging.  
> **username_13** (2023-06-30): Isn't this a good reason why the language *should* include these functions, because it's hard for the application to implement them itself without losing accuracy?  
---
### Answer by username_12 on 2023-06-29. Score: 11
Older processors had instructions to compute the sine, cosine and tangent of floating-point numbers, but not the secant, cosecant or cotangent. So the reason could just be that especially for older languages, the standard library's mathematical functions were just thin wrappers around the processor's capabilities; and newer languages might have just been copying from those languages ever since.
On the other hand, I can think of a concrete performance reason why it's better not to provide these functions in the standard library. In almost all use-cases, you don't want just the secant, cosecant or cotangent, you want it multiplied by some value; these trigonometric functions are defined as ratios of side lengths in triangles, so you can find an unknown side of a triangle by multiplying a known side by the appropriate trigonometric function of a known angle.
For example, you could write code like this:
let hypotenuse = adjacent * sec(theta);

But if sec(theta) is a function which returns 1.0 / cos(theta) then (without compiler optimisations) this code will do an unnecessary multiplication by 1 and also an extra function call. The alternative way of writing it is:
let hypotenuse = adjacent / cos(theta);

For the compiler to optimise the former into the latter, it must inline the sec function, rewrite the expression a * (1.0 / c) as (a * 1.0) / c, and then eliminate the unnecessary multiplication. In reality, even modern compilers don't do this optimisation, because it can change the result slightly, and the compiler can't know that the user doesn't mind the slight difference (or that the latter version is slightly more accurate according to the user's intent).
But even though the version with cos is more efficient and slightly more accurate, many programmers might presume that if sec exists in the standard library then it must be better to use it. Therefore, excluding it from the standard library causes users to write the better version with cos. Exactly the same reasoning applies to cosec and cot.
> **Comments:**
> **username_15** (2023-06-29): The original APL implementation only had the three basic ones from the outset, even though [the target processors didn't have any trig instructions](https://en.wikibooks.org/wiki/360_Assembly/360_Instructions) at all.  
> **username_6** (2023-06-30): Modern processors generally don't have instructions to calculate any trig functions, and those that do (e.g. x87) advise you very strongly not to use them.  
> **username_14** (2023-08-17): @Pseudonym: The x87 advise to not use is because they're bugged and can't be unbugged due to massive compatibility breakage. Too bad really. (They do the wrong thing where the trig functions wrap around.)  
---
### Answer by username_16 on 2023-06-30. Score: 10
A very huge system library with functions for trivial, easy to derive features is more difficult to remember. The code using them may easily be less readable. Imagine you see:
a = haversine(b)

Some will know, but for many, Google will be they friend, losing the productive time on that. And when the developer will need to write it next time, one may get in doubt, maybe it was hav or hsin or haversed_sine instead and need to google again. Maybe again. The only benefit, this would boost the page rank of web resources focused on this uncommon function. At the same time,
a = (1 - cos(b) )/2

(the same) would be understood by any developer in a fraction of second. haversine actually reduces readability, unless needed very often.
P.S: As correctly pointed in the comment to this answer, some rarely used functions make sense if there are code readers that have the fundamental knowledge about them, bringing up lots of useful associations. Maybe haversine is actually not a so good example if used for the task where it is commonly used (not if the expression matched just by chance). In any case the answer argues that smaller API is easier to remember and used without excessive and repeated googling.
P.S: Some "easy" functions may be present in the library if the naive formula may give overflow on intermediate result (like hypot(x, y) = sqrt(x*x + y*y)) or significant rounding errors. The actual way of computing in this case is actually different from naive.
It is important to keep the balance.
> **Comments:**
> **username_17** (2023-06-30): I actually disagree. If I read `(1-cos(b))/2` in code I might be mystified and have to wonder why they used that particular formula. If I read `haversine` in code I immediately know that they're using the haversine function, whose exact trigonometric formula I might have forgotten over the years, but whose usefulness in latitude/longitude I remember very well. So in this case, the name of the function is more important than the formula, and having a named function makes the code much easier to understand at a glance.  
> **username_16** (2023-06-30): This is because you know in depth about the function, and when you see the name this raises for you lots of the useful context. This is a useful observation.  
> **username_18** (2023-11-13): I have no familiarity with haversines or the use thereof, but I've sometimes thought a function to compute `1-cos(x)` would make sense since computing that value by first computing the cosine and then subtracting from 1 would yield poor precision when `x` is small.  When using double precision, for example, the computation `1-cos(x)` would yield zero for all `x` all `x` in the range +/- `1.0536712127723508e-8`--i.e. the output would have no correct bits for any `x` value near zero, other than zero itself.  
> **username_16** (2023-11-14): Agree, extended  
---
### Answer by username_15 on 2023-06-29. Score: 10
### Frequency of use

The main three are vastly more commonly used than the other three.
> **Comments:**
> **username_5** (2023-06-29): Counterpoint: sinh and cosh are commonly included but used even more rarely can csc and sec  
> **username_15** (2023-06-29): @mousetail But they are not easiliy defined in terms of the basic 3.  
> **username_6** (2023-06-30): And perhaps more to the point, calculating csc and sec from cos and sin doesn't involve any significance-losing calculations, since it's just one reciprocal. Calculating sinh from exp can cause problems with cancellation around x=0.  
> **username_19** (2023-06-30): The frequency of use depends heavily on what you work with, I would claim that sinh and cosh are more commonly used than csc and sec.  
---
