Skip to content

Commit

Permalink
feat(stdlib): Implement Number.sin and Number.cos (#1343)
Browse files Browse the repository at this point in the history
  • Loading branch information
FinnRG committed Jun 29, 2022
1 parent c9a05b1 commit 9357126
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 0 deletions.
11 changes: 11 additions & 0 deletions compiler/test/stdlib/number.test.gr
Original file line number Diff line number Diff line change
Expand Up @@ -216,3 +216,14 @@ assert Number.sign(BI.toNumber(1t)) == 1
assert 1 / Number.sign(0.0) == Float64.toNumber(Float64.infinity)
// TODO(#693): Replace with -Infinity literal when it exists
assert 1 / Number.sign(-0.0) == Number.neg(Float64.toNumber(Float64.infinity))

// Number.sin
assert Number.sin(0.0) == 0
assert Number.sin(1) > 0.84147 && Number.sin(1) < 0.84148
assert Number.sin(-1) < -0.84147 && Number.sin(-1) > -0.84148
assert Number.sin(20) > 0.91294 && Number.sin(20) < 0.91295

// Number.cos
assert Number.cos(1) > 0.5403 && Number.cos(1) < 0.5404
assert Number.cos(-1) > 0.5403 && Number.cos(-1) < 0.5404
assert Number.cos(15) < -0.7596 && Number.cos(15) > -0.7597
52 changes: 52 additions & 0 deletions stdlib/number.gr
Original file line number Diff line number Diff line change
Expand Up @@ -346,3 +346,55 @@ export let isInfinite = (x: Number) => {
* @since v0.4.5
*/
export parseInt

/**
* Computes how many times pi has to be subtracted to achieve the required bounds for sin.
*/
let reduceToPiBound = (radians: Number) => {
floor(radians / pi)
}

/**
* Computes the sine of a number using Chebyshev polynomials. Requires the input to be bounded to (-pi, pi). More information on the algorithm can be found here: http://mooooo.ooo/chebyshev-sine-approximation/.
*/
let chebyshevSine = (radians: Number) => {
let pi_minor = -0.00000008742278
let x2 = radians * radians
let p11 = 0.00000000013291342
let p9 = p11 * x2 + -0.000000023317787
let p7 = p9 * x2 + 0.0000025222919
let p5 = p7 * x2 + -0.00017350505
let p3 = p5 * x2 + 0.0066208798
let p1 = p3 * x2 + -0.10132118
(radians - pi - pi_minor) * (radians + pi + pi_minor) * p1 * radians
}

/**
* Computes the sine of a number (in radians) using Chebyshev polynomials.
*
* @param radians: The input in radians
* @returns The computed sine
*
* @since v0.5.2
*/
export let sin = (radians: Number) => {
let quot = reduceToPiBound(radians)
let bounded = radians - pi * quot
if (quot % 2 == 0) {
chebyshevSine(bounded)
} else {
neg(chebyshevSine(bounded))
}
}

/**
* Computes the cosine of a number (in radians) using Chebyshev polynomials.
*
* @param radians: The input in radians
* @returns The computed cosine
*
* @since v0.5.2
*/
export let cos = (radians: Number) => {
sin(pi / 2 + radians)
}
50 changes: 50 additions & 0 deletions stdlib/number.md
Original file line number Diff line number Diff line change
Expand Up @@ -535,3 +535,53 @@ Returns:
|----|-----------|
|`Result<Number, String>`|`Ok(value)` containing the parsed number on a successful parse or `Err(msg)` containing an error message string otherwise|

### Number.**sin**

<details disabled>
<summary tabindex="-1">Added in <code>next</code></summary>
No other changes yet.
</details>

```grain
sin : Number -> Number
```

Computes the sine of a number (in radians) using Chebyshev polynomials.

Parameters:

|param|type|description|
|-----|----|-----------|
|`radians`|`Number`|The input in radians|

Returns:

|type|description|
|----|-----------|
|`Number`|The computed sine|

### Number.**cos**

<details disabled>
<summary tabindex="-1">Added in <code>next</code></summary>
No other changes yet.
</details>

```grain
cos : Number -> Number
```

Computes the cosine of a number (in radians) using Chebyshev polynomials.

Parameters:

|param|type|description|
|-----|----|-----------|
|`radians`|`Number`|The input in radians|

Returns:

|type|description|
|----|-----------|
|`Number`|The computed cosine|

0 comments on commit 9357126

Please sign in to comment.