<p>In common languages, sine produces an error, NaN, or exception when evaluated at infinity. For example, in Python:</p>
<pre><code>&gt;&gt;&gt; math.sin(float(&quot;inf&quot;))
ValueError: math domain error
</code></pre>
<p>However, consider the fuzzy nature of floating-point arithmetic. Large floating-point numbers are sparse and prone to rounding errors. As a result, sine is frustratingly inexact on large inputs:</p>
<pre><code>&gt;&gt;&gt; math.sin(10**300)
-0.8178819121159085
&gt;&gt;&gt; math.sin(10**300 + 1)
-0.8178819121159085
&gt;&gt;&gt; math.sin(10**300 * math.pi)
-0.902464352009667
</code></pre>
<p>Consider an inexact large input as a continuous range. The average value of sine on that range is small, because most of the range covers pairs of peaks and troughs which cancel out to zero.</p>
<p>So, suppose that we attenuate sine for large inputs. Specifically, we assign each large input a range, and divide the result of sine at that input by the number of wavelengths in that range (effectively the range divided by 2π); at (positive) infinity, we let sine converge to (positive) zero. What breaks or has counterintuitive behavior as a result?</p>

<standard-library><error-handling><floating-point>
Can sine converge to zero at infinity?
CC BY-SA 4.0
2023-12-02T14:16:00.140Z
See also [this question](https://langdev.stackexchange.com/q/2732/715), which looks more generally at the pathologies of periodic functions on floating-point numbers.
Corbin
CC BY-SA 4.0
2023-12-02T20:31:04.420Z
I'm voting to close because I'm not convinced this is a programming language question and not a math/floating point question.
kouta-kun
CC BY-SA 4.0
2023-12-02T22:20:38.040Z
I'm voting to leave open. I can't quite put into words why I feel this should be on-topic but I do.
rydwolf
CC BY-SA 4.0
2023-12-02T22:27:25.953Z
I'm voting to close because this is not about programming languages. Its essentially a question about numerical issues.
feldentm
CC BY-SA 4.0
2023-12-02T23:02:31.740Z
What would the benefit of this be? Why should 0 be a better wrong answer than any other?
kaya3
CC BY-SA 4.0
2023-12-03T00:34:56.983Z
I'm voting to leave open. This essentially asks about the consequences of a programming language that defines `sin(infinity) = 0`.
CPlus
CC BY-SA 4.0
2023-12-03T03:39:08.210Z
[As I mentioned in chat](https://chat.stackexchange.com/transcript/message/64801650#64801650), this seems to be a question about the implications of making a standard library function have non-standard behaviour. Asking about standard library implementation is allowed on this site, so asking about the implications of a standard library implementation/design choice would be on topic for this site too.
lyxal
CC BY-SA 4.0
2023-12-03T12:55:35.070Z
Consider [scicomp.se]
Federico Poloni
CC BY-SA 4.0
2023-12-03T12:58:34.823Z
if you were to treat large FP values as ranges instead, shouldn't the result then also be a range? What would the rationale for dividing by the number of wavelengths be anyway? You do mention the average instead in the preceding paragraph.
ilkkachu
CC BY-SA 4.0
2023-12-03T13:21:05.610Z
IEEE floating-point numbers don't represent ranges, and they aren't suitable for representing ranges; fundamentally, a number like 1.5 could be known to various levels of precision, and the actual level of precision for the number in context will rarely equal the gap between 1.5 and the next representable floating-point number. Furthermore if floating-point numbers represent ranges then all floating-point arithmetic is wrong, because 1.5 (accurate to 1 ulp) minus 1.5 (accurate to 1 ulp) should not be considered accurate to the much smaller ulp for the number 0.0.
kaya3
CC BY-SA 4.0
2023-12-04T12:04:16.157Z
You should rather ask what doesn't break when you define `sin(∞) := 0`. Among others, since `∞ + pi / 2 == ∞` and `sin(x + pi / 2) == cos(x)`, your definition would imply that `sin(∞)` would be both 0 and 1. BTW, sympy returns the correct result : `sympy.sin(10**99999 * sympy.pi) # => 0`
Eric Duminil
CC BY-SA 4.0
2023-12-04T14:25:00.647Z
What are the use cases for `sin(inf)` (and if possible, of `sin(very large value)`)?
Pablo H
CC BY-SA 4.0
2023-12-04T23:29:59.063Z
BTW, [the mathematically exact value of sin(10**300)](https://www.wolframalpha.com/input?i=sin%2810%5E300%29&assumption=%22TrigRD%22+-%3E+%22R%22) (rounded to double-precision) is `-0.985750425160377`.
dan04
CC BY-SA 4.0
2023-12-05T02:59:50.293Z
It depends on your purpose. Early PHP was designed to ignore errors, with the idea that a bad web page is better than no page at all - for that, sin(inf)=0 makes sense as a failsafe. But if your language is used for financial decisions, being wrong has a cost - then, an impossible operation indicates broken code or input, and should throw an exception. Sin(∞) is undefined in real math.
Therac
CC BY-SA 4.0
2023-12-20T19:15:10.083Z
@Therac-PeaceforPalestine: IMHO, the proper approach is to distinguish between tasks whose priority is to produce correct output when possible, at the risk of also producing some incorrect output, those whose priority is to avoid producing seemingly-valid-but-wrong output, and those whose purpose is to validate all aspects of a data set, without regard for whether they would be necessary to correctly display the data.  All three tasks might be possible with different configurations of a common program, but all too often people attempt "compromise" approaches which don't do any task well.
supercat
CC BY-SA 4.0
2024-02-26T21:21:26.713Z
`sin` is "frustratingly inexact" because you don't know what that actual argument to `sin` is for such large *integer* arguments. `float(10**300) == float(10**300 + 1)`, so it's no surprise that both arguments produce the same `sin` value.
chepner
<p>This simply directly contradicts the mathematical (and sensible) notion of &quot;converges,&quot; which we usually interpret as the value at a limit.  The limit <span class="math-container">$\lim_{x \to \infty} \sin x$</span> doesn't exist.  (This can be proven by contradiction using the Epsilon-Delta definition and setting <span class="math-container">$\epsilon$</span> to 1/2).</p>
<p>Generally speaking, it is best when mathematical results in programming languages most closely match the representation of the mathematical result they represent in mathematics.  In the case of floats, <span class="math-container">$\sin \infty = [-1,1]$</span>, and a range is obviously Not a Number.</p>

CC BY-SA 4.0
2023-12-04T08:30:01.293Z
2024-01-19T17:34:31.027Z
2024-01-19T17:34:31.027Z
DanielN
CC BY-SA 4.0
2023-12-04T08:37:03.520Z
Hi! I agree fully with everything that you've said. One important bit of context, though: in numerical methods, ∞ is just the result of overflow. A floating-point number system has a maximum and minimum possible exponent, and sometimes a computation will underflow to 0 or overflow to ∞.  This could make for a good third paragraph.
Corbin
CC BY-SA 4.0
2023-12-04T08:40:24.813Z
Another cool possible direction to explore is user experience and human-computer interfaces. If we were programming a pocket calculator, we'd want `sin(∞)` to display something not like "overflow" or "ValueError", but perhaps "sin does not converge at inf". Something informative and helpful.
Corbin
CC BY-SA 4.0
2023-12-04T09:02:22.473Z
It depends on the calculator.  If it's a simple numeric calculator I would want NaN (or perhaps "Input Error".  For a CAS or symbolic calculator I would want the interval result--this IS informative and helpful.

It is, perhaps, worth reasoning out the why behind $sin(\infty) = [-1,1]$ (it's related to big O notation).  The user not understanding a correct result is not a defect of the result.
DanielN
CC BY-SA 4.0
2023-12-04T15:52:45.933Z
@Corbin "in numerical methods, ∞ is just the result of overflow." _or_ division by 0, IOWs a true infinity, not just an oversized one.
chux
CC BY-SA 4.0
2023-12-05T20:20:04.450Z
@chux-ReinstateMonica That wouldn't work because infinity is still signed. x/0 is indeterminate for x=0 (because the value of the limit can vary depending how we "reach" the two zeroes) and undefined otherwise (because the left-hand and right-hand limits as the denominator approaches 0 aren't equal). That should return NaN in all cases, not ∞ or -∞.
Idran
CC BY-SA 4.0
2023-12-05T20:37:40.840Z
@JustinHilyard, Rather than return NAN for finite/0 per your [should return NaN in all cases, not ∞ or -∞](https://langdev.stackexchange.com/questions/3284/can-sine-converge-to-zero-at-infinity/3306?noredirect=1#comment8197_3306),  IEEE-754 returns +/- ∞, without regard to how you/I think _should_ happen.
chux
CC BY-SA 4.0
2023-12-06T16:07:09.990Z
@chux-ReinstateMonica Oh, huh; fair point, then, I wasn't aware of the IEEE standard there. I'd still argue against division by 0 being a "true" infinity, but I'm clearly mistaken as to the proper approach in practice. Thanks for the correction!
Idran
CC BY-SA 4.0
2023-12-06T16:40:17.450Z
@JustinHilyard You may enjoy the affine/projective infinity discussed [here](https://en.wikipedia.org/wiki/Point_at_infinity).
chux
<p>The most obvious breakage, to me, would be the constraint that <span class="math-container">$\sin^2+\cos^2$</span> should be approximately one -- and related higher order constraints, like a rotation matrix being orthogonal.</p>
<p>I think math libraries generally consider floating point values as exact but sparse values, rather than intervals. It's worth mentioning that &quot;interval arithmetic&quot; does exist, and it comes with its own set of rounding rules.</p>

CC BY-SA 4.0
2023-12-02T18:20:54.813Z
2023-12-03T12:43:02.533Z
2023-12-03T12:43:02.533Z
Alex K
CC BY-SA 4.0
2023-12-03T00:00:14.743Z
Isn't the "sparse value" interpretation inconsistent with having signed zero?
Karl Knechtel
CC BY-SA 4.0
2023-12-03T12:56:04.267Z
@KarlKnechtel, why?
ilkkachu
CC BY-SA 4.0
2023-12-03T14:16:49.807Z
So you're arguing that if `sin(∞) = 0`, then `cos(∞) = 1`?
Bergi
CC BY-SA 4.0
2023-12-03T17:12:30.750Z
@Bergi well, for Inf, I think the current behavior (NaN) is better, but, if sin being 0 was a given, I would set cos to 1 or -1
Alex K
CC BY-SA 4.0
2023-12-03T17:43:22.327Z
Solid answer. I would be careful about appeals to trigonometry, since (in typical Euclidean geometry) we can only use trig identities on triangles of finite length, not infinitesimal or infinite length, but I think that a trig-oriented answer is still appropriate.
Corbin
CC BY-SA 4.0
2023-12-04T01:03:01.937Z
@ilkkachu because if the values are "exact but sparse", then there shouldn't be a reason to distinguish +0 from -0.
Karl Knechtel
CC BY-SA 4.0
2023-12-04T08:16:11.770Z
@KarlKnechtel, so? Those are also exact values. Mathematically speaking, they're the exact same value, and exist just as a bit of an odd feature of to the implementation (but may sometimes be useful to distinguish positive and negative really-close-to-zero values, which can't be represented accurately due to the inherent limits of FP numbers). Even if you object to having two zeroes, that has nothing to do with the other values being treated as exact, or not.
ilkkachu
CC BY-SA 4.0
2023-12-04T10:56:31.217Z
@Bergi: That would break another constraint, that cos(phi)=sin(phi + pi/2). That rule implies `cos(∞)=0`. There are no winners here.
MSalters
CC BY-SA 4.0
2023-12-05T02:14:55.613Z
@MSalters Er wait. Doesn't ∞ = ∞ + π/2?
candied_orange
CC BY-SA 4.0
2023-12-05T20:16:06.197Z
@candied_orange That's their point: cos(∞) = sin(∞ + pi/2) = sin(∞) = 0, which contradicts having cos(∞) = 1.
Idran
CC BY-SA 4.0
2023-12-06T01:54:56.320Z
-1 ≤ sin(∞) ≤ 1. Might not be a traditional number but neither are ∞ or 0.
candied_orange
CC BY-SA 4.0
2023-12-20T19:30:35.023Z
@MSalters: That constraint would only be meaningful in cases where `(phi+pi/2)-phi` is mathematically equal `pi/2`.  If an implementation has separate implementations of `sin` and `cos`, it could make the sum of squares of `sin(phi)` and `cos(phi)` yield approximately 1 even in cases where `phi+pi/2` would equal `phi`.  Though I suppose maybe having the magnitude of `sin(x)` and `cos(x)` be sqrt(2) for large `x` might allow an implementation to uphold both constraints whether or not the `sin(phi+pi/2)==cos(phi)` would be very meaningful.
supercat
<p>Asking for sin(1e300) in floating-point context is <a href="https://en.wikipedia.org/wiki/Not_even_wrong" rel="nofollow noreferrer">not even wrong</a>.</p>
<p>Way before 1e300, one gets into troubles with <a href="https://en.wikipedia.org/wiki/Aliasing" rel="nofollow noreferrer">aliasing</a>, <a href="//stackoverflow.com/q/46762053">π inaccuracies</a> and other bad things arising from the floating-point conceptual limitations that make asking for sine of big enough numbers pointless.</p>
<p>That said, you are proposing to make the result even more wrong (for some quite precise measure of wrong) by making the implementation more complex.</p>
<p>What you will get is generally some minor performance hit, because no sane person will use sin(x) in the range you are trying to alter, except by mistake.</p>
<p>But, good luck debugging such a mistake.</p>

CC BY-SA 4.0
2023-12-03T10:17:41.593Z
2023-12-20T18:02:50.940Z
2023-12-20T18:02:50.940Z
fraxinus
CC BY-SA 4.0
2023-12-03T17:49:48.013Z
This answer seems to not consider numerical error, which is always part of numerical methods. Folks asking for sines of large numbers are already aware that the results will not be especially accurate, and folks using sine-heavy algorithms already take care to scale their inputs to be near the unit circle. Consider e.g. [integration over bandlimited textures in the context of raytracing](https://iquilezles.org/articles/checkerfiltering/) for an analogous construction; a checkerboard texture is just a thresholded sine, after all.
Corbin
CC BY-SA 4.0
2023-12-05T05:37:33.033Z
OK, you need a sine-like function that works in particular manner outside of the reasonable sine application. Go on and implement it under appropriate name in your program or library. You may (or may not) have more luck using fixed-point?
fraxinus
CC BY-SA 4.0
2023-12-20T19:37:32.393Z
@fraxinus: In what non-contrived applications would a function that computes a floating-point value within 0.5ulp of `sin(x +/- 0.5ulp)` be any less useful than one that always computes `sin(x)` +/- 0.5ulp?  In what non-contrived applications would a function that precisely computes the latter value be more useful than a faster functiont that computes the faster?
supercat
CC BY-SA 4.0
2023-12-21T07:52:44.810Z
@supercat in FP world, any value is +/- 1/2ulp, isn't it?
fraxinus
CC BY-SA 4.0
2023-12-21T17:18:30.893Z
@fraxinus: An "ideal" transcendental function would be +/- 1/2ulp of the exact value specified, but in many cases achieving that level of precision may be *much* more expensive than a function with looser tolerances.  Computing within 1/2 LSB the double-precision sine of some numbers that are near 1E300 would require either performing computations with well over 1,000 bits of precision, or else having a table listing argument values that are extremely close to being exact multiples of pi, and the associated return values.
supercat
<p>Well, the IEEE-754 standard breaks, for a start. The standard specifies that, if supported, the domain of the <span class="math-container">$\sin$</span> operation is <span class="math-container">$\left( -\infty,\infty \right)$</span>.</p>
<p>The standard does not impose explicit requirements on how precise an implementation of <span class="math-container">$\sin$</span> should be, however there is an <em>objectively correct</em> answer for what, in an ideal world, <code>sin(1e300 * PI)</code> <em>should</em> return:</p>
<ul>
<li>Represent <code>1e300 * PI</code> as the nearest correctly-rounded floating-point number. Call this <span class="math-container">$x$</span>.</li>
<li>Return the nearest correctly-rounded floating point number to the <em>exact</em> value of <span class="math-container">$\sin(x)$</span>.</li>
</ul>
<p>It is the 21st century, and this is what a programmer should expect. Unsurprisingly, this is what most real math library implementations try very hard to do, along with proofs of correctness.</p>
<p>The cost is usually run-time performance. Evaluating <code>sin(1e300*PI)</code> requires some special-path code to handle that region of the domain which is likely to be much slower than, say, evaluating <span class="math-container">$\sin$</span> in the subset of the domain <span class="math-container">$\left(-10\pi,10\pi\right)$</span>. The feeling is that it's not an error to ask for <code>sin(1e300*PI)</code>, but the programmer arguably deserves the performance they get.</p>

CC BY-SA 4.0
2023-12-03T02:07:25.363Z
2023-12-05T00:30:01.383Z
2023-12-05T00:30:01.383Z
Pseudonym
CC BY-SA 4.0
2023-12-03T11:22:20.833Z
I just tried it now in Python, and asking for the sin of 1e300 * pi is only slightly slower than the sin of pi. However, the result is approximately -0.9.
Karl Knechtel
CC BY-SA 4.0
2023-12-03T17:03:38.570Z
It would be the fp number nearest to 1e300, multiplied by the FP number nearest to PI, rounded to the nearest FP number.
gnasher729
CC BY-SA 4.0
2023-12-04T07:37:05.203Z
(+1) Side remark: In an ideal world someone who wants to compute $\sin(10^{300}\pi)$ would invoke `sinpi (1e300)`.
njuffa
CC BY-SA 4.0
2023-12-04T11:25:17.287Z
...assuming that `sinpi` is available. The assumption here is that it's not, or that the value just happens to be $\sin\left(10^{300}\pi\right)$.
Pseudonym
CC BY-SA 4.0
2023-12-04T15:58:49.403Z
@Pseudonym To be clear: Does your "(−∞,∞)" include or exclude the endpoints?  I would expect exclude and "[−∞,∞]" includes the ends.
chux
CC BY-SA 4.0
2023-12-05T00:35:43.180Z
@chux-ReinstateMonica square brackets include, round brackets exclude
Nick Matteo
CC BY-SA 4.0
2023-12-05T01:13:37.017Z
@NickMatteo The question was for Pseudonym to clarify.  Yes `[]` and `()`in general usage follows as you suggest, I wanted to make certain that is what this answer was using.
chux
CC BY-SA 4.0
2023-12-05T10:26:32.930Z
Yes, that is what I meant.
Pseudonym
CC BY-SA 4.0
2023-12-07T23:29:43.800Z
Yah, this is a great answer. To elaborate a bit more on why the standard matters, a key part of languages is communication and that hinges on the expectations of the users. Users will expect a IEEE 754 compliant implementation to be linked into the standard library, so follow the standard. If you have some super compelling reason to do a custom type, make it very clear the operations (and probably the associated types) aren't IEEE 754 anymore... because they aren't and saying they are will confuse people badly.
IanH
CC BY-SA 4.0
2023-12-11T08:27:00.677Z
For how many real-world applications, other than boasting about the superiority of one's math library, would an implementation that performs argument reduction mod pi be more useful than one that performs argument reduction mod (argumentType)pi or--better yet--one whose argument represents the number of whole unit circles (i.e. behaves as though the function scaled the argument by 2pi)?  Note that for the latter function, no special effort would be required to process large inputs in "mathematically precise" fashion.
supercat
<p>A long time ago I was reading an article about game development somewhere and it said something along the lines of: &quot;If your algorithm does not fit in a <code>float</code> and you feel like you need a <code>double</code>, you're doing it wrong.&quot; And this really made floating point and significant digits click in my mind. In the real world, you don't need infinite precision. If you're talking about the distance from Earth to Mars, you're not going to care about millimeters. If you're talking about the size of an amoeba, you won't care about lightyears. Etc.</p>
<p>Looking at large values of floating-point numbers and bemoaning the &quot;large intervals&quot; and &quot;frustrating imprecision&quot; is missing the point. You're doing it wrong. You shouldn't care. (Of course, sometimes you <em>do</em> actually need a <code>double</code>, but in the grand scheme of things those cases are fairly rare)</p>
<p>Similarly about calculating <code>sin</code> at infinity. First of all, &quot;infinity&quot; isn't even a number in the mathematical sense. Doing math on it doesn't make sense in the first place. The IEEE floating point allows it because it's a neat &quot;sentinel value&quot; which you might find useful sometimes - but never as an actual value. It's just a marker to signify that some calculation you were doing went off the rails. Or maybe you can use it to mark some other condition. But don't use it in calculations.</p>
<p>So I think that debating about what value <code>sin(infinity)</code> should take is a moot discussion. It doesn't matter. You shouldn't be doing this. It doesn't make sense. There is no right answer. You can assign it 0 if you want to. Or 1. Or -1. Or NaN. Or throw an exception. Or <a href="https://en.wikipedia.org/wiki/Undefined_behavior" rel="nofollow noreferrer">nasal demons</a>.</p>
<p>Personally, I like the exception because it clearly shows that you're doing something wrong. However I also understand that exceptions can be expensive so maybe you'd rather use a sentinel value instead. May I suggest NaN?</p>

CC BY-SA 4.0
2023-12-04T02:29:01.727Z
2023-12-04T02:29:01.727Z
Vilx-
CC BY-SA 4.0
2023-12-04T08:18:17.790Z
Hi! I like your point about how ∞ is a sentinel value for errors; specifically, it indicates overflow conditions. In some ways, ∞ is just the edge of the number line.
Corbin
CC BY-SA 4.0
2023-12-04T08:19:41.583Z
Gonna channel Moonchild and link [Kahan's MINDLESS.PDF](https://people.eecs.berkeley.edu/~wkahan/Mindless.pdf), which has several examples of how just bumping up `float` to `double` doesn't work. Numerical analysis is required and fundamentally messy.
Corbin
CC BY-SA 4.0
2023-12-05T03:15:19.800Z
That's channeling me?!  I'm honoured.
Moonchild
CC BY-SA 4.0
2024-02-09T10:25:48.867Z
Hi. A bit off-topic, but what's your opinion on using `+inf` and `-inf` as initialisation values, especially in algorithms that compute minimums and maximums? For instance `function minimum(array) { m = +inf; foreach x in array { m = x < m ? x : m; } return m }`. Also useful to initialise the distances in Dijkstra's algorithm, the node values in a minmax tree search, etc.
Stef
CC BY-SA 4.0
2024-02-09T10:36:42.810Z
@Stef - Yeah, that's fair. Note that in this case you're not doing math on infinity - you're just comparing it to other values.
Vilx-
<p>It is unclear which properties of sine and cosine are most important to retain as we start to deal with roundoff.  The preferred set of properties would certainly be application specific.</p>
<p>A compromise I have seen in a few languages is to include a version of sin which multiplies by pi before taking the sine, such as C++23's <a href="https://en.cppreference.com/w/c/numeric/math/sinpi" rel="noreferrer">sinpi</a>.  This doesn't fix all of the roundoff issues that can occur, but it does align key values.  Inputting integers to sinpi always yields exactly 0 because the particular floating point subtraction needed is exact.</p>
<p>The real challenge with treating these numbers as ranges would be consistency.  If sin and cos were to treat the input as a range in a language, I would expect the other operations to do so as well.  In particular, multiplying a number by 4 should result in a range that is 4x larger than the smallest possible interval.  This does not have hardware support, which would make it tricky.  It also would lead to tricky challenges supporting inverses.</p>
<p>Fuzzy logic might be an interesting direction to go.  In such a case, the values are not ranges, but distributions over that range.  In such cases, assuming cos(x * HUGE_VALUE) is a uniform distribution from -1 to 1 may be a very reasonable approach.</p>

CC BY-SA 4.0
2023-12-03T16:37:10.487Z
2023-12-03T16:37:10.487Z
Cort Ammon
CC BY-SA 4.0
2023-12-05T15:48:04.210Z
For argument reduction, you can subtract the nearest even integer, which will always be an exact operation if x ≠ inf. Or subtract the nearest multiple of 0.5 and keep track of the quadrant for the sign and to decide whether to calculate sine or cosine from 0 to pi/2.
gnasher729
CC BY-SA 4.0
2023-12-05T20:01:02.730Z
@gnasher729 I'm not privvy to all the decisions the C++ team made regarding sinpi, but I woudln't be surprised if you nailed it on the head: subtracting 1.0 or 0.5 is always an exact operation.  Subtracting pi or pi/2 is not.
Cort Ammon
CC BY-SA 4.0
2023-12-05T22:22:17.327Z
Ideally, this would clarify that `sinpi` et al were specified in C23, and just imported to C++ by its reference to the C Standard Library. They have separate standards committees, who occasionally have worked in tandem.
Phil Miller
CC BY-SA 4.0
2023-12-08T00:34:48.853Z
"This doesn't fix all of the roundoff issues that can occur, but it does align key values." It fixes the biggest issue: Taking the fractional part of a floating-point number is an exact operation.
Pseudonym
<blockquote>
<p>What breaks or has counterintuitive behavior as a result?</p>
</blockquote>
<p>Well, if you define <span class="math-container">$\sin(\infty) = 0$</span>, then by the same reasoning you'd have to define <span class="math-container">$\cos(\infty) = 0$</span> as well, which breaks the Pythagorean identity <span class="math-container">$\sin^2 x + \cos^2 x = 1$</span>.  If you support complex numbers, then you also get <span class="math-container">$e^{i\infty} = 0$</span>, which breaks the assumption <span class="math-container">$|e^{i\infty}| = 1$</span>.  And then there's all the other trig identities for sums and differences of angles...</p>
<hr />
<p>The “correct” interpretation of an expression like <code>math.sin(10**300)</code> depends on what you consider <code>10**300</code> to <em>mean</em>.  Possible interpretations are:</p>
<ol>
<li>Exactly <span class="math-container">$10^{300}$</span>.  Then the correct (to IEEE 754 double-precision) result of the <code>sin</code> call is <code>-0.985750425160377</code>.</li>
<li>The nearest representable floating-point value to <span class="math-container">$10^{300}$</span>, which works out to <span class="math-container">$2^{946} \times 1681218273811815$</span> (again assuming double-precision).  Then <code>sin</code> should return <code>-0.8178819121159085</code>.  <strong>This is the interpretation that Python is using.</strong></li>
<li>Some unspecified number whose floating-point approximation is closer to <code>1e+300</code> than it is to either of the adjacent floating-point values (<code>9.999999999999999e+299</code> and <code>1.0000000000000002e+300</code>).  So, somewhere within an interval with a length on the order of <span class="math-container">$10^{284}$</span>.  But since that includes multiple complete periods of the <code>sin</code> function, we have no idea what the angle modulo <span class="math-container">$2\pi$</span> might be.</li>
</ol>
<p>If you use the “interval” interpretation of floating-point numbers (#3 above), then there are several ways that you could handle <code>sin(x)</code> given <span class="math-container">$x \in [a, b]$</span>:</p>
<ul>
<li>Arbitrarily pick a specific value within the interval, and take the sine of <em>that</em> as best as you can.  (#1 and #2 above are special cases of this.)</li>
<li>Return an <em>interval</em> (or value/tolerance pair) from the function instead of just a single number.  So <code>sin(10**300)</code> returns <span class="math-container">$[-1, 1]$</span> or <span class="math-container">$0 \pm 1$</span>, since we can't pinpoint the value any further.</li>
<li>Return the <em>average</em> value of <code>sin</code> within the interval <span class="math-container">$[a, b]$</span>.  From calculus, this works out to <span class="math-container">$\frac{\cos(a) - \cos(b)}{b - a}$</span>.  Or if the interval is represented as <span class="math-container">$x \pm \epsilon$</span>, then it's <span class="math-container">$\frac{\cos(x-\epsilon) - \cos(x+\epsilon)}{2\epsilon} = \frac{\sin(x)\sin(\epsilon)}{\epsilon}$</span>.  If <span class="math-container">$\epsilon$</span> is small, then <span class="math-container">$\sin(\epsilon) \approx \epsilon$</span>, so the average value over the interval <span class="math-container">$[x - \epsilon, x + \epsilon]$</span> approaches <span class="math-container">$\sin(x)$</span>.  But if <span class="math-container">$\epsilon$</span> is big, then <span class="math-container">$|\sin(\epsilon)|\le 1$</span> while <span class="math-container">$\epsilon$</span> grows without bound, so the average sine value is 0.  This is apparently how you want it to be handled.</li>
<li>Decide that if <span class="math-container">$|x| &gt; 10^{15}$</span> or so, then the inherent floating-point representation error in <code>x</code> is large enough that it's not even meaningful to try to compute <code>sin(x)</code>, and treat it as an error (throw an exception or return NaN).</li>
</ul>

CC BY-SA 4.0
2023-12-05T01:08:21.083Z
2023-12-05T01:08:21.083Z
dan04
CC BY-SA 4.0
2023-12-05T17:05:01.970Z
Great answer. I like the point about complex identities. One missing detail: trig identities usually don't hold in FP implementations; instead, we use trig identities as part of numerical methods when we are deciding how to encode formulae as algorithms, akin to [strength reduction](https://en.wikipedia.org/wiki/Strength_reduction).
Corbin
CC BY-SA 4.0
2023-12-20T14:53:01.787Z
Why would you "have to" define `cos(∞)` to be zero rather than, say one?  The latter would give consistent identities.  As you say, the reasoning isn't consistent, and we could equally well choose `sin(∞)==1 && cos(∞)==0` or any other consistent pair; that leads me to find returning NaN or throwing an exception the most reasonable result for both.
Toby Speight
CC BY-SA 4.0
2024-01-02T21:34:26.127Z
@TobySpeight: OP's justification for defining `sin(∞)`=0 is that `sin` has an average value of 0.  Since `cos` is just a horizontal shift of `sin`, it has the same average value of 0.
dan04
<p>The answer to the titular math question is no.
sine has no limit as its argument goes to infinity.
Whether a math library should assign 0 to sin(infinity) is a distinct question.  There is really no basis for assigning any particular number to sin(infinity).  NaN is really the only sensible alternative when NaN is available.
Whether to bother with sin(1e300) is yet another question. It's been done.  Look up crlibm.  It is practical.  At worst, it is good to just over half an ulp.  Probably it is good to better than half an ulp.  Not all floating point values are the result of rounding.  1e300 would certainly not be obtained by adding 1e300 ones.  Even when demanding a precise value for a sine seems silly, having a value that is consistent with the cosine is not silly.  Accurate values can accomplish that.</p>

CC BY-SA 4.0
2023-12-04T20:58:20.360Z
2023-12-04T23:07:41.977Z
2023-12-04T23:07:41.977Z
Michael Hennebry
<blockquote>
<p>Can sine converge to zero at infinity?</p>
</blockquote>
<p>No, since it violates the principle of least astonishment on several fronts.</p>
<p>Sine at infinity is NaN, because</p>
<ol>
<li>lim(x→∞) sin(x) doesn't exist,</li>
<li>sin(x) is not defined for non-numeric domain, and ∞ is not a number,</li>
<li>Having lim(x→∞) sin(x)=0 makes most of calculus internally inconsistent. Sure, you perhaps could have a calculus where this convergence is a fact, but it'd work differently from what everyone else calls basic univariate calculus.</li>
</ol>
<p>Whether it's a signaling or non-signaling NaN is an orthogonal problem.</p>
<blockquote>
<p>However, consider the fuzzy nature of floating-point arithmetic.</p>
</blockquote>
<p>There is absolutely nothing fuzzy about floating point arithmetic. Each non-NaN IEEE 754 bit pattern represents a specific, well-defined number on the real number line. Full stop.</p>
<blockquote>
<p>As a result, sine is frustratingly inexact on large inputs</p>
</blockquote>
<p>Nope. No matter how large an input, as long as it fits into the domain of the numbers a given <code>sin</code> works with (IEEE 754 single or double precision in C etc.), a sane <code>sin</code> implementation should provide a result accurate to the last bit.</p>
<blockquote>
<p>math.sin(10**300 + 1)</p>
</blockquote>
<p>The fact that <code>10**300+1 == 10**300</code> in double IEEE 754 arithmetic has nothing to do with the implementation of the sine function!</p>
<p>What you're really computing in both cases is <code>sin(1.0000000000000000525047602552E301)</code>, and this has very much a definite answer that can be computed to arbitrary precision. Mainstream C runtime libraries do provide an exact rounded answer for this, as they well should.</p>
<p>Python isn't a language designed for arbitrary precision computation on reals. It implements arbitrary width integers only. If you'd like to play with arbitrary precision transcendentals, Wolfram Language is your best bet. It has algorithms that compute sines to whatever precision you want, as long as you got time and memory :)</p>

CC BY-SA 4.0
2024-02-07T19:24:23.970Z
2024-02-07T23:46:36.907Z
2024-02-07T23:46:36.907Z
Kuba hasn't forgotten Monica
CC BY-SA 4.0
2024-02-07T19:26:10.733Z
There are a few inconsistencies in your stance which are worth examining. In particular, what is "exact rounded"? After rounding, a result is definitionally no longer exact!
Corbin
CC BY-SA 4.0
2024-02-09T10:33:03.260Z
@Corbin I can think of a one non-inconsistent interpretation of that particular sentence: the mathematical sine of 1.0000000000000000525047602552E301 is a transcendental real number between -1 and +1, and there is a unique floating-point number which is the closest floating-point number to that transcendental number, and this floating-point number is the value returned by `sin(1.0000000000000000525047602552E301)` in mainstream C runtime libraries. Less-accurate libraries possibly return another float approximation which is not the closest float, hence not "the exact rounded answer".
Stef
<p>I'll contrast other's saying it's not a proglang problem - IEEE-754 specifies aspects that're defined by languages and some that may be deferred to implementations.</p>
<p>If you make sine converge to 0 towards inf, then I suggest you make cosine converge to 1 similarly. This is required to preserve the invariant of Pythagorean theorem. Vincent Lefèvre (Co-author of &quot;<a href="https://link.springer.com/book/10.1007/978-3-319-76526-6" rel="nofollow noreferrer">Handbook of Floating Point Arithmetic</a>&quot;, and you might consider reading it if you're interested) said in his 2023-11-30 mail on the IEEE-754 standard revision mailing list:</p>
<blockquote>
<p>Some applications may require properties like <span class="math-container">$\operatorname{sin}^2 x + \operatorname{cos}^2 x = 1$</span>
(approximately).</p>
</blockquote>
<p>I used MathJax notation, while the original mail's in plaintext.</p>

CC BY-SA 4.0
2024-02-09T05:59:24.657Z
2024-09-09T11:39:09.380Z
2024-09-09T11:39:09.380Z
DannyNiu
CC BY-SA 4.0
2024-02-09T16:59:23.867Z
Why wouldn't cosine also converge towards zero, by the same logic given in the question? See discussion on [this answer](https://langdev.stackexchange.com/a/3315/715).
Corbin
<blockquote>
<p>So, suppose that we attenuate sine for large inputs. Specifically, we assign each large input a range, and divide the result of sine at that input by the number of wavelengths in that range (effectively the range divided by 2π); at (positive) infinity, we let sine converge to (positive) zero.</p>
</blockquote>
<p>This idea doesn't even remotely make <em>mathematical</em> sense, so changing things like this isn't going to improve the computer-science results. In particular:</p>
<ul>
<li><p>This kind of attenuation is just unsound; the limit of sin(x) as x goes to infinity does not exist, and the function does not converge in any sense.</p>
</li>
<li><p>As soon as the &quot;range&quot; (actually a domain) represented by a &quot;large input&quot; includes even <em>one</em> complete cycle (half a cycle in the worst case, actually), the result can meaningfully be anything in the range of the sin function (-1 to +1). Larger values for the input, meanwhile, <em>do not have any more uncertainty</em>.</p>
</li>
</ul>
<p>If you want a calculation to reflect an inexact result, other than imprecision inherent to the numeric type itself, that requires a custom <em>type that actually tracks the amount of inexactness</em>. This can be as simple as a pair of floats, a best-guess value and a size-of-the-error-bar value.</p>
<p>However, even this model has its faults. Simply saying that a value is &quot;0 +/- 1&quot; because it could possibly be anywhere in <code>[-1, 1]</code>, loses information about the best guess we might have for the value. The natural way to figure out the imprecision in a function, generally, is to use a straight-line (secant) approximation at the best-guess point, and use that to scale the error in the input value into an error in the output value. But that obviously breaks as the input errors get larger, and especially becomes nonsensical for periodic functions.</p>
<p>People who need to track a large number that represents a quantity in radians with which trigonometric functions need to be calculated later, should bear the responsibility for numerical instability. In particular, they have the option of storing it as a pair of values: an integer (perhaps arbitrary-precision) for the number of complete circular arcs, plus a floating-point value in <code>[0, 2pi)</code>.</p>
<p>One alternative to ensure that programmers don't attempt nonsensical calculations, is to restrict the permitted domain: either to something like <code>[0, 2pi)</code> or <code>[-pi, pi)</code>, or else to the values <em>that allow the output to be correct within floating-point precision</em>. (Someone else has probably already worked out what that limit is.)</p>

CC BY-SA 4.0
2023-12-04T12:11:53.093Z
2023-12-04T12:11:53.093Z
Karl Knechtel
<p>Sine, cosine etc have mathematical properties that you want to preserve.</p>
<p>For large <span class="math-container">$x$</span>, in an ideal world you would calculate <span class="math-container">$\sin (x-2\pi k)$</span> for a suitable integer <span class="math-container">$k$</span>, same for <span class="math-container">$\cos$</span>. In a less ideal world, we replace a large <span class="math-container">$x$</span> with a small <span class="math-container">$x’$</span> close to <span class="math-container">$x - 2\pi k$</span>, and with the same <span class="math-container">$x’$</span> for sin and cos. This preserves <span class="math-container">$|\sin x|\le 1$</span> and <span class="math-container">$|\cos x|\le 1$</span> which is much easier for small <span class="math-container">$x’$</span>, and <span class="math-container">$\sin^2 x + \cos^2 x \approx 1$</span>.</p>
<p>When <span class="math-container">$x$</span> is large enough that the difference between two floating point numbers is more than <span class="math-container">$2\pi$</span>, and <span class="math-container">$x$</span> is the result of some floating point operation, then <span class="math-container">$\sin x$</span> cannot produce a meaningful result, so we <em>can</em> let <span class="math-container">$x’=0$</span>, giving <span class="math-container">$\sin x = 0$</span> and <span class="math-container">$\cos x = 1$</span>. Or we can calculate <span class="math-container">$x’$</span> as precise as possible. You can find <span class="math-container">$x’$</span> with almost perfect precision if <span class="math-container">$x \le 10^{15}$</span> and degrading precision if <span class="math-container">$x \le 10^{30}$</span> very fast; you could do that and set <span class="math-container">$x’=0$</span> for larger <span class="math-container">$x’$</span> or use a <span class="math-container">$300$</span> digit approximation for <span class="math-container">$\pi$</span> and do it completely over the whole range.</p>

CC BY-SA 4.0
2023-12-24T21:44:02.383Z
2024-01-19T17:33:22.727Z
2024-01-19T17:33:22.727Z
gnasher729
# Can sine converge to zero at infinity?
Posted by: username_0 on 2023-12-02
In common languages, sine produces an error, NaN, or exception when evaluated at infinity. For example, in Python:
>>> math.sin(float("inf"))
ValueError: math domain error

However, consider the fuzzy nature of floating-point arithmetic. Large floating-point numbers are sparse and prone to rounding errors. As a result, sine is frustratingly inexact on large inputs:
>>> math.sin(10**300)
-0.8178819121159085
>>> math.sin(10**300 + 1)
-0.8178819121159085
>>> math.sin(10**300 * math.pi)
-0.902464352009667

Consider an inexact large input as a continuous range. The average value of sine on that range is small, because most of the range covers pairs of peaks and troughs which cancel out to zero.
So, suppose that we attenuate sine for large inputs. Specifically, we assign each large input a range, and divide the result of sine at that input by the number of wavelengths in that range (effectively the range divided by 2π); at (positive) infinity, we let sine converge to (positive) zero. What breaks or has counterintuitive behavior as a result?
**Tags:** standard-library error-handling floating-point
> **Comments:**
> **username_0**: See also [this question](https://langdev.stackexchange.com/q/2732/715), which looks more generally at the pathologies of periodic functions on floating-point numbers.  
> **username_1**: I'm voting to close because I'm not convinced this is a programming language question and not a math/floating point question.  
> **username_2**: I'm voting to leave open. I can't quite put into words why I feel this should be on-topic but I do.  
> **username_3**: I'm voting to close because this is not about programming languages. Its essentially a question about numerical issues.  
> **username_4**: What would the benefit of this be? Why should 0 be a better wrong answer than any other?  
> **username_5**: I'm voting to leave open. This essentially asks about the consequences of a programming language that defines `sin(infinity) = 0`.  
> **username_6**: [As I mentioned in chat](https://chat.stackexchange.com/transcript/message/64801650#64801650), this seems to be a question about the implications of making a standard library function have non-standard behaviour. Asking about standard library implementation is allowed on this site, so asking about the implications of a standard library implementation/design choice would be on topic for this site too.  
> **username_7**: Consider [scicomp.se]  
> **username_8**: if you were to treat large FP values as ranges instead, shouldn't the result then also be a range? What would the rationale for dividing by the number of wavelengths be anyway? You do mention the average instead in the preceding paragraph.  
> **username_4**: IEEE floating-point numbers don't represent ranges, and they aren't suitable for representing ranges; fundamentally, a number like 1.5 could be known to various levels of precision, and the actual level of precision for the number in context will rarely equal the gap between 1.5 and the next representable floating-point number. Furthermore if floating-point numbers represent ranges then all floating-point arithmetic is wrong, because 1.5 (accurate to 1 ulp) minus 1.5 (accurate to 1 ulp) should not be considered accurate to the much smaller ulp for the number 0.0.  
> **username_9**: You should rather ask what doesn't break when you define `sin(∞) := 0`. Among others, since `∞ + pi / 2 == ∞` and `sin(x + pi / 2) == cos(x)`, your definition would imply that `sin(∞)` would be both 0 and 1. BTW, sympy returns the correct result : `sympy.sin(10**99999 * sympy.pi) # => 0`  
> **username_10**: What are the use cases for `sin(inf)` (and if possible, of `sin(very large value)`)?  
> **username_11**: BTW, [the mathematically exact value of sin(10**300)](https://www.wolframalpha.com/input?i=sin%2810%5E300%29&assumption=%22TrigRD%22+-%3E+%22R%22) (rounded to double-precision) is `-0.985750425160377`.  
> **username_12**: It depends on your purpose. Early PHP was designed to ignore errors, with the idea that a bad web page is better than no page at all - for that, sin(inf)=0 makes sense as a failsafe. But if your language is used for financial decisions, being wrong has a cost - then, an impossible operation indicates broken code or input, and should throw an exception. Sin(∞) is undefined in real math.  
> **username_13**: @Therac-PeaceforPalestine: IMHO, the proper approach is to distinguish between tasks whose priority is to produce correct output when possible, at the risk of also producing some incorrect output, those whose priority is to avoid producing seemingly-valid-but-wrong output, and those whose purpose is to validate all aspects of a data set, without regard for whether they would be necessary to correctly display the data.  All three tasks might be possible with different configurations of a common program, but all too often people attempt "compromise" approaches which don't do any task well.  
> **username_14**: `sin` is "frustratingly inexact" because you don't know what that actual argument to `sin` is for such large *integer* arguments. `float(10**300) == float(10**300 + 1)`, so it's no surprise that both arguments produce the same `sin` value.  
---
## 12 answers
### Answer by username_18 on 2023-12-02. Score: 35
The most obvious breakage, to me, would be the constraint that $\sin^2+\cos^2$ should be approximately one -- and related higher order constraints, like a rotation matrix being orthogonal.

I think math libraries generally consider floating point values as exact but sparse values, rather than intervals. It's worth mentioning that "interval arithmetic" does exist, and it comes with its own set of rounding rules.
> **Comments:**
> **username_19** (2023-12-03): Isn't the "sparse value" interpretation inconsistent with having signed zero?  
> **username_8** (2023-12-03): @KarlKnechtel, why?  
> **username_20** (2023-12-03): So you're arguing that if `sin(∞) = 0`, then `cos(∞) = 1`?  
> **username_18** (2023-12-03): @Bergi well, for Inf, I think the current behavior (NaN) is better, but, if sin being 0 was a given, I would set cos to 1 or -1  
> **username_0** (2023-12-03): Solid answer. I would be careful about appeals to trigonometry, since (in typical Euclidean geometry) we can only use trig identities on triangles of finite length, not infinitesimal or infinite length, but I think that a trig-oriented answer is still appropriate.  
> **username_19** (2023-12-04): @ilkkachu because if the values are "exact but sparse", then there shouldn't be a reason to distinguish +0 from -0.  
> **username_8** (2023-12-04): @KarlKnechtel, so? Those are also exact values. Mathematically speaking, they're the exact same value, and exist just as a bit of an odd feature of to the implementation (but may sometimes be useful to distinguish positive and negative really-close-to-zero values, which can't be represented accurately due to the inherent limits of FP numbers). Even if you object to having two zeroes, that has nothing to do with the other values being treated as exact, or not.  
> **username_21** (2023-12-04): @Bergi: That would break another constraint, that cos(phi)=sin(phi + pi/2). That rule implies `cos(∞)=0`. There are no winners here.  
> **username_22** (2023-12-05): @MSalters Er wait. Doesn't ∞ = ∞ + π/2?  
> **username_17** (2023-12-05): @candied_orange That's their point: cos(∞) = sin(∞ + pi/2) = sin(∞) = 0, which contradicts having cos(∞) = 1.  
> **username_22** (2023-12-06): -1 ≤ sin(∞) ≤ 1. Might not be a traditional number but neither are ∞ or 0.  
> **username_13** (2023-12-20): @MSalters: That constraint would only be meaningful in cases where `(phi+pi/2)-phi` is mathematically equal `pi/2`.  If an implementation has separate implementations of `sin` and `cos`, it could make the sum of squares of `sin(phi)` and `cos(phi)` yield approximately 1 even in cases where `phi+pi/2` would equal `phi`.  Though I suppose maybe having the magnitude of `sin(x)` and `cos(x)` be sqrt(2) for large `x` might allow an implementation to uphold both constraints whether or not the `sin(phi+pi/2)==cos(phi)` would be very meaningful.  
---
### Answer by username_23 on 2023-12-03. Score: 18
Asking for sin(1e300) in floating-point context is [not even wrong](https://en.wikipedia.org/wiki/Not_even_wrong).

Way before 1e300, one gets into troubles with [aliasing](https://en.wikipedia.org/wiki/Aliasing), [π inaccuracies](//stackoverflow.com/q/46762053) and other bad things arising from the floating-point conceptual limitations that make asking for sine of big enough numbers pointless.

That said, you are proposing to make the result even more wrong (for some quite precise measure of wrong) by making the implementation more complex.

What you will get is generally some minor performance hit, because no sane person will use sin(x) in the range you are trying to alter, except by mistake.

But, good luck debugging such a mistake.
> **Comments:**
> **username_0** (2023-12-03): This answer seems to not consider numerical error, which is always part of numerical methods. Folks asking for sines of large numbers are already aware that the results will not be especially accurate, and folks using sine-heavy algorithms already take care to scale their inputs to be near the unit circle. Consider e.g. [integration over bandlimited textures in the context of raytracing](https://iquilezles.org/articles/checkerfiltering/) for an analogous construction; a checkerboard texture is just a thresholded sine, after all.  
> **username_23** (2023-12-05): OK, you need a sine-like function that works in particular manner outside of the reasonable sine application. Go on and implement it under appropriate name in your program or library. You may (or may not) have more luck using fixed-point?  
> **username_13** (2023-12-20): @fraxinus: In what non-contrived applications would a function that computes a floating-point value within 0.5ulp of `sin(x +/- 0.5ulp)` be any less useful than one that always computes `sin(x)` +/- 0.5ulp?  In what non-contrived applications would a function that precisely computes the latter value be more useful than a faster functiont that computes the faster?  
> **username_23** (2023-12-21): @supercat in FP world, any value is +/- 1/2ulp, isn't it?  
> **username_13** (2023-12-21): @fraxinus: An "ideal" transcendental function would be +/- 1/2ulp of the exact value specified, but in many cases achieving that level of precision may be *much* more expensive than a function with looser tolerances.  Computing within 1/2 LSB the double-precision sine of some numbers that are near 1E300 would require either performing computations with well over 1,000 bits of precision, or else having a table listing argument values that are extremely close to being exact multiples of pi, and the associated return values.  
---
### Answer by username_24 on 2023-12-03. Score: 14
Well, the IEEE-754 standard breaks, for a start. The standard specifies that, if supported, the domain of the $\sin$ operation is $\left( -\infty,\infty \right)$.

The standard does not impose explicit requirements on how precise an implementation of $\sin$ should be, however there is an *objectively correct* answer for what, in an ideal world, `sin(1e300 * PI)` *should* return:

* Represent `1e300 * PI` as the nearest correctly-rounded floating-point number. Call this $x$.
* Return the nearest correctly-rounded floating point number to the *exact* value of $\sin(x)$.

It is the 21st century, and this is what a programmer should expect. Unsurprisingly, this is what most real math library implementations try very hard to do, along with proofs of correctness.

The cost is usually run-time performance. Evaluating `sin(1e300*PI)` requires some special-path code to handle that region of the domain which is likely to be much slower than, say, evaluating $\sin$ in the subset of the domain $\left(-10\pi,10\pi\right)$. The feeling is that it's not an error to ask for `sin(1e300*PI)`, but the programmer arguably deserves the performance they get.
> **Comments:**
> **username_19** (2023-12-03): I just tried it now in Python, and asking for the sin of 1e300 * pi is only slightly slower than the sin of pi. However, the result is approximately -0.9.  
> **username_25** (2023-12-03): It would be the fp number nearest to 1e300, multiplied by the FP number nearest to PI, rounded to the nearest FP number.  
> **username_26** (2023-12-04): (+1) Side remark: In an ideal world someone who wants to compute $\sin(10^{300}\pi)$ would invoke `sinpi (1e300)`.  
> **username_24** (2023-12-04): ...assuming that `sinpi` is available. The assumption here is that it's not, or that the value just happens to be $\sin\left(10^{300}\pi\right)$.  
> **username_16** (2023-12-04): @Pseudonym To be clear: Does your "(−∞,∞)" include or exclude the endpoints?  I would expect exclude and "[−∞,∞]" includes the ends.  
> **username_27** (2023-12-05): @chux-ReinstateMonica square brackets include, round brackets exclude  
> **username_16** (2023-12-05): @NickMatteo The question was for Pseudonym to clarify.  Yes `[]` and `()`in general usage follows as you suggest, I wanted to make certain that is what this answer was using.  
> **username_24** (2023-12-05): Yes, that is what I meant.  
> **username_28** (2023-12-07): Yah, this is a great answer. To elaborate a bit more on why the standard matters, a key part of languages is communication and that hinges on the expectations of the users. Users will expect a IEEE 754 compliant implementation to be linked into the standard library, so follow the standard. If you have some super compelling reason to do a custom type, make it very clear the operations (and probably the associated types) aren't IEEE 754 anymore... because they aren't and saying they are will confuse people badly.  
> **username_13** (2023-12-11): For how many real-world applications, other than boasting about the superiority of one's math library, would an implementation that performs argument reduction mod pi be more useful than one that performs argument reduction mod (argumentType)pi or--better yet--one whose argument represents the number of whole unit circles (i.e. behaves as though the function scaled the argument by 2pi)?  Note that for the latter function, no special effort would be required to process large inputs in "mathematically precise" fashion.  
---
### Answer by username_15 on 2023-12-04. Score: 10
This simply directly contradicts the mathematical (and sensible) notion of "converges," which we usually interpret as the value at a limit. The limit $\lim\_{x \to \infty} \sin x$ doesn't exist. (This can be proven by contradiction using the Epsilon-Delta definition and setting $\epsilon$ to 1/2).

Generally speaking, it is best when mathematical results in programming languages most closely match the representation of the mathematical result they represent in mathematics. In the case of floats, $\sin \infty = [-1,1]$, and a range is obviously Not a Number.
> **Comments:**
> **username_0** (2023-12-04): Hi! I agree fully with everything that you've said. One important bit of context, though: in numerical methods, ∞ is just the result of overflow. A floating-point number system has a maximum and minimum possible exponent, and sometimes a computation will underflow to 0 or overflow to ∞.  This could make for a good third paragraph.  
> **username_0** (2023-12-04): Another cool possible direction to explore is user experience and human-computer interfaces. If we were programming a pocket calculator, we'd want `sin(∞)` to display something not like "overflow" or "ValueError", but perhaps "sin does not converge at inf". Something informative and helpful.  
> **username_15** (2023-12-04): It depends on the calculator.  If it's a simple numeric calculator I would want NaN (or perhaps "Input Error".  For a CAS or symbolic calculator I would want the interval result--this IS informative and helpful.

It is, perhaps, worth reasoning out the why behind $sin(\infty) = [-1,1]$ (it's related to big O notation).  The user not understanding a correct result is not a defect of the result.  
> **username_16** (2023-12-04): @Corbin "in numerical methods, ∞ is just the result of overflow." _or_ division by 0, IOWs a true infinity, not just an oversized one.  
> **username_17** (2023-12-05): @chux-ReinstateMonica That wouldn't work because infinity is still signed. x/0 is indeterminate for x=0 (because the value of the limit can vary depending how we "reach" the two zeroes) and undefined otherwise (because the left-hand and right-hand limits as the denominator approaches 0 aren't equal). That should return NaN in all cases, not ∞ or -∞.  
> **username_16** (2023-12-05): @JustinHilyard, Rather than return NAN for finite/0 per your [should return NaN in all cases, not ∞ or -∞](https://langdev.stackexchange.com/questions/3284/can-sine-converge-to-zero-at-infinity/3306?noredirect=1#comment8197_3306),  IEEE-754 returns +/- ∞, without regard to how you/I think _should_ happen.  
> **username_17** (2023-12-06): @chux-ReinstateMonica Oh, huh; fair point, then, I wasn't aware of the IEEE standard there. I'd still argue against division by 0 being a "true" infinity, but I'm clearly mistaken as to the proper approach in practice. Thanks for the correction!  
> **username_16** (2023-12-06): @JustinHilyard You may enjoy the affine/projective infinity discussed [here](https://en.wikipedia.org/wiki/Point_at_infinity).  
---
### Answer by username_32 on 2023-12-03. Score: 7
It is unclear which properties of sine and cosine are most important to retain as we start to deal with roundoff. The preferred set of properties would certainly be application specific.

A compromise I have seen in a few languages is to include a version of sin which multiplies by pi before taking the sine, such as C++23's [sinpi](https://en.cppreference.com/w/c/numeric/math/sinpi). This doesn't fix all of the roundoff issues that can occur, but it does align key values. Inputting integers to sinpi always yields exactly 0 because the particular floating point subtraction needed is exact.

The real challenge with treating these numbers as ranges would be consistency. If sin and cos were to treat the input as a range in a language, I would expect the other operations to do so as well. In particular, multiplying a number by 4 should result in a range that is 4x larger than the smallest possible interval. This does not have hardware support, which would make it tricky. It also would lead to tricky challenges supporting inverses.

Fuzzy logic might be an interesting direction to go. In such a case, the values are not ranges, but distributions over that range. In such cases, assuming cos(x \* HUGE\_VALUE) is a uniform distribution from -1 to 1 may be a very reasonable approach.
> **Comments:**
> **username_25** (2023-12-05): For argument reduction, you can subtract the nearest even integer, which will always be an exact operation if x ≠ inf. Or subtract the nearest multiple of 0.5 and keep track of the quadrant for the sign and to decide whether to calculate sine or cosine from 0 to pi/2.  
> **username_32** (2023-12-05): @gnasher729 I'm not privvy to all the decisions the C++ team made regarding sinpi, but I woudln't be surprised if you nailed it on the head: subtracting 1.0 or 0.5 is always an exact operation.  Subtracting pi or pi/2 is not.  
> **username_33** (2023-12-05): Ideally, this would clarify that `sinpi` et al were specified in C23, and just imported to C++ by its reference to the C Standard Library. They have separate standards committees, who occasionally have worked in tandem.  
> **username_24** (2023-12-08): "This doesn't fix all of the roundoff issues that can occur, but it does align key values." It fixes the biggest issue: Taking the fractional part of a floating-point number is an exact operation.  
---
### Answer by username_11 on 2023-12-05. Score: 7
> What breaks or has counterintuitive behavior as a result?

Well, if you define $\sin(\infty) = 0$, then by the same reasoning you'd have to define $\cos(\infty) = 0$ as well, which breaks the Pythagorean identity $\sin^2 x + \cos^2 x = 1$. If you support complex numbers, then you also get $e^{i\infty} = 0$, which breaks the assumption $|e^{i\infty}| = 1$. And then there's all the other trig identities for sums and differences of angles...

---

The “correct” interpretation of an expression like `math.sin(10**300)` depends on what you consider `10**300` to *mean*. Possible interpretations are:

1. Exactly $10^{300}$. Then the correct (to IEEE 754 double-precision) result of the `sin` call is `-0.985750425160377`.
2. The nearest representable floating-point value to $10^{300}$, which works out to $2^{946} \times 1681218273811815$ (again assuming double-precision). Then `sin` should return `-0.8178819121159085`. **This is the interpretation that Python is using.**
3. Some unspecified number whose floating-point approximation is closer to `1e+300` than it is to either of the adjacent floating-point values (`9.999999999999999e+299` and `1.0000000000000002e+300`). So, somewhere within an interval with a length on the order of $10^{284}$. But since that includes multiple complete periods of the `sin` function, we have no idea what the angle modulo $2\pi$ might be.

If you use the “interval” interpretation of floating-point numbers (#3 above), then there are several ways that you could handle `sin(x)` given $x \in [a, b]$:

* Arbitrarily pick a specific value within the interval, and take the sine of *that* as best as you can. (#1 and #2 above are special cases of this.)
* Return an *interval* (or value/tolerance pair) from the function instead of just a single number. So `sin(10**300)` returns $[-1, 1]$ or $0 \pm 1$, since we can't pinpoint the value any further.
* Return the *average* value of `sin` within the interval $[a, b]$. From calculus, this works out to $\frac{\cos(a) - \cos(b)}{b - a}$. Or if the interval is represented as $x \pm \epsilon$, then it's $\frac{\cos(x-\epsilon) - \cos(x+\epsilon)}{2\epsilon} = \frac{\sin(x)\sin(\epsilon)}{\epsilon}$. If $\epsilon$ is small, then $\sin(\epsilon) \approx \epsilon$, so the average value over the interval $[x - \epsilon, x + \epsilon]$ approaches $\sin(x)$. But if $\epsilon$ is big, then $|\sin(\epsilon)|\le 1$ while $\epsilon$ grows without bound, so the average sine value is 0. This is apparently how you want it to be handled.
* Decide that if $|x| > 10^{15}$ or so, then the inherent floating-point representation error in `x` is large enough that it's not even meaningful to try to compute `sin(x)`, and treat it as an error (throw an exception or return NaN).
> **Comments:**
> **username_0** (2023-12-05): Great answer. I like the point about complex identities. One missing detail: trig identities usually don't hold in FP implementations; instead, we use trig identities as part of numerical methods when we are deciding how to encode formulae as algorithms, akin to [strength reduction](https://en.wikipedia.org/wiki/Strength_reduction).  
> **username_34** (2023-12-20): Why would you "have to" define `cos(∞)` to be zero rather than, say one?  The latter would give consistent identities.  As you say, the reasoning isn't consistent, and we could equally well choose `sin(∞)==1 && cos(∞)==0` or any other consistent pair; that leads me to find returning NaN or throwing an exception the most reasonable result for both.  
> **username_11** (2024-01-02): @TobySpeight: OP's justification for defining `sin(∞)`=0 is that `sin` has an average value of 0.  Since `cos` is just a horizontal shift of `sin`, it has the same average value of 0.  
---
### Answer by username_29 on 2023-12-04. Score: 4
A long time ago I was reading an article about game development somewhere and it said something along the lines of: "If your algorithm does not fit in a `float` and you feel like you need a `double`, you're doing it wrong." And this really made floating point and significant digits click in my mind. In the real world, you don't need infinite precision. If you're talking about the distance from Earth to Mars, you're not going to care about millimeters. If you're talking about the size of an amoeba, you won't care about lightyears. Etc.

Looking at large values of floating-point numbers and bemoaning the "large intervals" and "frustrating imprecision" is missing the point. You're doing it wrong. You shouldn't care. (Of course, sometimes you *do* actually need a `double`, but in the grand scheme of things those cases are fairly rare)

Similarly about calculating `sin` at infinity. First of all, "infinity" isn't even a number in the mathematical sense. Doing math on it doesn't make sense in the first place. The IEEE floating point allows it because it's a neat "sentinel value" which you might find useful sometimes - but never as an actual value. It's just a marker to signify that some calculation you were doing went off the rails. Or maybe you can use it to mark some other condition. But don't use it in calculations.

So I think that debating about what value `sin(infinity)` should take is a moot discussion. It doesn't matter. You shouldn't be doing this. It doesn't make sense. There is no right answer. You can assign it 0 if you want to. Or 1. Or -1. Or NaN. Or throw an exception. Or [nasal demons](https://en.wikipedia.org/wiki/Undefined_behavior).

Personally, I like the exception because it clearly shows that you're doing something wrong. However I also understand that exceptions can be expensive so maybe you'd rather use a sentinel value instead. May I suggest NaN?
> **Comments:**
> **username_0** (2023-12-04): Hi! I like your point about how ∞ is a sentinel value for errors; specifically, it indicates overflow conditions. In some ways, ∞ is just the edge of the number line.  
> **username_0** (2023-12-04): Gonna channel Moonchild and link [Kahan's MINDLESS.PDF](https://people.eecs.berkeley.edu/~wkahan/Mindless.pdf), which has several examples of how just bumping up `float` to `double` doesn't work. Numerical analysis is required and fundamentally messy.  
> **username_30** (2023-12-05): That's channeling me?!  I'm honoured.  
> **username_31** (2024-02-09): Hi. A bit off-topic, but what's your opinion on using `+inf` and `-inf` as initialisation values, especially in algorithms that compute minimums and maximums? For instance `function minimum(array) { m = +inf; foreach x in array { m = x < m ? x : m; } return m }`. Also useful to initialise the distances in Dijkstra's algorithm, the node values in a minmax tree search, etc.  
> **username_29** (2024-02-09): @Stef - Yeah, that's fair. Note that in this case you're not doing math on infinity - you're just comparing it to other values.  
---
### Answer by username_35 on 2023-12-04. Score: 0
The answer to the titular math question is no.
sine has no limit as its argument goes to infinity.
Whether a math library should assign 0 to sin(infinity) is a distinct question. There is really no basis for assigning any particular number to sin(infinity). NaN is really the only sensible alternative when NaN is available.
Whether to bother with sin(1e300) is yet another question. It's been done. Look up crlibm. It is practical. At worst, it is good to just over half an ulp. Probably it is good to better than half an ulp. Not all floating point values are the result of rounding. 1e300 would certainly not be obtained by adding 1e300 ones. Even when demanding a precise value for a sine seems silly, having a value that is consistent with the cosine is not silly. Accurate values can accomplish that.
---
### Answer by username_36 on 2024-02-07. Score: 0
> Can sine converge to zero at infinity?

No, since it violates the principle of least astonishment on several fronts.

Sine at infinity is NaN, because

1. lim(x→∞) sin(x) doesn't exist,
2. sin(x) is not defined for non-numeric domain, and ∞ is not a number,
3. Having lim(x→∞) sin(x)=0 makes most of calculus internally inconsistent. Sure, you perhaps could have a calculus where this convergence is a fact, but it'd work differently from what everyone else calls basic univariate calculus.

Whether it's a signaling or non-signaling NaN is an orthogonal problem.

> However, consider the fuzzy nature of floating-point arithmetic.

There is absolutely nothing fuzzy about floating point arithmetic. Each non-NaN IEEE 754 bit pattern represents a specific, well-defined number on the real number line. Full stop.

> As a result, sine is frustratingly inexact on large inputs

Nope. No matter how large an input, as long as it fits into the domain of the numbers a given `sin` works with (IEEE 754 single or double precision in C etc.), a sane `sin` implementation should provide a result accurate to the last bit.

> math.sin(10\*\*300 + 1)

The fact that `10**300+1 == 10**300` in double IEEE 754 arithmetic has nothing to do with the implementation of the sine function!

What you're really computing in both cases is `sin(1.0000000000000000525047602552E301)`, and this has very much a definite answer that can be computed to arbitrary precision. Mainstream C runtime libraries do provide an exact rounded answer for this, as they well should.

Python isn't a language designed for arbitrary precision computation on reals. It implements arbitrary width integers only. If you'd like to play with arbitrary precision transcendentals, Wolfram Language is your best bet. It has algorithms that compute sines to whatever precision you want, as long as you got time and memory :)
> **Comments:**
> **username_0** (2024-02-07): There are a few inconsistencies in your stance which are worth examining. In particular, what is "exact rounded"? After rounding, a result is definitionally no longer exact!  
> **username_31** (2024-02-09): @Corbin I can think of a one non-inconsistent interpretation of that particular sentence: the mathematical sine of 1.0000000000000000525047602552E301 is a transcendental real number between -1 and +1, and there is a unique floating-point number which is the closest floating-point number to that transcendental number, and this floating-point number is the value returned by `sin(1.0000000000000000525047602552E301)` in mainstream C runtime libraries. Less-accurate libraries possibly return another float approximation which is not the closest float, hence not "the exact rounded answer".  
---
### Answer by username_37 on 2024-02-09. Score: 0
I'll contrast other's saying it's not a proglang problem - IEEE-754 specifies aspects that're defined by languages and some that may be deferred to implementations.

If you make sine converge to 0 towards inf, then I suggest you make cosine converge to 1 similarly. This is required to preserve the invariant of Pythagorean theorem. Vincent Lefèvre (Co-author of "[Handbook of Floating Point Arithmetic](https://link.springer.com/book/10.1007/978-3-319-76526-6)", and you might consider reading it if you're interested) said in his 2023-11-30 mail on the IEEE-754 standard revision mailing list:

> Some applications may require properties like $\operatorname{sin}^2 x + \operatorname{cos}^2 x = 1$
> (approximately).

I used MathJax notation, while the original mail's in plaintext.
> **Comments:**
> **username_0** (2024-02-09): Why wouldn't cosine also converge towards zero, by the same logic given in the question? See discussion on [this answer](https://langdev.stackexchange.com/a/3315/715).  
---
### Answer by username_19 on 2023-12-04. Score: 0
> So, suppose that we attenuate sine for large inputs. Specifically, we assign each large input a range, and divide the result of sine at that input by the number of wavelengths in that range (effectively the range divided by 2π); at (positive) infinity, we let sine converge to (positive) zero.

This idea doesn't even remotely make *mathematical* sense, so changing things like this isn't going to improve the computer-science results. In particular:

* This kind of attenuation is just unsound; the limit of sin(x) as x goes to infinity does not exist, and the function does not converge in any sense.
* As soon as the "range" (actually a domain) represented by a "large input" includes even *one* complete cycle (half a cycle in the worst case, actually), the result can meaningfully be anything in the range of the sin function (-1 to +1). Larger values for the input, meanwhile, *do not have any more uncertainty*.

If you want a calculation to reflect an inexact result, other than imprecision inherent to the numeric type itself, that requires a custom *type that actually tracks the amount of inexactness*. This can be as simple as a pair of floats, a best-guess value and a size-of-the-error-bar value.

However, even this model has its faults. Simply saying that a value is "0 +/- 1" because it could possibly be anywhere in `[-1, 1]`, loses information about the best guess we might have for the value. The natural way to figure out the imprecision in a function, generally, is to use a straight-line (secant) approximation at the best-guess point, and use that to scale the error in the input value into an error in the output value. But that obviously breaks as the input errors get larger, and especially becomes nonsensical for periodic functions.

People who need to track a large number that represents a quantity in radians with which trigonometric functions need to be calculated later, should bear the responsibility for numerical instability. In particular, they have the option of storing it as a pair of values: an integer (perhaps arbitrary-precision) for the number of complete circular arcs, plus a floating-point value in `[0, 2pi)`.

One alternative to ensure that programmers don't attempt nonsensical calculations, is to restrict the permitted domain: either to something like `[0, 2pi)` or `[-pi, pi)`, or else to the values *that allow the output to be correct within floating-point precision*. (Someone else has probably already worked out what that limit is.)
---
### Answer by username_25 on 2023-12-24. Score: -1
Sine, cosine etc have mathematical properties that you want to preserve.

For large $x$, in an ideal world you would calculate $\sin (x-2\pi k)$ for a suitable integer $k$, same for $\cos$. In a less ideal world, we replace a large $x$ with a small $x’$ close to $x - 2\pi k$, and with the same $x’$ for sin and cos. This preserves $|\sin x|\le 1$ and $|\cos x|\le 1$ which is much easier for small $x’$, and $\sin^2 x + \cos^2 x \approx 1$.

When $x$ is large enough that the difference between two floating point numbers is more than $2\pi$, and $x$ is the result of some floating point operation, then $\sin x$ cannot produce a meaningful result, so we *can* let $x’=0$, giving $\sin x = 0$ and $\cos x = 1$. Or we can calculate $x’$ as precise as possible. You can find $x’$ with almost perfect precision if $x \le 10^{15}$ and degrading precision if $x \le 10^{30}$ very fast; you could do that and set $x’=0$ for larger $x’$ or use a $300$ digit approximation for $\pi$ and do it completely over the whole range.
---
