FalkorDB / FalkorDB

A super fast Graph Database uses GraphBLAS under the hood for its sparse adjacency matrix graph representation. Our goal is to provide the best Knowledge Graph for LLM (GraphRAG).
https://www.falkordb.com/
Other
467 stars 17 forks source link

Support round(expression, precision), round(expression, precision, mode) #309

Open gkorland opened 8 months ago

gkorland commented 8 months ago

Created by: @LiorKogan Source: https://github.com/RedisGraph/RedisGraph/issues/2614 Currently, RedisGraph does not support the following arguments combinations for round():

round(expression, precision)
round(expression, precision, mode)
gkorland commented 8 months ago

Origin comment by: @LiorKogan https://neo4j.com/docs/cypher-manual/current/functions/mathematical-numeric/#functions-round2

gkorland commented 8 months ago

Origin comment by: @exitflynn i'd like to work on this issue!

gkorland commented 8 months ago

Origin comment by: @Khalid6468

https://neo4j.com/docs/cypher-manual/current/functions/mathematical-numeric/#functions-round2

@LiorKogan Please confirm if the given descriptions about different modes in this documentation are correct or not? I made changes as per this documentations definitions for all the modes.

gkorland commented 8 months ago

Origin comment by: @LiorKogan Reference implementation for HalfDown, HalfEven, and AwayFromZero rounding:

// round towards closest integer, with half-values always being rounded down
double RoundHalfDown(double f)
{
    double int_part;
    double frac_part = modf(f, &int_part);

    if (frac_part <= -0.5) return int_part - 1.0;
    if (frac_part <=  0.5) return int_part      ;
                           return int_part + 1.0;
}

// round towards closest integer, with half-values being rounded to the even neighbor
double RoundHalfEven(double f)
{
    double int_part;
    double frac_part = modf(f, &int_part);

    if ((frac_part == -0.5) || (frac_part == 0.5))
        return round(f * 0.5) * 2.0;

    if (frac_part < -0.5) return int_part - 1.0;
    if (frac_part <  0.5) return int_part      ;
                          return int_part + 1.0;
}

// round away from zero
double RoundAwayFromZero(double f)
{
    double int_part;
    double frac_part = modf(f, &int_part);

    if (frac_part < 0) return int_part - 1.0;
    if (frac_part > 0) return int_part + 1.0;
                       return int_part      ;
}
gkorland commented 8 months ago

Origin comment by: @LiorKogan @Khalid6468

I think there are some problems with their convention. Their naming makes sense only for positive numbers. They also have a bug with HALF_DOWN and negative x.5 numbers.

I would suggest the following:

Keep compatibility with

but the following are simply wrong:

gkorland commented 8 months ago

Origin comment by: @Khalid6468 Okay. Thanks for confirming.

gkorland commented 8 months ago

Origin comment by: @Khalid6468 @LiorKogan Done with the implementation. Please have a look at the PR #2668. Here are the sample outputs for the round function:

127.0.0.1:6379> GRAPH.QUERY social "RETURN round(3.14)" 1) 1) "round(3.14)" 2) 1) 1) "3" 127.0.0.1:6379> GRAPH.QUERY social "RETURN round(3.14653, 3)" 1) 1) "round(3.14653, 3)" 2) 1) 1) "3.147" 127.0.0.1:6379> GRAPH.QUERY social "RETURN round(3.1465, 3, 'HALF_UP')" 1) 1) "round(3.1465, 3, 'HALF_UP')" 2) 1) 1) "3.147" 127.0.0.1:6379> GRAPH.QUERY social "RETURN round(3.1465, 3, 'HALF_DOWN')" 1) 1) "round(3.1465, 3, 'HALF_DOWN')" 2) 1) 1) "3.146" 127.0.0.1:6379> GRAPH.QUERY social "RETURN round(3.1465, 3, 'HALF_EVEN')" 1) 1) "round(3.1465, 3, 'HALF_EVEN')" 2) 1) 1) "3.146" 127.0.0.1:6379> GRAPH.QUERY social "RETURN round(3.1365, 3, 'HALF_EVEN')" 1) 1) "round(3.1365, 3, 'HALF_EVEN')" 2) 1) 1) "3.136" 127.0.0.1:6379> GRAPH.QUERY social "RETURN round(3.1355, 3, 'HALF_EVEN')" 1) 1) "round(3.1355, 3, 'HALF_EVEN')" 2) 1) 1) "3.136" 127.0.0.1:6379> GRAPH.QUERY social "RETURN round(3.1351, 3, 'CEILING')" 1) 1) "round(3.1351, 3, 'CEILING')" 2) 1) 1) "3.136" 127.0.0.1:6379> GRAPH.QUERY social "RETURN round(3.1359, 3, 'CEILING')" 1) 1) "round(3.1359, 3, 'CEILING')" 2) 1) 1) "3.136" 127.0.0.1:6379> GRAPH.QUERY social "RETURN round(3.1359, 3, 'FLOOR')" 1) 1) "round(3.1359, 3, 'FLOOR')" 2) 1) 1) "3.135" 127.0.0.1:6379> GRAPH.QUERY social "RETURN round(3.1351, 3, 'FLOOR')" 1) 1) "round(3.1351, 3, 'FLOOR')" 2) 1) 1) "3.135" 127.0.0.1:6379> GRAPH.QUERY social "RETURN round(3.1351, 3, 'AWAY_FROM_ZERO')" 1) 1) "round(3.1351, 3, 'AWAY_FROM_ZERO')" 2) 1) 1) "3.136" 127.0.0.1:6379> GRAPH.QUERY social "RETURN round(3.1351, 3, 'TOWARD_ZERO')" 1) 1) "round(3.1351, 3, 'TOWARD_ZERO')" 2) 1) 1) "3.135" 127.0.0.1:6379> GRAPH.QUERY social "RETURN round(0.0, 3, 'TOWARD_ZERO')" 1) 1) "round(0.0, 3, 'TOWARD_ZERO')" 2) 1) 1) "0"

gkorland commented 8 months ago

Origin comment by: @LiorKogan @Khalid6468 thank you. We'll review. Please make sure there are tests specifically for -1.5, -0.5, 0.5, and 1.5. Also for NaN, -INF, +INF, and large inputs (e.g., 1.7E308).