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(fronted): cotd implementation #9259

Merged
merged 9 commits into from
Apr 24, 2023
68 changes: 68 additions & 0 deletions e2e_test/batch/functions/trigonometric_funcs.slt.part
Original file line number Diff line number Diff line change
Expand Up @@ -429,5 +429,73 @@ SELECT abs(tand(-120) + -1.7320508075688772) < 0.000000000000001
----
t

query R
SELECT abs(cotd(45) - 1) < 0.000000000000001;
----
t

query R
SELECT abs(cotd(60) - 0.5773502691896257) < 0.000000000000001;
----
t

query R
SELECT cotd(90);
----
0

query R
SELECT abs(cotd(-45) + 1) < 0.000000000000001;
----
t

query R
SELECT abs(cotd(-60) + 0.5773502691896257) < 0.000000000000001;
----
t

query R
SELECT cotd(-90);
----
0

query R
SELECT abs(cotd(30) - 1.7320508075688772) < 0.000000000000001;
----
t

query R
SELECT abs(cotd(-30) + 1.7320508075688772) < 0.000000000000001;
----
t


query R
SELECT abs(cotd(120) + 0.5773502691896255) < 0.000000000000001;
----
t

query R
SELECT abs(cotd(-120) - 0.5773502691896255) < 0.000000000000001;
----
t

query R
SELECT cotd(('-Inf'))
----
NaN

query R
SELECT cotd(('Inf'))
----
NaN

query R
SELECT cotd('NaN')
----
NaN

