diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2020-11-21 16:46:43 -0500 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2020-11-21 16:46:43 -0500 |
commit | 8597a48d01b6cc0b09ff626253ac93c67e5516d5 (patch) | |
tree | d5a9484437ac6162b248c3290edf22ebf998f1c1 /src/backend/utils/adt/geo_ops.c | |
parent | a45272b25d6fc8f96793623545fc1f836ac39d94 (diff) | |
download | postgresql-8597a48d01b6cc0b09ff626253ac93c67e5516d5.tar.gz postgresql-8597a48d01b6cc0b09ff626253ac93c67e5516d5.zip |
Fix FPeq() and friends to get the right answers for infinities.
"FPeq(infinity, infinity)" returned false, on account of getting NaN
when it subtracts the two inputs. Fix that by adding a separate
check for exact equality.
FPle() and FPge() similarly got the wrong answer for two like-signed
infinities. In those cases, we can just rearrange the comparisons
to avoid potentially subtracting infinities.
While the sibling functions FPne() etc accidentally gave the right
answers even with the internal NaN results, it seems best to make
similar adjustments to them to avoid depending on this.
FPeq() has to be converted to an inline function to avoid double
evaluations of its arguments, and I did the same for the others
just for consistency.
In passing, make the handling of NaN cases in line_eq() and
point_eq_point() simpler and easier to reason about, and perhaps
faster.
This results in just one visible regression test change: slope()
now gives DBL_MAX for two inputs of (inf,1e300), which is consistent
with what it does for (1e300,inf), so that seems like a bug fix.
Discussion: https://postgr.es/m/CAGf+fX70rWFOk5cd00uMfa__0yP+vtQg5ck7c2Onb-Yczp0URA@mail.gmail.com
Diffstat (limited to 'src/backend/utils/adt/geo_ops.c')
-rw-r--r-- | src/backend/utils/adt/geo_ops.c | 39 |
1 files changed, 22 insertions, 17 deletions
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c index a7db7839588..82286ef87a3 100644 --- a/src/backend/utils/adt/geo_ops.c +++ b/src/backend/utils/adt/geo_ops.c @@ -1155,9 +1155,6 @@ line_horizontal(PG_FUNCTION_ARGS) /* * Check whether the two lines are the same - * - * We consider NaNs values to be equal to each other to let those lines - * to be found. */ Datum line_eq(PG_FUNCTION_ARGS) @@ -1166,21 +1163,28 @@ line_eq(PG_FUNCTION_ARGS) LINE *l2 = PG_GETARG_LINE_P(1); float8 ratio; - if (!FPzero(l2->A) && !isnan(l2->A)) + /* If any NaNs are involved, insist on exact equality */ + if (unlikely(isnan(l1->A) || isnan(l1->B) || isnan(l1->C) || + isnan(l2->A) || isnan(l2->B) || isnan(l2->C))) + { + PG_RETURN_BOOL(float8_eq(l1->A, l2->A) && + float8_eq(l1->B, l2->B) && + float8_eq(l1->C, l2->C)); + } + + /* Otherwise, lines whose parameters are proportional are the same */ + if (!FPzero(l2->A)) ratio = float8_div(l1->A, l2->A); - else if (!FPzero(l2->B) && !isnan(l2->B)) + else if (!FPzero(l2->B)) ratio = float8_div(l1->B, l2->B); - else if (!FPzero(l2->C) && !isnan(l2->C)) + else if (!FPzero(l2->C)) ratio = float8_div(l1->C, l2->C); else ratio = 1.0; - PG_RETURN_BOOL((FPeq(l1->A, float8_mul(ratio, l2->A)) && - FPeq(l1->B, float8_mul(ratio, l2->B)) && - FPeq(l1->C, float8_mul(ratio, l2->C))) || - (float8_eq(l1->A, l2->A) && - float8_eq(l1->B, l2->B) && - float8_eq(l1->C, l2->C))); + PG_RETURN_BOOL(FPeq(l1->A, float8_mul(ratio, l2->A)) && + FPeq(l1->B, float8_mul(ratio, l2->B)) && + FPeq(l1->C, float8_mul(ratio, l2->C))); } @@ -1930,15 +1934,16 @@ point_ne(PG_FUNCTION_ARGS) /* * Check whether the two points are the same - * - * We consider NaNs coordinates to be equal to each other to let those points - * to be found. */ static inline bool point_eq_point(Point *pt1, Point *pt2) { - return ((FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y)) || - (float8_eq(pt1->x, pt2->x) && float8_eq(pt1->y, pt2->y))); + /* If any NaNs are involved, insist on exact equality */ + if (unlikely(isnan(pt1->x) || isnan(pt1->y) || + isnan(pt2->x) || isnan(pt2->y))) + return (float8_eq(pt1->x, pt2->x) && float8_eq(pt1->y, pt2->y)); + + return (FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y)); } |