147 lines
7.6 KiB
Markdown
147 lines
7.6 KiB
Markdown
# Sine
|
|
|
|
Sine, abbreviated *sin*, is a [trigonometric](trigonometry.md) [function](function.md) that simply said models a smooth oscillation, it is one of the most important and basic functions in geometry, [mathematics](math.md) and [physics](physics.md), and of course in [programming](programming.md). Along with [cosine](cos.md), [tangent](tan.md) and [cotangent](cot.md) it belongs to a group of functions that can be defined by ratios of sides of a right triangle depending on one of the angles in it (hence *trigonometric* -- "triangle measuring"). If some measurement looks like sine function, we say it is *harmonic*. This is very common in nature and technology, e.g. a weight on a spring goes up and down by this function, [alternating current](ac.md) voltage has the sine shape (because it is generated by a circular motion) etc.
|
|
|
|
The function is most commonly defined using a right triangle as follows. Consider the following triangle:
|
|
|
|
```
|
|
/|
|
|
/ |
|
|
/ |
|
|
c/ |
|
|
/ |a
|
|
/ |
|
|
/ _|
|
|
/A____|_|
|
|
b
|
|
```
|
|
|
|
*Sin(A)*, where *A* is the angle between side *b* and *c*, is the ratio *a* / *c*. The function can be defined in many other ways, for example it is the curve we get when tracking only one direction (e.g. horizontal) of a point moving alongside circle. It can also be defined as a solution to some [differential equations](differential_equation.md) etc.
|
|
|
|
The graph of the sine function is following:
|
|
|
|
```
|
|
^ sin(x)
|
|
|
|
|
1_|_
|
|
| .--'''--.
|
|
-1/2 pi | _.'' ''._ 3/2 pi
|
|
.________|________.'________|________'|________|________.' --> x
|
|
'._ | _.'|0 | |'._ | _.'|
|
|
''--___--'' _|_ 1/2 pi pi ''--___--'' 2 pi
|
|
-1 |
|
|
```
|
|
|
|
**Why the fuck are there these [pi](pi.md) values on the x line???** Nubs often can't comprehend this. These pi values are values in **[radians](radian.md)**, units of measuring angles where *2 pi* is the full angle (360 degrees). In fact sine is sometimes shown with [degrees](degree.md) instead of radians (so imagine 90 degrees on the line where there is 1/2 pi etc.), but mathematicians prefer radians. **But why are there angles in the first place???** Why doesn't it go e.g. from 0 to 1 like all other nice functions? Well, it's because of the relation to geometry, remember the fucking triangle above... also if you define sine with a circle it all repeats after *2 pi*. Just draw some picture if you don't get it.
|
|
|
|
Some additional facts and properties regarding the sine functions are:
|
|
|
|
- The domain are all [real numbers](real_number.md), the [codomain](codomain.md) are real numbers in interval <-1,1> (including both bounds).
|
|
- It is an [odd function](odd_function.md) (*-sin(x) = sin(-x)*).
|
|
- It is periodic, with a period of 2 [pi](pi.md).
|
|
- Sine is just shifted [cosine](cos.md), i.e. *sin(x) = cos(x - 1/2 pi)*
|
|
- Its inverse function is [arcus sine](asin.md), abbreviated *asin*, also written as *sin^-1* -- this function tells you what argument you need to give to sin to get a specific result number. It's actually an inverse of only part of the sine function because the whole sine function can't be inverted, it isn't [bijective](bijection.md).
|
|
- [Derivative](derivative.md) of *sin(x)* is *cos(x)*, the [integral](integral.md) of *sin(x) dx* is *-cos(x)*.
|
|
- By adding many differently shifted and scaled sine functions we can create basically any other function, see e.g. [cosine transform](cosine_transform.md).
|
|
- Sine and [cosine](cos.md) functions are used to draw [circles](circle.md). If you plot points with *x* coordinate equal to *sin(t)* and *y* coordinate equal to *cos(t)* for *t* going from 0 to *2 * pi*, you'll get a unit circle.
|
|
- *sin(x)^2 + cos(x)^2 = 1*
|
|
|
|
Some values of the sine function are:
|
|
|
|
| x (rad) | x (deg) | sin(x) |
|
|
|----------|----------|--------------------|
|
|
| 0 | 0 | 0 |
|
|
| pi / 12 | 15 | ~0.259 |
|
|
| pi / 6 | 30 | 0.5 |
|
|
| pi / 4 | 45 | sqrt(2)/2 ~= 0.707 |
|
|
| pi / 3 | 60 | sqrt(3)/2 ~= 0.866 |
|
|
| pi / 2 | 90 | 1 |
|
|
| 2 pi | 360 | 0 |
|
|
|
|
|
|
|
|
## Programming
|
|
|
|
In programming languages sine is generally available in some math library, for example in [C](c.md) the function `sin` is in `math.h`. Spare yourself bugs, **always check if your sin function expects [radians](radian.md) or degrees!**
|
|
|
|
There exists an **ugly engineering [approximation](approximation.md)** of sine that can be useful sometimes, it says that
|
|
|
|
*sin(x) = x, for small x*
|
|
|
|
Indeed, sine looks similar to a mere line near 0, but you can see it quickly diverges.
|
|
|
|
When implementing your own `sin` function, consider what you expect from it.
|
|
|
|
If you want a small, fast and perhaps integer only `sin` function (the one we'd prefer in [LRS](lrs.md)) that doesn't need extreme accuracy, consider using a **[look up table](lut.md)**. You simply precompute the values of the sine function into a static table in memory and the function just retrieves them when called -- this is super fast. Note that you can save a lot of space by **only storing sine values between 0 and 1/2 pi**, the remaining parts of the function are just different transformations of this part. You can further save space and/or make the function work with [floats](float.md) by further [interpolating](interpolation.md) (even just linearly) between the stored values, for example if `sin(3.45)` is called and you only have values stored for `sin(3.4)` and `sin(3.5)`, you simply average them.
|
|
|
|
Very rough and fast approximations e.g. for primitive music synthesis can be done with the traditional very basic [square](square_function.md) or [triangle](triangle_function.md) functions. The following is a simple 8bit linear approximation that's more accurate than square or triangle (approximates sine with a linear function in each octant):
|
|
|
|
```
|
|
unsigned char sinA(unsigned char x)
|
|
{
|
|
unsigned char quadrant = x / 64;
|
|
|
|
x %= 64;
|
|
|
|
if (quadrant % 2 == 1)
|
|
x = 63 - x;
|
|
|
|
x = x < 32 ? (2 * x + x) : (64 + x);
|
|
|
|
return quadrant <= 1 ? (128 + x) : (127 - x);
|
|
}
|
|
```
|
|
|
|
Similar approximation can be made with a quadratic curve, the following is a modification of the above function that does this (notice that now we need at least 16 bits for the computation so the data type changed to int): { I quickly made this just now, maybe it can be improved. ~drummyfish }
|
|
|
|
```
|
|
int sinA(int x)
|
|
{
|
|
unsigned char quadrant = x / 64;
|
|
|
|
x %= 64;
|
|
|
|
if (quadrant % 2 == 1)
|
|
x = 63 - x;
|
|
|
|
x -= 63;
|
|
x = (x * x) / 32;
|
|
|
|
return quadrant <= 1 ? (255 - x) : x;
|
|
}
|
|
```
|
|
|
|
If you don't need extreme speed there exist very nice sine [approximations](approximation.md), e.g. the extremely accurate **Bhaskara I's approximation** (angle in radians): *sin(x) ~= (16 * x * (pi - x)) / (5 * pi^2 - 4 * x * (pi - x))*. (This formula is actually more elegant for cosine, so it may be even better to consider using that.) Here is a [C](c.md) [fixed point](fixed_point.md) implementation:
|
|
|
|
```
|
|
#define UNIT 1024
|
|
#define PI ((int) (UNIT * 3.14159265))
|
|
|
|
/* Integer sine using Bhaskara's approx. Returns a number
|
|
in <-UNIT, UNIT> interval. Argument is in radians * UNIT. */
|
|
|
|
int sinInt(int x)
|
|
{
|
|
int sign = 1;
|
|
|
|
if (x < 0) // odd function
|
|
{
|
|
x *= -1;
|
|
sign = -1;
|
|
}
|
|
|
|
x %= 2 * PI;
|
|
|
|
if (x > PI)
|
|
{
|
|
x -= PI;
|
|
sign *= -1;
|
|
}
|
|
|
|
x *= PI - x;
|
|
|
|
return sign * (16 * x) / ((5 * PI * PI - 4 * x) / UNIT);
|
|
}
|
|
```
|
|
|
|
Another approach is to use [Taylor series](taylor_series.md) to approximate sine with a [polynomial](polynomial.md) to whatever precision we need (this is used e.g. in calculators etc.). |