query R
SELECT cotd('-NaN')
----
NaN
9 changes: 5 additions & 4 deletions proto/expr.proto
Original file line number Diff line number Diff line change
Expand Up @@ -113,10 +113,11 @@ message ExprNode {
ATAN2 = 252;
SIND = 253;
COSD = 254;
TAND = 255;
SQRT = 256;
DEGREES = 257;
RADIANS = 258;
COTD = 255;
TAND = 256;
SQRT = 257;
DEGREES = 258;
RADIANS = 259;

// Boolean comparison
IS_TRUE = 301;
Expand Down
75 changes: 68 additions & 7 deletions src/expr/src/vector_op/trigonometric.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,24 +60,25 @@ pub fn atan2_f64(input_x: F64, input_y: F64) -> F64 {
static RADIANS_PER_DEGREE: f64 = 0.017_453_292_519_943_295;
// Constants we use to get more accurate results.
// See PSQL: https://github.com/postgres/postgres/blob/78ec02d612a9b69039ec2610740f738968fe144d/src/backend/utils/adt/float.c#L2024
static SIN_30: f64 = 0.499_999_999_999_999_94;
static ONE_MINUS_COS_60: f64 = 0.499_999_999_999_999_9;
static TAN_45: f64 = 1.0;
static SIND_30: f64 = 0.499_999_999_999_999_94;
static ONE_MINUS_COSD_60: f64 = 0.499_999_999_999_999_9;
static TAND_45: f64 = 1.0;
static COTD_45: f64 = 1.0;
Comment on lines +63 to +66
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

renamed these to make sure that we are talking about degrees and not radians


// returns the cosine of an angle that lies between 0 and 60 degrees. This will return exactly 1
// when xi s 0, and exactly 0.5 when x is 60 degrees.
fn cosd_0_to_60(x: f64) -> f64 {
// https://github.com/postgres/postgres/blob/REL_15_2/src/backend/utils/adt/float.c
let one_minus_cos_x: f64 = 1.0 - f64::cos(x * RADIANS_PER_DEGREE);
1.0 - (one_minus_cos_x / ONE_MINUS_COS_60) / 2.0
1.0 - (one_minus_cos_x / ONE_MINUS_COSD_60) / 2.0
}

// returns the sine of an angle that lies between 0 and 30 degrees. This will return exactly 0 when
// x is 0, and exactly 0.5 when x is 30 degrees.
fn sind_0_to_30(x: f64) -> f64 {
// https://github.com/postgres/postgres/blob/REL_15_2/src/backend/utils/adt/float.c
let sin_x = f64::sin(x * RADIANS_PER_DEGREE);
(sin_x / SIN_30) / 2.0
(sin_x / SIND_30) / 2.0
}

// returns the cosine of an angle in the first quadrant (0 to 90 degrees).
Expand Down Expand Up @@ -184,6 +185,47 @@ pub fn sind_f64(input: F64) -> F64 {
}
}

#[function("cotd(float64) -> float64")]
pub fn cotd_f64(input: F64) -> F64 {
// PSQL implementation: https://github.com/postgres/postgres/blob/78ec02d612a9b69039ec2610740f738968fe144d/src/backend/utils/adt/float.c#L2378

// Returns NaN if input is NaN or infinite. Different from PSQL implementation.
if input.0.is_nan() || input.0.is_infinite() {
return f64::NAN.into();
}

let mut arg1 = input.0 % 360.0;
let mut sign = 1.0;

if arg1 < 0.0 {
// cotd(-x) = -cotd(x)
arg1 = -arg1;
sign = -sign;
}

if arg1 > 180.0 {
// cotd(360-x) = -cotd(x)
arg1 = 360.0 - arg1;
sign = -sign;
}

if arg1 > 90.0 {
// cotd(180-x) = -cotd(x)
arg1 = 180.0 - arg1;
sign = -sign;
}

let cot_arg1 = cosd_q1(arg1) / sind_q1(arg1);
let result = sign * (cot_arg1 / COTD_45);

// On some machines we get cotd(270) = minus zero, but this isn't always
// true. For portability, and because the user constituency for this
// function probably doesn't want minus zero, force it to plain zero.
let result = if result == 0.0 { 0.0 } else { result };
// Not checking for overflow because cotd(0) == Inf
result.into()
}

#[function("tand(float64) -> float64")]
pub fn tand_f64(input: F64) -> F64 {
// PSQL implementation: https://github.com/postgres/postgres/blob/REL_15_2/src/backend/utils/adt/float.c
Expand Down Expand Up @@ -219,7 +261,7 @@ pub fn tand_f64(input: F64) -> F64 {
}

let tan_arg1 = sind_q1(arg1) / cosd_q1(arg1);
let result = sign * (tan_arg1 / TAN_45);
let result = sign * (tan_arg1 / TAND_45);

// On some machines we get tand(180) = minus zero, but this isn't always
// true. For portability, and because the user constituency for this
Expand All @@ -240,9 +282,9 @@ pub fn radians_f64(input: F64) -> F64 {

#[cfg(test)]
mod tests {

use std::f64::consts::PI;

use num_traits::Float;
use risingwave_common::types::F64;

use crate::vector_op::trigonometric::*;
Expand Down Expand Up @@ -300,6 +342,25 @@ mod tests {
assert_eq!(cosd_f64(F64::from(0)).0, 1.0);
assert_eq!(cosd_f64(F64::from(90)).0, 0.0);

// cotd
assert_eq!(F64::from(-f64::INFINITY), cotd_f64(d));
assert!(cotd_f64(F64::from(-180)).is_infinite());
assert!(
(cotd_f64(F64::from(-190)) + F64::from(5.671281819617705))
.abs()
.0
<= 0.00000000000001,
);
assert_similar(cot_f64(50_f64.to_radians().into()), cotd_f64(F64::from(50)));
assert_similar(
cot_f64(100_f64.to_radians().into()),
cotd_f64(F64::from(100)),
);
assert_similar(
cot_f64(250_f64.to_radians().into()),
cotd_f64(F64::from(250)),
);

// tand
assert_similar(
tan_f64((-10_f64).to_radians().into()),
Expand Down
1 change: 1 addition & 0 deletions src/frontend/src/binder/expr/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,7 @@ impl Binder {
("atan2", raw_call(ExprType::Atan2)),
("sind", raw_call(ExprType::Sind)),
("cosd", raw_call(ExprType::Cosd)),
("cotd", raw_call(ExprType::Cotd)),
("tand", raw_call(ExprType::Tand)),
("degrees", raw_call(ExprType::Degrees)),
("radians", raw_call(ExprType::Radians)),
Expand Down
3 changes: 2 additions & 1 deletion src/frontend/src/expr/pure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,9 @@ impl ExprVisitor<bool> for ImpureAnalyzer {
| expr_node::Type::Pi
| expr_node::Type::Sind
| expr_node::Type::Cosd
| expr_node::Type::Encode
| expr_node::Type::Cotd
| expr_node::Type::Decode
| expr_node::Type::Encode
| expr_node::Type::Tand
| expr_node::Type::ArrayPositions
| expr_node::Type::StringToArray =>
Expand Down