Skip to content

Commit

Permalink
!feat: enable new math functions
Browse files Browse the repository at this point in the history
use the new math functions introduced in sqlite 3.35.0
this replaces some of the existing functions

BREAKING-CHANGE: previously log() computed the natural logarithm, now it computes a base-10 logarithm
  • Loading branch information
gotson committed Aug 10, 2022
1 parent 2022752 commit 5555729
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 21 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ $(SQLITE_OUT)/sqlite3.o : $(SQLITE_UNPACKED)
-DSQLITE_ENABLE_FTS5 \
-DSQLITE_ENABLE_RTREE \
-DSQLITE_ENABLE_STAT4 \
-DSQLITE_ENABLE_MATH_FUNCTIONS \
-DSQLITE_THREADSAFE=1 \
-DSQLITE_DEFAULT_MEMSTATUS=0 \
-DSQLITE_DEFAULT_FILE_PERMISSIONS=0666 \
Expand Down
47 changes: 39 additions & 8 deletions src/main/ext/extension-functions.c
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@ static void name(sqlite3_context *context, int argc, sqlite3_value **argv){\
}\


#ifndef SQLITE_ENABLE_MATH_FUNCTIONS
/*
** Example of GEN_MATH_WRAP_DOUBLE_1 usage
** this creates function sqrtFunc to wrap the math.h standard function sqrt(x)=x^0.5
Expand All @@ -365,6 +366,7 @@ GEN_MATH_WRAP_DOUBLE_1(sqrtFunc, sqrt)
GEN_MATH_WRAP_DOUBLE_1(acosFunc, acos)
GEN_MATH_WRAP_DOUBLE_1(asinFunc, asin)
GEN_MATH_WRAP_DOUBLE_1(atanFunc, atan)
#endif

/*
** Many of systems don't have inverse hyperbolic trig functions so this will emulate
Expand All @@ -378,23 +380,29 @@ static double acosh(double x){
}
#endif

#ifndef SQLITE_ENABLE_MATH_FUNCTIONS
GEN_MATH_WRAP_DOUBLE_1(acoshFunc, acosh)
#endif

#ifndef HAVE_ASINH
static double asinh(double x){
return log(x + sqrt(x*x + 1.0));
}
#endif

#ifndef SQLITE_ENABLE_MATH_FUNCTIONS
GEN_MATH_WRAP_DOUBLE_1(asinhFunc, asinh)
#endif

#ifndef HAVE_ATANH
static double atanh(double x){
return (1.0/2.0)*log((1+x)/(1-x)) ;
}
#endif

#ifndef SQLITE_ENABLE_MATH_FUNCTIONS
GEN_MATH_WRAP_DOUBLE_1(atanhFunc, atanh)
#endif

/*
** math.h doesn't require cot (cotangent) so it's defined here
Expand All @@ -403,9 +411,12 @@ static double cot(double x){
return 1.0/tan(x);
}

#ifndef SQLITE_ENABLE_MATH_FUNCTIONS
GEN_MATH_WRAP_DOUBLE_1(sinFunc, sin)
GEN_MATH_WRAP_DOUBLE_1(cosFunc, cos)
GEN_MATH_WRAP_DOUBLE_1(tanFunc, tan)
#endif

GEN_MATH_WRAP_DOUBLE_1(cotFunc, cot)

static double coth(double x){
Expand All @@ -422,23 +433,29 @@ static double sinh(double x){
}
#endif

#ifndef SQLITE_ENABLE_MATH_FUNCTIONS
GEN_MATH_WRAP_DOUBLE_1(sinhFunc, sinh)
#endif

#ifndef HAVE_COSH
static double cosh(double x){
return (exp(x)+exp(-x))/2.0;
}
#endif

#ifndef SQLITE_ENABLE_MATH_FUNCTIONS
GEN_MATH_WRAP_DOUBLE_1(coshFunc, cosh)
#endif

#ifndef HAVE_TANH
static double tanh(double x){
return sinh(x)/cosh(x);
}
#endif

#ifndef SQLITE_ENABLE_MATH_FUNCTIONS
GEN_MATH_WRAP_DOUBLE_1(tanhFunc, tanh)
#endif

GEN_MATH_WRAP_DOUBLE_1(cothFunc, coth)

Expand All @@ -456,9 +473,11 @@ static double log10(double x){
}
#endif

#ifndef SQLITE_ENABLE_MATH_FUNCTIONS
GEN_MATH_WRAP_DOUBLE_1(logFunc, log)
GEN_MATH_WRAP_DOUBLE_1(log10Func, log10)
GEN_MATH_WRAP_DOUBLE_1(expFunc, exp)
#endif

/*
** Fallback for systems where math.h doesn't define M_PI
Expand All @@ -472,6 +491,7 @@ GEN_MATH_WRAP_DOUBLE_1(expFunc, exp)
#define M_PI 3.14159265358979323846
#endif

#ifndef SQLITE_ENABLE_MATH_FUNCTIONS
/* Convert Degrees into Radians */
static double deg2rad(double x){
return x*M_PI/180.0;
Expand All @@ -484,11 +504,14 @@ static double rad2deg(double x){

GEN_MATH_WRAP_DOUBLE_1(rad2degFunc, rad2deg)
GEN_MATH_WRAP_DOUBLE_1(deg2radFunc, deg2rad)
#endif

#ifndef SQLITE_ENABLE_MATH_FUNCTIONS
/* constant function that returns the value of PI=3.1415... */
static void piFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
sqlite3_result_double(context, M_PI);
}
#endif

/*
** Implements the sqrt function, it has the peculiarity of returning an integer when the
Expand Down Expand Up @@ -517,6 +540,7 @@ static void squareFunc(sqlite3_context *context, int argc, sqlite3_value **argv)
}
}

#ifndef SQLITE_ENABLE_MATH_FUNCTIONS
/*
** Wraps the pow math.h function
** When both the base and the exponent are integers the result should be integer
Expand Down Expand Up @@ -546,6 +570,7 @@ static void powerFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
}
}
}
#endif

/*
** atan2 wrapper
Expand Down Expand Up @@ -1703,45 +1728,51 @@ int RegisterExtensionFunctions(sqlite3 *db){
u8 needCollSeq;
void (*xFunc)(sqlite3_context*,int,sqlite3_value **);
} aFuncs[] = {
#ifndef SQLITE_ENABLE_MATH_FUNCTIONS
/* math.h */
{ "acos", 1, 0, SQLITE_UTF8, 0, acosFunc },
{ "asin", 1, 0, SQLITE_UTF8, 0, asinFunc },
{ "atan", 1, 0, SQLITE_UTF8, 0, atanFunc },
{ "atn2", 2, 0, SQLITE_UTF8, 0, atn2Func },
/* XXX alias */
{ "atan2", 2, 0, SQLITE_UTF8, 0, atn2Func },
{ "acosh", 1, 0, SQLITE_UTF8, 0, acoshFunc },
{ "asinh", 1, 0, SQLITE_UTF8, 0, asinhFunc },
{ "atanh", 1, 0, SQLITE_UTF8, 0, atanhFunc },

{ "difference", 2, 0, SQLITE_UTF8, 0, differenceFunc},
{ "degrees", 1, 0, SQLITE_UTF8, 0, rad2degFunc },
{ "radians", 1, 0, SQLITE_UTF8, 0, deg2radFunc },

{ "cos", 1, 0, SQLITE_UTF8, 0, cosFunc },
{ "sin", 1, 0, SQLITE_UTF8, 0, sinFunc },
{ "tan", 1, 0, SQLITE_UTF8, 0, tanFunc },
{ "cot", 1, 0, SQLITE_UTF8, 0, cotFunc },

{ "cosh", 1, 0, SQLITE_UTF8, 0, coshFunc },
{ "sinh", 1, 0, SQLITE_UTF8, 0, sinhFunc },
{ "tanh", 1, 0, SQLITE_UTF8, 0, tanhFunc },
{ "coth", 1, 0, SQLITE_UTF8, 0, cothFunc },

{ "exp", 1, 0, SQLITE_UTF8, 0, expFunc },
{ "log", 1, 0, SQLITE_UTF8, 0, logFunc },
{ "log10", 1, 0, SQLITE_UTF8, 0, log10Func },
{ "power", 2, 0, SQLITE_UTF8, 0, powerFunc },
#if SQLITE_VERSION_NUMBER < 3035000
{ "sign", 1, 0, SQLITE_UTF8, 0, signFunc },
#endif

{ "sqrt", 1, 0, SQLITE_UTF8, 0, sqrtFunc },
{ "square", 1, 0, SQLITE_UTF8, 0, squareFunc },

{ "ceil", 1, 0, SQLITE_UTF8, 0, ceilFunc },
{ "floor", 1, 0, SQLITE_UTF8, 0, floorFunc },

{ "pi", 0, 0, SQLITE_UTF8, 1, piFunc },
#endif
{ "atn2", 2, 0, SQLITE_UTF8, 0, atn2Func },

{ "difference", 2, 0, SQLITE_UTF8, 0, differenceFunc},

{ "cot", 1, 0, SQLITE_UTF8, 0, cotFunc },
{ "coth", 1, 0, SQLITE_UTF8, 0, cothFunc },

#if SQLITE_VERSION_NUMBER < 3035000
{ "sign", 1, 0, SQLITE_UTF8, 0, signFunc },
#endif
{ "square", 1, 0, SQLITE_UTF8, 0, squareFunc },

/* string */
{ "replicate", 2, 0, SQLITE_UTF8, 0, replicateFunc },
Expand Down
89 changes: 76 additions & 13 deletions src/test/java/org/sqlite/MathFunctionsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,18 @@ public void atanh() throws Exception {

@Test
public void ceil() throws Exception {
ResultSet rs = stat.executeQuery("select ceil(0.5)");
assertTrue(rs.next());
assertEquals(1.0, rs.getDouble(1));
rs.close();
{
ResultSet rs = stat.executeQuery("select ceil(0.5)");
assertTrue(rs.next());
assertEquals(1.0, rs.getDouble(1));
rs.close();
}
{
ResultSet rs = stat.executeQuery("select ceiling(0.5)");
assertTrue(rs.next());
assertEquals(1.0, rs.getDouble(1));
rs.close();
}
}

@Test
Expand Down Expand Up @@ -156,22 +164,53 @@ public void floor() throws Exception {
}

@Test
// this actually performs ln()
public void log() throws Exception {
ResultSet rs = stat.executeQuery("select log(2)");
public void ln() throws Exception {
ResultSet rs = stat.executeQuery("select ln(2)");
assertTrue(rs.next());
assertEquals(0.693147180559945, rs.getDouble(1), 0.000000000000001);
rs.close();
}

@Test
public void log10() throws Exception {
ResultSet rs = stat.executeQuery("select log10(10)");
public void log() throws Exception {
ResultSet rs = stat.executeQuery("select log(3,3)");
assertTrue(rs.next());
assertEquals(1, rs.getDouble(1));
rs.close();
}

@Test
public void log2() throws Exception {
ResultSet rs = stat.executeQuery("select log2(2)");
assertTrue(rs.next());
assertEquals(1, rs.getDouble(1));
rs.close();
}

@Test
public void log10() throws Exception {
{
ResultSet rs = stat.executeQuery("select log10(10)");
assertTrue(rs.next());
assertEquals(1, rs.getDouble(1));
rs.close();
}
{
ResultSet rs = stat.executeQuery("select log(10)");
assertTrue(rs.next());
assertEquals(1, rs.getDouble(1));
rs.close();
}
}

@Test
public void mod() throws Exception {
ResultSet rs = stat.executeQuery("select mod(11,3.5)");
assertTrue(rs.next());
assertEquals(0.5, rs.getDouble(1));
rs.close();
}

@Test
public void pi() throws Exception {
ResultSet rs = stat.executeQuery("select pi()");
Expand All @@ -182,10 +221,18 @@ public void pi() throws Exception {

@Test
public void power() throws Exception {
ResultSet rs = stat.executeQuery("select power(10,2)");
assertTrue(rs.next());
assertEquals(100, rs.getDouble(1));
rs.close();
{
ResultSet rs = stat.executeQuery("select pow(10,2)");
assertTrue(rs.next());
assertEquals(100, rs.getDouble(1));
rs.close();
}
{
ResultSet rs = stat.executeQuery("select power(10,2)");
assertTrue(rs.next());
assertEquals(100, rs.getDouble(1));
rs.close();
}
}

@Test
Expand Down Expand Up @@ -243,4 +290,20 @@ public void tanh() throws Exception {
assertEquals(0.46211715726001, rs.getDouble(1), 0.000000000000001);
rs.close();
}

@Test
public void trunc() throws Exception {
{
ResultSet rs = stat.executeQuery("select trunc(1.5)");
assertTrue(rs.next());
assertEquals(1, rs.getDouble(1));
rs.close();
}
{
ResultSet rs = stat.executeQuery("select trunc(-1.5)");
assertTrue(rs.next());
assertEquals(-1, rs.getDouble(1));
rs.close();
}
}
}

0 comments on commit 5555729

Please sign in to comment.