Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add fast trigonometric functions #243

Merged
merged 2 commits into from
Jan 23, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/math/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Math

## [Fast trigonometric functions (sin, cos, tan)](./src/trigonometry.cairo)

The trigonometric functions are a set of mathematical functions that relate the angles of a triangle to the lengths of its sides. The most common trigonometric functions are sine, cosine, and tangent. These functions are used in many areas of mathematics, including geometry, calculus, and statistics. They are also used in physics, engineering, and other sciences.

Fast trigonometric functions are computational and spacial efficient, with minor errors compared to the standard trigonometric functions. Refer to http://hevi.info/tag/fast-sine-function/ for detailed information.

## [Aliquot sum](./src/aliquot_sum.cairo)

The aliquot sum algorithm calculates the sum of proper divisors of a given positive integer, providing insight into factors and divisors of a number, and classifying it as perfect, abundant, or deficient.
Expand Down
1 change: 1 addition & 0 deletions src/math/src/lib.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ mod perfect_number;
mod sha256;
mod sha512;
mod signed_u256;
mod trigonometry;

#[cfg(test)]
mod tests;
Expand Down
1 change: 1 addition & 0 deletions src/math/src/tests.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ mod signed_u256_test;
mod test_keccak256;
mod wad_ray_math_test;
mod zellers_congruence_test;
mod trigonometry_test;
51 changes: 51 additions & 0 deletions src/math/src/tests/trigonometry_test.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
use alexandria_math::trigonometry::fast_sin;
use alexandria_math::trigonometry::fast_cos;
use alexandria_math::trigonometry::fast_tan;

#[test]
#[available_gas(200000)]
fn sin_positive_test_1() {
assert(fast_sin(3000000000) == (true, 50000000), 'invalid result');
}

#[test]
#[available_gas(200000)]
fn sin_negative_test_1() {
assert(fast_sin(21000000000) == (false, 50000000), 'invalid result');
}

#[test]
#[available_gas(200000)]
fn sin_positive_test_2() {
assert(fast_sin(3500000000) == (true, 57367231), 'invalid result');
}

#[test]
#[available_gas(200000)]
fn sin_negative_test_2() {
assert(fast_sin(24300000000) == (false, 89101846), 'invalid result');
}

#[test]
#[available_gas(200000)]
fn sin_positive_test_3() {
assert(fast_sin(75000000000) == (true, 50000000), 'invalid result');
}

#[test]
#[available_gas(200000)]
fn cos_positive_test_1() {
assert(fast_cos(6000000000) == (true, 50000000), 'invalid result');
}

#[test]
#[available_gas(200000)]
fn cos_negative_test_1() {
assert(fast_cos(12000000000) == (false, 50000000), 'invalid result');
}

#[test]
#[available_gas(200000)]
fn tan_positive_test_1() {
assert(fast_tan(4500000000) == (true, 100000000), 'invalid result');
}
88 changes: 88 additions & 0 deletions src/math/src/trigonometry.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// Calculate fast sin(x)
// Since there is no float in cairo, we multiply every number by 1e8
// # Arguments
// * `x` - The number to calculate sin(x)
// # Returns
// * `bool` - true if the result is positive, false if the result is negative
// * `u64` - sin(x) * 1e8
// # Example
// * fast_sin(3000000000) = (true, 50000000)
fn fast_sin(x: u64) -> (bool, u64) {
Soptq marked this conversation as resolved.
Show resolved Hide resolved
let multipier = 100000000_u64;
let hollyst: u64 = 1745329_u64;
let sin_table = array![
0_u64, // sin(0)
17364818_u64, // sin(10)
34202014_u64, // sin(20)
50000000_u64, // sin(30)
64278761_u64, // sin(40)
76604444_u64, // sin(50)
86602540_u64, // sin(60)
93969262_u64, // sin(70)
98480775_u64, // sin(80)
100000000_u64 // sin(90)
];
let cos_table = array![
100000000_u64, // cos(0)
99984769_u64, // cos(1)
99939082_u64, // cos(2)
99862953_u64, // cos(3)
99756405_u64, // cos(4)
99619470_u64, // cos(5)
99452190_u64, // cos(6)
99254615_u64, // cos(7)
99026807_u64, // cos(8)
98768834_u64, // cos(9)
];

let mut a = x % (360_u64 * multipier);
let mut sig = true;
if a > (180_u64 * multipier) {
sig = false;
a = a - (180_u64 * multipier);
}

if a > (90_u64 * multipier) {
a = (180_u64 * multipier) - a;
}

let i: usize = (a / (10_u64 * multipier)).try_into().unwrap();
let j = a - i.into() * (10_u64 * multipier);
let int_j: usize = (j / multipier).try_into().unwrap();

let y = *sin_table[i] * *cos_table[int_j] / multipier + ((j * hollyst) / multipier) * *sin_table[9 - i] / multipier;

return (sig, y);
}

// Calculate fast cos(x)
// Since there is no float in cairo, we multiply every number by 1e8
// # Arguments
// * `x` - The number to calculate cos(x)
// # Returns
// * `bool` - true if the result is positive, false if the result is negative
// * `u64` - cos(x) * 1e8
// # Example
// * fast_cos(6000000000) = (true, 50000000)
fn fast_cos(x: u64) -> (bool, u64) {
let multipier = 100000000_u64;
Soptq marked this conversation as resolved.
Show resolved Hide resolved
return fast_sin(x + 90_u64 * multipier);
}

// Calculate fast tan(x)
// Since there is no float in cairo, we multiply every number by 1e8
// # Arguments
// * `x` - The number to calculate tan(x)
// # Returns
// * `bool` - true if the result is positive, false if the result is negative
// * `u64` - tan(x) * 1e8
// # Example
// * fast_tan(4500000000) = (true, 100000000)
fn fast_tan(x: u64) -> (bool, u64) {
Soptq marked this conversation as resolved.
Show resolved Hide resolved
let multipier = 100000000_u64;
let (sig_sin, sin) = fast_sin(x);
let (sig_cos, cos) = fast_cos(x);
let sig = sig_sin || sig_cos;
let value = sin * multipier / cos;
return (sig, value);
}
Loading